@opencloning/ui 1.0.1 → 1.1.0-dev.4

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 (61) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/package.json +12 -7
  3. package/scripts/inject-version.js +17 -0
  4. package/scripts/reset-version.js +16 -0
  5. package/src/components/DescriptionEditor.jsx +1 -2
  6. package/src/components/DragAndDropCloningHistoryWrapper.jsx +1 -1
  7. package/src/components/ExternalServicesStatusCheck.jsx +2 -1
  8. package/src/components/MainSequenceCheckBox.jsx +2 -5
  9. package/src/components/NetworkNode.jsx +1 -3
  10. package/src/components/OpenCloning.jsx +3 -3
  11. package/src/components/assembler/AssemblePartWidget.jsx +1 -1
  12. package/src/components/assembler/Assembler.jsx +1 -2
  13. package/src/components/dummy/DummyInterface.js +1 -2
  14. package/src/components/eLabFTW/eLabFTWInterface.js +1 -2
  15. package/src/components/form/EnzymeMultiSelect.cy.jsx +20 -9
  16. package/src/components/form/GetRequestMultiSelect.jsx +1 -3
  17. package/src/components/form/LabelWithTooltip.jsx +1 -1
  18. package/src/components/form/PostRequestSelect.jsx +1 -3
  19. package/src/components/index.js +2 -0
  20. package/src/components/navigation/ButtonWithMenu.jsx +1 -3
  21. package/src/components/navigation/MainAppBar.jsx +2 -9
  22. package/src/components/navigation/SelectTemplateDialog.jsx +1 -1
  23. package/src/components/primers/PrimerForm.jsx +2 -4
  24. package/src/components/primers/PrimerList.cy.jsx +86 -78
  25. package/src/components/primers/PrimerList.jsx +1 -1
  26. package/src/components/primers/PrimerTableRow.cy.jsx +31 -18
  27. package/src/components/primers/PrimerTableRow.jsx +1 -4
  28. package/src/components/primers/SelectPrimerForm.jsx +1 -1
  29. package/src/components/primers/import_primers/ImportPrimersButton.jsx +1 -4
  30. package/src/components/primers/import_primers/ImportPrimersTable.jsx +2 -5
  31. package/src/components/primers/import_primers/PrimerDatabaseImportForm.jsx +1 -2
  32. package/src/components/primers/primer_design/SequenceTabComponents/CollapsableLabel.jsx +1 -1
  33. package/src/components/primers/primer_design/SequenceTabComponents/PrimerDesignForm.jsx +1 -1
  34. package/src/components/primers/primer_design/SequenceTabComponents/RestrictionSpacerForm.jsx +1 -1
  35. package/src/components/primers/primer_details/PrimerInfoIcon.jsx +1 -2
  36. package/src/components/settings/SettingsTab.jsx +2 -3
  37. package/src/components/sources/CollectionSource.jsx +1 -1
  38. package/src/components/sources/MultipleOutputsSelector.jsx +1 -2
  39. package/src/components/sources/NewSourceBox.jsx +2 -3
  40. package/src/components/sources/PCRUnitForm.jsx +1 -3
  41. package/src/components/sources/Source.jsx +0 -3
  42. package/src/components/sources/SourceBox.jsx +2 -2
  43. package/src/components/sources/SourceFile.jsx +1 -2
  44. package/src/components/sources/SourceGenomeRegion.cy.jsx +24 -9
  45. package/src/components/sources/SourceGenomeRegion.jsx +1 -6
  46. package/src/components/sources/SourceRepositoryId.jsx +2 -9
  47. package/src/components/sources/SourceTypeSelector.jsx +3 -6
  48. package/src/components/verification/SequencingFileRow.jsx +1 -2
  49. package/src/components/verification/VerificationFileDialog.cy.jsx +35 -8
  50. package/src/hooks/useBackendRoute.js +3 -2
  51. package/src/hooks/useConfig.js +2 -0
  52. package/src/hooks/useDatabase.js +2 -2
  53. package/src/hooks/useHttpClient.js +9 -3
  54. package/src/hooks/useInitializeApp.js +15 -0
  55. package/src/hooks/useUrlParamsLoader.js +149 -0
  56. package/src/index.css +314 -0
  57. package/src/index.js +8 -0
  58. package/src/providers/ConfigProvider.jsx +51 -0
  59. package/src/providers/index.js +3 -0
  60. package/src/version.js +2 -0
  61. package/src/components/sources/KnownSourceErrors.jsx +0 -50
@@ -1,14 +1,21 @@
1
1
  import React from 'react';
2
2
  import PrimerTableRow from './PrimerTableRow';
3
3
  import { mockPrimerDetails, mockPCRDetails, mockPrimer } from '../../../../../tests/mockPrimerDetailsData';
4
+ import { ConfigProvider } from '../../providers/ConfigProvider';
5
+
6
+ const config = {
7
+ backendUrl: 'http://127.0.0.1:8000',
8
+ };
4
9
 
5
10
  describe('<PrimerTableRow />', () => {
6
11
  it('displays the right information with PCR details', () => {
7
12
  cy.mount(
8
- <PrimerTableRow
9
- primerDetails={mockPrimerDetails}
10
- pcrDetails={mockPCRDetails}
11
- />,
13
+ <ConfigProvider config={config}>
14
+ <PrimerTableRow
15
+ primerDetails={mockPrimerDetails}
16
+ pcrDetails={mockPCRDetails}
17
+ />
18
+ </ConfigProvider>,
12
19
  );
13
20
 
14
21
  cy.get('.name').should('contain', 'Test Primer');
@@ -19,10 +26,12 @@ describe('<PrimerTableRow />', () => {
19
26
  });
20
27
  it('displays the right information without PCR details', () => {
21
28
  cy.mount(
22
- <PrimerTableRow
23
- primerDetails={mockPrimerDetails}
24
- pcrDetails={[]}
25
- />,
29
+ <ConfigProvider config={config}>
30
+ <PrimerTableRow
31
+ primerDetails={mockPrimerDetails}
32
+ pcrDetails={[]}
33
+ />
34
+ </ConfigProvider>,
26
35
  );
27
36
  cy.get('.melting-temperature').should('contain', '60');
28
37
  cy.get('.gc-content').should('contain', '50');
@@ -30,10 +39,12 @@ describe('<PrimerTableRow />', () => {
30
39
  });
31
40
  it('shows skeletons when info missing', () => {
32
41
  cy.mount(
33
- <PrimerTableRow
34
- primerDetails={mockPrimer}
35
- pcrDetails={[]}
36
- />,
42
+ <ConfigProvider config={config}>
43
+ <PrimerTableRow
44
+ primerDetails={mockPrimer}
45
+ pcrDetails={[]}
46
+ />
47
+ </ConfigProvider>,
37
48
  );
38
49
  cy.get('.melting-temperature .MuiSkeleton-root').should('exist');
39
50
  cy.get('.gc-content .MuiSkeleton-root').should('exist');
@@ -43,12 +54,14 @@ describe('<PrimerTableRow />', () => {
43
54
  // but if we mistakenly test for bool and the value is 0, nothing will show.
44
55
  // This test is to make sure that we are testing for undefined instead of bool.
45
56
  cy.mount(
46
- <PrimerTableRow
47
- primerDetails={{ ...mockPrimerDetails, melting_temperature: 0, gc_content: 0, length: 0 }}
48
- pcrDetails={[
49
- { ...mockPCRDetails[0], fwdPrimer: { ...mockPCRDetails[0].fwdPrimer, melting_temperature: 0, gc_content: 0, length: 0 } },
50
- ]}
51
- />,
57
+ <ConfigProvider config={config}>
58
+ <PrimerTableRow
59
+ primerDetails={{ ...mockPrimerDetails, melting_temperature: 0, gc_content: 0, length: 0 }}
60
+ pcrDetails={[
61
+ { ...mockPCRDetails[0], fwdPrimer: { ...mockPCRDetails[0].fwdPrimer, melting_temperature: 0, gc_content: 0, length: 0 } },
62
+ ]}
63
+ />
64
+ </ConfigProvider>,
52
65
  );
53
66
  cy.get('.melting-temperature').should('contain', '0 (0)');
54
67
  cy.get('.gc-content').should('contain', '0 (0)');
@@ -1,9 +1,6 @@
1
1
  import { IconButton, Tooltip } from '@mui/material';
2
2
  import React, { useState } from 'react';
3
- import DeleteIcon from '@mui/icons-material/Delete';
4
- import EditIcon from '@mui/icons-material/Edit';
5
- import SaveIcon from '@mui/icons-material/Save';
6
- import ClearIcon from '@mui/icons-material/Clear';
3
+ import { Delete as DeleteIcon, Edit as EditIcon, Clear as ClearIcon } from '@mui/icons-material';
7
4
  import SubmitToDatabaseDialog from '../form/SubmitToDatabaseDialog';
8
5
  import useDatabase from '../../hooks/useDatabase';
9
6
  import PrimerDetailsTds from './primer_details/PrimerDetailsTds';
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import { FormControl, InputLabel, Select, MenuItem, Box, Chip } from '@mui/material';
3
- import AddCircleIcon from '@mui/icons-material/AddCircle';
3
+ import { AddCircle as AddCircleIcon } from '@mui/icons-material';
4
4
 
5
5
  function chipRenderer(selected, primers) {
6
6
  return (
@@ -1,9 +1,6 @@
1
1
  import React, { useState } from 'react';
2
2
  import { shallowEqual, useSelector } from 'react-redux';
3
- import Button from '@mui/material/Button';
4
- import Tooltip from '@mui/material/Tooltip';
5
- import Modal from '@mui/material/Modal';
6
- import Box from '@mui/material/Box';
3
+ import { Button, Tooltip, Modal, Box } from '@mui/material';
7
4
  import useAlerts from '../../../hooks/useAlerts';
8
5
  import './styles.css';
9
6
 
@@ -1,9 +1,6 @@
1
1
  import React from 'react';
2
- import { Table, TableCell, TableRow, TableHead, TableBody } from '@mui/material';
3
- import Tooltip from '@mui/material/Tooltip';
4
- import CancelIcon from '@mui/icons-material/Cancel';
5
- import WarningIcon from '@mui/icons-material/Warning';
6
- import CheckCircleIcon from '@mui/icons-material/CheckCircle';
2
+ import { Table, TableCell, TableRow, TableHead, TableBody, Tooltip } from '@mui/material';
3
+ import { Cancel as CancelIcon, Warning as WarningIcon, CheckCircle as CheckCircleIcon } from '@mui/icons-material';
7
4
 
8
5
  function CustomTableRow({ primer }) {
9
6
  const { name, sequence, error } = primer;
@@ -1,7 +1,6 @@
1
1
  import React, { useState } from 'react';
2
2
  import { shallowEqual, useSelector } from 'react-redux';
3
- import Alert from '@mui/material/Alert';
4
- import { Button, TextField } from '@mui/material';
3
+ import { Alert, Button, TextField } from '@mui/material';
5
4
 
6
5
  import useDatabase from '../../../hooks/useDatabase';
7
6
  import { stringIsNotDNA } from '@opencloning/store/cloning_utils';
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import { Box, FormLabel, IconButton, Collapse } from '@mui/material';
3
- import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
3
+ import { ExpandMore as ExpandMoreIcon } from '@mui/icons-material';
4
4
 
5
5
  function CollapsableLabel({ label, className, children, open = false }) {
6
6
  const [show, setShow] = React.useState(open);
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import Box from '@mui/material/Box';
2
+ import { Box } from '@mui/material';
3
3
  import PrimerDesignStepper from './PrimerDesignStepper';
4
4
  import TabPanelSelectRoi from './TabPanelSelectRoi';
5
5
  import TabPannelSettings from './TabPannelSettings';
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import { FormLabel, Box, FormControl, TextField, Tooltip, FormControlLabel, Checkbox } from '@mui/material';
3
- import InfoIcon from '@mui/icons-material/Info';
3
+ import { Info as InfoIcon } from '@mui/icons-material';
4
4
  import { useStore } from 'react-redux';
5
5
  import { updateEditor } from '@teselagen/ove';
6
6
  import EnzymeMultiSelect from '../../../form/EnzymeMultiSelect';
@@ -1,7 +1,6 @@
1
1
  import { Dialog, DialogContent, IconButton, Tooltip, Table, TableBody } from '@mui/material';
2
2
  import React from 'react';
3
- import InfoIcon from '@mui/icons-material/Info';
4
- import WarningIcon from '@mui/icons-material/Warning';
3
+ import { Info as InfoIcon, Warning as WarningIcon } from '@mui/icons-material';
5
4
  import { formatGcContent, formatMeltingTemperature, formatDeltaG } from './primerDetailsFormatting';
6
5
  import Primer3Figure from './Primer3Figure';
7
6
  import TableSection from './TableSection';
@@ -1,9 +1,8 @@
1
1
  import React from 'react';
2
2
  import { useDispatch, useSelector } from 'react-redux';
3
- import { Button, Card, CardContent, CardHeader, Stack, TextField, InputAdornment, Typography, IconButton, Box } from '@mui/material';
3
+ import { Button, Card, CardContent, CardHeader, Stack, TextField, InputAdornment, IconButton, Box, Tooltip } from '@mui/material';
4
4
  import { cloningActions } from '@opencloning/store/cloning';
5
- import Tooltip from '@mui/material/Tooltip';
6
- import InfoIcon from '@mui/icons-material/Info';
5
+ import { Info as InfoIcon } from '@mui/icons-material';
7
6
 
8
7
  const { setGlobalPrimerSettings } = cloningActions;
9
8
 
@@ -1,6 +1,6 @@
1
1
  import { FormControl, InputLabel, MenuItem, Select } from '@mui/material';
2
2
  import React from 'react';
3
- import AddCircleIcon from '@mui/icons-material/AddCircle';
3
+ import { AddCircle as AddCircleIcon } from '@mui/icons-material';
4
4
  import { useDispatch, useStore } from 'react-redux';
5
5
  import SubmitButtonBackendAPI from '../form/SubmitButtonBackendAPI';
6
6
  import { classNameToEndPointMap } from '@opencloning/utils/sourceFunctions';
@@ -1,7 +1,6 @@
1
1
  import { SimpleCircularOrLinearView } from '@teselagen/ove';
2
2
  import React from 'react';
3
- import ArrowForward from '@mui/icons-material/ArrowForward';
4
- import ArrowBack from '@mui/icons-material/ArrowBack';
3
+ import { ArrowForward, ArrowBack } from '@mui/icons-material';
5
4
  import { Button, IconButton } from '@mui/material';
6
5
  import { convertToTeselaJson } from '@opencloning/utils/readNwrite';
7
6
  import OverhangsDisplay from '../OverhangsDisplay';
@@ -1,8 +1,7 @@
1
1
  import React from 'react';
2
- import AddCircleIcon from '@mui/icons-material/AddCircle';
3
- import Tooltip from '@mui/material/Tooltip';
2
+ import { AddCircle as AddCircleIcon } from '@mui/icons-material';
3
+ import { Tooltip, IconButton } from '@mui/material';
4
4
  import { useDispatch } from 'react-redux';
5
- import { IconButton } from '@mui/material';
6
5
  import { cloningActions } from '@opencloning/store/cloning';
7
6
 
8
7
  // A component that is rendered on the side of the tree to add a new source
@@ -1,9 +1,7 @@
1
1
  import { Accordion, AccordionDetails, AccordionSummary, FormControl, InputLabel, ListItemText, MenuItem, Select, Tooltip } from '@mui/material';
2
2
  import React from 'react';
3
3
  import { useDispatch } from 'react-redux';
4
- import AddCircleIcon from '@mui/icons-material/AddCircle';
5
- import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
6
- import CancelIcon from '@mui/icons-material/Cancel';
4
+ import { ExpandMore as ExpandMoreIcon, Cancel as CancelIcon } from '@mui/icons-material';
7
5
  import { cloningActions } from '@opencloning/store/cloning';
8
6
  import SingleInputSelector from './SingleInputSelector';
9
7
  import SelectPrimerForm from '../primers/SelectPrimerForm';
@@ -14,7 +14,6 @@ import SourceAnnotation from './SourceAnnotation';
14
14
  import SourceDatabase from './SourceDatabase';
15
15
  import SourcePolymeraseExtension from './SourcePolymeraseExtension';
16
16
  import CollectionSource from './CollectionSource';
17
- import KnownSourceErrors from './KnownSourceErrors';
18
17
  import useBackendAPI from '../../hooks/useBackendAPI';
19
18
  import MultipleOutputsSelector from './MultipleOutputsSelector';
20
19
  import { cloningActions } from '@opencloning/store/cloning';
@@ -31,7 +30,6 @@ function Source({ sourceId }) {
31
30
  const { type: sourceType } = source;
32
31
  let specificSource = null;
33
32
  const templateOnlySources = ['CollectionSource', 'KnownGenomeCoordinatesSource'];
34
- const knownErrors = useSelector((state) => state.cloning.knownErrors, isEqual);
35
33
  const { requestStatus, sendPostRequest, sources, sequences } = useBackendAPI();
36
34
  const { addSequenceAndUpdateItsSource, updateSequenceAndItsSource } = cloningActions;
37
35
  const [chosenFragment, setChosenFragment] = React.useState(null);
@@ -115,7 +113,6 @@ function Source({ sourceId }) {
115
113
  return (
116
114
  <>
117
115
  {!templateOnlySources.includes(sourceType) && (<SourceTypeSelector {...{ source }} />)}
118
- {sourceType && knownErrors[sourceType] && <KnownSourceErrors errors={knownErrors[sourceType]} />}
119
116
  {specificSource}
120
117
  {sources.length > 1 && (<MultipleOutputsSelector {...{ sources, sequences, sourceId, onFragmentChosen: setChosenFragment }} />)}
121
118
  </>
@@ -1,7 +1,7 @@
1
1
  import React, { useState } from 'react';
2
2
  import { useDispatch, useStore } from 'react-redux';
3
- import Tooltip from '@mui/material/Tooltip';
4
- import DeleteIcon from '@mui/icons-material/Delete';
3
+ import { Tooltip } from '@mui/material';
4
+ import { Delete as DeleteIcon } from '@mui/icons-material';
5
5
  import { cloningActions } from '@opencloning/store/cloning';
6
6
  import './SourceBox.css';
7
7
  import VerifyDeleteDialog from './VerifyDeleteDialog';
@@ -1,6 +1,5 @@
1
1
  import React from 'react';
2
- import FormHelperText from '@mui/material/FormHelperText';
3
- import { Alert, Checkbox, FormControl, FormControlLabel, InputLabel, MenuItem, Select, TextField } from '@mui/material';
2
+ import { FormHelperText, Alert, Checkbox, FormControl, FormControlLabel, InputLabel, MenuItem, Select, TextField } from '@mui/material';
4
3
  import { useDispatch, batch, useStore, useSelector } from 'react-redux';
5
4
  import SubmitButtonBackendAPI from '../form/SubmitButtonBackendAPI';
6
5
  import LabelWithTooltip from '../form/LabelWithTooltip';
@@ -1,5 +1,10 @@
1
1
  import React from 'react';
2
2
  import { AssemblyIdSelector, SpeciesPicker, SequenceAccessionPicker, } from './SourceGenomeRegion';
3
+ import { ConfigProvider } from '../../providers/ConfigProvider';
4
+
5
+ const config = {
6
+ backendUrl: 'http://127.0.0.1:8000',
7
+ };
3
8
 
4
9
  describe('<AssemblyIdSelector />', () => {
5
10
  it('can propose a paired accession if the assembly has no annotation', () => {
@@ -43,11 +48,13 @@ describe('<AssemblyIdSelector />', () => {
43
48
  }).as('getPairedAssemblyInfo');
44
49
 
45
50
  cy.mount(
46
- <AssemblyIdSelector
47
- setAssemblyId={setAssemblyId}
48
- setHasAnnotation={setHasAnnotation}
49
- onAssemblyIdChange={onAssemblyIdChange}
50
- />
51
+ <ConfigProvider config={config}>
52
+ <AssemblyIdSelector
53
+ setAssemblyId={setAssemblyId}
54
+ setHasAnnotation={setHasAnnotation}
55
+ onAssemblyIdChange={onAssemblyIdChange}
56
+ />
57
+ </ConfigProvider>
51
58
  );
52
59
  cy.get('input').type('GCA_000002945.3');
53
60
  cy.wait('@getAssemblyInfo');
@@ -62,7 +69,9 @@ describe('<AssemblyIdSelector />', () => {
62
69
  }).as('getAssemblyInfo');
63
70
 
64
71
  cy.mount(
65
- <AssemblyIdSelector setAssemblyId={cy.spy()} setHasAnnotation={cy.spy()} onAssemblyIdChange={cy.spy()} />
72
+ <ConfigProvider config={config}>
73
+ <AssemblyIdSelector setAssemblyId={cy.spy()} setHasAnnotation={cy.spy()} onAssemblyIdChange={cy.spy()} />
74
+ </ConfigProvider>
66
75
  );
67
76
  cy.get('input').type('GCA_000002945.3', { delay: 0});
68
77
  cy.wait('@getAssemblyInfo');
@@ -76,7 +85,9 @@ describe('<SpeciesPicker />', () => {
76
85
  const setAssemblyId = cy.spy().as('setAssemblyId');
77
86
 
78
87
  cy.mount(
79
- <SpeciesPicker setSpecies={setSpecies} setAssemblyId={setAssemblyId} />
88
+ <ConfigProvider config={config}>
89
+ <SpeciesPicker setSpecies={setSpecies} setAssemblyId={setAssemblyId} />
90
+ </ConfigProvider>
80
91
  );
81
92
  cy.intercept('GET', 'https://api.ncbi.nlm.nih.gov/datasets/v2alpha/taxonomy/taxon_suggest/**', {
82
93
  statusCode: 500,
@@ -101,7 +112,9 @@ describe('<SequenceAccessionPicker />', () => {
101
112
  }).as('getSequenceReports');
102
113
 
103
114
  cy.mount(
104
- <SequenceAccessionPicker assemblyAccession={assemblyAccession} sequenceAccession={''} setSequenceAccession={setSequenceAccession} />
115
+ <ConfigProvider config={config}>
116
+ <SequenceAccessionPicker assemblyAccession={assemblyAccession} sequenceAccession={''} setSequenceAccession={setSequenceAccession} />
117
+ </ConfigProvider>
105
118
  );
106
119
  cy.contains('Could not load chromosomes').should('exist');
107
120
  });
@@ -115,7 +128,9 @@ describe('<SequenceAccessionPicker />', () => {
115
128
  }).as('getSequenceReports');
116
129
 
117
130
  cy.mount(
118
- <SequenceAccessionPicker assemblyAccession={assemblyAccession} setSequenceAccession={setSequenceAccession} />
131
+ <ConfigProvider config={config}>
132
+ <SequenceAccessionPicker assemblyAccession={assemblyAccession} setSequenceAccession={setSequenceAccession} />
133
+ </ConfigProvider>
119
134
  );
120
135
  cy.wait('@getSequenceReports');
121
136
  cy.get('label').siblings('div').first().click();
@@ -1,10 +1,5 @@
1
1
  import React from 'react';
2
- import InputLabel from '@mui/material/InputLabel';
3
- import MenuItem from '@mui/material/MenuItem';
4
- import TextField from '@mui/material/TextField';
5
- import FormControl from '@mui/material/FormControl';
6
- import Select from '@mui/material/Select';
7
- import { Alert, Box, FormHelperText, FormLabel } from '@mui/material';
2
+ import { InputLabel, MenuItem, TextField, FormControl, Select, Alert, Box, FormHelperText, FormLabel } from '@mui/material';
8
3
  import PostRequestSelect from '../form/PostRequestSelect';
9
4
  import { getReferenceAssemblyId, taxonSuggest, geneSuggest, getInfoFromAssemblyId, getInfoFromSequenceAccession } from '@opencloning/utils/ncbiRequests';
10
5
  import TextFieldValidate from '../form/TextFieldValidate';
@@ -1,13 +1,6 @@
1
1
  import React from 'react';
2
- import IconButton from '@mui/material/IconButton';
3
- import InputAdornment from '@mui/material/InputAdornment';
4
- import ClearIcon from '@mui/icons-material/Clear';
5
- import InputLabel from '@mui/material/InputLabel';
6
- import MenuItem from '@mui/material/MenuItem';
7
- import TextField from '@mui/material/TextField';
8
- import FormControl from '@mui/material/FormControl';
9
- import Select from '@mui/material/Select';
10
- import { Alert, Autocomplete, Table, TableBody, TableCell, TableRow } from '@mui/material';
2
+ import { IconButton, InputAdornment, InputLabel, MenuItem, TextField, FormControl, Select, Alert, Autocomplete, Table, TableBody, TableCell, TableRow } from '@mui/material';
3
+ import { Clear as ClearIcon } from '@mui/icons-material';
11
4
  import SubmitButtonBackendAPI from '../form/SubmitButtonBackendAPI';
12
5
  import RequestStatusWrapper from '../form/RequestStatusWrapper';
13
6
  import getHttpClient from '@opencloning/utils/getHttpClient';
@@ -1,12 +1,10 @@
1
1
  import React from 'react';
2
2
  import { shallowEqual, useDispatch, useSelector } from 'react-redux';
3
- import InputLabel from '@mui/material/InputLabel';
4
- import MenuItem from '@mui/material/MenuItem';
5
- import FormControl from '@mui/material/FormControl';
6
- import Select from '@mui/material/Select';
3
+ import { InputLabel, MenuItem, FormControl, Select } from '@mui/material';
7
4
  import { getInputSequencesFromSourceId } from '@opencloning/store/cloning_utils';
8
5
  import { cloningActions } from '@opencloning/store/cloning';
9
6
  import useDatabase from '../../hooks/useDatabase';
7
+ import { useConfig } from '../../hooks/useConfig';
10
8
 
11
9
  const { replaceSource } = cloningActions;
12
10
 
@@ -15,8 +13,7 @@ function SourceTypeSelector({ source }) {
15
13
  const dispatch = useDispatch();
16
14
  const database = useDatabase();
17
15
  const sourceIsPrimerDesign = useSelector((state) => Boolean(state.cloning.sequences.find((e) => e.id === source.id)?.primer_design));
18
- const noExternalRequests = useSelector((state) => state.cloning.config.noExternalRequests);
19
- const enablePlannotate = useSelector((state) => state.cloning.config.enablePlannotate);
16
+ const { noExternalRequests, enablePlannotate } = useConfig();
20
17
 
21
18
  const onChange = (event) => {
22
19
  // Clear the source other than these fields
@@ -1,6 +1,5 @@
1
1
  import React from 'react';
2
- import DeleteIcon from '@mui/icons-material/Delete';
3
- import DownloadIcon from '@mui/icons-material/Download';
2
+ import { Delete as DeleteIcon, Download as DownloadIcon } from '@mui/icons-material';
4
3
  import {
5
4
  TableCell,
6
5
  TableRow,
@@ -4,8 +4,14 @@ import store from '@opencloning/store';
4
4
  import { cloningActions } from '@opencloning/store/cloning';
5
5
  import { loadDataAndMount } from '../../../../../cypress/e2e/common_funcions_store';
6
6
  import { getVerificationFileName } from '@opencloning/utils/readNwrite';
7
+ import { ConfigProvider } from '@opencloning/ui/providers/ConfigProvider';
8
+ import { Provider } from 'react-redux';
7
9
 
8
- const { setFiles, setConfig } = cloningActions;
10
+ const { setFiles } = cloningActions;
11
+
12
+ const config = {
13
+ backendUrl: 'http://127.0.0.1:8000',
14
+ };
9
15
 
10
16
  const dummyFiles = [
11
17
  { file_name: 'file1.txt', sequence_id: 1, file_type: 'Sequencing file' },
@@ -22,7 +28,13 @@ describe('<VerificationFileDialog />', () => {
22
28
  it('renders and calls setDialogOpen with false when clicking close button', () => {
23
29
  // see: https://on.cypress.io/mounting-react
24
30
  const setDialogOpenSpy = cy.spy().as('setDialogOpenSpy');
25
- cy.mount(<VerificationFileDialog id={1} dialogOpen setDialogOpen={setDialogOpenSpy} />);
31
+ cy.mount(
32
+ <Provider store={store}>
33
+ <ConfigProvider config={config}>
34
+ <VerificationFileDialog id={1} dialogOpen setDialogOpen={setDialogOpenSpy} />
35
+ </ConfigProvider>
36
+ </Provider>
37
+ );
26
38
 
27
39
  // Click close button
28
40
  cy.get('button').contains('Close').click();
@@ -41,7 +53,13 @@ describe('<VerificationFileDialog />', () => {
41
53
  dummyFiles.forEach((file) => {
42
54
  sessionStorage.setItem(getVerificationFileName(file), base64str);
43
55
  });
44
- cy.mount(<VerificationFileDialog id={1} dialogOpen setDialogOpen={() => {}} />);
56
+ cy.mount(
57
+ <Provider store={store}>
58
+ <ConfigProvider config={config}>
59
+ <VerificationFileDialog id={1} dialogOpen setDialogOpen={() => {}} />
60
+ </ConfigProvider>
61
+ </Provider>
62
+ );
45
63
  // Even though there are two files with the same name, only one should be displayed
46
64
  cy.get('table td').filter(':contains("file1.txt")').should('have.length', 1);
47
65
  cy.get('table').contains('file2.txt');
@@ -64,13 +82,17 @@ describe('<VerificationFileDialog />', () => {
64
82
  });
65
83
 
66
84
  it('can submit files and aligns them', () => {
67
- store.dispatch(setConfig({ backendUrl: 'http://127.0.0.1:8000' }));
68
-
69
85
  loadDataAndMount(
70
86
  'cypress/test_files/sequencing/cloning_strategy_linear.json',
71
87
  store,
72
88
  () => {
73
- cy.mount(<VerificationFileDialog id={2} dialogOpen setDialogOpen={() => {}} />);
89
+ cy.mount(
90
+ <Provider store={store}>
91
+ <ConfigProvider config={config}>
92
+ <VerificationFileDialog id={2} dialogOpen setDialogOpen={() => {}} />
93
+ </ConfigProvider>
94
+ </Provider>
95
+ );
74
96
  },
75
97
  ).then(() => {
76
98
  cy.get('button').contains('Submit files').click();
@@ -118,12 +140,17 @@ describe('<VerificationFileDialog />', () => {
118
140
  });
119
141
  });
120
142
  it('handles errors', () => {
121
- store.dispatch(setConfig({ backendUrl: 'http://127.0.0.1:8000' }));
122
143
  loadDataAndMount(
123
144
  'cypress/test_files/sequencing/cloning_strategy_linear.json',
124
145
  store,
125
146
  () => {
126
- cy.mount(<VerificationFileDialog id={2} dialogOpen setDialogOpen={() => {}} />);
147
+ cy.mount(
148
+ <Provider store={store}>
149
+ <ConfigProvider config={config}>
150
+ <VerificationFileDialog id={2} dialogOpen setDialogOpen={() => {}} />
151
+ </ConfigProvider>
152
+ </Provider>
153
+ );
127
154
  },
128
155
  ).then(() => {
129
156
  // Error if submitting non-allowed files
@@ -1,7 +1,8 @@
1
- import { useSelector } from 'react-redux';
1
+ import { useConfig } from './useConfig';
2
2
 
3
3
  export default function useBackendRoute() {
4
- const configBackendUrl = useSelector((state) => state.cloning.config.backendUrl);
4
+ const { backendUrl: configBackendUrl } = useConfig();
5
+
5
6
  if (!configBackendUrl) {
6
7
  return () => {};
7
8
  }
@@ -0,0 +1,2 @@
1
+ // Re-export useConfig from ConfigProvider for convenience
2
+ export { useConfig } from '../providers/ConfigProvider';
@@ -1,10 +1,10 @@
1
1
  import React from 'react';
2
- import { useSelector } from 'react-redux';
2
+ import { useConfig } from './useConfig';
3
3
  import eLabFTWInterface from '../components/eLabFTW/eLabFTWInterface';
4
4
  import dummyInterface from '../components/dummy/DummyInterface';
5
5
 
6
6
  export default function useDatabase() {
7
- const databaseName = useSelector((state) => state.cloning.config.database);
7
+ const { database: databaseName } = useConfig();
8
8
 
9
9
  return React.useMemo(() => {
10
10
  if (databaseName === 'elabftw') {
@@ -1,12 +1,18 @@
1
- import { useSelector } from 'react-redux';
2
1
  import React from 'react';
3
2
  import getHttpClient from '@opencloning/utils/getHttpClient';
3
+ import { useConfig } from './useConfig';
4
4
 
5
5
  export default function useHttpClient() {
6
- const backendUrl = useSelector((state) => state.cloning.config.backendUrl);
6
+ const { backendUrl } = useConfig();
7
7
 
8
8
  // Memoize the client creation and interceptor setup
9
- const apiClient = React.useMemo(() => getHttpClient([backendUrl]), [backendUrl]);
9
+ const apiClient = React.useMemo(() => {
10
+ if (!backendUrl) {
11
+ // Return a client without backend URL if config not loaded yet
12
+ return getHttpClient([]);
13
+ }
14
+ return getHttpClient([backendUrl]);
15
+ }, [backendUrl]);
10
16
 
11
17
  return apiClient;
12
18
  }
@@ -0,0 +1,15 @@
1
+ import { useEffect } from 'react';
2
+
3
+ /**
4
+ * Hook to initialize application-level concerns
5
+ * - Clears session storage
6
+ */
7
+ export default function useInitializeApp() {
8
+
9
+ useEffect(() => {
10
+ // Clear session storage
11
+ // eslint-disable-next-line no-undef
12
+ sessionStorage.clear();
13
+ }, []);
14
+ }
15
+