@opencloning/ui 1.4.0 → 1.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# @opencloning/ui
|
|
2
2
|
|
|
3
|
+
## 1.4.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#616](https://github.com/manulera/OpenCloning_frontend/pull/616) [`1419d5c`](https://github.com/manulera/OpenCloning_frontend/commit/1419d5cb80f738b737076e4d3b958c31eeb0f7b4) Thanks [@manulera](https://github.com/manulera)! - Allow to "select all" when importing static sequences from server
|
|
8
|
+
|
|
9
|
+
- Updated dependencies []:
|
|
10
|
+
- @opencloning/store@1.4.1
|
|
11
|
+
- @opencloning/utils@1.4.1
|
|
12
|
+
|
|
3
13
|
## 1.4.0
|
|
4
14
|
|
|
5
15
|
### Minor Changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opencloning/ui",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./src/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -25,8 +25,8 @@
|
|
|
25
25
|
"@emotion/styled": "^11.14.0",
|
|
26
26
|
"@mui/icons-material": "^5.15.17",
|
|
27
27
|
"@mui/material": "^5.15.17",
|
|
28
|
-
"@opencloning/store": "1.4.
|
|
29
|
-
"@opencloning/utils": "1.4.
|
|
28
|
+
"@opencloning/store": "1.4.1",
|
|
29
|
+
"@opencloning/utils": "1.4.1",
|
|
30
30
|
"@teselagen/bio-parsers": "^0.4.34",
|
|
31
31
|
"@teselagen/ove": "^0.8.34",
|
|
32
32
|
"@teselagen/range-utils": "^0.3.20",
|
|
@@ -274,6 +274,115 @@ describe('<ServerStaticFileSelect />', () => {
|
|
|
274
274
|
expect(file.size).to.equal(28);
|
|
275
275
|
});
|
|
276
276
|
});
|
|
277
|
+
it('allows selecting all sequences with the Select all option when multiple', () => {
|
|
278
|
+
const httpGet = cy.stub(localFilesHttpClient, 'get').callsFake((url) => {
|
|
279
|
+
if (url.endsWith('/index.json')) {
|
|
280
|
+
return Promise.resolve({
|
|
281
|
+
data: dummyIndex,
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
if (url.endsWith('/example.fa')) {
|
|
285
|
+
return Promise.resolve({ data: 'ATGC' });
|
|
286
|
+
}
|
|
287
|
+
if (url.endsWith('/example2.gb')) {
|
|
288
|
+
return Promise.resolve({ data: 'ATGCA' });
|
|
289
|
+
}
|
|
290
|
+
if (url.endsWith('/example3.fa')) {
|
|
291
|
+
return Promise.resolve({ data: 'ATGCG' });
|
|
292
|
+
}
|
|
293
|
+
throw new Error(`Unexpected URL: ${url}`);
|
|
294
|
+
});
|
|
295
|
+
cy.wrap(httpGet).as('httpGet');
|
|
296
|
+
|
|
297
|
+
const onFileSelected = cy.spy().as('onFileSelected');
|
|
298
|
+
cy.mount(
|
|
299
|
+
<ConfigProvider config={config}>
|
|
300
|
+
<ServerStaticFileSelect
|
|
301
|
+
onFileSelected={onFileSelected}
|
|
302
|
+
multiple
|
|
303
|
+
/>
|
|
304
|
+
</ConfigProvider>,
|
|
305
|
+
);
|
|
306
|
+
|
|
307
|
+
cy.get('@httpGet').should('have.been.calledWithMatch', 'index.json');
|
|
308
|
+
|
|
309
|
+
// Use the Select all option to select all sequences
|
|
310
|
+
cy.get('#option-select').click();
|
|
311
|
+
cy.contains('Select all').click();
|
|
312
|
+
cy.get('body').click(0, 0);
|
|
313
|
+
|
|
314
|
+
// Submit form
|
|
315
|
+
cy.contains('button', 'Submit').click();
|
|
316
|
+
|
|
317
|
+
cy.get('@httpGet').should('have.been.calledWithMatch', 'example.fa');
|
|
318
|
+
cy.get('@httpGet').should('have.been.calledWithMatch', 'example2.gb');
|
|
319
|
+
cy.get('@httpGet').should('have.been.calledWithMatch', 'example3.fa');
|
|
320
|
+
|
|
321
|
+
cy.get('@onFileSelected').should('have.been.calledOnce');
|
|
322
|
+
cy.get('@onFileSelected').should((spy) => {
|
|
323
|
+
const [files] = spy.lastCall.args;
|
|
324
|
+
expect(files).to.have.length(3);
|
|
325
|
+
expect(files[0].name).to.equal('example.fa');
|
|
326
|
+
expect(files[0].type).to.equal('text/plain');
|
|
327
|
+
expect(files[1].name).to.equal('example2.gb');
|
|
328
|
+
expect(files[1].type).to.equal('text/plain');
|
|
329
|
+
expect(files[2].name).to.equal('example3.fa');
|
|
330
|
+
expect(files[2].type).to.equal('text/plain');
|
|
331
|
+
});
|
|
332
|
+
});
|
|
333
|
+
it('clicking select all only selects the sequences that were filtered by category', () => {
|
|
334
|
+
const httpGet = cy.stub(localFilesHttpClient, 'get').callsFake((url) => {
|
|
335
|
+
if (url.endsWith('/index.json')) {
|
|
336
|
+
return Promise.resolve({
|
|
337
|
+
data: dummyIndex,
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
if (url.endsWith('/example.fa')) {
|
|
341
|
+
return Promise.resolve({ data: 'ATGC' });
|
|
342
|
+
}
|
|
343
|
+
if (url.endsWith('/example3.fa')) {
|
|
344
|
+
return Promise.resolve({ data: 'ATGCG' });
|
|
345
|
+
}
|
|
346
|
+
});
|
|
347
|
+
cy.wrap(httpGet).as('httpGet');
|
|
348
|
+
const onFileSelected = cy.spy().as('onFileSelected');
|
|
349
|
+
cy.mount(
|
|
350
|
+
<ConfigProvider config={config}>
|
|
351
|
+
<ServerStaticFileSelect
|
|
352
|
+
onFileSelected={onFileSelected}
|
|
353
|
+
multiple
|
|
354
|
+
/>
|
|
355
|
+
</ConfigProvider>,
|
|
356
|
+
);
|
|
357
|
+
cy.get('@httpGet').should('have.been.calledWithMatch', 'index.json');
|
|
358
|
+
|
|
359
|
+
// Select category
|
|
360
|
+
cy.get('#category-select').click();
|
|
361
|
+
cy.contains('Test category').click();
|
|
362
|
+
|
|
363
|
+
// Select all
|
|
364
|
+
cy.get('#option-select').click();
|
|
365
|
+
cy.contains('Select all').click();
|
|
366
|
+
|
|
367
|
+
// Only one sequence should be shown
|
|
368
|
+
cy.get('#option-select').click();
|
|
369
|
+
cy.contains('Example sequence 1').should('exist');
|
|
370
|
+
cy.contains('Example sequence 2').should('not.exist');
|
|
371
|
+
cy.contains('Example sequence 3').should('exist');
|
|
372
|
+
|
|
373
|
+
// Click outside to close select element
|
|
374
|
+
cy.get('body').click(0, 0);
|
|
375
|
+
cy.contains('button', 'Submit').click();
|
|
376
|
+
|
|
377
|
+
cy.get('@httpGet').should('have.been.calledThrice');
|
|
378
|
+
cy.get('@onFileSelected').should('have.been.calledOnce');
|
|
379
|
+
cy.get('@onFileSelected').should((spy) => {
|
|
380
|
+
const [files] = spy.lastCall.args;
|
|
381
|
+
expect(files).to.have.length(2);
|
|
382
|
+
expect(files[0].name).to.equal('example.fa');
|
|
383
|
+
expect(files[1].name).to.equal('example3.fa');
|
|
384
|
+
});
|
|
385
|
+
})
|
|
277
386
|
it('works with multiple', () => {
|
|
278
387
|
const httpGet = cy.stub(localFilesHttpClient, 'get').callsFake((url) => {
|
|
279
388
|
if (url.endsWith('/index.json')) {
|
|
@@ -16,11 +16,12 @@ function ServerStaticFileSelect({ onFileSelected, multiple = false, type = 'sequ
|
|
|
16
16
|
if (type !== 'sequence') {
|
|
17
17
|
return index.syntaxes;
|
|
18
18
|
}
|
|
19
|
+
const prePendArray = multiple ? ['__all__'] : [];
|
|
19
20
|
if (selectedCategory === '') {
|
|
20
|
-
return index.sequences;
|
|
21
|
+
return [...prePendArray, ...index.sequences];
|
|
21
22
|
}
|
|
22
|
-
return index.sequences.filter((sequence) => sequence.categories?.includes(selectedCategory));
|
|
23
|
-
}, [type, index, selectedCategory]);
|
|
23
|
+
return [...prePendArray, ...index.sequences.filter((sequence) => sequence.categories?.includes(selectedCategory))];
|
|
24
|
+
}, [type, index, selectedCategory, multiple]);
|
|
24
25
|
|
|
25
26
|
const categoryOptions = React.useMemo(() => {
|
|
26
27
|
if (!index?.categories) return [];
|
|
@@ -72,6 +73,19 @@ function ServerStaticFileSelect({ onFileSelected, multiple = false, type = 'sequ
|
|
|
72
73
|
const buttonDisabled = multiple ? selectedOptions.length === 0 : !selectedOptions;
|
|
73
74
|
|
|
74
75
|
const label = type === 'sequence' ? 'Sequence' : 'Syntax';
|
|
76
|
+
|
|
77
|
+
const onOptionsChange = React.useCallback((event, value) => {
|
|
78
|
+
console.log('onOptionsChange', value);
|
|
79
|
+
if (multiple && type === 'sequence') {
|
|
80
|
+
if (value.includes('__all__')) {
|
|
81
|
+
const allSequences = options.filter((option) => option !== '__all__');
|
|
82
|
+
setSelectedOptions(allSequences);
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
setSelectedOptions(value);
|
|
87
|
+
}, [multiple, type, options]);
|
|
88
|
+
|
|
75
89
|
return (
|
|
76
90
|
<RequestStatusWrapper requestStatus={indexRequestStatus} retry={indexRetry}>
|
|
77
91
|
{error && <Alert severity="error">{error}</Alert>}
|
|
@@ -98,8 +112,8 @@ function ServerStaticFileSelect({ onFileSelected, multiple = false, type = 'sequ
|
|
|
98
112
|
multiple={multiple}
|
|
99
113
|
options={options}
|
|
100
114
|
value={selectedOptions}
|
|
101
|
-
onChange={
|
|
102
|
-
getOptionLabel={(option) => option?.name || option?.path || ''}
|
|
115
|
+
onChange={onOptionsChange}
|
|
116
|
+
getOptionLabel={(option) => (option === '__all__' ? 'Select all' : option?.name || option?.path || '')}
|
|
103
117
|
disableCloseOnSelect={multiple}
|
|
104
118
|
renderInput={(params) => (
|
|
105
119
|
<TextField
|
package/src/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Version placeholder - replaced at publish time via prepack script
|
|
2
|
-
export const version = "1.4.
|
|
2
|
+
export const version = "1.4.1";
|