@opencloning/ui 1.0.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 (207) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/package.json +37 -0
  3. package/src/components/AppAlerts.jsx +19 -0
  4. package/src/components/CloningHistory.jsx +40 -0
  5. package/src/components/DataModelDisplayer.jsx +30 -0
  6. package/src/components/DescriptionEditor.jsx +68 -0
  7. package/src/components/DownloadCloningStrategyDialog.jsx +84 -0
  8. package/src/components/DownloadSequenceFileDialog.jsx +90 -0
  9. package/src/components/DragAndDropCloningHistoryWrapper.jsx +39 -0
  10. package/src/components/DraggableDialogPaper.jsx +16 -0
  11. package/src/components/EditSequenceNameDialog.jsx +90 -0
  12. package/src/components/ExternalServicesStatusCheck.jsx +92 -0
  13. package/src/components/HistoryLoadedDialog.jsx +49 -0
  14. package/src/components/LoadCloningHistoryWrapper.jsx +166 -0
  15. package/src/components/MainSequenceCheckBox.jsx +83 -0
  16. package/src/components/MainSequenceEditor.jsx +165 -0
  17. package/src/components/NetworkNode.jsx +159 -0
  18. package/src/components/NetworkTree.css +127 -0
  19. package/src/components/ObjectTable.jsx +24 -0
  20. package/src/components/OpenCloning.jsx +102 -0
  21. package/src/components/OverhangsDisplay.jsx +25 -0
  22. package/src/components/SequenceEditor.jsx +120 -0
  23. package/src/components/SequenceTab.jsx +14 -0
  24. package/src/components/TemplateSequence.jsx +38 -0
  25. package/src/components/annotation/PlannotateAnnotationReport.jsx +33 -0
  26. package/src/components/annotation/useUpdateAnnotationInMainSequence.js +39 -0
  27. package/src/components/assembler/AssemblePartWidget.jsx +252 -0
  28. package/src/components/assembler/Assembler.jsx +273 -0
  29. package/src/components/assembler/AssemblerPart.jsx +99 -0
  30. package/src/components/assembler/StopIcon.jsx +34 -0
  31. package/src/components/assembler/assembler_data2.json +50 -0
  32. package/src/components/assembler/assembly_component.module.css +81 -0
  33. package/src/components/assembler/moclo.json +110 -0
  34. package/src/components/assembler/sbol_visual_glyphs/LICENSE.html +21 -0
  35. package/src/components/assembler/sbol_visual_glyphs/assembly-scar.svg +63 -0
  36. package/src/components/assembler/sbol_visual_glyphs/cds-stop.svg +85 -0
  37. package/src/components/assembler/sbol_visual_glyphs/cds.svg +60 -0
  38. package/src/components/assembler/sbol_visual_glyphs/chromosomal-locus.svg +78 -0
  39. package/src/components/assembler/sbol_visual_glyphs/engineered-region.svg +56 -0
  40. package/src/components/assembler/sbol_visual_glyphs/five-prime-sticky-restriction-site.svg +56 -0
  41. package/src/components/assembler/sbol_visual_glyphs/origin-of-replication.svg +57 -0
  42. package/src/components/assembler/sbol_visual_glyphs/primer-binding-site.svg +59 -0
  43. package/src/components/assembler/sbol_visual_glyphs/promoter.svg +60 -0
  44. package/src/components/assembler/sbol_visual_glyphs/ribosome-entry-site.svg +56 -0
  45. package/src/components/assembler/sbol_visual_glyphs/specific-recombination-site.svg +59 -0
  46. package/src/components/assembler/sbol_visual_glyphs/terminator.svg +60 -0
  47. package/src/components/assembler/sbol_visual_glyphs/three-prime-sticky-restriction-site.svg +56 -0
  48. package/src/components/assembler/sbol_visual_glyphs.js +36 -0
  49. package/src/components/assembler/useAssembler.js +71 -0
  50. package/src/components/dummy/DummyInterface.js +41 -0
  51. package/src/components/dummy/GetSequenceFileAndDatabaseIdComponent.jsx +59 -0
  52. package/src/components/eLabFTW/ELabFTWCategorySelect.cy.jsx +86 -0
  53. package/src/components/eLabFTW/ELabFTWCategorySelect.jsx +43 -0
  54. package/src/components/eLabFTW/ELabFTWFileSelect.cy.jsx +43 -0
  55. package/src/components/eLabFTW/ELabFTWFileSelect.jsx +29 -0
  56. package/src/components/eLabFTW/ELabFTWResourceSelect.cy.jsx +107 -0
  57. package/src/components/eLabFTW/ELabFTWResourceSelect.jsx +23 -0
  58. package/src/components/eLabFTW/GetPrimerComponent.cy.jsx +261 -0
  59. package/src/components/eLabFTW/GetPrimerComponent.jsx +55 -0
  60. package/src/components/eLabFTW/GetSequenceFileAndDatabaseIdComponent.cy.jsx +184 -0
  61. package/src/components/eLabFTW/GetSequenceFileAndDatabaseIdComponent.jsx +62 -0
  62. package/src/components/eLabFTW/LoadHistoryComponent.cy.jsx +235 -0
  63. package/src/components/eLabFTW/LoadHistoryComponent.jsx +51 -0
  64. package/src/components/eLabFTW/PrimersNotInDatabaseComponent.cy.jsx +159 -0
  65. package/src/components/eLabFTW/PrimersNotInDatabaseComponent.jsx +54 -0
  66. package/src/components/eLabFTW/SubmitToDatabaseComponent.cy.jsx +185 -0
  67. package/src/components/eLabFTW/SubmitToDatabaseComponent.jsx +51 -0
  68. package/src/components/eLabFTW/common.js +26 -0
  69. package/src/components/eLabFTW/eLabFTWInterface.js +294 -0
  70. package/src/components/eLabFTW/eLabFTWInterface.test.js +839 -0
  71. package/src/components/eLabFTW/envValues.js +7 -0
  72. package/src/components/eLabFTW/utils.js +39 -0
  73. package/src/components/form/CustomFormHelperText.jsx +10 -0
  74. package/src/components/form/EnzymeMultiSelect.cy.jsx +61 -0
  75. package/src/components/form/EnzymeMultiSelect.jsx +34 -0
  76. package/src/components/form/GetRequestMultiSelect.jsx +107 -0
  77. package/src/components/form/LabelWithTooltip.jsx +16 -0
  78. package/src/components/form/PostRequestSelect.cy.jsx +70 -0
  79. package/src/components/form/PostRequestSelect.jsx +86 -0
  80. package/src/components/form/RequestStatusWrapper.jsx +17 -0
  81. package/src/components/form/RetryAlert.jsx +20 -0
  82. package/src/components/form/ServerErrorMessage.jsx +10 -0
  83. package/src/components/form/SubmitButtonBackendAPI.jsx +15 -0
  84. package/src/components/form/SubmitToDatabaseDialog.jsx +133 -0
  85. package/src/components/form/TextFieldValidate.jsx +67 -0
  86. package/src/components/form/ValidatedTextField.jsx +33 -0
  87. package/src/components/form/intermediates_disclaimer.svg +181 -0
  88. package/src/components/navigation/ButtonWithMenu.jsx +43 -0
  89. package/src/components/navigation/CustomTab.jsx +14 -0
  90. package/src/components/navigation/FeedbackDialog.jsx +34 -0
  91. package/src/components/navigation/GithubCornerRight.jsx +29 -0
  92. package/src/components/navigation/MainAppBar.css +26 -0
  93. package/src/components/navigation/MainAppBar.jsx +205 -0
  94. package/src/components/navigation/SelectExampleDialog.jsx +69 -0
  95. package/src/components/navigation/SelectTemplateDialog.jsx +107 -0
  96. package/src/components/navigation/TabPanel.jsx +28 -0
  97. package/src/components/navigation/VersionDialog.jsx +33 -0
  98. package/src/components/primers/CreatePrimerFromSequenceForm.jsx +42 -0
  99. package/src/components/primers/DownloadPrimersButton.jsx +104 -0
  100. package/src/components/primers/PrimerForm.css +14 -0
  101. package/src/components/primers/PrimerForm.jsx +107 -0
  102. package/src/components/primers/PrimerList.css +46 -0
  103. package/src/components/primers/PrimerList.cy.jsx +95 -0
  104. package/src/components/primers/PrimerList.jsx +126 -0
  105. package/src/components/primers/PrimerTableRow.cy.jsx +57 -0
  106. package/src/components/primers/PrimerTableRow.jsx +84 -0
  107. package/src/components/primers/SelectPrimerForm.jsx +66 -0
  108. package/src/components/primers/import_primers/ImportPrimersButton.jsx +101 -0
  109. package/src/components/primers/import_primers/ImportPrimersTable.jsx +51 -0
  110. package/src/components/primers/import_primers/PrimerDatabaseImportForm.jsx +107 -0
  111. package/src/components/primers/import_primers/styles.css +60 -0
  112. package/src/components/primers/primer_design/SequenceTabComponents/CollapsableLabel.jsx +31 -0
  113. package/src/components/primers/primer_design/SequenceTabComponents/GatewayRoiSelect.jsx +164 -0
  114. package/src/components/primers/primer_design/SequenceTabComponents/OrientationPicker.jsx +37 -0
  115. package/src/components/primers/primer_design/SequenceTabComponents/PrimerDesignContext.jsx +369 -0
  116. package/src/components/primers/primer_design/SequenceTabComponents/PrimerDesignEBIC.jsx +24 -0
  117. package/src/components/primers/primer_design/SequenceTabComponents/PrimerDesignForm.jsx +29 -0
  118. package/src/components/primers/primer_design/SequenceTabComponents/PrimerDesignGatewayBP.jsx +36 -0
  119. package/src/components/primers/primer_design/SequenceTabComponents/PrimerDesignGibsonAssembly.jsx +26 -0
  120. package/src/components/primers/primer_design/SequenceTabComponents/PrimerDesignHomologousRecombination.jsx +32 -0
  121. package/src/components/primers/primer_design/SequenceTabComponents/PrimerDesignRestriction.jsx +25 -0
  122. package/src/components/primers/primer_design/SequenceTabComponents/PrimerDesignSimplePair.jsx +25 -0
  123. package/src/components/primers/primer_design/SequenceTabComponents/PrimerDesignStepper.jsx +53 -0
  124. package/src/components/primers/primer_design/SequenceTabComponents/PrimerDesigner.jsx +80 -0
  125. package/src/components/primers/primer_design/SequenceTabComponents/PrimerResultForm.jsx +49 -0
  126. package/src/components/primers/primer_design/SequenceTabComponents/PrimerSettingsForm.jsx +68 -0
  127. package/src/components/primers/primer_design/SequenceTabComponents/PrimerSpacerForm.jsx +84 -0
  128. package/src/components/primers/primer_design/SequenceTabComponents/RestrictionSpacerForm.jsx +85 -0
  129. package/src/components/primers/primer_design/SequenceTabComponents/StepNavigation.jsx +48 -0
  130. package/src/components/primers/primer_design/SequenceTabComponents/TabPanelEBICSettings.jsx +216 -0
  131. package/src/components/primers/primer_design/SequenceTabComponents/TabPanelResults.jsx +42 -0
  132. package/src/components/primers/primer_design/SequenceTabComponents/TabPanelSelectRoi.jsx +61 -0
  133. package/src/components/primers/primer_design/SequenceTabComponents/TabPannelSettings.jsx +59 -0
  134. package/src/components/primers/primer_design/SequenceTabComponents/primerDesignMinimalValues.json +5 -0
  135. package/src/components/primers/primer_design/SequenceTabComponents/useEBICPrimerDesignSettings.js +31 -0
  136. package/src/components/primers/primer_design/SequenceTabComponents/useEnzymePrimerDesignSettings.js +57 -0
  137. package/src/components/primers/primer_design/SequenceTabComponents/useGatewayPrimerDesignSettings.js +18 -0
  138. package/src/components/primers/primer_design/SequenceTabComponents/usePrimerDesignSettings.js +31 -0
  139. package/src/components/primers/primer_design/SourceComponents/PrimerDesignGatewayBP.jsx +88 -0
  140. package/src/components/primers/primer_design/SourceComponents/PrimerDesignGibsonAssembly.jsx +65 -0
  141. package/src/components/primers/primer_design/SourceComponents/PrimerDesignHomologousRecombination.jsx +84 -0
  142. package/src/components/primers/primer_design/SourceComponents/PrimerDesignSourceForm.jsx +74 -0
  143. package/src/components/primers/primer_design/common/NoAttPSitesError.jsx +31 -0
  144. package/src/components/primers/primer_details/PCRTable.cy.jsx +51 -0
  145. package/src/components/primers/primer_details/PCRTable.jsx +35 -0
  146. package/src/components/primers/primer_details/Primer3Figure.jsx +25 -0
  147. package/src/components/primers/primer_details/PrimerDetailsTds.jsx +39 -0
  148. package/src/components/primers/primer_details/PrimerInfoIcon.cy.jsx +137 -0
  149. package/src/components/primers/primer_details/PrimerInfoIcon.jsx +132 -0
  150. package/src/components/primers/primer_details/TableSection.jsx +17 -0
  151. package/src/components/primers/primer_details/primerDetailsFormatting.js +3 -0
  152. package/src/components/primers/primer_details/useMultiplePrimerDetails.js +29 -0
  153. package/src/components/primers/primer_details/usePCRDetails.js +47 -0
  154. package/src/components/primers/primer_details/usePrimerDetailsEndpoints.js +49 -0
  155. package/src/components/primers/primer_details/useSinglePrimerSequenceDetails.js +25 -0
  156. package/src/components/primers/primersToTabularFile.js +49 -0
  157. package/src/components/primers/primersToTabularFile.test.js +108 -0
  158. package/src/components/settings/SettingsTab.cy.jsx +267 -0
  159. package/src/components/settings/SettingsTab.jsx +170 -0
  160. package/src/components/sources/AssemblyPlanDisplayer.cy.jsx +22 -0
  161. package/src/components/sources/AssemblyPlanDisplayer.jsx +27 -0
  162. package/src/components/sources/CollectionSource.jsx +97 -0
  163. package/src/components/sources/FinishedSource.jsx +397 -0
  164. package/src/components/sources/KnownSourceErrors.jsx +50 -0
  165. package/src/components/sources/MultipleInputsSelector.jsx +63 -0
  166. package/src/components/sources/MultipleOutputsSelector.jsx +63 -0
  167. package/src/components/sources/NewSourceBox.jsx +37 -0
  168. package/src/components/sources/PCRUnitForm.jsx +102 -0
  169. package/src/components/sources/SingleInputSelector.jsx +36 -0
  170. package/src/components/sources/Source.jsx +125 -0
  171. package/src/components/sources/SourceAnnotation.jsx +44 -0
  172. package/src/components/sources/SourceAssembly.jsx +201 -0
  173. package/src/components/sources/SourceBox.css +18 -0
  174. package/src/components/sources/SourceBox.jsx +60 -0
  175. package/src/components/sources/SourceCopySequence.jsx +38 -0
  176. package/src/components/sources/SourceDatabase.jsx +28 -0
  177. package/src/components/sources/SourceFile.jsx +188 -0
  178. package/src/components/sources/SourceGenomeRegion.cy.jsx +131 -0
  179. package/src/components/sources/SourceGenomeRegion.jsx +486 -0
  180. package/src/components/sources/SourceHomologousRecombination.jsx +125 -0
  181. package/src/components/sources/SourceKnownGenomeRegion.jsx +60 -0
  182. package/src/components/sources/SourceManuallyTyped.jsx +116 -0
  183. package/src/components/sources/SourcePCRorHybridization.jsx +165 -0
  184. package/src/components/sources/SourcePolymeraseExtension.jsx +44 -0
  185. package/src/components/sources/SourceRepositoryId.jsx +409 -0
  186. package/src/components/sources/SourceRestriction.jsx +41 -0
  187. package/src/components/sources/SourceReverseComplement.jsx +33 -0
  188. package/src/components/sources/SourceTypeSelector.jsx +94 -0
  189. package/src/components/sources/SubSequenceDisplayer.jsx +70 -0
  190. package/src/components/sources/VerifyDeleteDialog.jsx +23 -0
  191. package/src/components/sources/repositoryMetadata.js +14 -0
  192. package/src/components/verification/LoadFromDatabaseButton.jsx +90 -0
  193. package/src/components/verification/SequencingFileRow.jsx +34 -0
  194. package/src/components/verification/VerificationFileDialog.cy.jsx +176 -0
  195. package/src/components/verification/VerificationFileDialog.jsx +248 -0
  196. package/src/config/defaultMainEditorProps.js +44 -0
  197. package/src/hooks/useAlerts.js +16 -0
  198. package/src/hooks/useBackendAPI.js +51 -0
  199. package/src/hooks/useBackendRoute.js +22 -0
  200. package/src/hooks/useDatabase.js +18 -0
  201. package/src/hooks/useDragAndDropFile.js +31 -0
  202. package/src/hooks/useGatewaySites.js +40 -0
  203. package/src/hooks/useHttpClient.js +12 -0
  204. package/src/hooks/useLoadDatabaseFile.js +108 -0
  205. package/src/hooks/useStoreEditor.js +101 -0
  206. package/src/hooks/useValidateState.js +43 -0
  207. package/vitest.config.js +18 -0
@@ -0,0 +1,170 @@
1
+ import React from 'react';
2
+ import { useDispatch, useSelector } from 'react-redux';
3
+ import { Button, Card, CardContent, CardHeader, Stack, TextField, InputAdornment, Typography, IconButton, Box } from '@mui/material';
4
+ import { cloningActions } from '@opencloning/store/cloning';
5
+ import Tooltip from '@mui/material/Tooltip';
6
+ import InfoIcon from '@mui/icons-material/Info';
7
+
8
+ const { setGlobalPrimerSettings } = cloningActions;
9
+
10
+ function HeaderWithTooltip() {
11
+ const tooltipMessage = (
12
+ <Box>
13
+ These settings affect thermodynamic calculations for:
14
+ <ul>
15
+ <li>Primer design</li>
16
+ <li>Values displayed in the primer table</li>
17
+ <li>Values displayed in the PCR details</li>
18
+ </ul>
19
+ </Box>
20
+ )
21
+ const title = (
22
+ <Box>
23
+ Global Primer Settings
24
+ <Tooltip title={tooltipMessage} arrow placement="right">
25
+ <IconButton size="small">
26
+ <InfoIcon />
27
+ </IconButton>
28
+ </Tooltip>
29
+ </Box>
30
+ )
31
+ return (
32
+ <CardHeader
33
+ title={title}
34
+ />
35
+ )
36
+ }
37
+
38
+
39
+
40
+
41
+
42
+ function GlobalPrimerSettingsSection() {
43
+ const dispatch = useDispatch();
44
+ const current = useSelector((state) => state.cloning.globalPrimerSettings);
45
+ const [editing, setEditing] = React.useState(false);
46
+ const [form, setForm] = React.useState({
47
+ primer_dna_conc: current.primer_dna_conc,
48
+ primer_salt_monovalent: current.primer_salt_monovalent,
49
+ primer_salt_divalent: current.primer_salt_divalent,
50
+ });
51
+
52
+ const fieldsValid = {
53
+ primer_dna_conc: form.primer_dna_conc > 0,
54
+ primer_salt_monovalent: form.primer_salt_monovalent > 0,
55
+ primer_salt_divalent: form.primer_salt_divalent > 0,
56
+ }
57
+ const allFieldsValid = Object.values(fieldsValid).every((valid) => valid);
58
+
59
+ React.useEffect(() => {
60
+ if (!editing) {
61
+ setForm({
62
+ primer_dna_conc: current.primer_dna_conc,
63
+ primer_salt_monovalent: current.primer_salt_monovalent,
64
+ primer_salt_divalent: current.primer_salt_divalent,
65
+ });
66
+ }
67
+ }, [current, editing]);
68
+
69
+ const onChange = (key) => (e) => {
70
+ setForm((prev) => ({ ...prev, [key]: e.target.value }));
71
+ };
72
+
73
+ const onCancel = () => {
74
+ setEditing(false);
75
+ setForm({
76
+ primer_dna_conc: current.primer_dna_conc,
77
+ primer_salt_monovalent: current.primer_salt_monovalent,
78
+ primer_salt_divalent: current.primer_salt_divalent,
79
+ });
80
+ };
81
+
82
+ const onSave = () => {
83
+ dispatch(setGlobalPrimerSettings({
84
+ primer_dna_conc: Number(form.primer_dna_conc),
85
+ primer_salt_monovalent: Number(form.primer_salt_monovalent),
86
+ primer_salt_divalent: Number(form.primer_salt_divalent),
87
+ }));
88
+ setEditing(false);
89
+ };
90
+
91
+ return (
92
+ <Card className="settings-tab">
93
+ <HeaderWithTooltip />
94
+ <CardContent sx={{ margin: 'auto' }}>
95
+
96
+ <Stack spacing={2} sx={{ maxWidth: 300, margin: 'auto' }}>
97
+ <TextField
98
+ label="Primer DNA concentration"
99
+ type="number"
100
+ value={form.primer_dna_conc}
101
+ onChange={onChange('primer_dna_conc')}
102
+ inputProps={{ min: 0, step: '1' }}
103
+ variant="standard"
104
+ required
105
+ disabled={!editing}
106
+ InputProps={{
107
+ endAdornment: <InputAdornment position="end">nM</InputAdornment>,
108
+ }}
109
+ error={!fieldsValid.primer_dna_conc}
110
+ helperText={!fieldsValid.primer_dna_conc ? 'Must be greater than 0' : ''}
111
+ />
112
+ <TextField
113
+ label="Monovalent ions"
114
+ type="number"
115
+ value={form.primer_salt_monovalent}
116
+ onChange={onChange('primer_salt_monovalent')}
117
+ inputProps={{ min: 0, step: '0.1' }}
118
+ variant="standard"
119
+ required
120
+ disabled={!editing}
121
+ InputProps={{
122
+ endAdornment: <InputAdornment position="end">mM</InputAdornment>,
123
+ }}
124
+ error={!fieldsValid.primer_salt_monovalent}
125
+ helperText={!fieldsValid.primer_salt_monovalent ? 'Must be greater than 0' : ''}
126
+ />
127
+ <TextField
128
+ label="Divalent ions"
129
+ type="number"
130
+ value={form.primer_salt_divalent}
131
+ onChange={onChange('primer_salt_divalent')}
132
+ inputProps={{ min: 0, step: '0.1' }}
133
+ variant="standard"
134
+ required
135
+ disabled={!editing}
136
+ InputProps={{
137
+ endAdornment: <InputAdornment position="end">mM</InputAdornment>,
138
+ }}
139
+ error={!fieldsValid.primer_salt_divalent}
140
+ helperText={!fieldsValid.primer_salt_divalent ? 'Must be greater than 0' : ''}
141
+ />
142
+ {!editing ? (
143
+ <Stack direction="row" justifyContent="center">
144
+ <Button variant="contained" onClick={() => setEditing(true)}>Edit</Button>
145
+ </Stack>
146
+ ) : (
147
+ <Stack direction="row" spacing={1} justifyContent="center">
148
+ <Button onClick={onCancel}>Cancel</Button>
149
+ <Button variant="contained" onClick={onSave} disabled={!allFieldsValid}>Save</Button>
150
+ </Stack>
151
+ )}
152
+ </Stack>
153
+ </CardContent>
154
+ </Card>
155
+ );
156
+ }
157
+
158
+ function SettingsTab() {
159
+ return (
160
+ <div style={{ padding: 16, display: 'flex', justifyContent: 'center' }}>
161
+ <div style={{ maxWidth: 600, width: '100%' }}>
162
+ <GlobalPrimerSettingsSection />
163
+ </div>
164
+ </div>
165
+ );
166
+ }
167
+
168
+ export default SettingsTab;
169
+
170
+
@@ -0,0 +1,22 @@
1
+ import React from 'react';
2
+ import AssemblyPlanDisplayer from './AssemblyPlanDisplayer';
3
+
4
+ describe('<AssemblyPlanDisplayer />', () => {
5
+ it('Represents the assembly plan', () => {
6
+ // see: https://on.cypress.io/mounting-react
7
+ cy.mount(<AssemblyPlanDisplayer source={{ input: [
8
+ { type: 'AssemblyFragment', sequence: 1, left_location: 'aa', right_location: 'bb', reverse_complemented: false },
9
+ { type: 'AssemblyFragment', sequence: 2, left_location: 'cc', right_location: 'dd', reverse_complemented: true },
10
+ ] }}
11
+ />);
12
+ cy.get('.assembly-plan-displayer').contains('1[aa,bb] - 2_rc[cc,dd]');
13
+ });
14
+ it('Represents the assembly plan with null coordinates', () => {
15
+ cy.mount(<AssemblyPlanDisplayer source={{ input: [
16
+ { type: 'AssemblyFragment', sequence: 1, left_location: null, right_location: 'aa', reverse_complemented: false },
17
+ { type: 'AssemblyFragment', sequence: 2, left_location: 'bb', right_location: null, reverse_complemented: true },
18
+ ] }}
19
+ />);
20
+ cy.get('.assembly-plan-displayer').contains('1[,aa] - 2_rc[bb,]');
21
+ });
22
+ });
@@ -0,0 +1,27 @@
1
+ import React from 'react';
2
+
3
+ function AssemblyPlanDisplayer({
4
+ source,
5
+ }) {
6
+ const assemblyFragments = source.input.filter(i => i.type === 'AssemblyFragment');
7
+ if (!assemblyFragments.length) {
8
+ return null;
9
+ }
10
+
11
+ const fragments = assemblyFragments.map((fragment) => {
12
+ const { sequence, left_location, right_location, reverse_complemented } = fragment;
13
+ const leftPart = left_location || '';
14
+ const rightPart = right_location || '';
15
+ return `${sequence}${reverse_complemented ? '_rc' : ''}[${leftPart},${rightPart}]`;
16
+ });
17
+
18
+ // Join left-right pairs with
19
+
20
+ return (
21
+ <div className="assembly-plan-displayer">
22
+ {fragments.join(' - ')}
23
+ </div>
24
+ );
25
+ }
26
+
27
+ export default React.memo(AssemblyPlanDisplayer);
@@ -0,0 +1,97 @@
1
+ import { FormControl, InputLabel, MenuItem, Select } from '@mui/material';
2
+ import React from 'react';
3
+ import AddCircleIcon from '@mui/icons-material/AddCircle';
4
+ import { useDispatch, useStore } from 'react-redux';
5
+ import SubmitButtonBackendAPI from '../form/SubmitButtonBackendAPI';
6
+ import { classNameToEndPointMap } from '@opencloning/utils/sourceFunctions';
7
+ import ObjectTable from '../ObjectTable';
8
+ import { cloningActions } from '@opencloning/store/cloning';
9
+
10
+ function CollectionSource({ source, requestStatus, sendPostRequest }) {
11
+ const { id: sourceId, options, image: imageInfo, title, description } = source;
12
+ const [image, imageWidth] = imageInfo || [null, null];
13
+ const [selectedOption, setSelectedOption] = React.useState(null);
14
+ const dispatch = useDispatch();
15
+ const store = useStore();
16
+ const { replaceSource } = cloningActions;
17
+
18
+ const onSubmit = (event) => {
19
+ event.preventDefault();
20
+ const { source: selectedSource } = options.find((option) => option.name === selectedOption);
21
+ // Delete options field
22
+ const modifySource = (s) => {
23
+ const sourceOut = { ...s };
24
+ delete sourceOut.options;
25
+ return sourceOut;
26
+ };
27
+ const endpoint = classNameToEndPointMap[selectedSource.type];
28
+ let requestData;
29
+ if (selectedSource.type === 'AddgeneIdSource') {
30
+ requestData = { id: sourceId, ...selectedSource };
31
+ } else if (selectedSource.type === 'OligoHybridizationSource') {
32
+ const { primers } = store.getState().cloning;
33
+ const forwardOligo = primers.find((primer) => primer.id === selectedSource.input[0].sequence);
34
+ const reverseOligo = primers.find((primer) => primer.id === selectedSource.input[1].sequence);
35
+ requestData = { source: { id: sourceId, ...selectedSource }, primers: [forwardOligo, reverseOligo] };
36
+ }
37
+ sendPostRequest({ endpoint, requestData, source, modifySource });
38
+ };
39
+
40
+ const onChange = (event) => {
41
+ setSelectedOption(event.target.value);
42
+ };
43
+
44
+ const turnIntoBlankSource = () => {
45
+ setSelectedOption(null);
46
+ dispatch(replaceSource({
47
+ id: sourceId,
48
+ input: [],
49
+ type: null,
50
+ }));
51
+ };
52
+
53
+ const selectedOptionObject = options.find((option) => option.name === selectedOption);
54
+ return (
55
+ <div className="collection-source">
56
+ {title && <h2>{title}</h2>}
57
+ {description && <p>{description}</p>}
58
+ {image && <img src={image} width={imageWidth} alt="Collection source icon" />}
59
+ <form onSubmit={onSubmit}>
60
+ <FormControl fullWidth>
61
+ <InputLabel id="select-collection-source">Select a sequence</InputLabel>
62
+ <Select
63
+ value={selectedOption !== null ? selectedOption : ''}
64
+ onChange={onChange}
65
+ labelId="select-collection-source"
66
+ label="Select a sequence"
67
+ // Limits the height of the dropdown (adds scroll)
68
+ MenuProps={{ PaperProps: { style: { maxHeight: 250 } } }}
69
+ >
70
+ <MenuItem onClick={turnIntoBlankSource} value="">
71
+ <AddCircleIcon color="success" />
72
+ <em style={{ marginLeft: 8 }}>Add your own</em>
73
+ </MenuItem>
74
+ {options.map((option) => (
75
+ <MenuItem key={option.name} value={option.name}>
76
+ {option.name}
77
+ </MenuItem>
78
+ ))}
79
+ </Select>
80
+ </FormControl>
81
+
82
+ {selectedOption !== null && (
83
+ <>
84
+ {selectedOptionObject.info && <ObjectTable object={selectedOptionObject.info} />}
85
+ <SubmitButtonBackendAPI
86
+ requestStatus={requestStatus}
87
+ {...(import.meta.env.VITE_UMAMI_WEBSITE_ID && { "data-umami-event": "submit-collection-source" })}
88
+ >Submit</SubmitButtonBackendAPI>
89
+ </>
90
+ )}
91
+ </form>
92
+ </div>
93
+
94
+ );
95
+ }
96
+
97
+ export default CollectionSource;