@opencloning/ui 1.5.6 → 1.6.0

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.
Files changed (27) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/package.json +10 -3
  3. package/src/components/dummy/index.js +1 -0
  4. package/src/hooks/useDatabase.js +2 -17
  5. package/src/providers/DatabaseContext.jsx +15 -0
  6. package/src/version.js +1 -1
  7. package/src/components/eLabFTW/ELabFTWCategorySelect.cy.jsx +0 -86
  8. package/src/components/eLabFTW/ELabFTWCategorySelect.jsx +0 -43
  9. package/src/components/eLabFTW/ELabFTWFileSelect.cy.jsx +0 -43
  10. package/src/components/eLabFTW/ELabFTWFileSelect.jsx +0 -29
  11. package/src/components/eLabFTW/ELabFTWResourceSelect.cy.jsx +0 -107
  12. package/src/components/eLabFTW/ELabFTWResourceSelect.jsx +0 -23
  13. package/src/components/eLabFTW/GetPrimerComponent.cy.jsx +0 -261
  14. package/src/components/eLabFTW/GetPrimerComponent.jsx +0 -55
  15. package/src/components/eLabFTW/GetSequenceFileAndDatabaseIdComponent.cy.jsx +0 -184
  16. package/src/components/eLabFTW/GetSequenceFileAndDatabaseIdComponent.jsx +0 -62
  17. package/src/components/eLabFTW/LoadHistoryComponent.cy.jsx +0 -235
  18. package/src/components/eLabFTW/LoadHistoryComponent.jsx +0 -51
  19. package/src/components/eLabFTW/PrimersNotInDatabaseComponent.cy.jsx +0 -159
  20. package/src/components/eLabFTW/PrimersNotInDatabaseComponent.jsx +0 -54
  21. package/src/components/eLabFTW/SubmitToDatabaseComponent.cy.jsx +0 -185
  22. package/src/components/eLabFTW/SubmitToDatabaseComponent.jsx +0 -51
  23. package/src/components/eLabFTW/common.js +0 -26
  24. package/src/components/eLabFTW/eLabFTWInterface.js +0 -293
  25. package/src/components/eLabFTW/eLabFTWInterface.test.js +0 -839
  26. package/src/components/eLabFTW/envValues.js +0 -7
  27. package/src/components/eLabFTW/utils.js +0 -30
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # @opencloning/ui
2
2
 
3
+ ## 1.6.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#668](https://github.com/manulera/OpenCloning_frontend/pull/668) [`dd0df39`](https://github.com/manulera/OpenCloning_frontend/commit/dd0df39c5fbf65feaab09f90d123e3776efed6bd) Thanks [@manulera](https://github.com/manulera)! - Moved eLabFTW interface into a separate package
8
+
9
+ ### Patch Changes
10
+
11
+ - [#668](https://github.com/manulera/OpenCloning_frontend/pull/668) [`dd0df39`](https://github.com/manulera/OpenCloning_frontend/commit/dd0df39c5fbf65feaab09f90d123e3776efed6bd) Thanks [@manulera](https://github.com/manulera)! - Added LICENSE to package.json
12
+
13
+ - Updated dependencies [[`dd0df39`](https://github.com/manulera/OpenCloning_frontend/commit/dd0df39c5fbf65feaab09f90d123e3776efed6bd)]:
14
+ - @opencloning/store@1.6.0
15
+ - @opencloning/utils@1.6.0
16
+
3
17
  ## 1.5.6
4
18
 
5
19
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
+ "license": "MIT",
2
3
  "name": "@opencloning/ui",
3
- "version": "1.5.6",
4
+ "version": "1.6.0",
4
5
  "type": "module",
5
6
  "main": "./src/index.js",
6
7
  "scripts": {
@@ -11,7 +12,13 @@
11
12
  ".": "./src/index.js",
12
13
  "./components": "./src/components/index.js",
13
14
  "./components/assembler": "./src/components/assembler/index.js",
15
+ "./components/dummy": "./src/components/dummy/index.js",
16
+ "./components/form/GetRequestMultiSelect": "./src/components/form/GetRequestMultiSelect.jsx",
17
+ "./components/form/RetryAlert": "./src/components/form/RetryAlert.jsx",
18
+ "./components/form/RequestStatusWrapper": "./src/components/form/RequestStatusWrapper.jsx",
19
+ "./components/form/PostRequestSelect": "./src/components/form/PostRequestSelect.jsx",
14
20
  "./providers/ConfigProvider": "./src/providers/index.js",
21
+ "./providers/DatabaseContext": "./src/providers/DatabaseContext.jsx",
15
22
  "./hooks/useConfig": "./src/hooks/useConfig.js",
16
23
  "./standalone": "./src/StandAloneOpenCloning.js"
17
24
  },
@@ -26,8 +33,8 @@
26
33
  "@mui/icons-material": "^5.15.17",
27
34
  "@mui/material": "^5.15.17",
28
35
  "@mui/x-data-grid": "^8.25.0",
29
- "@opencloning/store": "1.5.6",
30
- "@opencloning/utils": "1.5.6",
36
+ "@opencloning/store": "1.6.0",
37
+ "@opencloning/utils": "1.6.0",
31
38
  "@teselagen/bio-parsers": "^0.4.34",
32
39
  "@teselagen/ove": "^0.8.34",
33
40
  "@teselagen/range-utils": "^0.3.20",
@@ -0,0 +1 @@
1
+ export { default } from './DummyInterface.js';
@@ -1,18 +1,3 @@
1
- import React from 'react';
2
- import { useConfig } from './useConfig';
3
- import eLabFTWInterface from '../components/eLabFTW/eLabFTWInterface';
4
- import dummyInterface from '../components/dummy/DummyInterface';
1
+ import { useDatabase } from '../providers/DatabaseContext';
5
2
 
6
- export default function useDatabase() {
7
- const { database: databaseName } = useConfig();
8
-
9
- return React.useMemo(() => {
10
- if (databaseName === 'elabftw') {
11
- return eLabFTWInterface;
12
- }
13
- if (databaseName === 'dummy') {
14
- return dummyInterface;
15
- }
16
- return null;
17
- }, [databaseName]);
18
- }
3
+ export default useDatabase;
@@ -0,0 +1,15 @@
1
+ import React, { createContext, useContext } from 'react';
2
+
3
+ export const DatabaseContext = createContext(null);
4
+
5
+ export function DatabaseProvider({ value, children }) {
6
+ return (
7
+ <DatabaseContext.Provider value={value}>
8
+ {children}
9
+ </DatabaseContext.Provider>
10
+ );
11
+ }
12
+
13
+ export function useDatabase() {
14
+ return useContext(DatabaseContext);
15
+ }
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.5.6";
2
+ export const version = "1.6.0";
@@ -1,86 +0,0 @@
1
- import React from 'react';
2
- import ELabFTWCategorySelect from './ELabFTWCategorySelect';
3
- import { eLabFTWHttpClient } from './common';
4
-
5
- describe('<ELabFTWCategorySelect />', () => {
6
- it('Allows to retry if the request fails', () => {
7
- cy.stub(eLabFTWHttpClient, 'get').withArgs('/api/v2/info', { headers: { Authorization: 'test-read-key' } }).as('eLabFTWHttpClientSpy');
8
- cy.mount(<ELabFTWCategorySelect fullWidth />);
9
- cy.get('@eLabFTWHttpClientSpy.all').should('have.callCount', 1);
10
- cy.get('button').contains('Retry').click();
11
- cy.get('@eLabFTWHttpClientSpy.all').should('have.callCount', 2);
12
- });
13
- it('shows the right options for eLabFTW version 50300', () => {
14
- const setCategorySpy = cy.spy().as('setCategorySpy');
15
- cy.stub(eLabFTWHttpClient, 'get').withArgs('/api/v2/info', { headers: { Authorization: 'test-read-key' } }).resolves({
16
- data: {
17
- elabftw_version_int: 50300,
18
- },
19
- }).withArgs('/api/v2/teams/current/resources_categories', { headers: { Authorization: 'test-read-key' }, params: { limit: 9999 } }).resolves({
20
- data: [
21
- { id: 1, title: 'Category 1' },
22
- { id: 2, title: 'Category 2' },
23
- ],
24
- });
25
- cy.mount(<ELabFTWCategorySelect fullWidth setCategory={setCategorySpy} />);
26
- cy.get('.MuiAutocomplete-root').click();
27
- cy.get('li').contains('Category 1').should('exist');
28
- cy.get('li').contains('Category 2').should('exist');
29
- cy.get('li').contains('Category 1').click();
30
- cy.get('@setCategorySpy').should('have.been.calledWith', { id: 1, title: 'Category 1' });
31
- });
32
- it('shows the right options', () => {
33
- const setCategorySpy = cy.spy().as('setCategorySpy');
34
- cy.stub(eLabFTWHttpClient, 'get')
35
- .withArgs('/api/v2/items_types', { headers: { Authorization: 'test-read-key' }, params: { limit: 9999 } }).resolves({
36
- data: [
37
- { id: 1, title: 'Category 1' },
38
- { id: 2, title: 'Category 2' },
39
- ],
40
- })
41
- .withArgs('/api/v2/info', { headers: { Authorization: 'test-read-key' } }).resolves({
42
- data: {
43
- elabftw_version_int: 50200,
44
- },
45
- });
46
- cy.mount(<ELabFTWCategorySelect fullWidth setCategory={setCategorySpy} />);
47
- cy.get('.MuiAutocomplete-root').click();
48
- cy.get('li').contains('Category 1').should('exist');
49
- cy.get('li').contains('Category 2').should('exist');
50
- cy.get('li').contains('Category 1').click();
51
- cy.get('@setCategorySpy').should('have.been.calledWith', { id: 1, title: 'Category 1' });
52
- });
53
-
54
- it('shows empty options if no categories are found', () => {
55
- cy.mount(<ELabFTWCategorySelect fullWidth />);
56
- cy.stub(eLabFTWHttpClient, 'get')
57
- .withArgs('/api/v2/items_types', { headers: { Authorization: 'test-read-key' }, params: { limit: 9999 } }).resolves({
58
- data: [],
59
- })
60
- .withArgs('/api/v2/info', { headers: { Authorization: 'test-read-key' } }).resolves({
61
- data: {
62
- elabftw_version_int: 50200,
63
- },
64
- });
65
- cy.get('.MuiAutocomplete-root').click();
66
- cy.get('li').should('not.exist');
67
- });
68
-
69
- it('shows an error message if the request fails and can retry', () => {
70
- cy.mount(<ELabFTWCategorySelect fullWidth />);
71
- cy.stub(eLabFTWHttpClient, 'get')
72
- .withArgs('/api/v2/info', { headers: { Authorization: 'test-read-key' } })
73
- .resolves({
74
- data: {
75
- elabftw_version_int: 50300,
76
- },
77
- }).as('eLabFTWHttpClientSpyInfo')
78
- .withArgs('/api/v2/teams/current/resources_categories', { headers: { Authorization: 'test-read-key' }, params: { limit: 9999 } })
79
- .rejects(new Error('Connection error')).as('eLabFTWHttpClientSpy');
80
- cy.get('.MuiAlert-message').should('contain', 'Could not retrieve categories');
81
- // Clicking the retry button makes the request again
82
- cy.get('button').contains('Retry').click();
83
- cy.get('@eLabFTWHttpClientSpy').should('have.callCount', 2);
84
- cy.get('@eLabFTWHttpClientSpyInfo').should('have.callCount', 1);
85
- });
86
- });
@@ -1,43 +0,0 @@
1
- import React from 'react';
2
- import GetRequestMultiSelect from '../form/GetRequestMultiSelect';
3
- import { eLabFTWHttpClient, getELabFTWVersion, readHeaders } from './common';
4
- import RequestStatusWrapper from '../form/RequestStatusWrapper';
5
-
6
- function ELabFTWCategorySelect({ setCategory, label = 'Resource category', ...rest }) {
7
- const [eLabFTWVersion, setELabFTWVersion] = React.useState(null);
8
- const [requestStatus, setRequestStatus] = React.useState({ status: 'loading' });
9
- const [retry, setRetry] = React.useState(0);
10
- React.useEffect(() => {
11
- setRequestStatus({ status: 'loading' });
12
- getELabFTWVersion().then(
13
- (version) => {
14
- setELabFTWVersion(version);
15
- setRequestStatus({ status: 'success' });
16
- }
17
- ).catch(() => setRequestStatus({ status: 'error', message: 'Could not retrieve eLabFTW version' }));
18
- }, [retry]);
19
- const url = eLabFTWVersion && eLabFTWVersion >= 50300 ? '/api/v2/teams/current/resources_categories' : '/api/v2/items_types';
20
- const getOptionsFromResponse = (data) => data;
21
- const messages = { loadingMessage: 'retrieving categories', errorMessage: 'Could not retrieve categories from eLab' };
22
- const onChange = (value) => setCategory(value);
23
-
24
- return (
25
- <RequestStatusWrapper requestStatus={requestStatus} retry={() => { setRetry(retry + 1); }}>
26
- <GetRequestMultiSelect
27
- getOptionsFromResponse={getOptionsFromResponse}
28
- httpClient={eLabFTWHttpClient}
29
- requestHeaders={readHeaders}
30
- url={url}
31
- requestParams={{ limit: 9999 }}
32
- label={label}
33
- messages={messages}
34
- onChange={onChange}
35
- getOptionLabel={(option) => (option === '' ? '' : option.title)}
36
- multiple={false}
37
- {...rest}
38
- />
39
- </RequestStatusWrapper>
40
- );
41
- }
42
-
43
- export default ELabFTWCategorySelect;
@@ -1,43 +0,0 @@
1
- import React from 'react';
2
- import ELabFTWFileSelect from './ELabFTWFileSelect';
3
- import { eLabFTWHttpClient } from './common';
4
-
5
- describe('<ELabFTWFileSelect />', () => {
6
- it('shows the right options', () => {
7
- const setFileInfoSpy = cy.spy().as('setFileInfoSpy');
8
- // Stub the eLabFTWHttpClient similar to the pattern in eLabFTWInterface.test.js
9
- cy.stub(eLabFTWHttpClient, 'get').withArgs('/api/v2/items/1', { headers: { Authorization: 'test-read-key' }, params: {} }).resolves({
10
- data: {
11
- uploads: [
12
- { id: 1, real_name: 'file1.txt' },
13
- { id: 2, real_name: 'file2.txt' },
14
- ],
15
- },
16
- });
17
- cy.mount(<ELabFTWFileSelect fullWidth itemId={1} setFileInfo={setFileInfoSpy} />);
18
- cy.get('div.MuiSelect-select').click();
19
- cy.get('li').contains('file1.txt').should('exist');
20
- cy.get('li').contains('file2.txt').should('exist');
21
- cy.get('li').contains('file1.txt').click();
22
- cy.get('@setFileInfoSpy').should('have.been.calledWith', { id: 1, real_name: 'file1.txt' });
23
- });
24
- it('shows empty options if no files are found', () => {
25
- cy.mount(<ELabFTWFileSelect fullWidth itemId={1} />);
26
- cy.stub(eLabFTWHttpClient, 'get').withArgs('/api/v2/items/1', { headers: { Authorization: 'test-read-key' }, params: {} }).resolves({
27
- data: {
28
- uploads: [],
29
- },
30
- });
31
- cy.get('div.MuiSelect-select').click();
32
- cy.get('li').should('not.exist');
33
- });
34
-
35
- it('shows an error message if the request fails and can retry', () => {
36
- cy.mount(<ELabFTWFileSelect fullWidth itemId={1} />);
37
- cy.get('.MuiAlert-message').should('contain', 'Could not retrieve attachment');
38
- // Clicking the retry button makes the request again
39
- cy.spy(eLabFTWHttpClient, 'get').as('eLabFTWHttpClientSpy');
40
- cy.get('button').contains('Retry').click();
41
- cy.get('@eLabFTWHttpClientSpy').should('have.been.calledWith', '/api/v2/items/1', { headers: { Authorization: 'test-read-key' }, params: {} });
42
- });
43
- });
@@ -1,29 +0,0 @@
1
- import React from 'react';
2
- import GetRequestMultiSelect from '../form/GetRequestMultiSelect';
3
- import { eLabFTWHttpClient, readHeaders } from './common';
4
-
5
- function ELabFTWFileSelect({ itemId, setFileInfo, ...rest }) {
6
- const url = `/api/v2/items/${itemId}`;
7
- const getOptionsFromResponse = ({ uploads }) => uploads;
8
- const label = 'File with sequence';
9
- const messages = { loadingMessage: 'retrieving attachments', errorMessage: 'Could not retrieve attachment from eLab' };
10
- const onChange = (realName, options) => setFileInfo(options.find((option) => option.real_name === realName));
11
-
12
- return (
13
- <GetRequestMultiSelect
14
- getOptionsFromResponse={getOptionsFromResponse}
15
- httpClient={eLabFTWHttpClient}
16
- requestHeaders={readHeaders}
17
- url={url}
18
- label={label}
19
- messages={messages}
20
- onChange={onChange}
21
- getOptionLabel={(option) => (option === '' ? '' : option.real_name)}
22
- multiple={false}
23
- autoComplete={false}
24
- {...rest}
25
- />
26
- );
27
- }
28
-
29
- export default ELabFTWFileSelect;
@@ -1,107 +0,0 @@
1
- import React from 'react';
2
- import ELabFTWResourceSelect from './ELabFTWResourceSelect';
3
- import { eLabFTWHttpClient } from './common';
4
-
5
- describe('<ELabFTWResourceSelect />', () => {
6
- it('shows the right options when searching', () => {
7
- const setResourceSpy = cy.spy().as('setResourceSpy');
8
- cy.stub(eLabFTWHttpClient, 'get')
9
- .withArgs('/api/v2/items', {
10
- headers: { Authorization: 'test-read-key' },
11
- params: { cat: 1, extended: 'title:test', limit: 9999 },
12
- })
13
- .resolves({
14
- data: [
15
- { id: 1, title: 'Test Resource 1' },
16
- { id: 2, title: 'Test Resource 2' },
17
- ],
18
- });
19
-
20
- cy.mount(<ELabFTWResourceSelect fullWidth categoryId={1} setResource={setResourceSpy} />);
21
-
22
- // Type in the search field
23
- cy.get('.MuiAutocomplete-input').type('test');
24
-
25
- // Check if options are displayed
26
- cy.get('li').contains('Test Resource 1').should('exist');
27
- cy.get('li').contains('Test Resource 2').should('exist');
28
-
29
- // Select an option
30
- cy.get('li').contains('Test Resource 1').click();
31
- cy.get('@setResourceSpy').should('have.been.calledWith', { id: 1, title: 'Test Resource 1' });
32
- });
33
-
34
- it('shows empty options if no resources are found', () => {
35
- cy.stub(eLabFTWHttpClient, 'get')
36
- .withArgs('/api/v2/items', {
37
- headers: { Authorization: 'test-read-key' },
38
- params: { cat: 1, extended: 'title:nonexistent', limit: 9999 },
39
- })
40
- .resolves({
41
- data: [],
42
- });
43
-
44
- cy.mount(<ELabFTWResourceSelect fullWidth categoryId={1} />);
45
- cy.get('.MuiAutocomplete-input').type('nonexistent');
46
- cy.get('li').should('not.exist');
47
- });
48
-
49
- it('handles API errors gracefully', () => {
50
- let firstCall = true;
51
- cy.stub(eLabFTWHttpClient, 'get')
52
- .withArgs('/api/v2/items', {
53
- headers: { Authorization: 'test-read-key' },
54
- params: { cat: 1, extended: 'title:test', limit: 9999 },
55
- })
56
- .callsFake(() => {
57
- if (firstCall) {
58
- firstCall = false;
59
- return Promise.reject(new Error('API Error'));
60
- }
61
- return Promise.resolve({ data: [
62
- { id: 1, title: 'Test Resource 1' },
63
- { id: 2, title: 'Test Resource 2' },
64
- ] });
65
- });
66
-
67
- cy.mount(<ELabFTWResourceSelect fullWidth categoryId={1} />);
68
- cy.get('.MuiAutocomplete-input').type('test');
69
- // The component should handle the error gracefully
70
- cy.get('.MuiAlert-message').should('contain', 'Could not retrieve data');
71
- // Clicking the retry button makes the request again
72
- cy.get('button').contains('Retry').click();
73
- // Verify the second call was made
74
- cy.get('div.MuiInputBase-root').click();
75
- cy.get('li').contains('Test Resource 1').should('exist');
76
- cy.get('li').contains('Test Resource 2').should('exist');
77
- });
78
-
79
- it('updates search results when categoryId changes', () => {
80
- const getStub = cy.stub(eLabFTWHttpClient, 'get');
81
-
82
- // First category results
83
- getStub.withArgs('/api/v2/items', {
84
- headers: { Authorization: 'test-read-key' },
85
- params: { cat: 1, extended: 'title:test', limit: 9999 },
86
- }).resolves({
87
- data: [{ id: 1, title: 'Category 1 Resource' }],
88
- });
89
-
90
- // Second category results
91
- getStub.withArgs('/api/v2/items', {
92
- headers: { Authorization: 'test-read-key' },
93
- params: { cat: 2, extended: 'title:test', limit: 9999 },
94
- }).resolves({
95
- data: [{ id: 2, title: 'Category 2 Resource' }],
96
- });
97
-
98
- cy.mount(<ELabFTWResourceSelect fullWidth categoryId={1} />);
99
- cy.get('.MuiAutocomplete-input').type('test');
100
- cy.get('li').contains('Category 1 Resource').should('exist');
101
-
102
- // Change category and verify new results
103
- cy.mount(<ELabFTWResourceSelect fullWidth categoryId={2} />);
104
- cy.get('.MuiAutocomplete-input').type('test');
105
- cy.get('li').contains('Category 2 Resource').should('exist');
106
- });
107
- });
@@ -1,23 +0,0 @@
1
- import React from 'react';
2
- import PostRequestSelect from '../form/PostRequestSelect';
3
- import { eLabFTWHttpClient, readHeaders } from './common';
4
-
5
- function ELabFTWResourceSelect({ setResource, categoryId, ...rest }) {
6
- const url = '/api/v2/items';
7
-
8
- const resourcePostRequestSettings = React.useMemo(() => ({
9
- setValue: setResource,
10
- getOptions: async (userInput) => {
11
- const resp = await eLabFTWHttpClient.get(url, { headers: readHeaders, params: { cat: categoryId, extended: `title:${userInput}`, limit: 9999 } });
12
- return resp.data;
13
- },
14
- getOptionLabel: (option) => (option ? option.title : ''),
15
- isOptionEqualToValue: (option, value) => option?.id === value?.id,
16
- textLabel: 'Resource',
17
- }), [setResource, categoryId]);
18
- return (
19
- <PostRequestSelect {...resourcePostRequestSettings} {...rest} />
20
- );
21
- }
22
-
23
- export default ELabFTWResourceSelect;