Skip to content

Commit c883d5a

Browse files
authored
Merge pull request #6237 from xonas1101/fix/job-duration-running
frontend: workload: Hide Job duration while the job is still running
2 parents 3fa24d1 + ad5c897 commit c883d5a

5 files changed

Lines changed: 308 additions & 1 deletion

File tree

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
<body>
2+
<div>
3+
<dl
4+
class="MuiGrid-root MuiGrid-container css-kxuems-MuiGrid-root"
5+
>
6+
<dt
7+
class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-12 MuiGrid-grid-sm-3 MuiGrid-grid-md-2 css-9i4s51-MuiGrid-root"
8+
>
9+
Completions
10+
</dt>
11+
<dd
12+
class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-12 MuiGrid-grid-sm-9 MuiGrid-grid-md-10 css-1dbzfsd-MuiGrid-root"
13+
>
14+
<span
15+
class="MuiTypography-root MuiTypography-body1 css-e06lsu-MuiTypography-root"
16+
>
17+
1/1
18+
</span>
19+
</dd>
20+
<dt
21+
class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-12 MuiGrid-grid-sm-3 MuiGrid-grid-md-2 css-9i4s51-MuiGrid-root"
22+
>
23+
Parallelism
24+
</dt>
25+
<dd
26+
class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-12 MuiGrid-grid-sm-9 MuiGrid-grid-md-10 css-1dbzfsd-MuiGrid-root"
27+
>
28+
1
29+
</dd>
30+
<dt
31+
class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-12 MuiGrid-grid-sm-3 MuiGrid-grid-md-2 css-9i4s51-MuiGrid-root"
32+
>
33+
Suspend
34+
</dt>
35+
<dd
36+
class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-12 MuiGrid-grid-sm-9 MuiGrid-grid-md-10 css-1dbzfsd-MuiGrid-root"
37+
>
38+
<span
39+
class="MuiTypography-root MuiTypography-body1 css-e06lsu-MuiTypography-root"
40+
>
41+
false
42+
</span>
43+
</dd>
44+
<dt
45+
class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-12 MuiGrid-grid-sm-3 MuiGrid-grid-md-2 css-9i4s51-MuiGrid-root"
46+
>
47+
Backoff Limit
48+
</dt>
49+
<dd
50+
class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-12 MuiGrid-grid-sm-9 MuiGrid-grid-md-10 css-1dbzfsd-MuiGrid-root"
51+
>
52+
6
53+
</dd>
54+
<dt
55+
class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-12 MuiGrid-grid-sm-3 MuiGrid-grid-md-2 css-9i4s51-MuiGrid-root"
56+
>
57+
Pods Status
58+
</dt>
59+
<dd
60+
class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-12 MuiGrid-grid-sm-9 MuiGrid-grid-md-10 css-1dbzfsd-MuiGrid-root"
61+
>
62+
<span
63+
class="MuiTypography-root MuiTypography-body1 css-e06lsu-MuiTypography-root"
64+
>
65+
Succeeded: 1
66+
</span>
67+
</dd>
68+
<dt
69+
class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-12 MuiGrid-grid-sm-3 MuiGrid-grid-md-2 css-9i4s51-MuiGrid-root"
70+
>
71+
Start Time
72+
</dt>
73+
<dd
74+
class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-12 MuiGrid-grid-sm-9 MuiGrid-grid-md-10 css-1dbzfsd-MuiGrid-root"
75+
>
76+
<span
77+
class="MuiTypography-root MuiTypography-body1 css-e06lsu-MuiTypography-root"
78+
>
79+
2023-07-28T00:00:00.000Z
80+
</span>
81+
</dd>
82+
<dt
83+
class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-12 MuiGrid-grid-sm-3 MuiGrid-grid-md-2 css-9i4s51-MuiGrid-root"
84+
>
85+
Completion Time
86+
</dt>
87+
<dd
88+
class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-12 MuiGrid-grid-sm-9 MuiGrid-grid-md-10 css-1dbzfsd-MuiGrid-root"
89+
>
90+
<span
91+
class="MuiTypography-root MuiTypography-body1 css-e06lsu-MuiTypography-root"
92+
>
93+
2023-07-28T08:01:00.000Z
94+
</span>
95+
</dd>
96+
<dt
97+
class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-12 MuiGrid-grid-sm-3 MuiGrid-grid-md-2 css-1hrqr1q-MuiGrid-root"
98+
>
99+
Duration
100+
</dt>
101+
<dd
102+
class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-12 MuiGrid-grid-sm-9 MuiGrid-grid-md-10 css-ui3itl-MuiGrid-root"
103+
>
104+
<span
105+
class="MuiTypography-root MuiTypography-body1 css-e06lsu-MuiTypography-root"
106+
>
107+
8h 1m
108+
</span>
109+
</dd>
110+
</dl>
111+
</div>
112+
</body>
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
<body>
2+
<div>
3+
<dl
4+
class="MuiGrid-root MuiGrid-container css-kxuems-MuiGrid-root"
5+
>
6+
<dt
7+
class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-12 MuiGrid-grid-sm-3 MuiGrid-grid-md-2 css-9i4s51-MuiGrid-root"
8+
>
9+
Completions
10+
</dt>
11+
<dd
12+
class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-12 MuiGrid-grid-sm-9 MuiGrid-grid-md-10 css-1dbzfsd-MuiGrid-root"
13+
>
14+
<span
15+
class="MuiTypography-root MuiTypography-body1 css-e06lsu-MuiTypography-root"
16+
>
17+
1/1
18+
</span>
19+
</dd>
20+
<dt
21+
class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-12 MuiGrid-grid-sm-3 MuiGrid-grid-md-2 css-9i4s51-MuiGrid-root"
22+
>
23+
Parallelism
24+
</dt>
25+
<dd
26+
class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-12 MuiGrid-grid-sm-9 MuiGrid-grid-md-10 css-1dbzfsd-MuiGrid-root"
27+
>
28+
1
29+
</dd>
30+
<dt
31+
class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-12 MuiGrid-grid-sm-3 MuiGrid-grid-md-2 css-9i4s51-MuiGrid-root"
32+
>
33+
Suspend
34+
</dt>
35+
<dd
36+
class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-12 MuiGrid-grid-sm-9 MuiGrid-grid-md-10 css-1dbzfsd-MuiGrid-root"
37+
>
38+
<span
39+
class="MuiTypography-root MuiTypography-body1 css-e06lsu-MuiTypography-root"
40+
>
41+
false
42+
</span>
43+
</dd>
44+
<dt
45+
class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-12 MuiGrid-grid-sm-3 MuiGrid-grid-md-2 css-9i4s51-MuiGrid-root"
46+
>
47+
Backoff Limit
48+
</dt>
49+
<dd
50+
class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-12 MuiGrid-grid-sm-9 MuiGrid-grid-md-10 css-1dbzfsd-MuiGrid-root"
51+
>
52+
6
53+
</dd>
54+
<dt
55+
class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-12 MuiGrid-grid-sm-3 MuiGrid-grid-md-2 css-9i4s51-MuiGrid-root"
56+
>
57+
Pods Status
58+
</dt>
59+
<dd
60+
class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-12 MuiGrid-grid-sm-9 MuiGrid-grid-md-10 css-1dbzfsd-MuiGrid-root"
61+
>
62+
<span
63+
class="MuiTypography-root MuiTypography-body1 css-e06lsu-MuiTypography-root"
64+
>
65+
Succeeded: 1
66+
</span>
67+
</dd>
68+
<dt
69+
class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-12 MuiGrid-grid-sm-3 MuiGrid-grid-md-2 css-1hrqr1q-MuiGrid-root"
70+
>
71+
Start Time
72+
</dt>
73+
<dd
74+
class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-12 MuiGrid-grid-sm-9 MuiGrid-grid-md-10 css-ui3itl-MuiGrid-root"
75+
>
76+
<span
77+
class="MuiTypography-root MuiTypography-body1 css-e06lsu-MuiTypography-root"
78+
>
79+
2023-07-28T00:00:00.000Z
80+
</span>
81+
</dd>
82+
</dl>
83+
</div>
84+
</body>
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
* Copyright 2025 The Kubernetes Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import { Meta, StoryFn } from '@storybook/react';
18+
import { useTranslation } from 'react-i18next';
19+
import Job from '../../lib/k8s/job';
20+
import { TestContext } from '../../test';
21+
import NameValueTable from '../common/NameValueTable';
22+
import { jobs } from '../job/storyHelper';
23+
import { jobExtraInfo } from './extraInfo';
24+
25+
// Completed job from storyHelper has both startTime and completionTime, so it
26+
// has a real duration. The running variant drops completionTime, so
27+
// getDuration() returns -1 and the Duration row is hidden.
28+
const completedJob = new Job(jobs[0] as any);
29+
const runningJob = new Job({
30+
...jobs[0],
31+
status: { ...jobs[0].status, completionTime: undefined },
32+
} as any);
33+
34+
// jobExtraInfo takes a translator; render through NameValueTable to show which
35+
// rows are actually displayed (hidden rows are dropped by the table).
36+
function JobExtraInfo({ job }: { job: Job }) {
37+
const { t } = useTranslation();
38+
return <NameValueTable rows={jobExtraInfo(job, t)} />;
39+
}
40+
41+
export default {
42+
title: 'workload/JobExtraInfo',
43+
component: JobExtraInfo,
44+
decorators: [
45+
Story => (
46+
<TestContext>
47+
<Story />
48+
</TestContext>
49+
),
50+
],
51+
} as Meta;
52+
53+
const Template: StoryFn<{ job: Job }> = args => <JobExtraInfo {...args} />;
54+
55+
// Completed job: the Duration row is shown.
56+
export const Completed = Template.bind({});
57+
Completed.args = { job: completedJob };
58+
59+
// Running job: getDuration() is -1, so the Duration row is hidden.
60+
export const Running = Template.bind({});
61+
Running.args = { job: runningJob };
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright 2025 The Kubernetes Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import type { TFunction } from 'i18next';
18+
import { describe, expect, it } from 'vitest';
19+
import type Job from '../../lib/k8s/job';
20+
import { jobExtraInfo } from './extraInfo';
21+
22+
// Passthrough translator: returns the key so rows can be matched by name.
23+
const t = ((key: string) => key) as TFunction;
24+
25+
function jobWithDuration(durationMs: number): Job {
26+
return { status: {}, spec: {}, getDuration: () => durationMs } as unknown as Job;
27+
}
28+
29+
function durationRow(item: Job) {
30+
return jobExtraInfo(item, t).find(row => row && row.name === 'glossary|Duration');
31+
}
32+
33+
describe('jobExtraInfo duration', () => {
34+
it('hides the Duration row for a running job (getDuration() === -1)', () => {
35+
expect(durationRow(jobWithDuration(-1))?.hide).toBe(true);
36+
});
37+
38+
it('shows the Duration row once the job has a real duration', () => {
39+
// 0ms is a legitimate completed-job duration (startTime === completionTime).
40+
for (const durationMs of [0, 5000]) {
41+
const row = durationRow(jobWithDuration(durationMs));
42+
expect(row?.hide).toBeFalsy();
43+
expect(row?.value).toBeTruthy();
44+
}
45+
});
46+
});

frontend/src/components/workload/extraInfo.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,11 @@ export function jobExtraInfo(item: Job, t: TFunction): NameValueTableRow[] {
9393
]
9494
.filter(Boolean)
9595
.join(', ');
96-
const duration = formatDuration(item.getDuration());
96+
// getDuration() returns -1 while a job is still running (no completionTime yet);
97+
// hide the duration in that case. A completed job with startTime === completionTime
98+
// legitimately has a 0ms duration and stays visible as "0s".
99+
const durationMs = item.getDuration();
100+
const duration = durationMs >= 0 ? formatDuration(durationMs) : '';
97101

98102
return [
99103
{

0 commit comments

Comments
 (0)