Skip to content

Commit 6e65505

Browse files
committed
Changed job table columns order and set word break to header
1 parent 7056e04 commit 6e65505

File tree

4 files changed

+107
-96
lines changed

4 files changed

+107
-96
lines changed

__tests__/JobsList.test.js

Lines changed: 31 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -39,76 +39,76 @@ describe('JobsList', () => {
3939

4040
const filters = result.getAllByRole('combobox');
4141

42-
const projectFilter = filters[0];
42+
const statusFilter = filters[0];
43+
verifyOptions(statusFilter, ['', 'running', 'done', 'failed', 'submitted']);
44+
const projectFilter = filters[1];
4345
verifyOptions(projectFilter, ['', '1', '2']);
44-
const workflowFilter = filters[1];
46+
const workflowFilter = filters[2];
4547
verifyOptions(workflowFilter, ['', '1', '2']);
46-
const inputDatasetFilter = filters[2];
48+
const inputDatasetFilter = filters[3];
4749
verifyOptions(inputDatasetFilter, ['', '1', '3', '5']);
48-
const outputDatasetFilter = filters[3];
50+
const outputDatasetFilter = filters[4];
4951
verifyOptions(outputDatasetFilter, ['', '2', '4', '6']);
50-
const statusFilter = filters[4];
51-
verifyOptions(statusFilter, ['', 'running', 'done', 'failed', 'submitted']);
5252

5353
// Filter by project
5454
await fireEvent.change(projectFilter, { target: { value: '1' } });
5555
table = result.getByRole('table');
5656
expect(table.querySelectorAll('tbody tr').length).eq(1);
57-
expect(table.querySelectorAll('tbody tr td')[4].textContent).eq('input1');
57+
expect(table.querySelectorAll('tbody tr td')[6].textContent).eq('input1');
5858
await clearFilters(result);
5959

6060
// Filter by workflow
6161
await fireEvent.change(workflowFilter, { target: { value: '2' } });
6262
table = result.getByRole('table');
6363
expect(table.querySelectorAll('tbody tr').length).eq(2);
64-
expect(table.querySelectorAll('tbody tr:nth-child(1) td')[4].textContent).eq('input3');
65-
expect(table.querySelectorAll('tbody tr:nth-child(2) td')[4].textContent).eq('input2');
64+
expect(table.querySelectorAll('tbody tr:nth-child(1) td')[6].textContent).eq('input3');
65+
expect(table.querySelectorAll('tbody tr:nth-child(2) td')[6].textContent).eq('input2');
6666
await clearFilters(result);
6767

6868
// Filter by input dataset
6969
await fireEvent.change(inputDatasetFilter, { target: { value: '3' } });
7070
table = result.getByRole('table');
7171
expect(table.querySelectorAll('tbody tr').length).eq(1);
72-
expect(table.querySelectorAll('tbody tr td')[4].textContent).eq('input2');
72+
expect(table.querySelectorAll('tbody tr td')[6].textContent).eq('input2');
7373
await clearFilters(result);
7474

7575
// Filter by output dataset
7676
await fireEvent.change(outputDatasetFilter, { target: { value: '4' } });
7777
table = result.getByRole('table');
7878
expect(table.querySelectorAll('tbody tr').length).eq(1);
79-
expect(table.querySelectorAll('tbody tr td')[5].textContent).eq('output2');
79+
expect(table.querySelectorAll('tbody tr td')[7].textContent).eq('output2');
8080
await clearFilters(result);
8181

8282
// Filter by job status
8383
await fireEvent.change(statusFilter, { target: { value: 'running' } });
8484
table = result.getByRole('table');
8585
expect(table.querySelectorAll('tbody tr').length).eq(1);
86-
expect(table.querySelectorAll('tbody tr td')[4].textContent).eq('input3');
86+
expect(table.querySelectorAll('tbody tr td')[6].textContent).eq('input3');
8787
await clearFilters(result);
8888

8989
// Verify default sorting
9090
table = result.getByRole('table');
91-
expect(table.querySelectorAll('tbody tr:nth-child(1) td')[0].textContent).eq(
91+
expect(table.querySelectorAll('tbody tr:nth-child(1) td')[2].textContent).eq(
9292
'10/30/2023, 9:30:38 AM'
9393
);
94-
expect(table.querySelectorAll('tbody tr:nth-child(2) td')[0].textContent).eq(
94+
expect(table.querySelectorAll('tbody tr:nth-child(2) td')[2].textContent).eq(
9595
'10/30/2023, 9:15:38 AM'
9696
);
97-
expect(table.querySelectorAll('tbody tr:nth-child(3) td')[0].textContent).eq(
97+
expect(table.querySelectorAll('tbody tr:nth-child(3) td')[2].textContent).eq(
9898
'10/30/2023, 9:00:38 AM'
9999
);
100100

101101
// Sort by start date
102-
const startDateSorter = table.querySelector('thead th:nth-child(2)');
102+
const startDateSorter = table.querySelector('thead th:nth-child(3)');
103103
await fireEvent.click(startDateSorter);
104104
table = result.getByRole('table');
105-
expect(table.querySelectorAll('tbody tr:nth-child(1) td')[0].textContent).eq(
105+
expect(table.querySelectorAll('tbody tr:nth-child(1) td')[2].textContent).eq(
106106
'10/30/2023, 9:00:38 AM'
107107
);
108-
expect(table.querySelectorAll('tbody tr:nth-child(2) td')[0].textContent).eq(
108+
expect(table.querySelectorAll('tbody tr:nth-child(2) td')[2].textContent).eq(
109109
'10/30/2023, 9:15:38 AM'
110110
);
111-
expect(table.querySelectorAll('tbody tr:nth-child(3) td')[0].textContent).eq(
111+
expect(table.querySelectorAll('tbody tr:nth-child(3) td')[2].textContent).eq(
112112
'10/30/2023, 9:30:38 AM'
113113
);
114114
});
@@ -127,17 +127,17 @@ describe('JobsList', () => {
127127
});
128128
let table = result.getByRole('table');
129129
expect(table.querySelectorAll('tbody tr').length).eq(3);
130-
expect(table.querySelectorAll('tbody tr:nth-child(1) td')[6].textContent).eq('running');
131-
expect(table.querySelectorAll('tbody tr:nth-child(2) td')[6].textContent).eq('failed');
132-
expect(table.querySelectorAll('tbody tr:nth-child(3) td')[6].textContent).eq('done');
130+
expect(table.querySelectorAll('tbody tr:nth-child(1) td')[0].textContent).eq('running');
131+
expect(table.querySelectorAll('tbody tr:nth-child(2) td')[0].textContent).eq('failed');
132+
expect(table.querySelectorAll('tbody tr:nth-child(3) td')[0].textContent).eq('done');
133133

134134
const refreshButton = result.getByRole('button', { name: 'Refresh' });
135135
await fireEvent.click(refreshButton);
136136

137137
table = result.getByRole('table');
138-
expect(table.querySelectorAll('tbody tr:nth-child(1) td')[6].textContent).eq('done');
139-
expect(table.querySelectorAll('tbody tr:nth-child(2) td')[6].textContent).eq('failed');
140-
expect(table.querySelectorAll('tbody tr:nth-child(3) td')[6].textContent).eq('done');
138+
expect(table.querySelectorAll('tbody tr:nth-child(1) td')[0].textContent).eq('done');
139+
expect(table.querySelectorAll('tbody tr:nth-child(2) td')[0].textContent).eq('failed');
140+
expect(table.querySelectorAll('tbody tr:nth-child(3) td')[0].textContent).eq('done');
141141
});
142142

143143
it('cancel job', async () => {
@@ -190,19 +190,19 @@ describe('JobsList', () => {
190190
});
191191
let table = result.getByRole('table');
192192
expect(table.querySelectorAll('tbody tr').length).eq(3);
193-
expect(table.querySelectorAll('tbody tr:nth-child(1) td')[6].textContent).eq('running');
194-
expect(table.querySelectorAll('tbody tr:nth-child(2) td')[6].textContent).eq('failed');
195-
expect(table.querySelectorAll('tbody tr:nth-child(3) td')[6].textContent).eq('done');
193+
expect(table.querySelectorAll('tbody tr:nth-child(1) td')[0].textContent).eq('running');
194+
expect(table.querySelectorAll('tbody tr:nth-child(2) td')[0].textContent).eq('failed');
195+
expect(table.querySelectorAll('tbody tr:nth-child(3) td')[0].textContent).eq('done');
196196

197197
vi.advanceTimersByTime(3500);
198198
vi.useRealTimers();
199199
// trigger table update
200200
await new Promise(setTimeout);
201201

202202
table = result.getByRole('table');
203-
expect(table.querySelectorAll('tbody tr:nth-child(1) td')[6].textContent).eq('done');
204-
expect(table.querySelectorAll('tbody tr:nth-child(2) td')[6].textContent).eq('failed');
205-
expect(table.querySelectorAll('tbody tr:nth-child(3) td')[6].textContent).eq('done');
203+
expect(table.querySelectorAll('tbody tr:nth-child(1) td')[0].textContent).eq('done');
204+
expect(table.querySelectorAll('tbody tr:nth-child(2) td')[0].textContent).eq('failed');
205+
expect(table.querySelectorAll('tbody tr:nth-child(3) td')[0].textContent).eq('done');
206206
} finally {
207207
vi.useRealTimers();
208208
}
Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,26 @@
11
<script>
2+
/** @type {import('@vincjo/datatables').DataHandler} */
23
export let handler;
4+
/** @type {string} */
35
export let key;
6+
/** @type {string} */
47
export let label;
58
let filterLabel = label;
69
10+
/** @type {import('svelte/store').Writable<{ identifier: string | null, direction: 'asc' | 'desc' | null }>} */
711
let sorted;
812
$: {
913
sorted = handler.getSorted();
1014
if ($sorted.identifier === key) {
1115
if ($sorted.direction === 'asc') {
12-
filterLabel = label + ' ';
16+
filterLabel = label + '&nbsp;';
1317
} else {
14-
filterLabel = label + ' ';
18+
filterLabel = label + '&nbsp;';
1519
}
1620
} else {
17-
filterLabel = label + ' ';
21+
filterLabel = label + '&nbsp;';
1822
}
1923
}
2024
</script>
2125

22-
<th on:click={handler.sort(key)} style="cursor: pointer">{filterLabel}</th>
26+
<th on:click={() => handler.sort(key)} style="cursor: pointer">{@html filterLabel}</th>

src/lib/components/jobs/JobsList.svelte

Lines changed: 62 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -162,21 +162,23 @@
162162
<div id="jobUpdatesError" />
163163
<table class="table jobs-table">
164164
<colgroup>
165-
<col width="120" />
166-
<col width="120" />
165+
<col width="110" />
166+
<col width="110" />
167+
<col width="100" />
168+
<col width="100" />
167169
{#if !columnsToHide.includes('project')}
168-
<col width="120" />
170+
<col width="110" />
169171
{/if}
170172
{#if !columnsToHide.includes('workflow')}
171-
<col width="120" />
173+
<col width="110" />
172174
{/if}
173-
<col width="135" />
174-
<col width="145" />
175-
<col width="120" />
176-
<col width="120" />
175+
<col width="110" />
176+
<col width="110" />
177177
</colgroup>
178-
<thead class="table-light text-nowrap">
178+
<thead class="table-light">
179179
<tr>
180+
<Th handler={tableHandler} key="status" label="Status" />
181+
<th>Options</th>
180182
<Th handler={tableHandler} key="start_timestamp" label="Start" />
181183
<Th handler={tableHandler} key="end_timestamp" label="End" />
182184
{#if !columnsToHide.includes('project')}
@@ -187,10 +189,18 @@
187189
{/if}
188190
<Th handler={tableHandler} key="input_dataset_id" label="Input dataset" />
189191
<Th handler={tableHandler} key="output_dataset_id" label="Output dataset" />
190-
<Th handler={tableHandler} key="status" label="Status" />
191-
<th>Options</th>
192192
</tr>
193193
<tr>
194+
<th>
195+
<select class="form-control" bind:value={statusFilter}>
196+
<option value="">All</option>
197+
<option value="running">Running</option>
198+
<option value="done">Done</option>
199+
<option value="failed">Failed</option>
200+
<option value="submitted">Submitted</option>
201+
</select>
202+
</th>
203+
<th />
194204
<th />
195205
<th />
196206
{#if !columnsToHide.includes('project')}
@@ -235,23 +245,47 @@
235245
{/each}
236246
</select>
237247
</th>
238-
<th>
239-
<select class="form-control" bind:value={statusFilter}>
240-
<option value="">All</option>
241-
<option value="running">Running</option>
242-
<option value="done">Done</option>
243-
<option value="failed">Failed</option>
244-
<option value="submitted">Submitted</option>
245-
</select>
246-
</th>
247-
<th />
248248
</tr>
249249
</thead>
250250

251251
<tbody>
252252
{#if rows}
253253
{#each $rows as row}
254254
<tr class="align-middle">
255+
<td>
256+
<StatusBadge status={row.status} />
257+
</td>
258+
<td>
259+
<button
260+
class="btn btn-info"
261+
on:click|preventDefault={() =>
262+
jobInfoModal.show(row, getProjectName(row.project_id))}
263+
>
264+
<i class="bi-info-circle" />
265+
Info
266+
</button>
267+
{#if row.status === 'failed' || row.status === 'done'}
268+
<button
269+
class="btn btn-light"
270+
on:click|preventDefault={() => jobLogsModal.show(row.project_id, row.id)}
271+
>
272+
<i class="bi-list-columns-reverse" />
273+
Logs
274+
</button>
275+
<a
276+
class="btn btn-light"
277+
href={`/api/v1/project/${row.project_id}/job/${row.id}/download`}
278+
download={`${row.id}_logs.zip`}
279+
>
280+
<i class="bi-arrow-down-circle" />
281+
</a>
282+
{/if}
283+
{#if row.status === 'running'}
284+
<button class="btn btn-danger" on:click={() => handleJobCancel(row)}>
285+
<i class="bi-x-circle" /> Cancel
286+
</button>
287+
{/if}
288+
</td>
255289
<td>
256290
{row.start_timestamp ? new Date(row.start_timestamp).toLocaleString() : '-'}
257291
</td>
@@ -290,40 +324,6 @@
290324
</a>
291325
{/if}
292326
</td>
293-
<td>
294-
<StatusBadge status={row.status} />
295-
</td>
296-
<td>
297-
<button
298-
class="btn btn-info"
299-
on:click|preventDefault={() =>
300-
jobInfoModal.show(row, getProjectName(row.project_id))}
301-
>
302-
<i class="bi-info-circle" />
303-
Info
304-
</button>
305-
{#if row.status === 'failed' || row.status === 'done'}
306-
<button
307-
class="btn btn-light"
308-
on:click|preventDefault={() => jobLogsModal.show(row.project_id, row.id)}
309-
>
310-
<i class="bi-list-columns-reverse" />
311-
Logs
312-
</button>
313-
<a
314-
class="btn btn-light"
315-
href={`/api/v1/project/${row.project_id}/job/${row.id}/download`}
316-
download={`${row.id}_logs.zip`}
317-
>
318-
<i class="bi-arrow-down-circle" />
319-
</a>
320-
{/if}
321-
{#if row.status === 'running'}
322-
<button class="btn btn-danger" on:click={() => handleJobCancel(row)}>
323-
<i class="bi-x-circle" /> Cancel
324-
</button>
325-
{/if}
326-
</td>
327327
</tr>
328328
{/each}
329329
{/if}
@@ -337,6 +337,13 @@
337337
<style>
338338
.jobs-table {
339339
table-layout: fixed;
340+
}
341+
342+
.jobs-table thead {
343+
word-break: break-word;
344+
}
345+
346+
.jobs-table tbody {
340347
word-break: break-all;
341348
}
342349
</style>

tests/jobs.spec.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ test('Execute a job and show it on the job tables', async ({ page, workflow }) =
3737
await page.locator('table tbody').waitFor();
3838
expect(await page.locator('table tbody tr').count()).toEqual(1);
3939
const cells = await page.locator('table tbody tr td').allInnerTexts();
40-
expect(cells[2]).toEqual('input');
41-
expect(cells[3]).toEqual('output');
40+
expect(cells[4]).toEqual('input');
41+
expect(cells[5]).toEqual('output');
4242

4343
// Open Info modal
4444
await page.locator('table tbody tr').getByRole('button', { name: 'Info' }).click();
@@ -68,10 +68,10 @@ test('Execute a job and show it on the job tables', async ({ page, workflow }) =
6868
if (id === jobId) {
6969
jobRow = row;
7070
const cells = await row.locator('td').allInnerTexts();
71-
expect(cells[2]).toEqual(workflow.projectName);
72-
expect(cells[3]).toEqual(workflow.workflowName);
73-
expect(cells[4]).toEqual('input');
74-
expect(cells[5]).toEqual('output');
71+
expect(cells[4]).toEqual(workflow.projectName);
72+
expect(cells[5]).toEqual(workflow.workflowName);
73+
expect(cells[6]).toEqual('input');
74+
expect(cells[7]).toEqual('output');
7575
break;
7676
}
7777
}

0 commit comments

Comments
 (0)