@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,188 @@
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';
4
+ import { useDispatch, batch, useStore, useSelector } from 'react-redux';
5
+ import SubmitButtonBackendAPI from '../form/SubmitButtonBackendAPI';
6
+ import LabelWithTooltip from '../form/LabelWithTooltip';
7
+ import { cloningActions } from '@opencloning/store/cloning';
8
+ import { loadFilesToSessionStorage, loadHistoryFile, updateVerificationFileNames } from '@opencloning/utils/readNwrite';
9
+ import useValidateState from '../../hooks/useValidateState';
10
+ import { mergeStates, getGraftSequenceId, graftState } from '@opencloning/utils/network';
11
+
12
+ const { deleteSourceAndItsChildren, restoreSource, setState: setCloningState } = cloningActions;
13
+
14
+ const fileFormatToExtension = {
15
+ genbank: 'gb',
16
+ fasta: 'fasta',
17
+ snapgene: 'dna',
18
+ embl: 'embl',
19
+ json: 'json',
20
+ };
21
+
22
+ // A component providing an interface to import a file
23
+ function SourceFile({ source, requestStatus, sendPostRequest }) {
24
+ const [circularize, setCircularize] = React.useState(false);
25
+ const [showCoordinates, setShowCoordinates] = React.useState(false);
26
+ const [coordinates, setCoordinates] = React.useState({ start: null, end: null });
27
+ const [fileFormat, setFileFormat] = React.useState('');
28
+ const hasOutput = useSelector((state) => state.cloning.sequences.some((s) => s.id === source.id));
29
+ // Error message for json only
30
+ const [alert, setAlert] = React.useState(null);
31
+ const dispatch = useDispatch();
32
+ const validateState = useValidateState();
33
+ const store = useStore();
34
+
35
+ const onChange = async (event) => {
36
+ setAlert(null);
37
+ const files = Array.from(event.target.files);
38
+ if (files.length === 0) {
39
+ return;
40
+ }
41
+ event.target.value = null;
42
+ // If the file is a history file, we load it
43
+ if (
44
+ fileFormat === 'json' || fileFormat === 'zip'
45
+ || (fileFormat === '' && (files[0].name.endsWith('.json') || files[0].name.endsWith('.zip')))
46
+ ) {
47
+ // If file format is explicitly set, rename file to match that extension
48
+ if (fileFormat) {
49
+ files[0] = new File([files[0]], files[0].name.replace(/\.[^/.]+$/, `.${fileFormatToExtension[fileFormat]}`), {
50
+ type: fileFormat === 'json' ? 'application/json' : files[0].type,
51
+ });
52
+ }
53
+ let cloningStrategy;
54
+ let verificationFiles;
55
+ try {
56
+ ({ cloningStrategy, verificationFiles } = await loadHistoryFile(files[0]));
57
+ } catch (e) {
58
+ console.error(e);
59
+ setAlert({ message: e.message, severity: 'error' });
60
+ return;
61
+ }
62
+
63
+ const validatedCloningStrategy = await validateState(cloningStrategy);
64
+ // Update the verificationFiles names if needed
65
+ const updatedVerificationFiles = updateVerificationFileNames(verificationFiles, cloningStrategy.files, validatedCloningStrategy.files);
66
+
67
+ const canGraft = getGraftSequenceId(validatedCloningStrategy) !== null;
68
+ const graft = hasOutput && canGraft;
69
+
70
+ if (hasOutput && !canGraft) {
71
+ setAlert({ message: 'Cannot graft cloning strategy as it does not converge on a single sequence, you can load it on a source without outputs', severity: 'error' });
72
+ return;
73
+ }
74
+
75
+ batch(async () => {
76
+ if (!graft) {
77
+ // Replace the source with the new one
78
+ dispatch(deleteSourceAndItsChildren(source.id));
79
+ }
80
+ try {
81
+ const cloningState = store.getState().cloning;
82
+ let mergedState;
83
+ let idShift;
84
+ if (graft) {
85
+ ({ mergedState, idShift } = graftState(validatedCloningStrategy, cloningState, source.id));
86
+ } else {
87
+ ({ mergedState, idShift } = mergeStates(validatedCloningStrategy, cloningState));
88
+ }
89
+ dispatch(setCloningState(mergedState));
90
+ await loadFilesToSessionStorage(updatedVerificationFiles, idShift);
91
+ } catch (e) {
92
+ setAlert({ message: e.message, severity: 'error' });
93
+ dispatch(restoreSource({ ...source, type: 'UploadedFileSource' }));
94
+ }
95
+ });
96
+ return;
97
+ }
98
+ const requestData = new FormData();
99
+ requestData.append('file', files[0]);
100
+ const config = {
101
+ headers: {
102
+ 'content-type': 'multipart/form-data',
103
+ },
104
+ params: { circularize, sequence_file_format: fileFormat || null, ...coordinates },
105
+ };
106
+ sendPostRequest({ endpoint: 'read_from_file', requestData, config, source });
107
+ };
108
+
109
+ const updateCoordinates = (value, isStart) => {
110
+ setCoordinates((prev) => ({ ...prev, [isStart ? 'start' : 'end']: value }));
111
+ };
112
+
113
+ const onShowCoordinatesChange = () => {
114
+ const newShowCoordinates = !showCoordinates;
115
+ setShowCoordinates(newShowCoordinates);
116
+ if (!newShowCoordinates) {
117
+ setCoordinates({ start: null, end: null });
118
+ }
119
+ };
120
+
121
+ return (
122
+ <form className="submit-sequence-file" onSubmit={(e) => e.preventDefault()}>
123
+ <FormControl fullWidth>
124
+ <InputLabel id="select-file-format" shrink>File format</InputLabel>
125
+ <Select
126
+ labelId="select-file-format"
127
+ id="select-file-format"
128
+ value={fileFormat}
129
+ onChange={(e) => setFileFormat(e.target.value)}
130
+ label="File format"
131
+ displayEmpty
132
+ >
133
+ <MenuItem value="">Guess from extension</MenuItem>
134
+ <MenuItem value="genbank">Genbank / Ape</MenuItem>
135
+ <MenuItem value="fasta">FASTA</MenuItem>
136
+ <MenuItem value="snapgene">SnapGene (.dna)</MenuItem>
137
+ <MenuItem value="embl">EMBL</MenuItem>
138
+ <MenuItem value="json">JSON (history file)</MenuItem>
139
+ <MenuItem value="zip">Zip (history folder)</MenuItem>
140
+ </Select>
141
+ </FormControl>
142
+
143
+ <FormControl fullWidth>
144
+ <FormControlLabel
145
+ control={<Checkbox checked={circularize} onChange={() => setCircularize(!circularize)} />}
146
+ label={<LabelWithTooltip label="Circularize" tooltip="Make the sequence circular (for GenBank or Snapgene files, it will override the topology indicated in the file)" />}
147
+ />
148
+ <FormControlLabel
149
+ control={<Checkbox checked={showCoordinates} onChange={onShowCoordinatesChange} />}
150
+ label={<LabelWithTooltip label="Extract subsequence" tooltip="Does not work with JSON or Zip files" />}
151
+ />
152
+ {showCoordinates && (
153
+ <FormControl fullWidth className="extract-subsequence">
154
+ <TextField
155
+ label="Start"
156
+ value={coordinates.start}
157
+ onChange={(e) => updateCoordinates(e.target.value, true)}
158
+ type="number"
159
+ />
160
+ <TextField
161
+ label="End"
162
+ value={coordinates.end}
163
+ onChange={(e) => updateCoordinates(e.target.value, false)}
164
+ type="number"
165
+ />
166
+ </FormControl>
167
+ )}
168
+ </FormControl>
169
+
170
+ {alert && (<Alert sx={{ marginTop: '10px' }} severity={alert.severity}>{alert.message}</Alert>)}
171
+ <SubmitButtonBackendAPI
172
+ component="label"
173
+ requestStatus={requestStatus}
174
+ {...(import.meta.env.VITE_UMAMI_WEBSITE_ID && { "data-umami-event": "submit-file" })}
175
+ >
176
+ Select File
177
+ <input
178
+ type="file"
179
+ hidden
180
+ onChange={onChange}
181
+ />
182
+ </SubmitButtonBackendAPI>
183
+ <FormHelperText>Supports .gb, .dna, .embl, .fasta, .fa, .ape</FormHelperText>
184
+ </form>
185
+ );
186
+ }
187
+
188
+ export default SourceFile;
@@ -0,0 +1,131 @@
1
+ import React from 'react';
2
+ import { AssemblyIdSelector, SpeciesPicker, SequenceAccessionPicker, } from './SourceGenomeRegion';
3
+
4
+ describe('<AssemblyIdSelector />', () => {
5
+ it('can propose a paired accession if the assembly has no annotation', () => {
6
+ const setAssemblyId = cy.spy().as('setAssemblyId');
7
+ const setHasAnnotation = cy.spy().as('setHasAnnotation');
8
+ const onAssemblyIdChange = cy.spy().as('onAssemblyIdChange');
9
+
10
+ cy.intercept('GET', 'https://api.ncbi.nlm.nih.gov/datasets/v2alpha/genome/accession/GCA_000002945.3/dataset_report*', {
11
+ statusCode: 200,
12
+ body: {
13
+ reports: [{
14
+ accession: 'GCA_000002945.3',
15
+ organism: {
16
+ tax_id: 559292,
17
+ organism_name: 'Saccharomyces cerevisiae'
18
+ },
19
+ annotation_info: undefined,
20
+ paired_accession: 'GCF_000002945.3',
21
+ assembly_info: {
22
+ assembly_status: 'current'
23
+ }
24
+ }]
25
+ }
26
+ }).as('getAssemblyInfo');
27
+
28
+ cy.intercept('GET', 'https://api.ncbi.nlm.nih.gov/datasets/v2alpha/genome/accession/GCF_000002945.3/dataset_report*', {
29
+ statusCode: 200,
30
+ body: {
31
+ reports: [{
32
+ accession: 'GCF_000002945.3',
33
+ organism: {
34
+ tax_id: 559292,
35
+ organism_name: 'Saccharomyces cerevisiae'
36
+ },
37
+ annotation_info: {},
38
+ assembly_info: {
39
+ assembly_status: 'current'
40
+ }
41
+ }]
42
+ }
43
+ }).as('getPairedAssemblyInfo');
44
+
45
+ cy.mount(
46
+ <AssemblyIdSelector
47
+ setAssemblyId={setAssemblyId}
48
+ setHasAnnotation={setHasAnnotation}
49
+ onAssemblyIdChange={onAssemblyIdChange}
50
+ />
51
+ );
52
+ cy.get('input').type('GCA_000002945.3');
53
+ cy.wait('@getAssemblyInfo');
54
+
55
+ cy.wait('@getPairedAssemblyInfo');
56
+ cy.contains('Equivalent assembly GCF_000002945.3 has annotation').should('exist');
57
+ });
58
+ it('handles NCBI being down displaying the right error', () => {
59
+ cy.intercept('GET', 'https://api.ncbi.nlm.nih.gov/datasets/v2alpha/genome/accession/GCA_000002945.3/dataset_report*', {
60
+ statusCode: 500,
61
+ body: {}
62
+ }).as('getAssemblyInfo');
63
+
64
+ cy.mount(
65
+ <AssemblyIdSelector setAssemblyId={cy.spy()} setHasAnnotation={cy.spy()} onAssemblyIdChange={cy.spy()} />
66
+ );
67
+ cy.get('input').type('GCA_000002945.3', { delay: 0});
68
+ cy.wait('@getAssemblyInfo');
69
+ cy.contains('Could not connect to server for validation.').should('exist');
70
+ });
71
+ });
72
+
73
+ describe('<SpeciesPicker />', () => {
74
+ it('handles NCBI being down displaying the right error', () => {
75
+ const setSpecies = cy.spy().as('setSpecies');
76
+ const setAssemblyId = cy.spy().as('setAssemblyId');
77
+
78
+ cy.mount(
79
+ <SpeciesPicker setSpecies={setSpecies} setAssemblyId={setAssemblyId} />
80
+ );
81
+ cy.intercept('GET', 'https://api.ncbi.nlm.nih.gov/datasets/v2alpha/taxonomy/taxon_suggest/**', {
82
+ statusCode: 500,
83
+ body: {}
84
+ }).as('getTaxonSuggest');
85
+
86
+ cy.get('input').type('Saccharomyces cerevisiae', { delay: 0});
87
+ cy.wait('@getTaxonSuggest');
88
+ cy.contains('Could not retrieve data').should('exist');
89
+ // cy.get('li').contains('Saccharomyces cerevisiae - 559292').click();
90
+ });
91
+ });
92
+
93
+ describe('<SequenceAccessionPicker />', () => {
94
+ it('handles NCBI being down displaying the right error', () => {
95
+ const setSequenceAccession = cy.spy().as('setSequenceAccession');
96
+ const assemblyAccession = 'GCA_000002945.3';
97
+
98
+ cy.intercept('GET', 'https://api.ncbi.nlm.nih.gov/datasets/v2alpha/genome/accession/GCA_000002945.3/sequence_reports*', {
99
+ statusCode: 500,
100
+ body: {}
101
+ }).as('getSequenceReports');
102
+
103
+ cy.mount(
104
+ <SequenceAccessionPicker assemblyAccession={assemblyAccession} sequenceAccession={''} setSequenceAccession={setSequenceAccession} />
105
+ );
106
+ cy.contains('Could not load chromosomes').should('exist');
107
+ });
108
+ it('displays the chromosomes', () => {
109
+ const setSequenceAccession = cy.spy().as('setSequenceAccession');
110
+ const assemblyAccession = 'GCA_000002945.3';
111
+
112
+ cy.intercept('GET', 'https://api.ncbi.nlm.nih.gov/datasets/v2alpha/genome/accession/GCA_000002945.3/sequence_reports*', {
113
+ statusCode: 200,
114
+ body: { reports: [{ chr_name: 'chr1', refseq_accession: 'NC_000001.10' }, { chr_name: 'chr2', refseq_accession: 'NC_000002.11' }] }
115
+ }).as('getSequenceReports');
116
+
117
+ cy.mount(
118
+ <SequenceAccessionPicker assemblyAccession={assemblyAccession} setSequenceAccession={setSequenceAccession} />
119
+ );
120
+ cy.wait('@getSequenceReports');
121
+ cy.get('label').siblings('div').first().click();
122
+ cy.contains('chr1 - NC_000001.10').should('exist');
123
+ cy.contains('chr2 - NC_000002.11').should('exist');
124
+ cy.get('div[role="presentation"]').contains('chr1 - NC_000001.10').click();
125
+ // Check that the spy was called with the expected value
126
+ cy.get('@setSequenceAccession').should('have.been.calledWith', 'NC_000001.10');
127
+
128
+ });
129
+ });
130
+
131
+