Skip to content

Commit 2114dae

Browse files
authored
Merge pull request #401 from fractal-analytics-platform/timestamps
Alignment with fractal-server 1.4.3
2 parents 5e0d948 + 2e585f7 commit 2114dae

File tree

18 files changed

+127
-115
lines changed

18 files changed

+127
-115
lines changed

.github/workflows/unit_tests.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,5 @@ jobs:
3131

3232
- name: Run vitest tests
3333
run: npx vitest run
34+
env:
35+
TZ: Europe/Rome

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
# Unreleased
44

5+
* Removed `running` job status (\#401).
6+
* Aligned timestamp definitions with fractal-server 1.4.3 (\#401).
7+
* Sorted projects by descending creation timestamp (\#401).
58
* Removed coverage setup from Playwright tests and CI (\#399).
69

710
# 0.8.2

__tests__/JobsList.test.js

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ describe('JobsList', () => {
4040
const filters = result.getAllByRole('combobox');
4141

4242
const statusFilter = filters[0];
43-
verifyOptions(statusFilter, ['', 'running', 'done', 'failed', 'submitted']);
43+
verifyOptions(statusFilter, ['', 'submitted', 'done', 'failed']);
4444
const projectFilter = filters[1];
4545
verifyOptions(projectFilter, ['', '1', '2']);
4646
const workflowFilter = filters[2];
@@ -80,7 +80,7 @@ describe('JobsList', () => {
8080
await clearFilters(result);
8181

8282
// Filter by job status
83-
await fireEvent.change(statusFilter, { target: { value: 'running' } });
83+
await fireEvent.change(statusFilter, { target: { value: 'submitted' } });
8484
table = result.getByRole('table');
8585
expect(table.querySelectorAll('tbody tr').length).eq(1);
8686
expect(table.querySelectorAll('tbody tr td')[6].textContent).eq('input3');
@@ -89,27 +89,27 @@ describe('JobsList', () => {
8989
// Verify default sorting
9090
table = result.getByRole('table');
9191
expect(table.querySelectorAll('tbody tr:nth-child(1) td')[2].textContent).eq(
92-
'10/30/2023, 9:30:38 AM'
92+
'10/30/2023, 10:30:38 AM'
9393
);
9494
expect(table.querySelectorAll('tbody tr:nth-child(2) td')[2].textContent).eq(
95-
'10/30/2023, 9:15:38 AM'
95+
'10/30/2023, 10:15:38 AM'
9696
);
9797
expect(table.querySelectorAll('tbody tr:nth-child(3) td')[2].textContent).eq(
98-
'10/30/2023, 9:00:38 AM'
98+
'10/30/2023, 10:00:38 AM'
9999
);
100100

101101
// Sort by start date
102102
const startDateSorter = table.querySelector('thead th:nth-child(3)');
103103
await fireEvent.click(startDateSorter);
104104
table = result.getByRole('table');
105105
expect(table.querySelectorAll('tbody tr:nth-child(1) td')[2].textContent).eq(
106-
'10/30/2023, 9:00:38 AM'
106+
'10/30/2023, 10:00:38 AM'
107107
);
108108
expect(table.querySelectorAll('tbody tr:nth-child(2) td')[2].textContent).eq(
109-
'10/30/2023, 9:15:38 AM'
109+
'10/30/2023, 10:15:38 AM'
110110
);
111111
expect(table.querySelectorAll('tbody tr:nth-child(3) td')[2].textContent).eq(
112-
'10/30/2023, 9:30:38 AM'
112+
'10/30/2023, 10:30:38 AM'
113113
);
114114
});
115115

@@ -162,14 +162,14 @@ describe('JobsList', () => {
162162
vi.useFakeTimers();
163163
try {
164164
const jobUpdater = function () {
165-
return data.jobs.map((j) => (j.status === 'running' ? { ...j, status: 'done' } : j));
165+
return data.jobs.map((j) => (j.status === 'submitted' ? { ...j, status: 'done' } : j));
166166
};
167167
const result = render(JobsList, {
168168
props: { jobUpdater }
169169
});
170170
let table = result.getByRole('table');
171171
expect(table.querySelectorAll('tbody tr').length).eq(3);
172-
expect(table.querySelectorAll('tbody tr:nth-child(1) td')[0].textContent).contain('running');
172+
expect(table.querySelectorAll('tbody tr:nth-child(1) td')[0].textContent).contain('submitted');
173173
expect(table.querySelectorAll('tbody tr:nth-child(2) td')[0].textContent).contain('failed');
174174
expect(table.querySelectorAll('tbody tr:nth-child(3) td')[0].textContent).contain('done');
175175

__tests__/component_utilities.test.js

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { it, expect } from 'vitest';
22
import {
33
orderTasksByOwnerThenByNameThenByVersion,
4-
removeDuplicatedItems
4+
removeDuplicatedItems,
5+
sortProjectsByTimestampCreatedDesc
56
} from '$lib/common/component_utilities.js';
67

78
it('should order tasks by owner, then by name, then by version', () => {
@@ -63,3 +64,17 @@ it('removes duplicated datasets and sort by name', () => {
6364
expect(datasets[2].id).toEqual(3);
6465
expect(datasets[2].name).toEqual('test');
6566
});
67+
68+
it('sort projects by timestamp_created DESC', () => {
69+
const projects = [
70+
{ name: 'p1', read_only: false, id: 2, timestamp_created: '2024-01-29T09:34:40.687256+00:00' },
71+
{ name: 'p3', read_only: false, id: 5, timestamp_created: '2024-01-29T09:36:40.380260+00:00' },
72+
{ name: 'p2', read_only: false, id: 4, timestamp_created: '2024-01-29T09:35:20.571999+00:00' }
73+
];
74+
75+
sortProjectsByTimestampCreatedDesc(projects);
76+
77+
expect(projects[0].name).eq('p3');
78+
expect(projects[1].name).eq('p2');
79+
expect(projects[2].name).eq('p1');
80+
});

__tests__/mock/jobs-list.js

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,9 @@ export const data = {
3939
workflow_id: 1,
4040
input_dataset_id: 1,
4141
output_dataset_id: 2,
42-
start_timestamp: '2023-10-30T09:00:38.442196',
43-
end_timestamp: '2023-10-30T09:10:38.442196',
42+
start_timestamp: '2023-10-30T09:00:38.442196+00:00',
43+
end_timestamp: '2023-10-30T09:10:38.442196+00:00',
44+
project_dump: { id: 1, name: 'project 1' },
4445
workflow_dump: { id: 1, name: 'workflow 1' },
4546
input_dataset_dump: { id: 1, name: 'input1' },
4647
output_dataset_dump: { id: 2, name: 'output1' },
@@ -53,8 +54,9 @@ export const data = {
5354
workflow_id: 2,
5455
input_dataset_id: 3,
5556
output_dataset_id: 4,
56-
start_timestamp: '2023-10-30T09:15:38.442196',
57-
end_timestamp: '2023-10-30T09:20:38.442196',
57+
start_timestamp: '2023-10-30T09:15:38.442196+00:00',
58+
end_timestamp: '2023-10-30T09:20:38.442196+00:00',
59+
project_dump: { id: 2, name: 'project 2' },
5860
workflow_dump: { id: 2, name: 'workflow 2' },
5961
input_dataset_dump: { id: 3, name: 'input2' },
6062
output_dataset_dump: { id: 4, name: 'output2' },
@@ -67,11 +69,13 @@ export const data = {
6769
workflow_id: 2,
6870
input_dataset_id: 5,
6971
output_dataset_id: 6,
70-
start_timestamp: '2023-10-30T09:30:38.442196',
72+
start_timestamp: '2023-10-30T09:30:38.442196+00:00',
73+
project_dump: { id: 2, name: 'project 2' },
74+
workflow_dump: { id: 2, name: 'workflow 2' },
7175
input_dataset_dump: { id: 5, name: 'input3' },
7276
output_dataset_dump: { id: 6, name: 'output3' },
7377
end_timestamp: null,
74-
status: 'running',
78+
status: 'submitted',
7579
user_email: '[email protected]'
7680
}
7781
]

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
"lint": "prettier --check . && eslint .",
1212
"format": "prettier --write .",
1313
"pre-commit": "lint-staged",
14-
"test": "vitest"
14+
"test": "TZ=Europe/Rome vitest"
1515
},
1616
"devDependencies": {
1717
"@playwright/test": "^1.40.0",

playwright.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ export default defineConfig({
3939

4040
webServer: [
4141
{
42-
command: './tests/start-test-server.sh 1.4.2',
42+
command: './tests/start-test-server.sh 1.4.3a2',
4343
port: 8000,
4444
waitForPort: true,
4545
stdout: 'pipe',

src/lib/common/component_utilities.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,3 +212,16 @@ export function removeDuplicatedItems(allItems) {
212212
}
213213
return items.sort((a, b) => (a.name < b.name ? -1 : a.name === b.name ? 0 : 1));
214214
}
215+
216+
/**
217+
* @param {import('$lib/types').Project[]} projects
218+
*/
219+
export function sortProjectsByTimestampCreatedDesc(projects) {
220+
projects.sort((p1, p2) =>
221+
p1.timestamp_created < p2.timestamp_created
222+
? 1
223+
: p1.timestamp_created > p2.timestamp_created
224+
? -1
225+
: 0
226+
);
227+
}

src/lib/components/jobs/JobInfoModal.svelte

Lines changed: 12 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,31 +4,18 @@
44
import { page } from '$app/stores';
55
import Modal from '../common/Modal.svelte';
66
7-
/** @type {number|undefined} */
8-
let workflowJobId = undefined;
97
/** @type {import('$lib/types').ApplyWorkflow|undefined} */
108
let job = undefined;
11-
/** @type {number|undefined} */
12-
let projectId = undefined;
13-
/** @type {string|undefined} */
14-
let projectName = undefined;
15-
let jobStatus = undefined;
169
1710
let errorAlert = undefined;
1811
/** @type {Modal} */
1912
let modal;
2013
2114
/**
2215
* @param jobToDisplay {import('$lib/types').ApplyWorkflow}
23-
* @param projectNameToDisplay {string}
2416
*/
25-
export async function show(jobToDisplay, projectNameToDisplay) {
17+
export async function show(jobToDisplay) {
2618
job = jobToDisplay;
27-
workflowJobId = job.id;
28-
projectId = job.project_id;
29-
projectName = projectNameToDisplay;
30-
jobStatus = job.status;
31-
3219
modal.show();
3320
}
3421
@@ -37,8 +24,11 @@
3724
if (errorAlert) {
3825
errorAlert.hide();
3926
}
27+
if (!job) {
28+
return;
29+
}
4030
41-
const response = await fetch(`/api/v1/project/${projectId}/job/${workflowJobId}`, {
31+
const response = await fetch(`/api/v1/project/${job.project_dump.id}/job/${job.id}`, {
4232
method: 'GET',
4333
credentials: 'include'
4434
});
@@ -54,7 +44,7 @@
5444

5545
<Modal id="workflowJobInfoModal" bind:this={modal} size="lg">
5646
<svelte:fragment slot="header">
57-
<h1 class="h5 modal-title flex-grow-1">Workflow Job #{workflowJobId}</h1>
47+
<h1 class="h5 modal-title flex-grow-1">Workflow Job #{job?.id}</h1>
5848
{#if job && job.user_email === $page.data.userInfo.email && job.project_id !== null}
5949
<button class="btn btn-light me-3" on:click={fetchJob}>
6050
<i class="bi-arrow-clockwise" />
@@ -71,16 +61,16 @@
7161
<li class="list-group-item list-group-item-light fw-bold">Id</li>
7262
<li class="list-group-item">{job.id}</li>
7363
<li class="list-group-item list-group-item-light fw-bold">Workflow</li>
74-
<li class="list-group-item">{job.workflow_dump?.name || '-'}</li>
64+
<li class="list-group-item">{job.workflow_dump.name}</li>
7565
<li class="list-group-item list-group-item-light fw-bold">Project</li>
76-
<li class="list-group-item">{projectName || '-'}</li>
66+
<li class="list-group-item">{job.project_dump.name}</li>
7767
<li class="list-group-item list-group-item-light fw-bold">Input dataset</li>
78-
<li class="list-group-item">{job.input_dataset_dump?.name || '-'}</li>
68+
<li class="list-group-item">{job.input_dataset_dump.name}</li>
7969
<li class="list-group-item list-group-item-light fw-bold">Output dataset</li>
80-
<li class="list-group-item">{job.output_dataset_dump?.name || '-'}</li>
70+
<li class="list-group-item">{job.output_dataset_dump.name}</li>
8171
<li class="list-group-item list-group-item-light fw-bold">Status</li>
82-
{#key jobStatus}
83-
<li class="list-group-item"><StatusBadge status={jobStatus} /></li>
72+
{#key job.status}
73+
<li class="list-group-item"><StatusBadge status={job.status} /></li>
8474
{/key}
8575
<li class="list-group-item list-group-item-light fw-bold">Working directory</li>
8676
<li class="list-group-item"><code>{job.working_dir}</code></li>

src/lib/components/jobs/JobStatusIcon.svelte

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,7 @@
66
{#if status}
77
<span title={status}>
88
{#if status === 'submitted'}
9-
<i class="bi bi-hourglass text-secondary job-status-submitted" />
10-
{:else if status === 'running'}
11-
<div class="spinner-border spinner-border-sm text-primary job-status-icon-running" role="status">
9+
<div class="spinner-border spinner-border-sm text-primary job-status-icon-submitted" role="status">
1210
<span class="visually-hidden">Loading...</span>
1311
</div>
1412
{:else if status === 'done'}
@@ -33,7 +31,7 @@
3331
border-radius: 50%;
3432
}
3533
36-
:global(.active .job-status-icon-running, .active .job-status-submitted) {
34+
:global(.active .job-status-submitted) {
3735
color: #fff !important;
3836
}
3937
</style>

0 commit comments

Comments
 (0)