Skip to content

Commit 2acb6de

Browse files
authored
[Feature]: Show probe statuses in the UI (#3521)
* [Feature]: Show probe statuses in the UI #3204
1 parent 0c3e564 commit 2acb6de

File tree

10 files changed

+102
-9
lines changed

10 files changed

+102
-9
lines changed

frontend/package-lock.json

Lines changed: 6 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

frontend/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@
101101
"@cloudscape-design/chat-components": "^1.0.62",
102102
"@cloudscape-design/collection-hooks": "^1.0.74",
103103
"@cloudscape-design/component-toolkit": "^1.0.0-beta.120",
104-
"@cloudscape-design/components": "^3.0.1091",
104+
"@cloudscape-design/components": "^3.0.1188",
105105
"@cloudscape-design/design-tokens": "^3.0.60",
106106
"@cloudscape-design/global-styles": "^1.0.45",
107107
"@hookform/resolvers": "^2.9.10",

frontend/src/components/NavigateLink/index.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import React from 'react';
22
import { useNavigate } from 'react-router-dom';
33
import Link, { LinkProps } from '@cloudscape-design/components/link';
4+
5+
import styles from './style.module.scss';
6+
47
export const NavigateLink: React.FC<LinkProps> = ({ onFollow, ...props }) => {
58
const navigate = useNavigate();
69
const onFollowHandler: LinkProps['onFollow'] = (event) => {
@@ -10,5 +13,9 @@ export const NavigateLink: React.FC<LinkProps> = ({ onFollow, ...props }) => {
1013
if (event.detail.href) navigate(event.detail.href);
1114
};
1215

13-
return <Link {...props} onFollow={onFollowHandler} />;
16+
return (
17+
<span className={styles.link}>
18+
<Link {...props} onFollow={onFollowHandler} />
19+
</span>
20+
);
1421
};
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
.link {
2+
& > a {
3+
text-decoration: underline !important;
4+
}
5+
}

frontend/src/libs/run.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { StatusIndicatorProps } from '@cloudscape-design/components';
44
import { capitalize } from 'libs';
55

66
import { finishedRunStatuses } from '../pages/Runs/constants';
7+
import { getJobProbesStatuses } from '../pages/Runs/Details/Jobs/List/helpers';
78

89
import { IModelExtended } from '../pages/Models/List/types';
910

@@ -75,6 +76,16 @@ export const getRunError = (run: IRun): string | null => {
7576
return error ? capitalize(error) : null;
7677
};
7778

79+
export const getRunProbeStatuses = (run: IRun): StatusIndicatorProps.Type[] => {
80+
const job = run.jobs[0];
81+
82+
if (!job) {
83+
return [];
84+
}
85+
86+
return getJobProbesStatuses(run.jobs[0]);
87+
};
88+
7889
export const getRunPriority = (run: IRun): number | null => {
7990
return run.run_spec.configuration?.priority ?? null;
8091
};

frontend/src/locale/en.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,7 @@
402402
"priority": "Priority",
403403
"provider_name": "Provider",
404404
"status": "Status",
405+
"probe": "Probes",
405406
"submitted_at": "Submitted",
406407
"finished_at": "Finished",
407408
"metrics": {
@@ -477,6 +478,7 @@
477478
"offer": "Offer",
478479
"offer_description": "Select an offer for the dev environment.",
479480
"name": "Name",
481+
"name_description": "The name of the run, e.g. 'my-dev-env'",
480482
"name_constraint": "Example: 'my-fleet' or 'default'. If not specified, generated automatically.",
481483
"name_placeholder": "Optional",
482484
"ide": "IDE",

frontend/src/pages/Runs/Details/Jobs/List/helpers.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { format } from 'date-fns';
2+
import type { StatusIndicatorProps } from '@cloudscape-design/components/status-indicator';
23

34
import { DATE_TIME_FORMAT } from 'consts';
45
import { capitalize } from 'libs';
@@ -48,6 +49,28 @@ export const getJobStatus = (job: IJob) => {
4849
return job.job_submissions?.[job.job_submissions.length - 1].status;
4950
};
5051

52+
export const getJobSubmissionProbes = (job: IJob) => {
53+
return job.job_submissions?.[job.job_submissions.length - 1].probes;
54+
};
55+
56+
export const getJobProbesStatuses = (job: IJob): StatusIndicatorProps.Type[] => {
57+
const status = getJobStatus(job);
58+
const probes = getJobSubmissionProbes(job);
59+
60+
if (!probes?.length || status !== 'running') {
61+
return [];
62+
}
63+
64+
return probes.map((probe, index) => {
65+
if (job.job_spec?.probes?.[index] && probe.success_streak >= job.job_spec.probes[index].ready_after) {
66+
return 'success';
67+
} else if (probe.success_streak > 0) {
68+
return 'in-progress';
69+
}
70+
return 'not-started';
71+
});
72+
};
73+
5174
export const getJobTerminationReason = (job: IJob) => {
5275
return job.job_submissions?.[job.job_submissions.length - 1].termination_reason ?? '-';
5376
};

frontend/src/pages/Runs/Details/Jobs/List/hooks.tsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
getJobListItemRegion,
1616
getJobListItemResources,
1717
getJobListItemSpot,
18+
getJobProbesStatuses,
1819
getJobStatus,
1920
getJobStatusMessage,
2021
getJobSubmittedAt,
@@ -67,6 +68,14 @@ export const useColumnsDefinitions = ({
6768
);
6869
},
6970
},
71+
{
72+
id: 'probe',
73+
header: t('projects.run.probe'),
74+
cell: (item: IJob) => {
75+
const statuses = getJobProbesStatuses(item);
76+
return statuses.map((statusType, index) => <StatusIndicator key={index} type={statusType} />);
77+
},
78+
},
7079
{
7180
id: 'priority',
7281
header: t('projects.run.priority'),

frontend/src/pages/Runs/Details/RunDetails/index.tsx

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,14 @@ import { format } from 'date-fns';
77
import { Box, ColumnLayout, Container, Header, Loader, NavigateLink, StatusIndicator } from 'components';
88

99
import { DATE_TIME_FORMAT } from 'consts';
10-
import { getRunError, getRunPriority, getRunStatusMessage, getStatusIconColor, getStatusIconType } from 'libs/run';
10+
import {
11+
getRunError,
12+
getRunPriority,
13+
getRunProbeStatuses,
14+
getRunStatusMessage,
15+
getStatusIconColor,
16+
getStatusIconType,
17+
} from 'libs/run';
1118
import { ROUTES } from 'routes';
1219
import { useGetRunQuery } from 'services/run';
1320

@@ -65,6 +72,14 @@ export const RunDetails = () => {
6572

6673
const statusMessage = getRunStatusMessage(runData);
6774

75+
const renderRobeStatuses = () => {
76+
const statuses = getRunProbeStatuses(runData);
77+
78+
if (!statuses.length) return '-';
79+
80+
return statuses.map((statusType, index) => <StatusIndicator key={index} type={statusType} />);
81+
};
82+
6883
return (
6984
<>
7085
<Container header={<Header variant="h2">{t('common.general')}</Header>}>
@@ -112,6 +127,7 @@ export const RunDetails = () => {
112127

113128
<div>
114129
<Box variant="awsui-key-label">{t('projects.run.status')}</Box>
130+
115131
<div>
116132
<StatusIndicator
117133
type={getStatusIconType(status, terminationReason)}
@@ -122,6 +138,13 @@ export const RunDetails = () => {
122138
</div>
123139
</div>
124140

141+
{runData.jobs.length <= 1 && (
142+
<div>
143+
<Box variant="awsui-key-label">{t('projects.run.probe')}</Box>
144+
<div>{renderRobeStatuses()}</div>
145+
</div>
146+
)}
147+
125148
<div>
126149
<Box variant="awsui-key-label">{t('projects.run.error')}</Box>
127150
<div>{getRunError(runData) ?? '-'}</div>

frontend/src/types/run.d.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,17 @@ declare interface IAppSpec {
171171
url_query_params?: { [key: string]: string };
172172
}
173173

174+
declare interface IJobProbe {
175+
type: 'http';
176+
url: string;
177+
method?: 'head' | 'post' | 'put' | 'patch' | 'delete' | 'get';
178+
headers?: Array<{ name: string; value: string }>;
179+
body?: string;
180+
timeout: number;
181+
interval: number;
182+
ready_after: number;
183+
}
184+
174185
declare interface IJobSpec {
175186
app_specs?: IAppSpec;
176187
commands: string[];
@@ -181,6 +192,7 @@ declare interface IJobSpec {
181192
job_num: number;
182193
max_duration?: number;
183194
working_dir: string;
195+
probes?: IJobProbe[];
184196
}
185197

186198
declare interface IGpu {
@@ -234,6 +246,7 @@ declare interface IJobSubmission {
234246
exit_status?: number | null;
235247
status_message?: string | null;
236248
error?: string | null;
249+
probes?: Array<{ success_streak: number }>;
237250
}
238251

239252
declare interface IJob {

0 commit comments

Comments
 (0)