Skip to content

Commit 6cea96d

Browse files
authored
Merge pull request #686 from fractal-analytics-platform/workflow-task-images
Displayed list of images in run workflow modal
2 parents 05c4ab3 + 6562f87 commit 6cea96d

33 files changed

+1848
-1195
lines changed

.env

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,4 @@ LOG_LEVEL_CONSOLE=warn
2020

2121
FRACTAL_RUNNER_BACKEND=local
2222
#WARNING_BANNER_PATH=/path/to/banner.txt
23+
ENABLE_INTERACTIVE_ATTRIBUTE_FILTERS=false

.env.development

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,4 @@ LOG_LEVEL_CONSOLE=info
1919

2020
FRACTAL_RUNNER_BACKEND=local
2121
#WARNING_BANNER_PATH=/path/to/banner.txt
22+
ENABLE_INTERACTIVE_ATTRIBUTE_FILTERS=false

CHANGELOG.md

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

33
# Unreleased
4+
5+
* Refactored code to new filters format and sent selected filters in run workflow modal (\#686);
6+
* Displayed list of images that would be processed by the first task of a job (\#686);
7+
* Added environment variable `ENABLE_INTERACTIVE_ATTRIBUTE_FILTERS`, to enable attribute filters on the "Run workflow" modal (\#686);
48
* Fixed findings based on `zizmor 1.0.1` audit (\#687).
59

610
# 1.14.0

__tests__/v2/CreateDatasetModal.test.js

Lines changed: 1 addition & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -81,112 +81,12 @@ describe('CreateDatasetModal', () => {
8181
await fireEvent.input(result.getByRole('textbox', { name: 'Zarr dir' }), {
8282
target: { value: '/tmp' }
8383
});
84-
await fireEvent.click(result.getByRole('button', { name: 'Add attribute filter' }));
85-
await fireEvent.input(result.getByPlaceholderText('Key'), { target: { value: 'my-key' } });
86-
await fireEvent.input(result.getByPlaceholderText('Value'), { target: { value: 'my-value' } });
8784
await fireEvent.click(result.getByRole('button', { name: 'Save' }));
8885
expect(fetch).toHaveBeenLastCalledWith(
8986
'/api/v2/project/1/dataset',
9087
expect.objectContaining({
9188
body: JSON.stringify({
9289
name: 'my dataset',
93-
filters: {
94-
attributes: { 'my-key': 'my-value' },
95-
types: {}
96-
},
97-
zarr_dir: '/tmp'
98-
})
99-
})
100-
);
101-
});
102-
103-
it('create dataset with number filter', async () => {
104-
mockFetch(null);
105-
const createDatasetCallback = vi.fn();
106-
const result = render(CreateDatasetModal, {
107-
props: { createDatasetCallback }
108-
});
109-
await fireEvent.input(result.getByRole('textbox', { name: 'Dataset Name' }), {
110-
target: { value: 'my dataset' }
111-
});
112-
await fireEvent.input(result.getByRole('textbox', { name: 'Zarr dir' }), {
113-
target: { value: '/tmp' }
114-
});
115-
await fireEvent.click(result.getByRole('button', { name: 'Add attribute filter' }));
116-
await fireEvent.input(result.getByPlaceholderText('Key'), { target: { value: 'my-key' } });
117-
await fireEvent.input(result.getByPlaceholderText('Value'), { target: { value: '123' } });
118-
await fireEvent.change(result.getByLabelText('Type'), { target: { value: 'number' } });
119-
await fireEvent.click(result.getByRole('button', { name: 'Save' }));
120-
expect(fetch).toHaveBeenLastCalledWith(
121-
'/api/v2/project/1/dataset',
122-
expect.objectContaining({
123-
body: JSON.stringify({
124-
name: 'my dataset',
125-
filters: {
126-
attributes: { 'my-key': 123 },
127-
types: {}
128-
},
129-
zarr_dir: '/tmp'
130-
})
131-
})
132-
);
133-
});
134-
135-
it('create dataset with type filter set to false', async () => {
136-
mockFetch(null);
137-
const createDatasetCallback = vi.fn();
138-
const result = render(CreateDatasetModal, {
139-
props: { createDatasetCallback }
140-
});
141-
await fireEvent.input(result.getByRole('textbox', { name: 'Dataset Name' }), {
142-
target: { value: 'my dataset' }
143-
});
144-
await fireEvent.input(result.getByRole('textbox', { name: 'Zarr dir' }), {
145-
target: { value: '/tmp' }
146-
});
147-
await fireEvent.click(result.getByRole('button', { name: 'Add type filter' }));
148-
await fireEvent.input(result.getByPlaceholderText('Key'), { target: { value: 'my-key' } });
149-
await fireEvent.click(result.getByRole('button', { name: 'Save' }));
150-
expect(fetch).toHaveBeenLastCalledWith(
151-
'/api/v2/project/1/dataset',
152-
expect.objectContaining({
153-
body: JSON.stringify({
154-
name: 'my dataset',
155-
filters: {
156-
attributes: {},
157-
types: { 'my-key': false }
158-
},
159-
zarr_dir: '/tmp'
160-
})
161-
})
162-
);
163-
});
164-
165-
it('create dataset with type filter set to true', async () => {
166-
mockFetch(null);
167-
const createDatasetCallback = vi.fn();
168-
const result = render(CreateDatasetModal, {
169-
props: { createDatasetCallback }
170-
});
171-
await fireEvent.input(result.getByRole('textbox', { name: 'Dataset Name' }), {
172-
target: { value: 'my dataset' }
173-
});
174-
await fireEvent.input(result.getByRole('textbox', { name: 'Zarr dir' }), {
175-
target: { value: '/tmp' }
176-
});
177-
await fireEvent.click(result.getByRole('button', { name: 'Add type filter' }));
178-
await fireEvent.input(result.getByPlaceholderText('Key'), { target: { value: 'my-key' } });
179-
await fireEvent.click(result.getByLabelText('Value for my-key'));
180-
await fireEvent.click(result.getByRole('button', { name: 'Save' }));
181-
expect(fetch).toHaveBeenLastCalledWith(
182-
'/api/v2/project/1/dataset',
183-
expect.objectContaining({
184-
body: JSON.stringify({
185-
name: 'my dataset',
186-
filters: {
187-
attributes: {},
188-
types: { 'my-key': true }
189-
},
19090
zarr_dir: '/tmp'
19191
})
19292
})
@@ -207,11 +107,7 @@ describe('CreateDatasetModal', () => {
207107
'/api/v2/project/1/dataset',
208108
expect.objectContaining({
209109
body: JSON.stringify({
210-
name: 'my dataset',
211-
filters: {
212-
attributes: {},
213-
types: {}
214-
}
110+
name: 'my dataset'
215111
})
216112
})
217113
);
@@ -262,10 +158,6 @@ describe('CreateDatasetModal', () => {
262158
expect.objectContaining({
263159
body: JSON.stringify({
264160
name: 'my dataset',
265-
filters: {
266-
attributes: {},
267-
types: {}
268-
},
269161
zarr_dir: 'foo'
270162
})
271163
})

__tests__/v2/AttributesTypesForm.test.js renamed to __tests__/v2/ImageAttributesTypesForm.test.js

Lines changed: 40 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import { describe, it, expect } from 'vitest';
22
import { fireEvent, render } from '@testing-library/svelte';
33

4-
import AttributesTypesForm from '../../src/lib/components/v2/projects/datasets/AttributesTypesForm.svelte';
4+
import ImageAttributesTypesForm from '../../src/lib/components/v2/projects/datasets/ImageAttributesTypesForm.svelte';
55
import { tick } from 'svelte';
66

77
describe('AttributesTypesForm', () => {
8-
it('init with existing filters', async () => {
9-
const result = render(AttributesTypesForm);
8+
it('init with existing values', async () => {
9+
const result = render(ImageAttributesTypesForm);
1010
result.component.init(
1111
{
1212
key1: 'value1',
@@ -28,46 +28,46 @@ describe('AttributesTypesForm', () => {
2828
expect(values[1]).eq('42');
2929
});
3030

31-
it('add and remove attribute filter', async () => {
32-
const result = render(AttributesTypesForm);
31+
it('add and remove attribute', async () => {
32+
const result = render(ImageAttributesTypesForm);
3333
expect(result.queryAllByPlaceholderText('Key').length).eq(0);
34-
await fireEvent.click(result.getByRole('button', { name: 'Add attribute filter' }));
34+
await fireEvent.click(result.getByRole('button', { name: 'Add attribute' }));
3535
expect(result.queryAllByPlaceholderText('Key').length).eq(1);
36-
await fireEvent.click(result.getByRole('button', { name: 'Remove attribute filter' }));
36+
await fireEvent.click(result.getByRole('button', { name: 'Remove attribute' }));
3737
expect(result.queryAllByPlaceholderText('Key').length).eq(0);
3838
});
3939

40-
it('add and remove type filter', async () => {
41-
const result = render(AttributesTypesForm);
40+
it('add and remove type', async () => {
41+
const result = render(ImageAttributesTypesForm);
4242
expect(result.queryAllByPlaceholderText('Key').length).eq(0);
43-
await fireEvent.click(result.getByRole('button', { name: 'Add type filter' }));
43+
await fireEvent.click(result.getByRole('button', { name: 'Add type' }));
4444
expect(result.queryAllByPlaceholderText('Key').length).eq(1);
45-
await fireEvent.click(result.getByRole('button', { name: 'Remove type filter' }));
45+
await fireEvent.click(result.getByRole('button', { name: 'Remove type' }));
4646
expect(result.queryAllByPlaceholderText('Key').length).eq(0);
4747
});
4848

49-
it('validate missing attribute filter key', async () => {
50-
const result = render(AttributesTypesForm);
49+
it('validate missing attribute key', async () => {
50+
const result = render(ImageAttributesTypesForm);
5151
result.component.init({}, {});
52-
await fireEvent.click(result.getByRole('button', { name: 'Add attribute filter' }));
52+
await fireEvent.click(result.getByRole('button', { name: 'Add attribute' }));
5353
expect(result.component.validateFields()).false;
5454
await tick();
5555
expect(result.getByText('Key is required')).toBeDefined();
5656
});
5757

58-
it('validate missing attribute filter value', async () => {
59-
const result = render(AttributesTypesForm);
58+
it('validate missing attribute value', async () => {
59+
const result = render(ImageAttributesTypesForm);
6060
result.component.init({}, {});
61-
await fireEvent.click(result.getByRole('button', { name: 'Add attribute filter' }));
61+
await fireEvent.click(result.getByRole('button', { name: 'Add attribute' }));
6262
await fireEvent.input(result.getByPlaceholderText('Key'), { target: { value: 'my-key' } });
6363
expect(result.component.validateFields()).false;
6464
await tick();
6565
expect(result.getByText('Value is required')).toBeDefined();
6666
});
6767

6868
it('validate invalid number', async () => {
69-
const result = render(AttributesTypesForm);
70-
await fireEvent.click(result.getByRole('button', { name: 'Add attribute filter' }));
69+
const result = render(ImageAttributesTypesForm);
70+
await fireEvent.click(result.getByRole('button', { name: 'Add attribute' }));
7171
await fireEvent.input(result.getByPlaceholderText('Key'), { target: { value: 'my-key' } });
7272
await fireEvent.change(result.getByLabelText('Type'), { target: { value: 'number' } });
7373
await fireEvent.input(result.getByPlaceholderText('Value'), { target: { value: 'foo' } });
@@ -77,8 +77,8 @@ describe('AttributesTypesForm', () => {
7777
});
7878

7979
it('switch to number attribute from string containing a numeric value (number is preserved)', async () => {
80-
const result = render(AttributesTypesForm);
81-
await fireEvent.click(result.getByRole('button', { name: 'Add attribute filter' }));
80+
const result = render(ImageAttributesTypesForm);
81+
await fireEvent.click(result.getByRole('button', { name: 'Add attribute' }));
8282
await fireEvent.input(result.getByPlaceholderText('Key'), { target: { value: 'my-key' } });
8383
await fireEvent.input(result.getByPlaceholderText('Value'), { target: { value: '42' } });
8484
await fireEvent.change(result.getByLabelText('Type'), { target: { value: 'number' } });
@@ -87,8 +87,8 @@ describe('AttributesTypesForm', () => {
8787
});
8888

8989
it('switch to number attribute from string containing text (number is reset)', async () => {
90-
const result = render(AttributesTypesForm);
91-
await fireEvent.click(result.getByRole('button', { name: 'Add attribute filter' }));
90+
const result = render(ImageAttributesTypesForm);
91+
await fireEvent.click(result.getByRole('button', { name: 'Add attribute' }));
9292
await fireEvent.input(result.getByPlaceholderText('Key'), { target: { value: 'my-key' } });
9393
await fireEvent.input(result.getByPlaceholderText('Value'), { target: { value: 'foo' } });
9494
await fireEvent.change(result.getByLabelText('Type'), { target: { value: 'number' } });
@@ -97,17 +97,17 @@ describe('AttributesTypesForm', () => {
9797
});
9898

9999
it('switch to boolean attribute, default to false', async () => {
100-
const result = render(AttributesTypesForm);
101-
await fireEvent.click(result.getByRole('button', { name: 'Add attribute filter' }));
100+
const result = render(ImageAttributesTypesForm);
101+
await fireEvent.click(result.getByRole('button', { name: 'Add attribute' }));
102102
await fireEvent.input(result.getByPlaceholderText('Key'), { target: { value: 'my-key' } });
103103
await fireEvent.change(result.getByLabelText('Type'), { target: { value: 'boolean' } });
104104
expect(result.getByLabelText('Value').value).eq('false');
105105
expect(result.component.validateFields()).true;
106106
});
107107

108108
it('switch to boolean attribute from string equals to "true", true is set', async () => {
109-
const result = render(AttributesTypesForm);
110-
await fireEvent.click(result.getByRole('button', { name: 'Add attribute filter' }));
109+
const result = render(ImageAttributesTypesForm);
110+
await fireEvent.click(result.getByRole('button', { name: 'Add attribute' }));
111111
await fireEvent.input(result.getByPlaceholderText('Key'), { target: { value: 'my-key' } });
112112
await fireEvent.input(result.getByPlaceholderText('Value'), { target: { value: 'true' } });
113113
await fireEvent.change(result.getByLabelText('Type'), { target: { value: 'boolean' } });
@@ -116,11 +116,11 @@ describe('AttributesTypesForm', () => {
116116
});
117117

118118
it('validate duplicated attribute key', async () => {
119-
const result = render(AttributesTypesForm);
120-
await fireEvent.click(result.getByRole('button', { name: 'Add attribute filter' }));
119+
const result = render(ImageAttributesTypesForm);
120+
await fireEvent.click(result.getByRole('button', { name: 'Add attribute' }));
121121
await fireEvent.input(result.getByPlaceholderText('Key'), { target: { value: 'my-key' } });
122122
await fireEvent.input(result.getByPlaceholderText('Value'), { target: { value: 'foo' } });
123-
await fireEvent.click(result.getByRole('button', { name: 'Add attribute filter' }));
123+
await fireEvent.click(result.getByRole('button', { name: 'Add attribute' }));
124124
await fireEvent.input(result.queryAllByPlaceholderText('Key')[1], {
125125
target: { value: 'my-key' }
126126
});
@@ -133,32 +133,32 @@ describe('AttributesTypesForm', () => {
133133
});
134134

135135
it('allow same key for attribute and type', async () => {
136-
const result = render(AttributesTypesForm);
137-
await fireEvent.click(result.getByRole('button', { name: 'Add attribute filter' }));
136+
const result = render(ImageAttributesTypesForm);
137+
await fireEvent.click(result.getByRole('button', { name: 'Add attribute' }));
138138
await fireEvent.input(result.getByPlaceholderText('Key'), { target: { value: 'my-key' } });
139139
await fireEvent.input(result.getByPlaceholderText('Value'), { target: { value: 'foo' } });
140-
await fireEvent.click(result.getByRole('button', { name: 'Add type filter' }));
140+
await fireEvent.click(result.getByRole('button', { name: 'Add type' }));
141141
await fireEvent.input(result.queryAllByPlaceholderText('Key')[1], {
142142
target: { value: 'my-key' }
143143
});
144144
expect(result.component.validateFields()).true;
145145
});
146146

147-
it('validate missing type filter key', async () => {
148-
const result = render(AttributesTypesForm);
147+
it('validate missing type key', async () => {
148+
const result = render(ImageAttributesTypesForm);
149149
result.component.init({}, {});
150-
await fireEvent.click(result.getByRole('button', { name: 'Add type filter' }));
150+
await fireEvent.click(result.getByRole('button', { name: 'Add type' }));
151151
expect(result.component.validateFields()).false;
152152
await tick();
153153
expect(result.getByText('Key is required')).toBeDefined();
154154
});
155155

156-
it('validate duplicated type filter key', async () => {
157-
const result = render(AttributesTypesForm);
156+
it('validate duplicated type key', async () => {
157+
const result = render(ImageAttributesTypesForm);
158158
result.component.init({}, {});
159-
await fireEvent.click(result.getByRole('button', { name: 'Add type filter' }));
159+
await fireEvent.click(result.getByRole('button', { name: 'Add type' }));
160160
await fireEvent.input(result.getByPlaceholderText('Key'), { target: { value: 'my-key' } });
161-
await fireEvent.click(result.getByRole('button', { name: 'Add type filter' }));
161+
await fireEvent.click(result.getByRole('button', { name: 'Add type' }));
162162
await fireEvent.input(result.queryAllByPlaceholderText('Key')[1], {
163163
target: { value: 'my-key' }
164164
});

0 commit comments

Comments
 (0)