Skip to content

Commit 87543e4

Browse files
authored
Merge pull request #422 from fractal-analytics-platform/fix-meta-update-bug
Fixed bug in workflow task meta properties update
2 parents b7ee02b + ed2159b commit 87543e4

File tree

5 files changed

+78
-61
lines changed

5 files changed

+78
-61
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
*Note: Numbers like (\#123) point to closed Pull Requests on the fractal-web repository.*
22

3+
# Unreleased
4+
5+
* Fixed bug in workflow task meta properties update (\#422).
6+
37
# 0.10.0
48

59
This release requires fractal-server 1.4.6.

src/lib/components/workflow/MetaPropertiesForm.svelte

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,15 @@
1414
1515
// Workflow id
1616
export let workflowId;
17-
// Workflow task id
18-
export let taskId;
19-
// Workflow task meta properties
20-
export let metaProperties;
21-
export let originalMetaProperties;
17+
/** @type {import('$lib/types').WorkflowTask} */
18+
export let workflowTask;
2219
23-
if (metaProperties === null || metaProperties === undefined) {
24-
metaProperties = {};
25-
}
26-
if (originalMetaProperties === null || originalMetaProperties === undefined) {
27-
originalMetaProperties = {};
20+
let metaProperties = {};
21+
let originalMetaProperties = {};
22+
23+
$: {
24+
metaProperties = workflowTask.meta || {};
25+
updateOriginalMetaProperties();
2826
}
2927
3028
async function handleEntryUpdate() {
@@ -34,20 +32,25 @@
3432
const updatedMetaProperties = await updateFormEntry(
3533
projectId,
3634
workflowId,
37-
taskId,
35+
workflowTask.id,
3836
modifiedProperties,
3937
'meta'
4038
);
39+
workflowTask.meta = updatedMetaProperties.meta;
4140
metaProperties = updatedMetaProperties.meta;
4241
// Updating original properties again
43-
for (let key in metaProperties) {
44-
originalMetaProperties[key] = metaProperties[key];
45-
}
42+
updateOriginalMetaProperties();
4643
} catch (error) {
4744
console.log(error);
4845
displayStandardErrorAlert(error, 'metaPropertiesFormError');
4946
}
5047
}
48+
49+
function updateOriginalMetaProperties() {
50+
for (let key in metaProperties) {
51+
originalMetaProperties[key] = metaProperties[key];
52+
}
53+
}
5154
</script>
5255

5356
<div>

src/routes/projects/[projectId]/workflows/[workflowId]/+page.svelte

Lines changed: 6 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
<script>
2-
import { onDestroy, onMount } from 'svelte';
3-
import { writable } from 'svelte/store';
2+
import { onMount } from 'svelte';
43
import { goto, beforeNavigate } from '$app/navigation';
54
import { page } from '$app/stores';
65
import ArgumentForm from '$lib/components/workflow/ArgumentForm.svelte';
@@ -29,13 +28,10 @@
2928
*/
3029
let availableTasks = [];
3130
32-
/** @type {import('svelte/store').Writable<import('$lib/types').WorkflowTask|undefined>} */
33-
let workflowTaskContext = writable(undefined);
3431
let workflowTabContextId = 0;
3532
let workflowSuccessMessage = '';
3633
/** @type {import('$lib/types').WorkflowTask|undefined} */
3734
let selectedWorkflowTask = undefined;
38-
let originalMetaProperties = {};
3935
let checkingConfiguration = false;
4036
let inputDatasetControl = '';
4137
let outputDatasetControl = '';
@@ -77,16 +73,6 @@
7773
7874
$: updatableWorkflowList = workflow?.task_list || [];
7975
80-
const unsubscribe = workflowTaskContext.subscribe((value) => {
81-
selectedWorkflowTask = value;
82-
originalMetaProperties = {};
83-
if (value && value.meta) {
84-
for (let key in value.meta) {
85-
originalMetaProperties[key] = value.meta[key];
86-
}
87-
}
88-
});
89-
9076
onMount(async () => {
9177
workflow = /** @type {import('$lib/types').Workflow} */ ($page.data.workflow);
9278
project = workflow.project;
@@ -332,7 +318,7 @@
332318
333319
// Successfully deleted task
334320
workflow = workflowResult;
335-
workflowTaskContext.set(undefined);
321+
selectedWorkflowTask = undefined;
336322
}
337323
338324
async function setActiveWorkflowTaskContext(event) {
@@ -360,7 +346,7 @@
360346
* @param {import('$lib/types').WorkflowTask} wft
361347
*/
362348
function setWorkflowTaskContext(wft) {
363-
workflowTaskContext.set(wft);
349+
selectedWorkflowTask = wft;
364350
// Check if args schema is available
365351
argsSchemaAvailable =
366352
wft.task.args_schema === undefined || wft.task.args_schema === null ? false : true;
@@ -570,8 +556,6 @@
570556
async function updateNewVersionsCount(count) {
571557
newVersionsCount = count;
572558
}
573-
574-
onDestroy(unsubscribe);
575559
</script>
576560
577561
<div class="d-flex justify-content-between align-items-center mb-4">
@@ -660,8 +644,8 @@
660644
{#each workflow.task_list as workflowTask}
661645
<button
662646
style="cursor: pointer"
663-
class="list-group-item list-group-item-action {$workflowTaskContext !==
664-
undefined && $workflowTaskContext.id == workflowTask.id
647+
class="list-group-item list-group-item-action {selectedWorkflowTask !==
648+
undefined && selectedWorkflowTask.id == workflowTask.id
665649
? 'active'
666650
: ''}"
667651
data-fs-target={workflowTask.id}
@@ -785,9 +769,7 @@
785769
{#key selectedWorkflowTask}
786770
<MetaPropertiesForm
787771
workflowId={workflow.id}
788-
taskId={selectedWorkflowTask.id}
789-
metaProperties={selectedWorkflowTask.meta}
790-
{originalMetaProperties}
772+
workflowTask={selectedWorkflowTask}
791773
/>
792774
{/key}
793775
{/if}

src/routes/projects/[projectId]/workflows/experimental/[workflowId]/+page.svelte

Lines changed: 5 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
<script>
22
import { env } from '$env/dynamic/public';
33
import { onDestroy, onMount } from 'svelte';
4-
import { writable } from 'svelte/store';
54
import { beforeNavigate } from '$app/navigation';
65
import { page } from '$app/stores';
76
import ArgumentForm from '$lib/components/workflow/ArgumentForm.svelte';
@@ -42,13 +41,10 @@
4241
/** @type {import('$lib/components/common/StandardErrorAlert.svelte').default|undefined} */
4342
let workflowErrorAlert = undefined;
4443
45-
/** @type {import('svelte/store').Writable<import('$lib/types').WorkflowTask|undefined>} */
46-
let workflowTaskContext = writable(undefined);
4744
let workflowTabContextId = 0;
4845
let workflowSuccessMessage = '';
4946
/** @type {import('$lib/types').WorkflowTask|undefined} */
5047
let selectedWorkflowTask = undefined;
51-
let originalMetaProperties = {};
5248
let checkingConfiguration = false;
5349
let setSlurmAccount = true;
5450
let slurmAccount =
@@ -91,16 +87,6 @@
9187
9288
$: updatableWorkflowList = workflow.task_list || [];
9389
94-
const unsubscribe = workflowTaskContext.subscribe((value) => {
95-
selectedWorkflowTask = value;
96-
originalMetaProperties = {};
97-
if (value && value.meta) {
98-
for (let key in value.meta) {
99-
originalMetaProperties[key] = value.meta[key];
100-
}
101-
}
102-
});
103-
10490
const updateJobsInterval = env.PUBLIC_UPDATE_JOBS_INTERVAL
10591
? parseInt(env.PUBLIC_UPDATE_JOBS_INTERVAL)
10692
: 3000;
@@ -345,7 +331,7 @@
345331
346332
// Successfully deleted task
347333
workflow = workflowResult;
348-
workflowTaskContext.set(undefined);
334+
selectedWorkflowTask = undefined;
349335
}
350336
351337
async function setActiveWorkflowTaskContext(event) {
@@ -369,12 +355,11 @@
369355
unsavedChangesModal.toggle();
370356
}
371357
372-
373358
/**
374359
* @param {import('$lib/types').WorkflowTask} wft
375360
*/
376361
function setWorkflowTaskContext(wft) {
377-
workflowTaskContext.set(wft);
362+
selectedWorkflowTask = wft;
378363
// Check if args schema is available
379364
argsSchemaAvailable =
380365
wft.task.args_schema === undefined || wft.task.args_schema === null ? false : true;
@@ -651,7 +636,6 @@
651636
652637
onDestroy(() => {
653638
clearTimeout(statusWatcherTimer);
654-
unsubscribe();
655639
});
656640
</script>
657641

@@ -805,8 +789,8 @@
805789
{#each workflow.task_list as workflowTask}
806790
<button
807791
style="cursor: pointer"
808-
class="list-group-item list-group-item-action {$workflowTaskContext !==
809-
undefined && $workflowTaskContext.id == workflowTask.id
792+
class="list-group-item list-group-item-action {selectedWorkflowTask !==
793+
undefined && selectedWorkflowTask.id == workflowTask.id
810794
? 'active'
811795
: ''}"
812796
data-fs-target={workflowTask.id}
@@ -933,9 +917,7 @@
933917
{#key selectedWorkflowTask}
934918
<MetaPropertiesForm
935919
workflowId={workflow.id}
936-
taskId={selectedWorkflowTask.id}
937-
metaProperties={selectedWorkflowTask.meta}
938-
{originalMetaProperties}
920+
workflowTask={selectedWorkflowTask}
939921
/>
940922
{/key}
941923
{/if}

tests/workflow_meta.spec.js

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { waitPageLoading } from './utils.js';
2+
import { expect, test } from './workflow_fixture.js';
3+
4+
test('Workflow task meta', async ({ page, workflow }) => {
5+
await page.waitForURL(workflow.url);
6+
await waitPageLoading(page);
7+
8+
await test.step('Add 2 tasks to workflow', async () => {
9+
await workflow.addFakeTask();
10+
await workflow.addFakeTask();
11+
});
12+
13+
await test.step('Select first task meta', async () => {
14+
await page.getByText('Fake Task').first().click();
15+
await page.getByText('Meta', { exact: true }).click();
16+
});
17+
18+
await test.step('Add meta property to first task', async () => {
19+
await page.getByRole('button', { name: 'Add property' }).click();
20+
await page.getByRole('textbox').nth(0).fill('key1');
21+
await page.getByRole('textbox').nth(1).fill('value1');
22+
await page.getByLabel('Save argument').click();
23+
await page.waitForFunction(
24+
() => document.querySelectorAll('#meta-tab input[type="text"]').length === 0
25+
);
26+
});
27+
28+
await test.step('Select second task and then go back to first task', async () => {
29+
await page.getByText('Fake Task').nth(1).click();
30+
await page.getByText('Fake Task').nth(0).click();
31+
});
32+
33+
await test.step('Verify that the inserted values are still there', async () => {
34+
await expect(page.getByText('key1')).toBeVisible();
35+
await expect(page.getByText('value1')).toBeVisible();
36+
});
37+
38+
await test.step('Verify that the inserted values have been saved', async () => {
39+
await page.reload();
40+
await waitPageLoading(page);
41+
await page.getByText('Fake Task').first().click();
42+
await page.getByText('Meta', { exact: true }).click();
43+
await expect(page.getByText('key1')).toBeVisible();
44+
await expect(page.getByText('value1')).toBeVisible();
45+
});
46+
});

0 commit comments

Comments
 (0)