@teselagen/ove 0.6.1-beta.1 → 0.7.2
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/DigestTool/DigestTool.d.ts +2 -10
- package/Menlo.ttf +0 -0
- package/Monaco.ttf +0 -0
- package/helperComponents/PropertiesDialog/index.d.ts +2 -7
- package/helperComponents/PropertiesDialog/utils.d.ts +5 -5
- package/html2canvas.esm--JN4fLQL.mjs +7891 -0
- package/html2canvas.esm-B7d7VJmQ.js +7891 -0
- package/html2canvas.esm-GLpiTZLt.cjs +7891 -0
- package/html2canvas.esm-GLpiTZLt.js +7891 -0
- package/html2canvas.esm-nFNn58sx.js +7891 -0
- package/html2canvas.esm-nFNn58sx.mjs +7891 -0
- package/index.cjs.js +78073 -73781
- package/index.es.js +78467 -74175
- package/index.umd.js +81406 -77036
- package/package.json +7 -8
- package/src/AutoAnnotate.js +1 -0
- package/src/CircularView/Labels/index.js +1 -15
- package/src/CircularView/index.js +3 -4
- package/src/CreateAnnotationsPage.js +1 -1
- package/src/CutsiteFilter/index.js +51 -55
- package/src/DigestTool/DigestTool.js +193 -188
- package/src/GlobalDialogUtils.js +1 -0
- package/src/PCRTool/PCRTool.js +8 -2
- package/src/Reflex/reflex-styles.css +10 -10
- package/src/RowItem/CutsiteSelectionLayers.js +1 -1
- package/src/RowItem/SelectionLayer/index.js +2 -2
- package/src/RowItem/Sequence.js +0 -1
- package/src/RowItem/Translations/Translation.js +1 -0
- package/src/RowItem/index.js +0 -1
- package/src/helperComponents/AddOrEditAnnotationDialog/index.js +8 -4
- package/src/helperComponents/AddOrEditFeatureDialog/index.js +9 -7
- package/src/helperComponents/AddOrEditPartDialog/index.js +3 -3
- package/src/helperComponents/AddOrEditPrimerDialog/index.js +3 -7
- package/src/helperComponents/PropertiesDialog/CutsiteProperties.js +126 -135
- package/src/helperComponents/PropertiesDialog/GenericAnnotationProperties.js +52 -50
- package/src/helperComponents/PropertiesDialog/OrfProperties.js +1 -1
- package/src/helperComponents/PropertiesDialog/SingleEnzymeCutsiteInfo.js +59 -51
- package/src/helperComponents/PropertiesDialog/index.js +115 -114
- package/src/helperComponents/PropertiesDialog/utils.js +5 -5
- package/src/helperComponents/RemoveDuplicates/index.js +149 -165
- package/src/utils/useFormValue.js +7 -0
- package/src/withEditorInteractions/index.js +8 -7
- package/style.css +287 -263
- package/utils/useFormValue.d.ts +1 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@teselagen/ove",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.2",
|
|
4
4
|
"main": "./src/index.js",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"dependencies": {
|
|
13
13
|
"@teselagen/sequence-utils": "0.3.27",
|
|
14
14
|
"@teselagen/range-utils": "0.3.7",
|
|
15
|
-
"@teselagen/ui": "0.6
|
|
15
|
+
"@teselagen/ui": "0.7.6",
|
|
16
16
|
"@teselagen/file-utils": "0.3.16",
|
|
17
17
|
"@teselagen/bounce-loader": "0.3.11",
|
|
18
18
|
"@teselagen/bio-parsers": "0.4.22",
|
|
@@ -58,7 +58,6 @@
|
|
|
58
58
|
"lodash-es": "^4.17.21",
|
|
59
59
|
"math-expression-evaluator": "^1.3.7",
|
|
60
60
|
"mobx": "^6.10.2",
|
|
61
|
-
"mobx-react": "^9.0.1",
|
|
62
61
|
"mock-fs": "5.2.0",
|
|
63
62
|
"nanoid": "^4.0.0",
|
|
64
63
|
"node-interval-tree": "^1.3.3",
|
|
@@ -68,16 +67,16 @@
|
|
|
68
67
|
"popper.js": "^1.16.1",
|
|
69
68
|
"prop-types": "^15.6.2",
|
|
70
69
|
"qs": "^6.9.6",
|
|
71
|
-
"react": "^18.
|
|
70
|
+
"react": "^18.3.1",
|
|
72
71
|
"react-color": "^2.19.3",
|
|
73
|
-
"react-dom": "^18.
|
|
72
|
+
"react-dom": "^18.3.1",
|
|
74
73
|
"react-draggable": "4.4.5",
|
|
75
74
|
"react-dropzone": "^11.4.2",
|
|
76
|
-
"react-markdown": "
|
|
75
|
+
"react-markdown": "8.0.7",
|
|
77
76
|
"react-measure": "^2.5.2",
|
|
78
77
|
"react-redux": "^8.0.5",
|
|
79
78
|
"react-rnd": "^10.2.4",
|
|
80
|
-
"react-router-dom": "
|
|
79
|
+
"react-router-dom": "4",
|
|
81
80
|
"react-sizeme": "^2.6.12",
|
|
82
81
|
"react-transition-group": "^2.4.0",
|
|
83
82
|
"recompose": "npm:react-recompose@0.31.1",
|
|
@@ -85,7 +84,7 @@
|
|
|
85
84
|
"redux-act": "^1.8.0",
|
|
86
85
|
"redux-form": "^8.3.10",
|
|
87
86
|
"redux-thunk": "2.4.1",
|
|
88
|
-
"remark-gfm": "^
|
|
87
|
+
"remark-gfm": "^3.0.1",
|
|
89
88
|
"reselect": "^4.1.7",
|
|
90
89
|
"shortid": "^2.2.16",
|
|
91
90
|
"tg-use-local-storage-state": "^16.0.3",
|
package/src/AutoAnnotate.js
CHANGED
|
@@ -416,23 +416,9 @@ function LabelLine(pointArray, options) {
|
|
|
416
416
|
});
|
|
417
417
|
return (
|
|
418
418
|
<React.Fragment key="labelLine">
|
|
419
|
-
{/* <polyline
|
|
420
|
-
{...{
|
|
421
|
-
key: "polyline-short",
|
|
422
|
-
points,
|
|
423
|
-
stroke: "black",
|
|
424
|
-
fill: "none",
|
|
425
|
-
strokeWidth: 1,
|
|
426
|
-
// style: {
|
|
427
|
-
// opacity: 0.2
|
|
428
|
-
// },
|
|
429
|
-
className: "veLabelLine",
|
|
430
|
-
...options
|
|
431
|
-
}}
|
|
432
|
-
/> */}
|
|
433
419
|
<polyline
|
|
420
|
+
key="polyline-long"
|
|
434
421
|
{...{
|
|
435
|
-
key: "polyline-long",
|
|
436
422
|
points,
|
|
437
423
|
stroke: "black",
|
|
438
424
|
fill: "none",
|
|
@@ -597,12 +597,11 @@ export function CircularView(props) {
|
|
|
597
597
|
) {
|
|
598
598
|
return (
|
|
599
599
|
<SelectionLayer
|
|
600
|
-
key={index}
|
|
600
|
+
key={"veCircularViewSelectionLayer" + index}
|
|
601
601
|
{...{
|
|
602
602
|
index,
|
|
603
603
|
isDraggable: true,
|
|
604
604
|
isProtein,
|
|
605
|
-
key: "veCircularViewSelectionLayer" + index,
|
|
606
605
|
selectionLayer,
|
|
607
606
|
onRightClicked: selectionLayer.isSearchLayer
|
|
608
607
|
? searchLayerRightClicked
|
|
@@ -635,13 +634,13 @@ export function CircularView(props) {
|
|
|
635
634
|
//only render if there is no selection layer
|
|
636
635
|
return (
|
|
637
636
|
<Caret
|
|
637
|
+
key="veCircularViewCaret"
|
|
638
638
|
{...{
|
|
639
639
|
caretPosition,
|
|
640
640
|
sequenceLength,
|
|
641
641
|
isProtein,
|
|
642
642
|
innerRadius,
|
|
643
|
-
outerRadius: radius
|
|
644
|
-
key: "veCircularViewCaret"
|
|
643
|
+
outerRadius: radius
|
|
645
644
|
}}
|
|
646
645
|
/>
|
|
647
646
|
);
|
|
@@ -152,48 +152,46 @@ export function CutsiteFilter(props) {
|
|
|
152
152
|
filteredRestrictionEnzymes.length > 1;
|
|
153
153
|
const [queryTracker, setQueryTracker] = useState("");
|
|
154
154
|
|
|
155
|
-
const renderOptions = (
|
|
156
|
-
|
|
157
|
-
|
|
155
|
+
const renderOptions = (
|
|
156
|
+
{ label, value, canBeHidden },
|
|
157
|
+
{ filteredRestrictionEnzymes, filteredRestrictionEnzymesUpdate }
|
|
158
|
+
) => (
|
|
159
|
+
<div
|
|
160
|
+
style={{
|
|
161
|
+
display: "flex",
|
|
162
|
+
justifyContent: "space-between",
|
|
163
|
+
width: "100%"
|
|
164
|
+
}}
|
|
165
|
+
>
|
|
166
|
+
{label}{" "}
|
|
167
|
+
{canBeHidden && (
|
|
168
|
+
<Icon
|
|
169
|
+
onClick={e => {
|
|
170
|
+
e.stopPropagation();
|
|
158
171
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
isHidden: true,
|
|
183
|
-
canBeHidden
|
|
184
|
-
})
|
|
185
|
-
);
|
|
186
|
-
}}
|
|
187
|
-
htmlTitle="Hide this enzyme"
|
|
188
|
-
className="veHideEnzymeBtn"
|
|
189
|
-
style={{ paddingTop: 5 }}
|
|
190
|
-
iconSize={14}
|
|
191
|
-
icon="eye-off"
|
|
192
|
-
></Icon>
|
|
193
|
-
)}
|
|
194
|
-
</div>
|
|
195
|
-
);
|
|
196
|
-
};
|
|
172
|
+
filteredRestrictionEnzymesUpdate(
|
|
173
|
+
flatMap(filteredRestrictionEnzymes, e => {
|
|
174
|
+
if (e.value === value) return [];
|
|
175
|
+
return e;
|
|
176
|
+
}).concat({
|
|
177
|
+
label,
|
|
178
|
+
className: "veHiddenEnzyme",
|
|
179
|
+
value,
|
|
180
|
+
// hiddenEnzyme: true,
|
|
181
|
+
isHidden: true,
|
|
182
|
+
canBeHidden
|
|
183
|
+
})
|
|
184
|
+
);
|
|
185
|
+
}}
|
|
186
|
+
htmlTitle="Hide this enzyme"
|
|
187
|
+
className="veHideEnzymeBtn"
|
|
188
|
+
style={{ paddingTop: 5 }}
|
|
189
|
+
iconSize={14}
|
|
190
|
+
icon="eye-off"
|
|
191
|
+
/>
|
|
192
|
+
)}
|
|
193
|
+
</div>
|
|
194
|
+
);
|
|
197
195
|
const filteredRestrictionEnzymesUpdate = enzymes => {
|
|
198
196
|
_filteredRestrictionEnzymesUpdate(enzymes);
|
|
199
197
|
if (sequenceData?.id) {
|
|
@@ -285,7 +283,7 @@ export function CutsiteFilter(props) {
|
|
|
285
283
|
data-tip="Manage Enzymes"
|
|
286
284
|
onClick={onManageClick}
|
|
287
285
|
icon="cog"
|
|
288
|
-
|
|
286
|
+
/>
|
|
289
287
|
)}
|
|
290
288
|
<div
|
|
291
289
|
style={{
|
|
@@ -345,19 +343,17 @@ export function CutsiteFilter(props) {
|
|
|
345
343
|
wrapperStyle={{ zIndex: 11 }}
|
|
346
344
|
noResultsText={
|
|
347
345
|
<NoResults
|
|
348
|
-
{
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
}}
|
|
360
|
-
></NoResults>
|
|
346
|
+
inputSequenceToTestAgainst={sequenceData.sequence}
|
|
347
|
+
manageEnzymesLink={manageEnzymesLink}
|
|
348
|
+
closeDropDown={closeDropDown}
|
|
349
|
+
onHiddenEnzymeAdd={onHiddenEnzymeAdd}
|
|
350
|
+
queryString={queryTracker}
|
|
351
|
+
additionalEnzymes={additionalEnzymes}
|
|
352
|
+
enzymeGroupsOverride={enzymeGroupsOverride}
|
|
353
|
+
cutsitesByNameActive={filteredCutsites.cutsitesByName}
|
|
354
|
+
cutsitesByName={allCutsites.cutsitesByName}
|
|
355
|
+
editorName={editorName}
|
|
356
|
+
/>
|
|
361
357
|
}
|
|
362
358
|
onInputChange={queryTracker => {
|
|
363
359
|
setQueryTracker(queryTracker);
|
|
@@ -1,13 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import { compose, withProps } from "recompose";
|
|
4
|
-
// import selectionLayer from "../redux/selectionLayer";
|
|
5
|
-
import React from "react";
|
|
6
|
-
import { DataTable } from "@teselagen/ui";
|
|
1
|
+
import React, { useMemo, useState } from "react";
|
|
2
|
+
import { DataTable, useStableReference } from "@teselagen/ui";
|
|
7
3
|
import { getCutsiteType, getVirtualDigest } from "@teselagen/sequence-utils";
|
|
8
4
|
import CutsiteFilter from "../CutsiteFilter";
|
|
9
5
|
import Ladder from "./Ladder";
|
|
10
|
-
// import getCutsiteType from "./getCutsiteType";
|
|
11
6
|
import {
|
|
12
7
|
Tabs,
|
|
13
8
|
Tab,
|
|
@@ -18,153 +13,206 @@ import {
|
|
|
18
13
|
} from "@blueprintjs/core";
|
|
19
14
|
import withEditorInteractions from "../withEditorInteractions";
|
|
20
15
|
import { userDefinedHandlersAndOpts } from "../Editor/userDefinedHandlersAndOpts";
|
|
21
|
-
import {
|
|
16
|
+
import { pick } from "lodash-es";
|
|
22
17
|
|
|
23
18
|
const MAX_DIGEST_CUTSITES = 50;
|
|
24
19
|
const MAX_PARTIAL_DIGEST_CUTSITES = 10;
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
20
|
+
const onSingleSelectRow = ({ onFragmentSelect }) => {
|
|
21
|
+
onFragmentSelect();
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export const DigestTool = props => {
|
|
25
|
+
const [selectedTab, setSelectedTab] = useState("virtualDigest");
|
|
26
|
+
const {
|
|
27
|
+
editorName,
|
|
28
|
+
dimensions = {},
|
|
29
|
+
digestTool: { selectedFragment, computePartialDigest },
|
|
30
|
+
onDigestSave,
|
|
31
|
+
updateComputePartialDigest,
|
|
32
|
+
boxHeight,
|
|
33
|
+
digestLaneRightClicked,
|
|
34
|
+
ladders,
|
|
35
|
+
sequenceData,
|
|
36
|
+
sequenceLength,
|
|
37
|
+
selectionLayerUpdate: _selectionLayerUpdate,
|
|
38
|
+
updateSelectedFragment
|
|
39
|
+
} = props;
|
|
40
|
+
|
|
41
|
+
const isCircular = sequenceData.circular;
|
|
42
|
+
const cutsites = sequenceData.cutsites;
|
|
43
|
+
const computePartialDigestDisabled =
|
|
44
|
+
cutsites.length > MAX_PARTIAL_DIGEST_CUTSITES;
|
|
45
|
+
const computeDigestDisabled = cutsites.length > MAX_DIGEST_CUTSITES;
|
|
46
|
+
// The selection layer update function is memoized to prevent re-renders
|
|
47
|
+
// It changes triggered by the DataTables below
|
|
48
|
+
const selectionLayerUpdate = useStableReference(_selectionLayerUpdate);
|
|
49
|
+
|
|
50
|
+
// This useMemo might not be necessary once if we figure out
|
|
51
|
+
// why the DataTables below triggers a re-render outside of them.
|
|
52
|
+
const lanes = useMemo(() => {
|
|
53
|
+
const { fragments } = getVirtualDigest({
|
|
54
|
+
cutsites,
|
|
55
|
+
sequenceLength,
|
|
56
|
+
isCircular,
|
|
57
|
+
computePartialDigest,
|
|
35
58
|
computePartialDigestDisabled,
|
|
36
|
-
computeDigestDisabled
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
59
|
+
computeDigestDisabled
|
|
60
|
+
});
|
|
61
|
+
const _lanes = [
|
|
62
|
+
fragments.map(f => ({
|
|
63
|
+
...f,
|
|
64
|
+
onFragmentSelect: () => {
|
|
65
|
+
selectionLayerUpdate.current({
|
|
66
|
+
start: f.start,
|
|
67
|
+
end: f.end,
|
|
68
|
+
name: f.name
|
|
69
|
+
});
|
|
70
|
+
updateSelectedFragment(f.Intentid);
|
|
71
|
+
}
|
|
72
|
+
}))
|
|
73
|
+
];
|
|
74
|
+
return _lanes;
|
|
75
|
+
}, [
|
|
76
|
+
computeDigestDisabled,
|
|
77
|
+
computePartialDigest,
|
|
78
|
+
computePartialDigestDisabled,
|
|
79
|
+
cutsites,
|
|
80
|
+
isCircular,
|
|
81
|
+
selectionLayerUpdate,
|
|
82
|
+
sequenceLength,
|
|
83
|
+
updateSelectedFragment
|
|
84
|
+
]);
|
|
85
|
+
|
|
86
|
+
// Same comment as above
|
|
87
|
+
const digestInfoLanes = useMemo(
|
|
88
|
+
() =>
|
|
89
|
+
lanes[0].map(({ id, cut1, cut2, start, end, size, ...rest }) => {
|
|
90
|
+
return {
|
|
91
|
+
...rest,
|
|
92
|
+
id,
|
|
93
|
+
start,
|
|
94
|
+
end,
|
|
95
|
+
length: size,
|
|
96
|
+
leftCutter: cut1.restrictionEnzyme.name,
|
|
97
|
+
rightCutter: cut2.restrictionEnzyme.name,
|
|
98
|
+
leftOverhang: getCutsiteType(cut1.restrictionEnzyme),
|
|
99
|
+
rightOverhang: getCutsiteType(cut2.restrictionEnzyme)
|
|
100
|
+
};
|
|
101
|
+
}),
|
|
102
|
+
[lanes]
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
return (
|
|
106
|
+
<div
|
|
107
|
+
style={{
|
|
108
|
+
height: typeof dimensions.height === "string" ? 100 : dimensions.height,
|
|
109
|
+
overflowY: "auto",
|
|
110
|
+
padding: 10
|
|
111
|
+
}}
|
|
112
|
+
>
|
|
113
|
+
{onDigestSave && (
|
|
114
|
+
<div style={{ display: "flex", marginBottom: 10 }}>
|
|
115
|
+
<InputGroup placeholder="My Digest" />
|
|
116
|
+
<Button
|
|
117
|
+
intent={Intent.PRIMARY}
|
|
118
|
+
onClick={() => {
|
|
119
|
+
onDigestSave({});
|
|
68
120
|
}}
|
|
69
|
-
|
|
70
|
-
label={
|
|
71
|
-
<span>
|
|
72
|
-
Show Partial Digests{" "}
|
|
73
|
-
{computePartialDigestDisabled ? (
|
|
74
|
-
<span style={{ fontSize: 10 }}>
|
|
75
|
-
{" "}
|
|
76
|
-
-- Disabled (only supports {MAX_PARTIAL_DIGEST_CUTSITES} or
|
|
77
|
-
fewer cut sites){" "}
|
|
78
|
-
</span>
|
|
79
|
-
) : null}
|
|
80
|
-
</span>
|
|
81
|
-
}
|
|
82
|
-
disabled={computePartialDigestDisabled}
|
|
83
|
-
></Checkbox>
|
|
84
|
-
<a
|
|
85
|
-
target="_blank"
|
|
86
|
-
rel="noopener noreferrer"
|
|
87
|
-
href="http://docs.teselagen.com/en/articles/5489322-restriction-digest-in-the-vector-editor"
|
|
121
|
+
style={{ marginLeft: 5 }}
|
|
88
122
|
>
|
|
89
|
-
|
|
90
|
-
|
|
123
|
+
{" "}
|
|
124
|
+
Save
|
|
125
|
+
</Button>
|
|
91
126
|
</div>
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
<br />
|
|
98
|
-
{computeDigestDisabled && (
|
|
99
|
-
<div
|
|
100
|
-
style={{
|
|
101
|
-
color: "red",
|
|
102
|
-
marginBottom: "6px",
|
|
103
|
-
fontSize: "15px"
|
|
104
|
-
}}
|
|
105
|
-
>
|
|
106
|
-
{`>${MAX_DIGEST_CUTSITES} cut sites detected. Filter out additional
|
|
107
|
-
restriction enzymes to visualize digest results`}
|
|
108
|
-
</div>
|
|
109
|
-
)}
|
|
110
|
-
<Tabs
|
|
111
|
-
selectedTabId={selectedTab}
|
|
112
|
-
onChange={id => {
|
|
113
|
-
this.setState({ selectedTab: id });
|
|
127
|
+
)}
|
|
128
|
+
<div style={{ display: "flex", justifyContent: "space-between" }}>
|
|
129
|
+
<Checkbox
|
|
130
|
+
onChange={() => {
|
|
131
|
+
updateComputePartialDigest(!computePartialDigest);
|
|
114
132
|
}}
|
|
133
|
+
checked={computePartialDigest}
|
|
134
|
+
label={
|
|
135
|
+
<span>
|
|
136
|
+
Show Partial Digests{" "}
|
|
137
|
+
{computePartialDigestDisabled ? (
|
|
138
|
+
<span style={{ fontSize: 10 }}>
|
|
139
|
+
{" "}
|
|
140
|
+
-- Disabled (only supports {MAX_PARTIAL_DIGEST_CUTSITES} or
|
|
141
|
+
fewer cut sites){" "}
|
|
142
|
+
</span>
|
|
143
|
+
) : null}
|
|
144
|
+
</span>
|
|
145
|
+
}
|
|
146
|
+
disabled={computePartialDigestDisabled}
|
|
147
|
+
/>
|
|
148
|
+
<a
|
|
149
|
+
target="_blank"
|
|
150
|
+
rel="noopener noreferrer"
|
|
151
|
+
href="http://docs.teselagen.com/en/articles/5489322-restriction-digest-in-the-vector-editor"
|
|
115
152
|
>
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
id="virtualDigest"
|
|
119
|
-
panel={<Ladder {...this.props} editorName={editorName} />}
|
|
120
|
-
/>
|
|
121
|
-
<Tab
|
|
122
|
-
title="Digest Info"
|
|
123
|
-
id="table"
|
|
124
|
-
panel={
|
|
125
|
-
<DataTable
|
|
126
|
-
noRouter
|
|
127
|
-
isSimple
|
|
128
|
-
maxHeight={400}
|
|
129
|
-
// noFooter
|
|
130
|
-
withSearch={false}
|
|
131
|
-
onSingleRowSelect={({ onFragmentSelect }) => {
|
|
132
|
-
onFragmentSelect();
|
|
133
|
-
}}
|
|
134
|
-
reduxFormSelectedEntityIdMap={{
|
|
135
|
-
input: {
|
|
136
|
-
value: {
|
|
137
|
-
[selectedFragment]: true
|
|
138
|
-
},
|
|
139
|
-
onChange: noop
|
|
140
|
-
}
|
|
141
|
-
}}
|
|
142
|
-
formName="digestInfoTable"
|
|
143
|
-
entities={lanes[0].map(
|
|
144
|
-
({ id, cut1, cut2, start, end, size, ...rest }) => {
|
|
145
|
-
return {
|
|
146
|
-
...rest,
|
|
147
|
-
id,
|
|
148
|
-
start,
|
|
149
|
-
end,
|
|
150
|
-
length: size,
|
|
151
|
-
leftCutter: cut1.restrictionEnzyme.name,
|
|
152
|
-
rightCutter: cut2.restrictionEnzyme.name,
|
|
153
|
-
leftOverhang: getCutsiteType(cut1.restrictionEnzyme),
|
|
154
|
-
rightOverhang: getCutsiteType(cut2.restrictionEnzyme)
|
|
155
|
-
};
|
|
156
|
-
}
|
|
157
|
-
)}
|
|
158
|
-
schema={schema}
|
|
159
|
-
/>
|
|
160
|
-
}
|
|
161
|
-
/>
|
|
162
|
-
</Tabs>
|
|
163
|
-
<br />
|
|
153
|
+
Read the docs
|
|
154
|
+
</a>
|
|
164
155
|
</div>
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
}
|
|
156
|
+
Choose your enzymes:
|
|
157
|
+
<CutsiteFilter
|
|
158
|
+
{...pick(props, userDefinedHandlersAndOpts)}
|
|
159
|
+
editorName={editorName}
|
|
160
|
+
/>
|
|
161
|
+
<br />
|
|
162
|
+
{computeDigestDisabled && (
|
|
163
|
+
<div
|
|
164
|
+
style={{
|
|
165
|
+
color: "red",
|
|
166
|
+
marginBottom: "6px",
|
|
167
|
+
fontSize: "15px"
|
|
168
|
+
}}
|
|
169
|
+
>
|
|
170
|
+
{`>${MAX_DIGEST_CUTSITES} cut sites detected. Filter out additional
|
|
171
|
+
restriction enzymes to visualize digest results`}
|
|
172
|
+
</div>
|
|
173
|
+
)}
|
|
174
|
+
<Tabs
|
|
175
|
+
selectedTabId={selectedTab}
|
|
176
|
+
onChange={id => {
|
|
177
|
+
setSelectedTab(id);
|
|
178
|
+
}}
|
|
179
|
+
>
|
|
180
|
+
<Tab
|
|
181
|
+
title="Virtual Digest"
|
|
182
|
+
id="virtualDigest"
|
|
183
|
+
panel={
|
|
184
|
+
<Ladder
|
|
185
|
+
boxHeight={boxHeight}
|
|
186
|
+
lanes={lanes}
|
|
187
|
+
digestLaneRightClicked={digestLaneRightClicked}
|
|
188
|
+
selectedFragment={selectedFragment}
|
|
189
|
+
ladders={ladders}
|
|
190
|
+
/>
|
|
191
|
+
}
|
|
192
|
+
/>
|
|
193
|
+
<Tab
|
|
194
|
+
title="Digest Info"
|
|
195
|
+
id="table"
|
|
196
|
+
panel={
|
|
197
|
+
<DataTable
|
|
198
|
+
noRouter
|
|
199
|
+
isSimple
|
|
200
|
+
maxHeight={400}
|
|
201
|
+
// noFooter
|
|
202
|
+
withSearch={false}
|
|
203
|
+
onSingleRowSelect={onSingleSelectRow}
|
|
204
|
+
formName="digestInfoTable"
|
|
205
|
+
entities={digestInfoLanes}
|
|
206
|
+
schema={schema}
|
|
207
|
+
/>
|
|
208
|
+
}
|
|
209
|
+
/>
|
|
210
|
+
</Tabs>
|
|
211
|
+
<br />
|
|
212
|
+
</div>
|
|
213
|
+
);
|
|
214
|
+
};
|
|
215
|
+
|
|
168
216
|
const schema = {
|
|
169
217
|
fields: [
|
|
170
218
|
{ width: 60, path: "start", displayName: "Start", type: "string" },
|
|
@@ -177,47 +225,4 @@ const schema = {
|
|
|
177
225
|
]
|
|
178
226
|
};
|
|
179
227
|
|
|
180
|
-
export default
|
|
181
|
-
withEditorInteractions,
|
|
182
|
-
withProps(props => {
|
|
183
|
-
const {
|
|
184
|
-
sequenceData,
|
|
185
|
-
sequenceLength,
|
|
186
|
-
selectionLayerUpdate,
|
|
187
|
-
updateSelectedFragment,
|
|
188
|
-
digestTool: { computePartialDigest }
|
|
189
|
-
} = props;
|
|
190
|
-
const isCircular = sequenceData.circular;
|
|
191
|
-
const cutsites = sequenceData.cutsites;
|
|
192
|
-
const computePartialDigestDisabled =
|
|
193
|
-
cutsites.length > MAX_PARTIAL_DIGEST_CUTSITES;
|
|
194
|
-
const computeDigestDisabled = cutsites.length > MAX_DIGEST_CUTSITES;
|
|
195
|
-
|
|
196
|
-
const { fragments, overlappingEnzymes } = getVirtualDigest({
|
|
197
|
-
cutsites,
|
|
198
|
-
sequenceLength,
|
|
199
|
-
isCircular,
|
|
200
|
-
computePartialDigest,
|
|
201
|
-
computePartialDigestDisabled,
|
|
202
|
-
computeDigestDisabled
|
|
203
|
-
});
|
|
204
|
-
return {
|
|
205
|
-
computePartialDigestDisabled,
|
|
206
|
-
computeDigestDisabled,
|
|
207
|
-
lanes: [
|
|
208
|
-
fragments.map(f => ({
|
|
209
|
-
...f,
|
|
210
|
-
onFragmentSelect: () => {
|
|
211
|
-
selectionLayerUpdate({
|
|
212
|
-
start: f.start,
|
|
213
|
-
end: f.end,
|
|
214
|
-
name: f.name
|
|
215
|
-
});
|
|
216
|
-
updateSelectedFragment(f.Intentid);
|
|
217
|
-
}
|
|
218
|
-
}))
|
|
219
|
-
],
|
|
220
|
-
overlappingEnzymes
|
|
221
|
-
};
|
|
222
|
-
})
|
|
223
|
-
)(DigestTool);
|
|
228
|
+
export default withEditorInteractions(DigestTool);
|
package/src/GlobalDialogUtils.js
CHANGED