@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.
- package/CHANGELOG.md +18 -0
- package/package.json +37 -0
- package/src/components/AppAlerts.jsx +19 -0
- package/src/components/CloningHistory.jsx +40 -0
- package/src/components/DataModelDisplayer.jsx +30 -0
- package/src/components/DescriptionEditor.jsx +68 -0
- package/src/components/DownloadCloningStrategyDialog.jsx +84 -0
- package/src/components/DownloadSequenceFileDialog.jsx +90 -0
- package/src/components/DragAndDropCloningHistoryWrapper.jsx +39 -0
- package/src/components/DraggableDialogPaper.jsx +16 -0
- package/src/components/EditSequenceNameDialog.jsx +90 -0
- package/src/components/ExternalServicesStatusCheck.jsx +92 -0
- package/src/components/HistoryLoadedDialog.jsx +49 -0
- package/src/components/LoadCloningHistoryWrapper.jsx +166 -0
- package/src/components/MainSequenceCheckBox.jsx +83 -0
- package/src/components/MainSequenceEditor.jsx +165 -0
- package/src/components/NetworkNode.jsx +159 -0
- package/src/components/NetworkTree.css +127 -0
- package/src/components/ObjectTable.jsx +24 -0
- package/src/components/OpenCloning.jsx +102 -0
- package/src/components/OverhangsDisplay.jsx +25 -0
- package/src/components/SequenceEditor.jsx +120 -0
- package/src/components/SequenceTab.jsx +14 -0
- package/src/components/TemplateSequence.jsx +38 -0
- package/src/components/annotation/PlannotateAnnotationReport.jsx +33 -0
- package/src/components/annotation/useUpdateAnnotationInMainSequence.js +39 -0
- package/src/components/assembler/AssemblePartWidget.jsx +252 -0
- package/src/components/assembler/Assembler.jsx +273 -0
- package/src/components/assembler/AssemblerPart.jsx +99 -0
- package/src/components/assembler/StopIcon.jsx +34 -0
- package/src/components/assembler/assembler_data2.json +50 -0
- package/src/components/assembler/assembly_component.module.css +81 -0
- package/src/components/assembler/moclo.json +110 -0
- package/src/components/assembler/sbol_visual_glyphs/LICENSE.html +21 -0
- package/src/components/assembler/sbol_visual_glyphs/assembly-scar.svg +63 -0
- package/src/components/assembler/sbol_visual_glyphs/cds-stop.svg +85 -0
- package/src/components/assembler/sbol_visual_glyphs/cds.svg +60 -0
- package/src/components/assembler/sbol_visual_glyphs/chromosomal-locus.svg +78 -0
- package/src/components/assembler/sbol_visual_glyphs/engineered-region.svg +56 -0
- package/src/components/assembler/sbol_visual_glyphs/five-prime-sticky-restriction-site.svg +56 -0
- package/src/components/assembler/sbol_visual_glyphs/origin-of-replication.svg +57 -0
- package/src/components/assembler/sbol_visual_glyphs/primer-binding-site.svg +59 -0
- package/src/components/assembler/sbol_visual_glyphs/promoter.svg +60 -0
- package/src/components/assembler/sbol_visual_glyphs/ribosome-entry-site.svg +56 -0
- package/src/components/assembler/sbol_visual_glyphs/specific-recombination-site.svg +59 -0
- package/src/components/assembler/sbol_visual_glyphs/terminator.svg +60 -0
- package/src/components/assembler/sbol_visual_glyphs/three-prime-sticky-restriction-site.svg +56 -0
- package/src/components/assembler/sbol_visual_glyphs.js +36 -0
- package/src/components/assembler/useAssembler.js +71 -0
- package/src/components/dummy/DummyInterface.js +41 -0
- package/src/components/dummy/GetSequenceFileAndDatabaseIdComponent.jsx +59 -0
- package/src/components/eLabFTW/ELabFTWCategorySelect.cy.jsx +86 -0
- package/src/components/eLabFTW/ELabFTWCategorySelect.jsx +43 -0
- package/src/components/eLabFTW/ELabFTWFileSelect.cy.jsx +43 -0
- package/src/components/eLabFTW/ELabFTWFileSelect.jsx +29 -0
- package/src/components/eLabFTW/ELabFTWResourceSelect.cy.jsx +107 -0
- package/src/components/eLabFTW/ELabFTWResourceSelect.jsx +23 -0
- package/src/components/eLabFTW/GetPrimerComponent.cy.jsx +261 -0
- package/src/components/eLabFTW/GetPrimerComponent.jsx +55 -0
- package/src/components/eLabFTW/GetSequenceFileAndDatabaseIdComponent.cy.jsx +184 -0
- package/src/components/eLabFTW/GetSequenceFileAndDatabaseIdComponent.jsx +62 -0
- package/src/components/eLabFTW/LoadHistoryComponent.cy.jsx +235 -0
- package/src/components/eLabFTW/LoadHistoryComponent.jsx +51 -0
- package/src/components/eLabFTW/PrimersNotInDatabaseComponent.cy.jsx +159 -0
- package/src/components/eLabFTW/PrimersNotInDatabaseComponent.jsx +54 -0
- package/src/components/eLabFTW/SubmitToDatabaseComponent.cy.jsx +185 -0
- package/src/components/eLabFTW/SubmitToDatabaseComponent.jsx +51 -0
- package/src/components/eLabFTW/common.js +26 -0
- package/src/components/eLabFTW/eLabFTWInterface.js +294 -0
- package/src/components/eLabFTW/eLabFTWInterface.test.js +839 -0
- package/src/components/eLabFTW/envValues.js +7 -0
- package/src/components/eLabFTW/utils.js +39 -0
- package/src/components/form/CustomFormHelperText.jsx +10 -0
- package/src/components/form/EnzymeMultiSelect.cy.jsx +61 -0
- package/src/components/form/EnzymeMultiSelect.jsx +34 -0
- package/src/components/form/GetRequestMultiSelect.jsx +107 -0
- package/src/components/form/LabelWithTooltip.jsx +16 -0
- package/src/components/form/PostRequestSelect.cy.jsx +70 -0
- package/src/components/form/PostRequestSelect.jsx +86 -0
- package/src/components/form/RequestStatusWrapper.jsx +17 -0
- package/src/components/form/RetryAlert.jsx +20 -0
- package/src/components/form/ServerErrorMessage.jsx +10 -0
- package/src/components/form/SubmitButtonBackendAPI.jsx +15 -0
- package/src/components/form/SubmitToDatabaseDialog.jsx +133 -0
- package/src/components/form/TextFieldValidate.jsx +67 -0
- package/src/components/form/ValidatedTextField.jsx +33 -0
- package/src/components/form/intermediates_disclaimer.svg +181 -0
- package/src/components/navigation/ButtonWithMenu.jsx +43 -0
- package/src/components/navigation/CustomTab.jsx +14 -0
- package/src/components/navigation/FeedbackDialog.jsx +34 -0
- package/src/components/navigation/GithubCornerRight.jsx +29 -0
- package/src/components/navigation/MainAppBar.css +26 -0
- package/src/components/navigation/MainAppBar.jsx +205 -0
- package/src/components/navigation/SelectExampleDialog.jsx +69 -0
- package/src/components/navigation/SelectTemplateDialog.jsx +107 -0
- package/src/components/navigation/TabPanel.jsx +28 -0
- package/src/components/navigation/VersionDialog.jsx +33 -0
- package/src/components/primers/CreatePrimerFromSequenceForm.jsx +42 -0
- package/src/components/primers/DownloadPrimersButton.jsx +104 -0
- package/src/components/primers/PrimerForm.css +14 -0
- package/src/components/primers/PrimerForm.jsx +107 -0
- package/src/components/primers/PrimerList.css +46 -0
- package/src/components/primers/PrimerList.cy.jsx +95 -0
- package/src/components/primers/PrimerList.jsx +126 -0
- package/src/components/primers/PrimerTableRow.cy.jsx +57 -0
- package/src/components/primers/PrimerTableRow.jsx +84 -0
- package/src/components/primers/SelectPrimerForm.jsx +66 -0
- package/src/components/primers/import_primers/ImportPrimersButton.jsx +101 -0
- package/src/components/primers/import_primers/ImportPrimersTable.jsx +51 -0
- package/src/components/primers/import_primers/PrimerDatabaseImportForm.jsx +107 -0
- package/src/components/primers/import_primers/styles.css +60 -0
- package/src/components/primers/primer_design/SequenceTabComponents/CollapsableLabel.jsx +31 -0
- package/src/components/primers/primer_design/SequenceTabComponents/GatewayRoiSelect.jsx +164 -0
- package/src/components/primers/primer_design/SequenceTabComponents/OrientationPicker.jsx +37 -0
- package/src/components/primers/primer_design/SequenceTabComponents/PrimerDesignContext.jsx +369 -0
- package/src/components/primers/primer_design/SequenceTabComponents/PrimerDesignEBIC.jsx +24 -0
- package/src/components/primers/primer_design/SequenceTabComponents/PrimerDesignForm.jsx +29 -0
- package/src/components/primers/primer_design/SequenceTabComponents/PrimerDesignGatewayBP.jsx +36 -0
- package/src/components/primers/primer_design/SequenceTabComponents/PrimerDesignGibsonAssembly.jsx +26 -0
- package/src/components/primers/primer_design/SequenceTabComponents/PrimerDesignHomologousRecombination.jsx +32 -0
- package/src/components/primers/primer_design/SequenceTabComponents/PrimerDesignRestriction.jsx +25 -0
- package/src/components/primers/primer_design/SequenceTabComponents/PrimerDesignSimplePair.jsx +25 -0
- package/src/components/primers/primer_design/SequenceTabComponents/PrimerDesignStepper.jsx +53 -0
- package/src/components/primers/primer_design/SequenceTabComponents/PrimerDesigner.jsx +80 -0
- package/src/components/primers/primer_design/SequenceTabComponents/PrimerResultForm.jsx +49 -0
- package/src/components/primers/primer_design/SequenceTabComponents/PrimerSettingsForm.jsx +68 -0
- package/src/components/primers/primer_design/SequenceTabComponents/PrimerSpacerForm.jsx +84 -0
- package/src/components/primers/primer_design/SequenceTabComponents/RestrictionSpacerForm.jsx +85 -0
- package/src/components/primers/primer_design/SequenceTabComponents/StepNavigation.jsx +48 -0
- package/src/components/primers/primer_design/SequenceTabComponents/TabPanelEBICSettings.jsx +216 -0
- package/src/components/primers/primer_design/SequenceTabComponents/TabPanelResults.jsx +42 -0
- package/src/components/primers/primer_design/SequenceTabComponents/TabPanelSelectRoi.jsx +61 -0
- package/src/components/primers/primer_design/SequenceTabComponents/TabPannelSettings.jsx +59 -0
- package/src/components/primers/primer_design/SequenceTabComponents/primerDesignMinimalValues.json +5 -0
- package/src/components/primers/primer_design/SequenceTabComponents/useEBICPrimerDesignSettings.js +31 -0
- package/src/components/primers/primer_design/SequenceTabComponents/useEnzymePrimerDesignSettings.js +57 -0
- package/src/components/primers/primer_design/SequenceTabComponents/useGatewayPrimerDesignSettings.js +18 -0
- package/src/components/primers/primer_design/SequenceTabComponents/usePrimerDesignSettings.js +31 -0
- package/src/components/primers/primer_design/SourceComponents/PrimerDesignGatewayBP.jsx +88 -0
- package/src/components/primers/primer_design/SourceComponents/PrimerDesignGibsonAssembly.jsx +65 -0
- package/src/components/primers/primer_design/SourceComponents/PrimerDesignHomologousRecombination.jsx +84 -0
- package/src/components/primers/primer_design/SourceComponents/PrimerDesignSourceForm.jsx +74 -0
- package/src/components/primers/primer_design/common/NoAttPSitesError.jsx +31 -0
- package/src/components/primers/primer_details/PCRTable.cy.jsx +51 -0
- package/src/components/primers/primer_details/PCRTable.jsx +35 -0
- package/src/components/primers/primer_details/Primer3Figure.jsx +25 -0
- package/src/components/primers/primer_details/PrimerDetailsTds.jsx +39 -0
- package/src/components/primers/primer_details/PrimerInfoIcon.cy.jsx +137 -0
- package/src/components/primers/primer_details/PrimerInfoIcon.jsx +132 -0
- package/src/components/primers/primer_details/TableSection.jsx +17 -0
- package/src/components/primers/primer_details/primerDetailsFormatting.js +3 -0
- package/src/components/primers/primer_details/useMultiplePrimerDetails.js +29 -0
- package/src/components/primers/primer_details/usePCRDetails.js +47 -0
- package/src/components/primers/primer_details/usePrimerDetailsEndpoints.js +49 -0
- package/src/components/primers/primer_details/useSinglePrimerSequenceDetails.js +25 -0
- package/src/components/primers/primersToTabularFile.js +49 -0
- package/src/components/primers/primersToTabularFile.test.js +108 -0
- package/src/components/settings/SettingsTab.cy.jsx +267 -0
- package/src/components/settings/SettingsTab.jsx +170 -0
- package/src/components/sources/AssemblyPlanDisplayer.cy.jsx +22 -0
- package/src/components/sources/AssemblyPlanDisplayer.jsx +27 -0
- package/src/components/sources/CollectionSource.jsx +97 -0
- package/src/components/sources/FinishedSource.jsx +397 -0
- package/src/components/sources/KnownSourceErrors.jsx +50 -0
- package/src/components/sources/MultipleInputsSelector.jsx +63 -0
- package/src/components/sources/MultipleOutputsSelector.jsx +63 -0
- package/src/components/sources/NewSourceBox.jsx +37 -0
- package/src/components/sources/PCRUnitForm.jsx +102 -0
- package/src/components/sources/SingleInputSelector.jsx +36 -0
- package/src/components/sources/Source.jsx +125 -0
- package/src/components/sources/SourceAnnotation.jsx +44 -0
- package/src/components/sources/SourceAssembly.jsx +201 -0
- package/src/components/sources/SourceBox.css +18 -0
- package/src/components/sources/SourceBox.jsx +60 -0
- package/src/components/sources/SourceCopySequence.jsx +38 -0
- package/src/components/sources/SourceDatabase.jsx +28 -0
- package/src/components/sources/SourceFile.jsx +188 -0
- package/src/components/sources/SourceGenomeRegion.cy.jsx +131 -0
- package/src/components/sources/SourceGenomeRegion.jsx +486 -0
- package/src/components/sources/SourceHomologousRecombination.jsx +125 -0
- package/src/components/sources/SourceKnownGenomeRegion.jsx +60 -0
- package/src/components/sources/SourceManuallyTyped.jsx +116 -0
- package/src/components/sources/SourcePCRorHybridization.jsx +165 -0
- package/src/components/sources/SourcePolymeraseExtension.jsx +44 -0
- package/src/components/sources/SourceRepositoryId.jsx +409 -0
- package/src/components/sources/SourceRestriction.jsx +41 -0
- package/src/components/sources/SourceReverseComplement.jsx +33 -0
- package/src/components/sources/SourceTypeSelector.jsx +94 -0
- package/src/components/sources/SubSequenceDisplayer.jsx +70 -0
- package/src/components/sources/VerifyDeleteDialog.jsx +23 -0
- package/src/components/sources/repositoryMetadata.js +14 -0
- package/src/components/verification/LoadFromDatabaseButton.jsx +90 -0
- package/src/components/verification/SequencingFileRow.jsx +34 -0
- package/src/components/verification/VerificationFileDialog.cy.jsx +176 -0
- package/src/components/verification/VerificationFileDialog.jsx +248 -0
- package/src/config/defaultMainEditorProps.js +44 -0
- package/src/hooks/useAlerts.js +16 -0
- package/src/hooks/useBackendAPI.js +51 -0
- package/src/hooks/useBackendRoute.js +22 -0
- package/src/hooks/useDatabase.js +18 -0
- package/src/hooks/useDragAndDropFile.js +31 -0
- package/src/hooks/useGatewaySites.js +40 -0
- package/src/hooks/useHttpClient.js +12 -0
- package/src/hooks/useLoadDatabaseFile.js +108 -0
- package/src/hooks/useStoreEditor.js +101 -0
- package/src/hooks/useValidateState.js +43 -0
- package/vitest.config.js +18 -0
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Checkbox, FormControl, FormControlLabel, TextField } from '@mui/material';
|
|
3
|
+
import SubmitButtonBackendAPI from '../form/SubmitButtonBackendAPI';
|
|
4
|
+
import ValidatedTextField from '../form/ValidatedTextField';
|
|
5
|
+
import { stringIsNotDNA } from '@opencloning/store/cloning_utils';
|
|
6
|
+
|
|
7
|
+
function SourceManuallyTyped({ source, requestStatus, sendPostRequest }) {
|
|
8
|
+
const { id: sourceId } = source;
|
|
9
|
+
|
|
10
|
+
const [userInput, setUserInput] = React.useState('');
|
|
11
|
+
const [isCircular, setIsCircular] = React.useState(false);
|
|
12
|
+
const [overhangCrick3prime, setOverhangCrick3prime] = React.useState(0);
|
|
13
|
+
const [overhangWatson3prime, setOverhangWatson3prime] = React.useState(0);
|
|
14
|
+
const [errorStatus, setErrorStatus] = React.useState({ sequence: true });
|
|
15
|
+
const [touched, setTouched] = React.useState(false);
|
|
16
|
+
const [submissionAttempted, setSubmissionAttempted] = React.useState(false);
|
|
17
|
+
|
|
18
|
+
const submissionAllowed = touched && Object.values(errorStatus).every((error) => !error);
|
|
19
|
+
const updateValidationStatus = (fieldName, valid) => {
|
|
20
|
+
setTouched(true);
|
|
21
|
+
// Update the validation status for the given field (taken from the ref.id)
|
|
22
|
+
setErrorStatus((prevErrorStatus) => ({
|
|
23
|
+
...prevErrorStatus,
|
|
24
|
+
[fieldName]: valid,
|
|
25
|
+
}));
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const onInputChange = (event) => {
|
|
29
|
+
// Remove all non-letter characters on paste
|
|
30
|
+
if (event.nativeEvent.inputType === 'insertFromPaste') {
|
|
31
|
+
setUserInput(event.target.value.replace(/[^a-zA-Z]/g, ''));
|
|
32
|
+
} else {
|
|
33
|
+
setUserInput(event.target.value);
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const onSubmit = (event) => {
|
|
38
|
+
event.preventDefault();
|
|
39
|
+
setSubmissionAttempted(true);
|
|
40
|
+
if (submissionAllowed) {
|
|
41
|
+
const requestData = {
|
|
42
|
+
source: { id: sourceId },
|
|
43
|
+
sequence: {
|
|
44
|
+
id: sourceId,
|
|
45
|
+
sequence: userInput,
|
|
46
|
+
circular: isCircular,
|
|
47
|
+
overhang_crick_3prime: overhangCrick3prime,
|
|
48
|
+
overhang_watson_3prime: overhangWatson3prime,
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
sendPostRequest({ endpoint: 'manually_typed', requestData, source });
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const onCircularChange = () => {
|
|
56
|
+
// See constrains of ManuallyTyped in the backend
|
|
57
|
+
const newIsCircular = !isCircular;
|
|
58
|
+
setIsCircular(newIsCircular);
|
|
59
|
+
if (newIsCircular) {
|
|
60
|
+
setOverhangCrick3prime(0);
|
|
61
|
+
setOverhangWatson3prime(0);
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const sequenceErrorChecker = (s) => (stringIsNotDNA(s) ? { error: true, helperText: 'invalid DNA sequence' } : { error: false, helperText: '' });
|
|
66
|
+
|
|
67
|
+
return (
|
|
68
|
+
<form onSubmit={onSubmit}>
|
|
69
|
+
<ValidatedTextField
|
|
70
|
+
fullWidth
|
|
71
|
+
id="sequence"
|
|
72
|
+
label="Sequence"
|
|
73
|
+
variant="outlined"
|
|
74
|
+
value={userInput}
|
|
75
|
+
onInputChange={onInputChange}
|
|
76
|
+
className="sequence"
|
|
77
|
+
submissionAttempted={submissionAttempted}
|
|
78
|
+
required
|
|
79
|
+
errorChecker={sequenceErrorChecker}
|
|
80
|
+
updateValidationStatus={updateValidationStatus}
|
|
81
|
+
/>
|
|
82
|
+
{
|
|
83
|
+
!isCircular && (
|
|
84
|
+
<>
|
|
85
|
+
<FormControl fullWidth>
|
|
86
|
+
<TextField
|
|
87
|
+
label="Overhang crick 3'"
|
|
88
|
+
value={overhangCrick3prime}
|
|
89
|
+
type="number"
|
|
90
|
+
onChange={(event) => setOverhangCrick3prime(event.target.value)}
|
|
91
|
+
/>
|
|
92
|
+
</FormControl>
|
|
93
|
+
<FormControl fullWidth>
|
|
94
|
+
<TextField
|
|
95
|
+
label="Overhang watson 3'"
|
|
96
|
+
value={overhangWatson3prime}
|
|
97
|
+
type="number"
|
|
98
|
+
onChange={(event) => setOverhangWatson3prime(event.target.value)}
|
|
99
|
+
/>
|
|
100
|
+
</FormControl>
|
|
101
|
+
</>
|
|
102
|
+
)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
<FormControl fullWidth style={{ textAlign: 'left' }}>
|
|
106
|
+
<FormControlLabel control={<Checkbox value={isCircular} onChange={onCircularChange} />} label="Circular DNA" />
|
|
107
|
+
</FormControl>
|
|
108
|
+
<SubmitButtonBackendAPI
|
|
109
|
+
requestStatus={requestStatus}
|
|
110
|
+
{...(import.meta.env.VITE_UMAMI_WEBSITE_ID && { "data-umami-event": "submit-manually-typed" })}
|
|
111
|
+
>Submit</SubmitButtonBackendAPI>
|
|
112
|
+
</form>
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export default SourceManuallyTyped;
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { shallowEqual, useDispatch, useSelector } from 'react-redux';
|
|
3
|
+
import { Button, Checkbox, FormControl, FormControlLabel, InputAdornment, TextField } from '@mui/material';
|
|
4
|
+
|
|
5
|
+
import { doesSourceHaveOutput, getInputSequencesFromSourceId, getPcrTemplateSequenceId } from '@opencloning/store/cloning_utils';
|
|
6
|
+
import SubmitButtonBackendAPI from '../form/SubmitButtonBackendAPI';
|
|
7
|
+
import PCRUnitForm from './PCRUnitForm';
|
|
8
|
+
import PrimerDesignSourceForm from '../primers/primer_design/SourceComponents/PrimerDesignSourceForm';
|
|
9
|
+
import { cloningActions } from '@opencloning/store/cloning';
|
|
10
|
+
import useStoreEditor from '../../hooks/useStoreEditor';
|
|
11
|
+
import LabelWithTooltip from '../form/LabelWithTooltip';
|
|
12
|
+
|
|
13
|
+
function SourcePCRorHybridization({ source, requestStatus, sendPostRequest }) {
|
|
14
|
+
// Represents a PCR if inputs != [], else is a oligo hybridization
|
|
15
|
+
|
|
16
|
+
const dispatch = useDispatch();
|
|
17
|
+
const { updateStoreEditor } = useStoreEditor();
|
|
18
|
+
const { setCurrentTab, setMainSequenceId } = cloningActions;
|
|
19
|
+
const { id: sourceId } = source;
|
|
20
|
+
|
|
21
|
+
const inputSequences = useSelector((state) => getInputSequencesFromSourceId(state, sourceId), shallowEqual);
|
|
22
|
+
const primers = useSelector((state) => state.cloning.primers);
|
|
23
|
+
const isPcr = inputSequences.length !== 0;
|
|
24
|
+
const hasOutput = useSelector((state) => doesSourceHaveOutput(state.cloning, sourceId));
|
|
25
|
+
const outputIsPrimerDesign = useSelector((state) => isPcr && hasOutput && state.cloning.sequences.find((e) => e.id === source.id).primer_design !== undefined);
|
|
26
|
+
|
|
27
|
+
const [forwardPrimerId, setForwardPrimerId] = React.useState('');
|
|
28
|
+
const [reversePrimerId, setReversePrimerId] = React.useState('');
|
|
29
|
+
const [designingPrimers, setDesigningPrimers] = React.useState(false);
|
|
30
|
+
const [addPrimerFeatures, setAddPrimerFeatures] = React.useState(false);
|
|
31
|
+
|
|
32
|
+
const minimalAnnealingRef = React.useRef(null);
|
|
33
|
+
const allowedMismatchesRef = React.useRef(null);
|
|
34
|
+
|
|
35
|
+
React.useEffect(() => {
|
|
36
|
+
if (isPcr && source.input.length === 3) {
|
|
37
|
+
setForwardPrimerId(source.input[0].sequence);
|
|
38
|
+
setReversePrimerId(source.input[2].sequence);
|
|
39
|
+
} else if (!isPcr && source.input.length === 2) {
|
|
40
|
+
setForwardPrimerId(source.input[0].sequence);
|
|
41
|
+
setReversePrimerId(source.input[1].sequence);
|
|
42
|
+
}
|
|
43
|
+
}, [source.input]);
|
|
44
|
+
|
|
45
|
+
React.useEffect(() => {
|
|
46
|
+
if (source.add_primer_annotations) { setAddPrimerFeatures(source.add_primer_annotations); }
|
|
47
|
+
}, [source.add_primer_annotations]);
|
|
48
|
+
|
|
49
|
+
const onSubmit = (event) => {
|
|
50
|
+
event.preventDefault();
|
|
51
|
+
|
|
52
|
+
const requestData = {
|
|
53
|
+
sequences: inputSequences,
|
|
54
|
+
primers: [forwardPrimerId, reversePrimerId].map((id) => primers.find((p) => p.id === id)),
|
|
55
|
+
source: { id: sourceId, input: inputSequences.map((e) => ({ sequence: e.id })), output_name: source.output_name },
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
if (!isPcr) {
|
|
59
|
+
requestData.source.input = [forwardPrimerId, reversePrimerId].map((id) => ({ sequence: id }));
|
|
60
|
+
const config = { params: { minimal_annealing: minimalAnnealingRef.current.value } };
|
|
61
|
+
sendPostRequest({ endpoint: 'oligonucleotide_hybridization', requestData, config, source });
|
|
62
|
+
} else {
|
|
63
|
+
const config = { params: {
|
|
64
|
+
minimal_annealing: minimalAnnealingRef.current.value,
|
|
65
|
+
allowed_mismatches: allowedMismatchesRef.current.value,
|
|
66
|
+
} };
|
|
67
|
+
requestData.source.add_primer_features = addPrimerFeatures;
|
|
68
|
+
sendPostRequest({ endpoint: 'pcr', requestData, config, source });
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const onPrimerDesign = () => {
|
|
73
|
+
setDesigningPrimers(true);
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
if (outputIsPrimerDesign && !forwardPrimerId && !reversePrimerId) {
|
|
77
|
+
const goToPrimerDesign = () => {
|
|
78
|
+
dispatch(setCurrentTab(3));
|
|
79
|
+
const templateSequenceId = getPcrTemplateSequenceId(source);
|
|
80
|
+
dispatch(setMainSequenceId(templateSequenceId));
|
|
81
|
+
updateStoreEditor('mainEditor', templateSequenceId);
|
|
82
|
+
// Scroll to the top of the tab panels container
|
|
83
|
+
document.querySelector('.tab-panels-container')?.scrollTo({
|
|
84
|
+
top: 0,
|
|
85
|
+
behavior: 'instant',
|
|
86
|
+
});
|
|
87
|
+
};
|
|
88
|
+
return (
|
|
89
|
+
<Button variant="contained" color="success" sx={{ mt: 1 }} onClick={goToPrimerDesign}>
|
|
90
|
+
<span style={{ fontSize: '1.2em', marginRight: 12 }}>✨</span>
|
|
91
|
+
{' '}
|
|
92
|
+
Design primers
|
|
93
|
+
{' '}
|
|
94
|
+
<span style={{ fontSize: '1.2em', marginLeft: 12 }}>✨</span>
|
|
95
|
+
</Button>
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (designingPrimers && !hasOutput) {
|
|
100
|
+
return <PrimerDesignSourceForm source={source} />;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return (
|
|
104
|
+
<div className="pcr_or_hybridization">
|
|
105
|
+
<form onSubmit={onSubmit}>
|
|
106
|
+
{isPcr && !hasOutput && !forwardPrimerId && !reversePrimerId && (
|
|
107
|
+
<Button variant="contained" color="success" sx={{ my: 2 }} onClick={onPrimerDesign}>Design primers</Button>
|
|
108
|
+
)}
|
|
109
|
+
<PCRUnitForm
|
|
110
|
+
sourceId={sourceId}
|
|
111
|
+
primers={primers}
|
|
112
|
+
forwardPrimerId={forwardPrimerId}
|
|
113
|
+
reversePrimerId={reversePrimerId}
|
|
114
|
+
onChangeForward={setForwardPrimerId}
|
|
115
|
+
onChangeReverse={setReversePrimerId}
|
|
116
|
+
/>
|
|
117
|
+
<FormControl fullWidth>
|
|
118
|
+
<TextField
|
|
119
|
+
label="Minimal annealing length"
|
|
120
|
+
inputRef={minimalAnnealingRef}
|
|
121
|
+
type="number"
|
|
122
|
+
defaultValue={12}
|
|
123
|
+
InputProps={{
|
|
124
|
+
endAdornment: <InputAdornment position="end">bp</InputAdornment>,
|
|
125
|
+
sx: { '& input': { textAlign: 'center' } },
|
|
126
|
+
}}
|
|
127
|
+
/>
|
|
128
|
+
</FormControl>
|
|
129
|
+
{isPcr && (
|
|
130
|
+
<>
|
|
131
|
+
<FormControl fullWidth>
|
|
132
|
+
<TextField
|
|
133
|
+
label="Mismatches allowed"
|
|
134
|
+
inputRef={allowedMismatchesRef}
|
|
135
|
+
type="number"
|
|
136
|
+
defaultValue={0}
|
|
137
|
+
InputProps={{
|
|
138
|
+
sx: { '& input': { textAlign: 'center' } },
|
|
139
|
+
}}
|
|
140
|
+
/>
|
|
141
|
+
</FormControl>
|
|
142
|
+
<FormControl fullWidth>
|
|
143
|
+
<FormControlLabel
|
|
144
|
+
control={<Checkbox checked={addPrimerFeatures} onChange={() => setAddPrimerFeatures(!addPrimerFeatures)} />}
|
|
145
|
+
label={(
|
|
146
|
+
<LabelWithTooltip label="Add primer features" tooltip="Add features representing the primers to the PCR product" />
|
|
147
|
+
)}
|
|
148
|
+
/>
|
|
149
|
+
</FormControl>
|
|
150
|
+
</>
|
|
151
|
+
)}
|
|
152
|
+
{forwardPrimerId && reversePrimerId && (
|
|
153
|
+
<SubmitButtonBackendAPI
|
|
154
|
+
requestStatus={requestStatus}
|
|
155
|
+
{...(import.meta.env.VITE_UMAMI_WEBSITE_ID && { "data-umami-event": !isPcr ? "submit-hybridization" : "submit-pcr" })}
|
|
156
|
+
>
|
|
157
|
+
{!isPcr ? 'Perform hybridization' : 'Perform PCR'}
|
|
158
|
+
</SubmitButtonBackendAPI>
|
|
159
|
+
)}
|
|
160
|
+
</form>
|
|
161
|
+
</div>
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export default SourcePCRorHybridization;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { shallowEqual, useSelector } from 'react-redux';
|
|
3
|
+
import { Alert } from '@mui/material';
|
|
4
|
+
import { getInputSequencesFromSourceId } from '@opencloning/store/cloning_utils';
|
|
5
|
+
import SubmitButtonBackendAPI from '../form/SubmitButtonBackendAPI';
|
|
6
|
+
|
|
7
|
+
function SourcePolymeraseExtension({ source, requestStatus, sendPostRequest }) {
|
|
8
|
+
const { id: sourceId } = source;
|
|
9
|
+
const inputSequences = useSelector((state) => getInputSequencesFromSourceId(state, sourceId), shallowEqual);
|
|
10
|
+
const { overhang_crick_3prime, overhang_watson_3prime } = inputSequences[0];
|
|
11
|
+
const invalidInput = (overhang_crick_3prime >= 0) && (overhang_watson_3prime >= 0);
|
|
12
|
+
const onSubmit = (event) => {
|
|
13
|
+
event.preventDefault();
|
|
14
|
+
|
|
15
|
+
const requestData = {
|
|
16
|
+
sequences: inputSequences,
|
|
17
|
+
source: { id: sourceId, input: inputSequences.map((e) => ({ sequence: e.id })) },
|
|
18
|
+
};
|
|
19
|
+
sendPostRequest({ endpoint: 'polymerase_extension', requestData, source });
|
|
20
|
+
};
|
|
21
|
+
// No need for MultipleOutputsSelector, since there is only one output
|
|
22
|
+
return (
|
|
23
|
+
<div className="PolymeraseExtensionSource">
|
|
24
|
+
<form onSubmit={onSubmit}>
|
|
25
|
+
{invalidInput ? (
|
|
26
|
+
<Alert severity="error">
|
|
27
|
+
<strong>Invalid input:</strong>
|
|
28
|
+
{' '}
|
|
29
|
+
no 5' overhangs.
|
|
30
|
+
</Alert>
|
|
31
|
+
) : (
|
|
32
|
+
<SubmitButtonBackendAPI
|
|
33
|
+
requestStatus={requestStatus}
|
|
34
|
+
{...(import.meta.env.VITE_UMAMI_WEBSITE_ID && { "data-umami-event": "submit-polymerase-extension" })}
|
|
35
|
+
>
|
|
36
|
+
Extend with polymerase
|
|
37
|
+
</SubmitButtonBackendAPI>
|
|
38
|
+
)}
|
|
39
|
+
</form>
|
|
40
|
+
</div>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export default SourcePolymeraseExtension;
|