diff --git a/locales/en/public.json b/locales/en/public.json index d03e4adc4..c28650831 100644 --- a/locales/en/public.json +++ b/locales/en/public.json @@ -4,6 +4,8 @@ }, "AboutDescription": { "BUGS": "Bugs", + "BUILD_INFO": "Build Information", + "COMMIT": "commit {{ hash }}", "FILE_A_REPORT": "File a report", "HOMEPAGE": "Homepage", "KNOWN_ISSUES": "Known issues", diff --git a/src/app/About/AboutDescription.tsx b/src/app/About/AboutDescription.tsx index af4282917..d2d2047cb 100644 --- a/src/app/About/AboutDescription.tsx +++ b/src/app/About/AboutDescription.tsx @@ -15,8 +15,10 @@ */ import build from '@app/build.json'; +import { BuildInfo } from '@app/Shared/Services/api.types'; import { NotificationsContext } from '@app/Shared/Services/Notifications.service'; import { ServiceContext } from '@app/Shared/Services/Services'; +import { useSubscriptions } from '@app/utils/hooks/useSubscriptions'; import { Text, TextContent, TextList, TextListItem, TextVariants } from '@patternfly/react-core'; import * as React from 'react'; import { useTranslation } from 'react-i18next'; @@ -25,14 +27,16 @@ export const AboutDescription: React.FC = () => { const serviceContext = React.useContext(ServiceContext); const notificationsContext = React.useContext(NotificationsContext); const [cryostatVersion, setCryostatVersion] = React.useState(undefined as string | undefined); + const [buildInfo, setBuildInfo] = React.useState({ git: { hash: '' } }); const { t } = useTranslation(); + const addSubscription = useSubscriptions(); React.useEffect(() => { - const sub = serviceContext.api.cryostatVersion().subscribe(setCryostatVersion); - return () => sub.unsubscribe(); - }, [serviceContext]); + addSubscription(serviceContext.api.cryostatVersion().subscribe(setCryostatVersion)); + addSubscription(serviceContext.api.buildInfo().subscribe(setBuildInfo)); + }, [addSubscription, serviceContext]); - const cryostatCommitHash = React.useMemo(() => { + const cryostatReleaseTag = React.useMemo(() => { if (!cryostatVersion) { return; } @@ -55,8 +59,8 @@ export const AboutDescription: React.FC = () => { component={TextVariants.a} target="_blank" href={ - cryostatCommitHash - ? build.releaseTagUrl.replace('__REPLACE_HASH__', cryostatCommitHash) + cryostatReleaseTag + ? build.releaseTagUrl.replace('__REPLACE_HASH__', cryostatReleaseTag) : build.developmentUrl } > @@ -66,7 +70,23 @@ export const AboutDescription: React.FC = () => { } else { return {cryostatVersion}; } - }, [cryostatVersion, cryostatCommitHash]); + }, [cryostatVersion, cryostatReleaseTag]); + + const buildInfoComponent = React.useMemo(() => { + if (build.commitUrl) { + return ( + + {t('AboutDescription.COMMIT', { hash: buildInfo.git.hash })} + + ); + } else { + return {t('AboutDescription.COMMIT', { hash: buildInfo.git.hash })}; + } + }, [t, buildInfo]); return ( <> @@ -74,6 +94,8 @@ export const AboutDescription: React.FC = () => { {t('AboutDescription.VERSION')} {versionComponent} + {t('AboutDescription.BUILD_INFO')} + {buildInfoComponent} {t('AboutDescription.HOMEPAGE')} diff --git a/src/app/Shared/Services/Api.service.tsx b/src/app/Shared/Services/Api.service.tsx index 803ec5fbf..8a43d8ba1 100644 --- a/src/app/Shared/Services/Api.service.tsx +++ b/src/app/Shared/Services/Api.service.tsx @@ -73,6 +73,7 @@ import { TargetMetadata, isTargetMetadata, MBeanMetricsResponse, + BuildInfo, } from './api.types'; import { isHttpError, @@ -91,6 +92,7 @@ import { TargetService } from './Target.service'; export class ApiService { private readonly archiveEnabled = new BehaviorSubject(true); private readonly cryostatVersionSubject = new ReplaySubject(1); + private readonly buildInfoSubject = new ReplaySubject(1); private readonly grafanaDatasourceUrlSubject = new ReplaySubject(1); private readonly grafanaDashboardUrlSubject = new ReplaySubject(1); @@ -128,6 +130,7 @@ export class ApiService { .pipe( concatMap((jsonResp) => { this.cryostatVersionSubject.next(jsonResp.cryostatVersion); + this.buildInfoSubject.next(jsonResp.build); const toFetch: unknown[] = []; const unconfigured: string[] = []; const unavailable: string[] = []; @@ -737,6 +740,10 @@ export class ApiService { return this.cryostatVersionSubject.asObservable(); } + buildInfo(): Observable { + return this.buildInfoSubject.asObservable(); + } + grafanaDatasourceUrl(): Observable { return this.grafanaDatasourceUrlSubject.asObservable(); } diff --git a/src/app/Shared/Services/api.types.ts b/src/app/Shared/Services/api.types.ts index d92ba5d92..329b84c1c 100644 --- a/src/app/Shared/Services/api.types.ts +++ b/src/app/Shared/Services/api.types.ts @@ -23,6 +23,13 @@ export type ApiVersion = 'v1' | 'v2' | 'v2.1' | 'v2.2' | 'v2.3' | 'v2.4' | 'v3' // ====================================== // Common Resources // ====================================== + +export interface BuildInfo { + git: { + hash: string; + }; +} + export interface KeyValue { key: string; value: string; @@ -127,6 +134,7 @@ export interface GrafanaDatasourceUrlGetResponse { export interface HealthGetResponse { cryostatVersion: string; + build: BuildInfo; datasourceConfigured: boolean; datasourceAvailable: boolean; dashboardConfigured: boolean; diff --git a/src/app/build.json b/src/app/build.json index df5c1c810..0f940b1ca 100644 --- a/src/app/build.json +++ b/src/app/build.json @@ -2,6 +2,7 @@ "productName": "Cryostat", "developmentUrl": "https://github.com/cryostatio/cryostat", "releaseTagUrl": "https://github.com/cryostatio/cryostat/releases/tag/__REPLACE_HASH__", + "commitUrl": "https://github.com/cryostatio/cryostat/commit/__REPLACE_HASH__", "homePageUrl": "https://cryostat.io", "blogPageUrl": "https://cryostat.io/blog", "documentationUrl": "https://cryostat.io/guides",