Skip to content

Commit

Permalink
Display APIs version in UI (#21)
Browse files Browse the repository at this point in the history
* added ca import with hierarchy relation

Signed-off-by: Haritz S. Sierra <[email protected]>

* adding Info UI for API version details

Signed-off-by: Haritz S. Sierra <[email protected]>

---------

Signed-off-by: Haritz S. Sierra <[email protected]>
  • Loading branch information
haritzsaiz authored Feb 13, 2024
1 parent cb5828e commit be98b9b
Show file tree
Hide file tree
Showing 10 changed files with 204 additions and 52 deletions.
3 changes: 2 additions & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ jobs:
with:
context: .
build-args: |
BASE_IMAGE=alpine:3.14
SHA1VER=${{ env.SHA1VER }}
VERSION=${{ github.event.inputs.release_version }}
tags: |
ghcr.io/lamassuiot/lamassu-ui:${{ github.event.inputs.release_version }}
ghcr.io/lamassuiot/lamassu-ui:latest
Expand Down
9 changes: 9 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,17 @@ LABEL authors="[email protected]"
COPY --from=build /app/build /usr/share/nginx/html
COPY ./nginx.conf /etc/nginx/conf.d/server.conf

ARG SHA1VER= # set by build script
ARG VERSION= # set by build script

WORKDIR /usr/share/nginx/html
COPY ./env-docker-config.js /tmpl/env-config.js.tmpl

RUN now=$(TZ=GMT date +"%Y-%m-%dT%H:%M:%SZ") && \
sed -i "s/XXX_UI_VERSION/$VERSION/g" "/tmpl/env-config.js.tmpl" && \
sed -i "s/XXX_BUILD_ID/$SHA1VER/g" "/tmpl/env-config.js.tmpl" && \
sed -i "s/XXX_BUILD_TIME/$now/g" "/tmpl/env-config.js.tmpl"

COPY ./docker-entrypoint.sh /docker-entrypoint.sh
RUN chmod +x /docker-entrypoint.sh

Expand Down
7 changes: 7 additions & 0 deletions env-docker-config.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
window._env_ = {
INFO: {
UI_VERSION: "XXX_UI_VERSION",
BUILD_ID: "XXX_BUILD_ID",
BUILD_TIME: "XXX_BUILD_TIME",
CHART_VERSION: "${CHART_VERSION}",
HELM_REVISION: "${HELM_REVISION}",
},
AUTH_COGNITO_ENABLED: "${COGNITO_ENABLED}",
AUTH_COGNITO_HOSTED_UI_DOMAIN: "${COGNITO_HOSTED_UI_DOMAIN}",
AUTH_OIDC_AUTHORITY: "${OIDC_AUTHORITY}",
Expand Down
8 changes: 8 additions & 0 deletions src/ducks/features/alerts/apicalls.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
import { apiRequest } from "ducks/services/api";
import { Event, SubChannel, Subscription, SubscriptionCondition } from "./models";
import { APIServiceInfo } from "ducks/models";

export const getApiInfo = async (): Promise<APIServiceInfo> => {
return apiRequest({
method: "GET",
url: `${window._env_.LAMASSU_ALERTS}/health`
}) as Promise<APIServiceInfo>;
};

export const getEvents = async (): Promise<Array<Event>> => {
return apiRequest({
Expand Down
9 changes: 8 additions & 1 deletion src/ducks/features/cav3/apicalls.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
import { apiRequest, queryParametersToURL } from "ducks/services/api";
import * as models from "./models";
import { ListResponse, QueryParameters } from "ducks/models";
import { APIServiceInfo, ListResponse, QueryParameters } from "ducks/models";

export const getApiInfo = async (): Promise<APIServiceInfo> => {
return apiRequest({
method: "GET",
url: `${window._env_.LAMASSU_CA_API}/health`
}) as Promise<APIServiceInfo>;
};

export const getStats = async (): Promise<models.CAStats> => {
return apiRequest({
Expand Down
9 changes: 8 additions & 1 deletion src/ducks/features/devices/apicalls.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
import { ListResponse, QueryParameters } from "ducks/models";
import { APIServiceInfo, ListResponse, QueryParameters } from "ducks/models";
import { apiRequest, queryParametersToURL } from "ducks/services/api";
import { CreateDevicePayload, Device, DeviceStats, Slot } from "./models";

export const getApiInfo = async (): Promise<APIServiceInfo> => {
return apiRequest({
method: "GET",
url: `${window._env_.LAMASSU_DEVMANAGER}/health`
}) as Promise<APIServiceInfo>;
};

export const getStats = async (): Promise<DeviceStats> => {
return apiRequest({
method: "GET",
Expand Down
9 changes: 8 additions & 1 deletion src/ducks/features/ra/apicalls.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
import { ListResponse, QueryParameters } from "ducks/models";
import { APIServiceInfo, ListResponse, QueryParameters } from "ducks/models";
import { apiRequest, queryParametersToURL } from "ducks/services/api";
import { BindResponse, CreateUpdateDMSPayload, DMS, DMSStats } from "./models";

export const getApiInfo = async (): Promise<APIServiceInfo> => {
return apiRequest({
method: "GET",
url: `${window._env_.LAMASSU_DMS_MANAGER_API}/health`
}) as Promise<APIServiceInfo>;
};

export const getStats = async (): Promise<DMSStats> => {
return apiRequest({
method: "GET",
Expand Down
7 changes: 7 additions & 0 deletions src/ducks/models.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@

export type QueryParameters = {
bookmark: string
filters: string[]
Expand All @@ -12,3 +13,9 @@ export interface ListResponse<T> {
next: string,
list: T[]
}

export interface APIServiceInfo{
build: string,
build_time: string,
version: string
}
5 changes: 5 additions & 0 deletions src/theme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ export const light: any = {
gray: {
main: "#EFF0F2"
},
blue: {
light: "#184d60", // 184d60 4a6952
main: "#0068D1", // 2099C6 25ee32
dark: "#104c63" // 104c63 2F6140
},
scrollbar: {
thumb: "#555555",
track: "#EEEEEE"
Expand Down
190 changes: 142 additions & 48 deletions src/views/Info/index.tsx
Original file line number Diff line number Diff line change
@@ -1,76 +1,170 @@
import { Box, Divider, Grid, Paper, Typography, useTheme } from "@mui/material";
import CheckCircleIcon from "@mui/icons-material/CheckCircle";
import { useEffect } from "react";
import { useDispatch } from "react-redux";
import { useEffect, useState } from "react";
import { apicalls } from "ducks/apicalls";
import { LamassuChip } from "components/LamassuComponents/Chip";
import moment from "moment";

type ServiceInfo = {
name: string
version: string
build_time: string
build: string
loading: boolean
}

export const InfoView = () => {
const theme = useTheme();

const dispatch = useDispatch();
const [servicesInfo, setServicesInfo] = useState<Array<ServiceInfo>>([]);

const refreshAction = async () => {
const services = [
{ name: "CA", fetcher: apicalls.cas.getApiInfo },
{ name: "DMS Manager", fetcher: apicalls.dms.getApiInfo },
{ name: "Device Manager", fetcher: apicalls.devices.getApiInfo },
{ name: "Alerts", fetcher: apicalls.alerts.getApiInfo }
];

const initSvc : Array<ServiceInfo> = [];
for (let i = 0; i < services.length; i++) {
const svc = services[i];
initSvc.push({
name: svc.name,
build: "-",
build_time: "-",
version: "-",
loading: true
});
}

setServicesInfo([...initSvc]);

const refreshAction = () => {
// dispatch(alertsAction.getInfoAction.request());
for (let i = 0; i < services.length; i++) {
const svc = services[i];
const fetcher = svc.fetcher;
const apiInfo = await fetcher();
initSvc[i] = {
name: initSvc[i].name,
build: apiInfo.build,
build_time: apiInfo.build_time,
version: apiInfo.version,
loading: false
};

setServicesInfo([...initSvc]);
}
};

useEffect(() => {
refreshAction();
}, []);

const alertsInfo: Array<[string, any]> = [
["Build Version", "-1"],
["Build Time", "-1"]
];

const servicesInfo = [
{ service: "Alerts", info: alertsInfo }
];

return (
<Box sx={{ display: "flex", flexDirection: "column", height: "100%" }}>
<Grid sx={{ overflowY: "auto", flexGrow: 1, height: "300px" }} component={Paper}>
<Box style={{ display: "flex", flexDirection: "column", height: "100%" }}>
<Box style={{ padding: "40px" }}>
<Grid container spacing={2} flexDirection={"column"}>
<Grid container spacing={3} flexDirection={"column"}>
<Grid item container>
<Grid item>
<Typography style={{ color: theme.palette.primary.main, fontWeight: "500", fontSize: 30, lineHeight: "24px", marginRight: "10px" }}>UI</Typography>
</Grid>

<Grid item container spacing={0} justifyContent="space-between">
<Grid item xs={6}>
<Typography style={{ color: theme.palette.text.primary, fontWeight: "500", fontSize: 13, marginTop: "10px" }}>Version</Typography>
</Grid>
<Grid item xs={6}>
<LamassuChip color={"blue"} label={window._env_.INFO.UI_VERSION} />
</Grid>
<Grid item xs={6}>
<Typography style={{ color: theme.palette.text.primary, fontWeight: "500", fontSize: 13, marginTop: "10px" }}>Build Time</Typography>
</Grid>
<Grid item xs={6}>
<Typography style={{ color: theme.palette.text.primaryLight, fontWeight: "500", fontSize: 13 }}>
{moment(window._env_.INFO.BUILD_TIME).format("DD-MM-YYYY HH:mm")}
</Typography>
<Typography style={{ color: theme.palette.text.primaryLight, fontWeight: "400", fontSize: 11 }}>
{moment(window._env_.INFO.BUILD_TIME).fromNow(false)}
</Typography>
</Grid>
<Grid item xs={6}>
<Typography style={{ color: theme.palette.text.primary, fontWeight: "500", fontSize: 13, marginTop: "10px" }}>Build ID</Typography>
</Grid>
<Grid item xs={6}>
<Typography style={{ color: theme.palette.text.primaryLight, fontWeight: "500", fontSize: 13 }}>{window._env_.INFO.BUILD_ID}</Typography>
</Grid>
{
window._env_.INFO.CHART_VERSION && (
<>
<Grid item xs={6}>
<Typography style={{ color: theme.palette.text.primary, fontWeight: "500", fontSize: 13, marginTop: "10px" }}>Helm Chart Version</Typography>
</Grid>
<Grid item xs={6}>
<Typography style={{ color: theme.palette.text.primaryLight, fontWeight: "500", fontSize: 13 }}>{window._env_.INFO.CHART_VERSION}</Typography>
</Grid>
</>
)
}
{
window._env_.INFO.HELM_REVISION && (
<>
<Grid item xs={6}>
<Typography style={{ color: theme.palette.text.primary, fontWeight: "500", fontSize: 13, marginTop: "10px" }}>Helm Chart Revision</Typography>
</Grid>
<Grid item xs={6}>
<Typography style={{ color: theme.palette.text.primaryLight, fontWeight: "500", fontSize: 13 }}>{window._env_.INFO.HELM_REVISION}</Typography>
</Grid>
</>
)
}
</Grid>

<Grid item container sx={{ marginBottom: "10px" }}>
<Divider sx={{ marginTop: "20px", width: "100%" }} />
</Grid>
</Grid>
{
servicesInfo.map((si, idx) => (
<Grid key={idx} item container>
<Grid item container spacing={2} justifyContent="flex-start">
<Grid key={idx} item container spacing={0} flexDirection={"column"}>
<Grid item container spacing={1} justifyContent="flex-start">
<Grid item xs={12}>
<Box style={{ display: "flex", alignItems: "center" }}>
<Typography style={{ color: theme.palette.text.primary, fontWeight: "500", fontSize: 26, lineHeight: "24px", marginRight: "10px" }}>{si.service}</Typography>
<Typography style={{ color: theme.palette.text.primary, fontWeight: "500", fontSize: 26, lineHeight: "24px", marginRight: "10px" }}>{si.name}</Typography>
</Box>
</Grid>
</Grid>
<Grid sx={{ marginBottom: "10px" }}>
<Typography style={{ color: theme.palette.text.secondary, fontWeight: "400", fontSize: 13, marginTop: "10px" }}>Version, Build number, and other information regarding Lamassu Alerts API</Typography>

<Grid item container spacing={1} justifyContent="space-between">
<Grid item xs={6}>
<Typography style={{ color: theme.palette.text.primary, fontWeight: "500", fontSize: 13, marginTop: "10px" }}>Version</Typography>
</Grid>
<Grid item xs={6}>
<LamassuChip color={"blue"} label={si.version} />
</Grid>
<Grid item xs={6}>
<Typography style={{ color: theme.palette.text.primary, fontWeight: "500", fontSize: 13, marginTop: "10px" }}>Build Time</Typography>
</Grid>
<Grid item xs={6}>
<Typography style={{ color: theme.palette.text.primaryLight, fontWeight: "500", fontSize: 13 }}>
{moment(si.build_time).format("DD-MM-YYYY HH:mm")}
</Typography>
<Typography style={{ color: theme.palette.text.primaryLight, fontWeight: "400", fontSize: 11 }}>
{moment(si.build_time).fromNow(false)}
</Typography>
</Grid>
<Grid item xs={6}>
<Typography style={{ color: theme.palette.text.primary, fontWeight: "500", fontSize: 13, marginTop: "10px" }}>Build ID</Typography>
</Grid>
<Grid item xs={6}>
<Typography style={{ color: theme.palette.text.primaryLight, fontWeight: "500", fontSize: 13 }}>{si.build}</Typography>
</Grid>
</Grid>

<Grid item sx={{ marginBottom: "10px" }}>
<Divider sx={{ marginTop: "20px" }} />
</Grid>
{
si.info.map((info: any, index: number) => {
return (
<Grid key={index} item container spacing={2} justifyContent="space-between">
<Grid item xs={6}>
<Typography style={{ color: theme.palette.text.primary, fontWeight: "500", fontSize: 13, marginTop: "10px" }}>{info[0]}</Typography>
</Grid>
<Grid item xs={6}>
{
typeof info[1] === "boolean" && (
<CheckCircleIcon htmlColor={theme.palette.success.main} />
)
}
{
typeof info[1] === "string" && (
<Typography style={{ color: theme.palette.text.primaryLight, fontWeight: "500", fontSize: 13 }}>
{info[1]}
</Typography>
)
}
</Grid>
</Grid>
);
})
}

<Divider sx={{ marginTop: "20px", marginBottom: "20px" }} />

</Grid>
))
}
Expand Down

0 comments on commit be98b9b

Please sign in to comment.