From 09ec67aa9365e62b2aaeb9276948655db5fa14dd Mon Sep 17 00:00:00 2001 From: Kiahna Tucker Date: Tue, 7 Jan 2025 16:29:22 -0500 Subject: [PATCH] Display time the endpoint was last successfully reached --- .../Logs/Status/Overview/SectionUpdated.tsx | 46 +++++++++++++++++++ .../Logs/Status/Overview/TimestampDetail.tsx | 11 +++-- .../Entity/Details/Logs/Status/index.tsx | 3 ++ src/hooks/entityStatus/useEntityStatus.ts | 6 +++ src/lang/en-US/Details.ts | 3 +- src/stores/EntityStatus/Store.ts | 13 +++++- src/stores/EntityStatus/types.ts | 6 ++- 7 files changed, 79 insertions(+), 9 deletions(-) create mode 100644 src/components/shared/Entity/Details/Logs/Status/Overview/SectionUpdated.tsx diff --git a/src/components/shared/Entity/Details/Logs/Status/Overview/SectionUpdated.tsx b/src/components/shared/Entity/Details/Logs/Status/Overview/SectionUpdated.tsx new file mode 100644 index 000000000..cf0d4cca2 --- /dev/null +++ b/src/components/shared/Entity/Details/Logs/Status/Overview/SectionUpdated.tsx @@ -0,0 +1,46 @@ +import { Box, Grid, Stack, Typography } from '@mui/material'; +import { diminishedTextColor } from 'context/Theme'; +import { useIntl } from 'react-intl'; +import { useEntityStatusStore } from 'stores/EntityStatus/Store'; + +export default function SectionUpdated() { + const intl = useIntl(); + + const lastUpdated = useEntityStatusStore((state) => state.lastUpdated); + + return ( + + {lastUpdated ? ( + + + diminishedTextColor[theme.palette.mode], + }} + variant="caption" + > + {intl.formatMessage( + { + id: 'details.ops.status.message.lastUpdated', + }, + { + timestamp: `${lastUpdated.toLocaleString({ + hour: '2-digit', + minute: '2-digit', + second: '2-digit', + timeZoneName: 'short', + })}, ${lastUpdated.toLocaleString({ + day: '2-digit', + month: '2-digit', + year: 'numeric', + })}`, + } + )} + + + ) : ( + + )} + + ); +} diff --git a/src/components/shared/Entity/Details/Logs/Status/Overview/TimestampDetail.tsx b/src/components/shared/Entity/Details/Logs/Status/Overview/TimestampDetail.tsx index 860109daa..3839d576e 100644 --- a/src/components/shared/Entity/Details/Logs/Status/Overview/TimestampDetail.tsx +++ b/src/components/shared/Entity/Details/Logs/Status/Overview/TimestampDetail.tsx @@ -16,15 +16,16 @@ export default function TimestampDetail({ ); const content = time - ? intl.formatDate(time, { - day: '2-digit', - month: '2-digit', - year: 'numeric', + ? `${intl.formatDate(time, { hour: '2-digit', minute: '2-digit', second: '2-digit', timeZoneName: 'short', - }) + })}, ${intl.formatDate(time, { + day: '2-digit', + month: '2-digit', + year: 'numeric', + })}` : '--'; return ( diff --git a/src/components/shared/Entity/Details/Logs/Status/index.tsx b/src/components/shared/Entity/Details/Logs/Status/index.tsx index 261e78eb8..cc4fdc605 100644 --- a/src/components/shared/Entity/Details/Logs/Status/index.tsx +++ b/src/components/shared/Entity/Details/Logs/Status/index.tsx @@ -5,6 +5,7 @@ import useGlobalSearchParams, { } from 'hooks/searchParams/useGlobalSearchParams'; import { Refresh } from 'iconoir-react'; import { useIntl } from 'react-intl'; +import SectionUpdated from './Overview/SectionUpdated'; import SectionFormatter from './SectionFormatter'; import SectionViews from './SectionViews'; @@ -55,6 +56,8 @@ export default function Status() { + + ); } diff --git a/src/hooks/entityStatus/useEntityStatus.ts b/src/hooks/entityStatus/useEntityStatus.ts index 6dd5f880c..223c4efef 100644 --- a/src/hooks/entityStatus/useEntityStatus.ts +++ b/src/hooks/entityStatus/useEntityStatus.ts @@ -1,5 +1,6 @@ import { getEntityStatus } from 'api/entityStatus'; import { useUserStore } from 'context/User/useUserContextStore'; +import { DateTime } from 'luxon'; import { logRocketEvent } from 'services/shared'; import { CustomEvents } from 'services/types'; import { useEntitiesStore_capabilities_readable } from 'stores/Entities/hooks'; @@ -21,6 +22,10 @@ export default function useEntityStatus(catalogName: string) { const session = useUserStore((state) => state.session); const grants = useEntitiesStore_capabilities_readable(); + + const setLastUpdated = useEntityStatusStore( + (state) => state.setLastUpdated + ); const setResponse = useEntityStatusStore((state) => state.setResponse); const authorizedPrefix = grants.some((grant) => @@ -45,6 +50,7 @@ export default function useEntityStatus(catalogName: string) { responses[0].catalog_name === catalogName ) { setResponse(responses[0]); + setLastUpdated(DateTime.now()); } }, } diff --git a/src/lang/en-US/Details.ts b/src/lang/en-US/Details.ts index 7c92d0ffd..90a5dd965 100644 --- a/src/lang/en-US/Details.ts +++ b/src/lang/en-US/Details.ts @@ -9,9 +9,10 @@ export const Details: Record = { 'details.history.noPublications': `No publications were found.`, - 'details.ops.status.header': `Status`, 'details.ops.status.cta.formatted': `Dashboard`, 'details.ops.status.cta.raw': `Code`, + 'details.ops.status.header': `Status`, + 'details.ops.status.message.lastUpdated': `Updated at {timestamp}`, 'details.ops.status.overview.autoDiscovery.header': `Auto Discovery`, 'details.ops.status.overview.autoDiscovery.subheaderFirstFailure': `First Failed`, 'details.ops.status.overview.autoDiscovery.subheaderLastSuccess': `Last Success`, diff --git a/src/stores/EntityStatus/Store.ts b/src/stores/EntityStatus/Store.ts index 083371ee3..c6d0ce2fd 100644 --- a/src/stores/EntityStatus/Store.ts +++ b/src/stores/EntityStatus/Store.ts @@ -6,9 +6,10 @@ import { EntityStatusState } from './types'; const getInitialStateData = (): Pick< EntityStatusState, - 'format' | 'response' + 'format' | 'lastUpdated' | 'response' > => ({ format: 'dashboard', + lastUpdated: null, response: null, }); @@ -28,6 +29,16 @@ const getInitialState = ( ); }, + setLastUpdated: (value) => { + set( + produce((state: EntityStatusState) => { + state.lastUpdated = value; + }), + false, + 'Last updated set' + ); + }, + setResponse: (value) => { set( produce((state: EntityStatusState) => { diff --git a/src/stores/EntityStatus/types.ts b/src/stores/EntityStatus/types.ts index b9992083c..634d23bdf 100644 --- a/src/stores/EntityStatus/types.ts +++ b/src/stores/EntityStatus/types.ts @@ -1,12 +1,14 @@ import { EntityStatusResponse } from 'deps/control-plane/types'; +import { DateTime } from 'luxon'; export interface EntityStatusState { response: EntityStatusResponse | null; - setResponse: (value: EntityStatusResponse) => void; - format: 'code' | 'dashboard'; + lastUpdated: DateTime | null; setFormat: ( value: EntityStatusState['format'], invertedValue: EntityStatusState['format'] ) => void; + setLastUpdated: (value: EntityStatusState['lastUpdated']) => void; + setResponse: (value: EntityStatusResponse) => void; }