From 71bc030dcea12ec97758b9023ba567744666c09a Mon Sep 17 00:00:00 2001 From: Vedant Gupta <49195734+veds-g@users.noreply.github.com> Date: Sun, 2 Jun 2024 13:28:48 +0530 Subject: [PATCH] feat: adding numaflow version to the UI (#1744) Signed-off-by: veds-g --- ui/src/App.tsx | 65 +++++++++++++++-- .../common/SlidingSidebar/index.tsx | 12 ++++ .../partials/VersionDetails/index.tsx | 72 +++++++++++++++++++ .../partials/VersionDetails/style.css | 5 ++ .../plugin/NumaflowMonitorApp/App.tsx | 45 ++++++++++++ ui/src/utils/models/systemInfo.ts | 1 + 6 files changed, 195 insertions(+), 5 deletions(-) create mode 100644 ui/src/components/common/SlidingSidebar/partials/VersionDetails/index.tsx create mode 100644 ui/src/components/common/SlidingSidebar/partials/VersionDetails/style.css diff --git a/ui/src/App.tsx b/ui/src/App.tsx index fcb006d076..4bad9078f2 100644 --- a/ui/src/App.tsx +++ b/ui/src/App.tsx @@ -12,12 +12,14 @@ import AppBar from "@mui/material/AppBar"; import Toolbar from "@mui/material/Toolbar"; import CircularProgress from "@mui/material/CircularProgress"; import { Switch, Route, useLocation, useHistory } from "react-router-dom"; +import { isEqual } from "lodash"; import { Breadcrumbs } from "./components/common/Breadcrumbs"; import { Routes } from "./components/common/Routes"; import { Login } from "./components/pages/Login"; import { useSystemInfoFetch } from "./utils/fetchWrappers/systemInfoFetch"; import { notifyError } from "./utils/error"; import { + SidebarType, SlidingSidebar, SlidingSidebarProps, } from "./components/common/SlidingSidebar"; @@ -28,6 +30,7 @@ import { AppProps, UserInfo, } from "./types/declarations/app"; +import { VersionDetailsProps } from "./components/common/SlidingSidebar/partials/VersionDetails"; import AccountMenu from "./components/common/AccountMenu"; import { getBaseHref } from "./utils"; import logo from "./images/icon.png"; @@ -75,6 +78,9 @@ function App(props: AppProps) { >(); const [errors, setErrors] = useState([]); const [userInfo, setUserInfo] = useState(); + const [versionDetails, setVersionDetails] = useState< + VersionDetailsProps | undefined + >(undefined); const { systemInfo, error: systemInfoError, @@ -93,6 +99,17 @@ function App(props: AppProps) { history.push(`?namespace=${systemInfo.managedNamespace}`); } } + if (systemInfo?.version) { + const parts = systemInfo?.version.split(", "); + const kv_pairs: { [key: string]: string } = {}; + for (const part of parts) { + const [key, value] = part.split(": "); + kv_pairs[key.trim()] = value.trim() === "" ? "unknown" : value.trim(); + } + if (!isEqual(versionDetails, kv_pairs)) { + setVersionDetails(kv_pairs); + } + } }, [location, history, systemInfo]); useEffect(() => { @@ -169,6 +186,24 @@ function App(props: AppProps) { setErrors([]); }, []); + const handleVersionDetails = useCallback(() => { + setSidebarProps({ + type: SidebarType.VERSION_DETAILS, + slide: false, + pageWidth, + versionDetailsProps: { + Version: versionDetails?.Version, + BuildDate: versionDetails?.BuildDate, + GitCommit: versionDetails?.GitCommit, + GitTag: versionDetails?.GitTag, + GitTreeState: versionDetails?.GitTreeState, + GoVersion: versionDetails?.GoVersion, + Compiler: versionDetails?.Compiler, + Platform: versionDetails?.Platform, + }, + }); + }, [versionDetails, pageWidth]); + const routes = useMemo(() => { if (loading) { // System info loading @@ -285,11 +320,31 @@ function App(props: AppProps) { > logo - text-logo + + + text-logo + + {versionDetails?.Version} + + + diff --git a/ui/src/components/common/SlidingSidebar/index.tsx b/ui/src/components/common/SlidingSidebar/index.tsx index 0dcd83c05f..b225eca341 100644 --- a/ui/src/components/common/SlidingSidebar/index.tsx +++ b/ui/src/components/common/SlidingSidebar/index.tsx @@ -13,6 +13,7 @@ import { GeneratorDetails, GeneratorDetailsProps, } from "./partials/GeneratorDetails"; +import { VersionDetails, VersionDetailsProps } from "./partials/VersionDetails"; import { Errors } from "./partials/Errors"; import { PipelineCreate } from "./partials/PipelineCreate"; import { PipelineUpdate } from "./partials/PipelineUpdate"; @@ -40,6 +41,7 @@ export enum SidebarType { EDGE_DETAILS, GENERATOR_DETAILS, ERRORS, + VERSION_DETAILS, } const MIN_WIDTH_BY_TYPE = { @@ -53,6 +55,7 @@ const MIN_WIDTH_BY_TYPE = { [SidebarType.EDGE_DETAILS]: 750, [SidebarType.GENERATOR_DETAILS]: 750, [SidebarType.ERRORS]: 350, + [SidebarType.VERSION_DETAILS]: 350, }; export interface SpecEditorModalProps { @@ -79,6 +82,7 @@ export interface SlidingSidebarProps { vertexDetailsProps?: VertexDetailsProps; edgeDetailsProps?: EdgeDetailsProps; generatorDetailsProps?: GeneratorDetailsProps; + versionDetailsProps?: VersionDetailsProps; specEditorProps?: SpecEditorSidebarProps; parentCloseIndicator?: string; } @@ -91,6 +95,7 @@ export function SlidingSidebar({ vertexDetailsProps, edgeDetailsProps, generatorDetailsProps, + versionDetailsProps, specEditorProps, parentCloseIndicator, }: SlidingSidebarProps) { @@ -98,6 +103,8 @@ export function SlidingSidebar({ const [width, setWidth] = useState( type === SidebarType.ERRORS ? MIN_WIDTH_BY_TYPE[SidebarType.ERRORS] + : type === SidebarType.VERSION_DETAILS + ? MIN_WIDTH_BY_TYPE[SidebarType.VERSION_DETAILS] : pageWidth * 0.75 ); const [minWidth] = useState(0); @@ -242,6 +249,11 @@ export function SlidingSidebar({ return ; case SidebarType.ERRORS: return ; + case SidebarType.VERSION_DETAILS: + if (!versionDetailsProps) { + break; + } + return ; default: break; } diff --git a/ui/src/components/common/SlidingSidebar/partials/VersionDetails/index.tsx b/ui/src/components/common/SlidingSidebar/partials/VersionDetails/index.tsx new file mode 100644 index 0000000000..9653238b66 --- /dev/null +++ b/ui/src/components/common/SlidingSidebar/partials/VersionDetails/index.tsx @@ -0,0 +1,72 @@ +import React from "react"; +import Box from "@mui/material/Box"; +import Grid from "@mui/material/Grid"; +import Paper from "@mui/material/Paper"; + +import "./style.css"; + +export interface VersionDetailsProps { + Version?: string; + BuildDate?: string; + GitCommit?: string; + GitTag?: string; + GitTreeState?: string; + GoVersion?: string; + Compiler?: string; + Platform?: string; +} + +const paperStyle = { + display: "flex", + padding: "1.6rem", + overflow: "scroll", +}; + +const keyStyle = { + fontWeight: "bold", + marginRight: "1rem", + minWidth: "10rem", +}; + +const versionDetails = [ + "Version", + "BuildDate", + "GitCommit", + "GitTag", + "GitTreeState", + "GoVersion", + "Compiler", + "Platform", +] as const; + +export function VersionDetails(props: VersionDetailsProps) { + return ( + + Numaflow Server Version + + {versionDetails.map((detail) => ( + + + {detail} + {props?.[detail] ?? "unknown"} + + + ))} + + + ); +} diff --git a/ui/src/components/common/SlidingSidebar/partials/VersionDetails/style.css b/ui/src/components/common/SlidingSidebar/partials/VersionDetails/style.css new file mode 100644 index 0000000000..34c2d0c2bd --- /dev/null +++ b/ui/src/components/common/SlidingSidebar/partials/VersionDetails/style.css @@ -0,0 +1,5 @@ +.version-header-text { + font-size: 2rem; + font-style: normal; + font-weight: 500; +} diff --git a/ui/src/components/plugin/NumaflowMonitorApp/App.tsx b/ui/src/components/plugin/NumaflowMonitorApp/App.tsx index 4d0d866ded..28bc5880e9 100644 --- a/ui/src/components/plugin/NumaflowMonitorApp/App.tsx +++ b/ui/src/components/plugin/NumaflowMonitorApp/App.tsx @@ -10,16 +10,20 @@ import Box from "@mui/material/Box"; import Drawer from "@mui/material/Drawer"; import CircularProgress from "@mui/material/CircularProgress"; import { Route, useLocation, useHistory, Switch } from "react-router-dom"; +import { isEqual } from "lodash"; import { Breadcrumbs } from "../Breadcrumbs/Breadcrumbs"; import { Routes } from "../Routes/Routes"; import { useSystemInfoFetch } from "../../../utils/fetchWrappers/systemInfoFetch"; import { notifyError } from "../../../utils/error"; import { + SidebarType, SlidingSidebar, SlidingSidebarProps, } from "../../common/SlidingSidebar"; import { ErrorDisplay } from "../../common/ErrorDisplay"; import { AppError, AppProps, UserInfo } from "../../../types/declarations/app"; +import { VersionDetailsProps } from "../../common/SlidingSidebar/partials/VersionDetails"; + import { AppContext } from "../../../App"; import "./App.css"; @@ -47,6 +51,9 @@ function App(props: AppProps) { >(); const [errors, setErrors] = useState([]); const [userInfo, setUserInfo] = useState(); + const [versionDetails, setVersionDetails] = useState< + VersionDetailsProps | undefined + >(undefined); const { systemInfo, error: systemInfoError, @@ -65,6 +72,20 @@ function App(props: AppProps) { } }, [location, history, namespace]); + useEffect(() => { + if (systemInfo?.version) { + const parts = systemInfo?.version.split(", "); + const kv_pairs: any = {}; + for (const part of parts) { + const [key, value] = part.split(": "); + kv_pairs[key.trim()] = value.trim() === "" ? "unknown" : value.trim(); + } + if (!isEqual(versionDetails, kv_pairs)) { + setVersionDetails(kv_pairs); + } + } + }, [systemInfo]); + useEffect(() => { // Route changed setErrors([]); @@ -114,6 +135,24 @@ function App(props: AppProps) { setErrors([]); }, []); + const handleVersionDetails = useCallback(() => { + setSidebarProps({ + type: SidebarType.VERSION_DETAILS, + slide: false, + pageWidth, + versionDetailsProps: { + Version: versionDetails?.Version, + BuildDate: versionDetails?.BuildDate, + GitCommit: versionDetails?.GitCommit, + GitTag: versionDetails?.GitTag, + GitTreeState: versionDetails?.GitTreeState, + GoVersion: versionDetails?.GoVersion, + Compiler: versionDetails?.Compiler, + Platform: versionDetails?.Platform, + }, + }); + }, [versionDetails, pageWidth]); + const routes = useMemo(() => { if (loading) { // System info loading @@ -202,6 +241,12 @@ function App(props: AppProps) { height: "100%", }} > + + {versionDetails?.Version} +