Skip to content

Commit 0bef439

Browse files
committed
feat: Show deployed timestamp in config/overview
https://harperdb.atlassian.net/browse/STUDIO-680
1 parent bfbec9b commit 0bef439

3 files changed

Lines changed: 58 additions & 6 deletions

File tree

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { TextLoadingSkeleton } from '@/components/TextLoadingSkeleton';
2+
3+
export const LastDeployedTimestamp = ({
4+
loading,
5+
timestamp,
6+
}: {
7+
loading?: boolean;
8+
timestamp?: number | null;
9+
}) => {
10+
const dateString = timestamp ? new Date(timestamp).toLocaleString() : 'Never';
11+
return (
12+
<>
13+
<dt className="font-bold text-sm/6">Last Deployed</dt>
14+
<dd className="text-sm/6 sm:mt-2">
15+
{loading ? <TextLoadingSkeleton className="w-24" /> : dateString}
16+
</dd>
17+
</>
18+
);
19+
};

src/features/instance/config/overview/index.tsx

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,13 @@ import { ClusterDomainsList } from '@/features/instance/config/overview/componen
1111
import { HarperVersion } from '@/features/instance/config/overview/components/HarperVersion';
1212
import { InstanceNodeName } from '@/features/instance/config/overview/components/InstanceNodeName';
1313
import { InstanceURL } from '@/features/instance/config/overview/components/InstanceURL';
14+
import { LastDeployedTimestamp } from '@/features/instance/config/overview/components/LastDeployedTimestamp';
1415
import { useRollingConfigUpdate } from '@/hooks/useRollingConfigUpdate';
16+
import {
17+
APIDirectoryEntry,
18+
APIFileEntry,
19+
getComponentsQueryOptions,
20+
} from '@/integrations/api/instance/applications/getComponents';
1521
import { getConfigurationQueryOptions } from '@/integrations/api/instance/status/getConfiguration';
1622
import {
1723
getRegistrationInfoQueryOptions,
@@ -57,6 +63,26 @@ export function ConfigOverviewIndex() {
5763
const { data: configurationInfo, isLoading: loadingConfig } = useQuery(
5864
getConfigurationQueryOptions(instanceParams),
5965
);
66+
const { data: components, isLoading: loadingComponents } = useQuery(
67+
getComponentsQueryOptions(instanceParams),
68+
);
69+
70+
const lastDeployedTimestamp = useMemo(() => {
71+
if (!components) { return null; }
72+
73+
let maxMtime = 0;
74+
const traverse = (entry: APIDirectoryEntry | APIFileEntry) => {
75+
if (entry.mtime) {
76+
maxMtime = Math.max(maxMtime, new Date(entry.mtime).getTime());
77+
}
78+
if ('entries' in entry && entry.entries) {
79+
entry.entries.forEach(traverse);
80+
}
81+
};
82+
83+
traverse(components);
84+
return maxMtime || null;
85+
}, [components]);
6086

6187
const sanitizedConfigInfo = useMemo(() => {
6288
if (!configurationInfo) { return null; }
@@ -152,9 +178,12 @@ export function ConfigOverviewIndex() {
152178
? (
153179
<LocalStudioOverview>
154180
<dl className="grid grid-cols-1 sm:grid-cols-3">
155-
<div className="px-4 pb-4 sm:col-span-2 sm:px-0">
181+
<div className="px-4 pb-4 sm:col-span-1 sm:px-0">
156182
<HarperVersion loadingRegistration={loadingRegistration} registrationInfo={registrationInfo} />
157183
</div>
184+
<div className="px-4 pb-4 sm:col-span-1 sm:px-0">
185+
<LastDeployedTimestamp loading={loadingComponents} timestamp={lastDeployedTimestamp} />
186+
</div>
158187
<div className="px-4 pb-4 text-right sm:col-span-1 sm:px-0">
159188
<RestartButton
160189
targetNoun={targetNoun}
@@ -168,11 +197,14 @@ export function ConfigOverviewIndex() {
168197
: (
169198
<CloudStudioOverview>
170199
<dl className="flex-none grid grid-cols-1 sm:grid-cols-4">
200+
<div className="px-4 pb-4 sm:col-span-1 sm:px-0">
201+
<InstanceNodeName loadingInstanceInfo={loadingInstanceInfo} instanceInfo={instanceInfo} />
202+
</div>
171203
<div className="px-4 pb-4 sm:col-span-1 sm:px-0">
172204
<HarperVersion loadingRegistration={loadingRegistration} registrationInfo={registrationInfo} />
173205
</div>
174-
<div className="px-4 pb-4 sm:col-span-2 sm:px-0">
175-
<InstanceURL loadingInstanceInfo={loadingInstanceInfo} instanceInfo={instanceInfo} />
206+
<div className="px-4 pb-4 sm:col-span-1 sm:px-0">
207+
<LastDeployedTimestamp loading={loadingComponents} timestamp={lastDeployedTimestamp} />
176208
</div>
177209
<div className="px-4 pb-4 text-right sm:col-span-1 sm:px-0 grid gap-1">
178210
{newLicenses?.length > 0 && <ApplyLicensesButton newLicenses={newLicenses} />}
@@ -182,10 +214,10 @@ export function ConfigOverviewIndex() {
182214
operation="restart"
183215
/>
184216
</div>
185-
<div className="px-4 pb-4 sm:col-span-1 sm:px-0">
186-
<InstanceNodeName loadingInstanceInfo={loadingInstanceInfo} instanceInfo={instanceInfo} />
217+
<div className="px-4 pb-4 sm:col-span-3 sm:px-0">
218+
<InstanceURL loadingInstanceInfo={loadingInstanceInfo} instanceInfo={instanceInfo} />
187219
</div>
188-
<div className="px-4 pb-4 sm:col-span-2 sm:px-0">
220+
<div className="px-4 pb-4 sm:col-span-3 sm:px-0">
189221
<ApplicationURL loadingInstanceInfo={loadingInstanceInfo} clusterInfo={clusterInfo} />
190222
</div>
191223
{clusterInfo?.domains?.length && (

src/integrations/api/instance/applications/getComponents.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export interface APIDirectoryEntry extends APIFileEntry {
88

99
export interface APIFileEntry {
1010
name: string;
11+
mtime?: number;
1112
}
1213

1314
export async function getComponents({ instanceClient }: InstanceClientIdConfig) {

0 commit comments

Comments
 (0)