@opencloning/ui 1.7.2 → 1.8.1
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 +90 -0
- package/package.json +20 -14
- package/src/components/AppAlerts.jsx +7 -7
- package/src/components/CloningHistory.jsx +2 -0
- package/src/components/CloningSpeedDial.jsx +102 -0
- package/src/components/DownloadCloningStrategyDialog.jsx +2 -2
- package/src/components/LoadCloningHistoryWrapper.jsx +29 -22
- package/src/components/MainSequenceEditor.jsx +41 -34
- package/src/components/NetworkNode.jsx +35 -33
- package/src/components/OpenCloning.jsx +4 -3
- package/src/components/SequenceViewer.cy.jsx +27 -0
- package/src/components/SequenceViewer.jsx +211 -0
- package/src/components/annotation/AnnotationChangedAlert.jsx +26 -0
- package/src/components/annotation/useUpdateAnnotationInMainSequence.js +2 -2
- package/src/components/assembler/Assembler.jsx +3 -3
- package/src/components/domesticate/DomesticateDialog.jsx +274 -0
- package/src/components/form/GetRequestMultiSelect.jsx +0 -1
- package/src/components/form/PostRequestSelect.jsx +0 -1
- package/src/components/form/QuerySelect.jsx +128 -0
- package/src/components/form/QueryStatusWrapper.jsx +31 -0
- package/src/components/form/SubmitToDatabaseDialog.jsx +63 -58
- package/src/components/form/TextFieldQueryValidated.jsx +93 -0
- package/src/components/index.js +4 -0
- package/src/components/navigation/FeedbackDialog.jsx +1 -1
- package/src/components/navigation/MainAppBar.jsx +5 -5
- package/src/components/primers/import_primers/ImportPrimersButton.jsx +2 -2
- package/src/components/primers/import_primers/PrimerDatabaseImportForm.jsx +6 -3
- package/src/components/sources/FinishedSource.jsx +3 -0
- package/src/components/sources/MultipleOutputsSelector.cy.jsx +95 -0
- package/src/components/sources/MultipleOutputsSelector.jsx +32 -19
- package/src/components/sources/RecombinaseList.cy.jsx +1 -1
- package/src/components/sources/RecombinaseList.jsx +1 -1
- package/src/components/sources/SourceAssembly.jsx +36 -2
- package/src/components/sources/SourceFile.jsx +9 -1
- package/src/components/sources/SourceRepositoryId.jsx +0 -1
- package/src/components/sources/SourceTypeSelector.jsx +1 -1
- package/src/components/verification/ImportSequencingFilesInput.jsx +17 -0
- package/src/components/verification/LoadFromDatabaseButton.jsx +17 -10
- package/src/components/verification/VerificationFileDialog.jsx +16 -22
- package/src/components/verification/index.js +1 -0
- package/src/config/defaultMainEditorProps.js +1 -0
- package/src/hooks/useAlerts.js +3 -4
- package/src/hooks/useBackendAPI.js +5 -2
- package/src/hooks/useCloningAlerts.js +7 -0
- package/src/hooks/useDebouncedSearchQuery.js +42 -0
- package/src/hooks/useLoadDatabaseFile.js +6 -2
- package/src/hooks/useSequencingAlignment.js +26 -0
- package/src/hooks/useSnapgeneHistoryEndpoint.js +72 -0
- package/src/hooks/useStoreEditor.js +10 -68
- package/src/hooks/useUrlParamsLoader.js +2 -2
- package/src/hooks/useValidateState.js +3 -3
- package/src/index.css +3 -11
- package/src/version.js +1 -1
|
@@ -2,8 +2,7 @@ import { useStore } from 'react-redux';
|
|
|
2
2
|
import { updateEditor, addAlignment } from '@teselagen/ove';
|
|
3
3
|
import { getPCRPrimers } from '@opencloning/store/cloning_utils';
|
|
4
4
|
import { getTeselaJsonFromBase64 } from '@opencloning/utils/readNwrite';
|
|
5
|
-
import {
|
|
6
|
-
import { getReverseComplementSequenceAndAnnotations, getReverseComplementSequenceString, rotateSequenceDataToPosition } from '@teselagen/sequence-utils';
|
|
5
|
+
import { buildAlignmentTrack, buildReferenceTrack, buildAlignmentConfig, removePanelFromShown, updatePanelsShownWithAlignment } from '@opencloning/utils/alignmentUtils';
|
|
7
6
|
|
|
8
7
|
export default function useStoreEditor() {
|
|
9
8
|
const store = useStore();
|
|
@@ -27,74 +26,17 @@ export default function useStoreEditor() {
|
|
|
27
26
|
const pcrPrimers = getPCRPrimers(cloning, id);
|
|
28
27
|
const alignmentFiles = cloning.files.filter((e) => e.sequence_id === id && e.file_type === 'Sequencing file');
|
|
29
28
|
let { panelsShown } = store.getState().VectorEditor.mainEditor;
|
|
30
|
-
panelsShown =
|
|
29
|
+
panelsShown = removePanelFromShown(panelsShown, 'simpleAlignment');
|
|
31
30
|
|
|
32
31
|
if (alignmentFiles.length > 0) {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
translations: true,
|
|
42
|
-
},
|
|
43
|
-
alignmentTracks: [
|
|
44
|
-
{
|
|
45
|
-
sequenceData,
|
|
46
|
-
alignmentData: {
|
|
47
|
-
// the alignmentData just needs the sequence < TODO this has to be changed to be the largest ---
|
|
48
|
-
sequence: alignmentFiles[0].alignment[0],
|
|
49
|
-
name: sequenceData.name
|
|
50
|
-
},
|
|
51
|
-
},
|
|
52
|
-
...await Promise.all(alignmentFiles.map(async (aln) => {
|
|
53
|
-
const fileContent = await getTeselaJsonFromBase64(sessionStorage.getItem(`verification-${id}-${aln.file_name}`), aln.file_name);
|
|
54
|
-
let chromatogramData = fileContent.chromatogramData;
|
|
55
|
-
let alignmentSequenceData = {
|
|
56
|
-
name: aln.file_name,
|
|
57
|
-
sequence: aln.alignment[1].replaceAll('-', ''),
|
|
58
|
-
};
|
|
59
|
-
if (chromatogramData) {
|
|
60
|
-
chromatogramData = syncChromatogramDataWithAlignment(chromatogramData, aln.alignment[1]);
|
|
61
|
-
}
|
|
62
|
-
if (fileContent.features && fileContent.features.length > 0) {
|
|
63
|
-
alignmentSequenceData = fileContent;
|
|
64
|
-
const alignmentSequence = aln.alignment[1].replaceAll('-', '');
|
|
65
|
-
let rotation = findRotation(fileContent.sequence, alignmentSequence);
|
|
66
|
-
// If the rotation is -1, it may be reverse complemented
|
|
67
|
-
const reverseComplemented = rotation === -1;
|
|
68
|
-
if (reverseComplemented) {
|
|
69
|
-
rotation = findRotation(fileContent.sequence, getReverseComplementSequenceString(alignmentSequence));
|
|
70
|
-
alignmentSequenceData = getReverseComplementSequenceAndAnnotations(fileContent);
|
|
71
|
-
}
|
|
72
|
-
if (rotation !== -1 && rotation !== 0) {
|
|
73
|
-
rotation = reverseComplemented ? fileContent.sequence.length - rotation : rotation;
|
|
74
|
-
alignmentSequenceData = rotateSequenceDataToPosition(alignmentSequenceData, rotation);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
return {
|
|
78
|
-
sequenceData: {...alignmentSequenceData, name: aln.file_name},
|
|
79
|
-
alignmentData: {
|
|
80
|
-
sequence: aln.alignment[1],
|
|
81
|
-
name: aln.file_name
|
|
82
|
-
},
|
|
83
|
-
chromatogramData,
|
|
84
|
-
};
|
|
85
|
-
})),
|
|
86
|
-
],
|
|
87
|
-
});
|
|
88
|
-
panelsShown = [[
|
|
89
|
-
...panelsShown[0].filter((p) => p.id !== 'simpleAlignment'),
|
|
90
|
-
{
|
|
91
|
-
id: 'simpleAlignment',
|
|
92
|
-
type: 'alignment',
|
|
93
|
-
name: 'Alignments',
|
|
94
|
-
active: true,
|
|
95
|
-
isFullscreen: false,
|
|
96
|
-
},
|
|
97
|
-
]];
|
|
32
|
+
const referenceTrack = buildReferenceTrack(sequenceData, alignmentFiles[0].alignment[0]);
|
|
33
|
+
const otherTracks = await Promise.all(alignmentFiles.map(async (aln) => {
|
|
34
|
+
const fileContent = await getTeselaJsonFromBase64(sessionStorage.getItem(`verification-${id}-${aln.file_name}`), aln.file_name);
|
|
35
|
+
return buildAlignmentTrack(fileContent, aln);
|
|
36
|
+
}));
|
|
37
|
+
const alignmentConfig = buildAlignmentConfig(id, sequenceData, [referenceTrack, ...otherTracks]);
|
|
38
|
+
addAlignment(store, alignmentConfig);
|
|
39
|
+
panelsShown = updatePanelsShownWithAlignment(panelsShown);
|
|
98
40
|
}
|
|
99
41
|
sequenceData.primers = sequenceData.primers.concat([...pcrPrimers]);
|
|
100
42
|
updateEditor(store, editorName, { sequenceData, selectionLayer, panelsShown, sequenceDataHistory: {} });
|
|
@@ -3,7 +3,7 @@ import { useDispatch } from 'react-redux';
|
|
|
3
3
|
import { cloningActions } from '@opencloning/store/cloning';
|
|
4
4
|
import useDatabase from './useDatabase';
|
|
5
5
|
import useLoadDatabaseFile from './useLoadDatabaseFile';
|
|
6
|
-
import
|
|
6
|
+
import useCloningAlerts from './useCloningAlerts';
|
|
7
7
|
import useHttpClient from './useHttpClient';
|
|
8
8
|
import useValidateState from './useValidateState';
|
|
9
9
|
import { formatSequenceLocationString, getUrlParameters } from '@opencloning/utils/other';
|
|
@@ -18,7 +18,7 @@ const { setState: setCloningState, updateSource } = cloningActions;
|
|
|
18
18
|
export default function useUrlParamsLoader() {
|
|
19
19
|
const dispatch = useDispatch();
|
|
20
20
|
const database = useDatabase();
|
|
21
|
-
const { addAlert } =
|
|
21
|
+
const { addAlert } = useCloningAlerts();
|
|
22
22
|
const setHistoryFileError = (e) => addAlert({ message: e, severity: 'error' });
|
|
23
23
|
const { loadDatabaseFile } = useLoadDatabaseFile({ source: { id: 1 }, sendPostRequest: null, setHistoryFileError });
|
|
24
24
|
const validateState = useValidateState();
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import
|
|
2
|
+
import useCloningAlerts from './useCloningAlerts';
|
|
3
3
|
import useBackendRoute from './useBackendRoute';
|
|
4
4
|
import useHttpClient from './useHttpClient';
|
|
5
5
|
|
|
6
6
|
export default function useValidateState() {
|
|
7
7
|
const backendRoute = useBackendRoute();
|
|
8
|
-
const { addAlert } =
|
|
8
|
+
const { addAlert } = useCloningAlerts();
|
|
9
9
|
const httpClient = useHttpClient();
|
|
10
10
|
|
|
11
11
|
const validateState = React.useCallback(async (newState) => {
|
|
@@ -37,7 +37,7 @@ export default function useValidateState() {
|
|
|
37
37
|
}
|
|
38
38
|
return newState;
|
|
39
39
|
}
|
|
40
|
-
}, [addAlert, backendRoute]);
|
|
40
|
+
}, [addAlert, backendRoute, httpClient]);
|
|
41
41
|
|
|
42
42
|
return validateState;
|
|
43
43
|
}
|
package/src/index.css
CHANGED
|
@@ -7,15 +7,6 @@ button {
|
|
|
7
7
|
border-color: rgb(25, 118, 210);
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
ul.hidden-ancestors {
|
|
11
|
-
display: none;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
/* So that the eye icon is visible */
|
|
15
|
-
li.hidden-ancestors {
|
|
16
|
-
margin-bottom: 30px;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
10
|
.app-container {
|
|
20
11
|
display: flex;
|
|
21
12
|
flex-direction: column;
|
|
@@ -288,14 +279,15 @@ div.MuiPaper-root[role=alert] {
|
|
|
288
279
|
}
|
|
289
280
|
|
|
290
281
|
div#global-error-message-wrapper {
|
|
291
|
-
position:
|
|
282
|
+
position: relative;
|
|
292
283
|
top: 0;
|
|
293
284
|
z-index: 999;
|
|
294
285
|
max-width: 25em;
|
|
295
286
|
}
|
|
296
287
|
|
|
297
288
|
div#global-error-message-wrapper > div {
|
|
298
|
-
margin: 10px;
|
|
289
|
+
margin-left: 10px;
|
|
290
|
+
margin-bottom: 10px;
|
|
299
291
|
/* Allow line breaks in very long strings only when necessary */
|
|
300
292
|
word-break: break-word;
|
|
301
293
|
}
|
package/src/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Version placeholder - replaced at publish time via prepack script
|
|
2
|
-
export const version = "1.
|
|
2
|
+
export const version = "1.8.1";
|