@teselagen/ove 0.7.3-beta.7 → 0.7.3
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 +1 -1
- package/helperComponents/PropertiesDialog/index.d.ts +2 -7
- package/index.cjs.js +6501 -494
- package/index.es.js +6490 -483
- package/index.umd.js +6501 -494
- package/package.json +2 -2
- package/src/CreateAnnotationsPage.js +1 -1
- package/src/DigestTool/DigestTool.js +78 -75
- package/src/GlobalDialogUtils.js +1 -0
- package/src/helperComponents/PropertiesDialog/CutsiteProperties.js +126 -135
- package/src/helperComponents/PropertiesDialog/SingleEnzymeCutsiteInfo.js +59 -51
- package/src/helperComponents/PropertiesDialog/index.js +115 -114
- package/src/helperComponents/RemoveDuplicates/index.js +144 -160
- package/src/utils/useFormValue.js +7 -0
- package/src/withEditorInteractions/index.js +16 -11
- 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.7.3
|
|
3
|
+
"version": "0.7.3",
|
|
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.7.
|
|
15
|
+
"@teselagen/ui": "0.7.7",
|
|
16
16
|
"@teselagen/file-utils": "0.3.16",
|
|
17
17
|
"@teselagen/bounce-loader": "0.3.11",
|
|
18
18
|
"@teselagen/bio-parsers": "0.4.22",
|
|
@@ -1,13 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import { compose, withProps } from "recompose";
|
|
4
|
-
// import selectionLayer from "../redux/selectionLayer";
|
|
5
|
-
import React, { useState } 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,
|
|
@@ -22,23 +17,91 @@ import { pick } from "lodash-es";
|
|
|
22
17
|
|
|
23
18
|
const MAX_DIGEST_CUTSITES = 50;
|
|
24
19
|
const MAX_PARTIAL_DIGEST_CUTSITES = 10;
|
|
20
|
+
const onSingleSelectRow = ({ onFragmentSelect }) => {
|
|
21
|
+
onFragmentSelect();
|
|
22
|
+
};
|
|
25
23
|
|
|
26
24
|
export const DigestTool = props => {
|
|
27
25
|
const [selectedTab, setSelectedTab] = useState("virtualDigest");
|
|
28
26
|
const {
|
|
29
27
|
editorName,
|
|
30
|
-
// height = 100,
|
|
31
28
|
dimensions = {},
|
|
32
|
-
lanes,
|
|
33
29
|
digestTool: { selectedFragment, computePartialDigest },
|
|
34
30
|
onDigestSave,
|
|
35
|
-
computePartialDigestDisabled,
|
|
36
|
-
computeDigestDisabled,
|
|
37
31
|
updateComputePartialDigest,
|
|
38
32
|
boxHeight,
|
|
39
33
|
digestLaneRightClicked,
|
|
40
|
-
ladders
|
|
34
|
+
ladders,
|
|
35
|
+
sequenceData,
|
|
36
|
+
sequenceLength,
|
|
37
|
+
selectionLayerUpdate: _selectionLayerUpdate,
|
|
38
|
+
updateSelectedFragment
|
|
41
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,
|
|
58
|
+
computePartialDigestDisabled,
|
|
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
|
+
|
|
42
105
|
return (
|
|
43
106
|
<div
|
|
44
107
|
style={{
|
|
@@ -137,25 +200,9 @@ export const DigestTool = props => {
|
|
|
137
200
|
maxHeight={400}
|
|
138
201
|
// noFooter
|
|
139
202
|
withSearch={false}
|
|
140
|
-
onSingleRowSelect={
|
|
141
|
-
onFragmentSelect();
|
|
142
|
-
}}
|
|
203
|
+
onSingleRowSelect={onSingleSelectRow}
|
|
143
204
|
formName="digestInfoTable"
|
|
144
|
-
entities={
|
|
145
|
-
({ id, cut1, cut2, start, end, size, ...rest }) => {
|
|
146
|
-
return {
|
|
147
|
-
...rest,
|
|
148
|
-
id,
|
|
149
|
-
start,
|
|
150
|
-
end,
|
|
151
|
-
length: size,
|
|
152
|
-
leftCutter: cut1.restrictionEnzyme.name,
|
|
153
|
-
rightCutter: cut2.restrictionEnzyme.name,
|
|
154
|
-
leftOverhang: getCutsiteType(cut1.restrictionEnzyme),
|
|
155
|
-
rightOverhang: getCutsiteType(cut2.restrictionEnzyme)
|
|
156
|
-
};
|
|
157
|
-
}
|
|
158
|
-
)}
|
|
205
|
+
entities={digestInfoLanes}
|
|
159
206
|
schema={schema}
|
|
160
207
|
/>
|
|
161
208
|
}
|
|
@@ -178,48 +225,4 @@ const schema = {
|
|
|
178
225
|
]
|
|
179
226
|
};
|
|
180
227
|
|
|
181
|
-
export default
|
|
182
|
-
withEditorInteractions,
|
|
183
|
-
withProps(
|
|
184
|
-
({
|
|
185
|
-
sequenceData,
|
|
186
|
-
sequenceLength,
|
|
187
|
-
selectionLayerUpdate,
|
|
188
|
-
updateSelectedFragment,
|
|
189
|
-
digestTool: { computePartialDigest }
|
|
190
|
-
}) => {
|
|
191
|
-
const isCircular = sequenceData.circular;
|
|
192
|
-
const cutsites = sequenceData.cutsites;
|
|
193
|
-
const computePartialDigestDisabled =
|
|
194
|
-
cutsites.length > MAX_PARTIAL_DIGEST_CUTSITES;
|
|
195
|
-
const computeDigestDisabled = cutsites.length > MAX_DIGEST_CUTSITES;
|
|
196
|
-
|
|
197
|
-
const { fragments, overlappingEnzymes } = getVirtualDigest({
|
|
198
|
-
cutsites,
|
|
199
|
-
sequenceLength,
|
|
200
|
-
isCircular,
|
|
201
|
-
computePartialDigest,
|
|
202
|
-
computePartialDigestDisabled,
|
|
203
|
-
computeDigestDisabled
|
|
204
|
-
});
|
|
205
|
-
return {
|
|
206
|
-
computePartialDigestDisabled,
|
|
207
|
-
computeDigestDisabled,
|
|
208
|
-
lanes: [
|
|
209
|
-
fragments.map(f => ({
|
|
210
|
-
...f,
|
|
211
|
-
onFragmentSelect: () => {
|
|
212
|
-
selectionLayerUpdate({
|
|
213
|
-
start: f.start,
|
|
214
|
-
end: f.end,
|
|
215
|
-
name: f.name
|
|
216
|
-
});
|
|
217
|
-
updateSelectedFragment(f.Intentid);
|
|
218
|
-
}
|
|
219
|
-
}))
|
|
220
|
-
],
|
|
221
|
-
overlappingEnzymes
|
|
222
|
-
};
|
|
223
|
-
}
|
|
224
|
-
)
|
|
225
|
-
)(DigestTool);
|
|
228
|
+
export default withEditorInteractions(DigestTool);
|
package/src/GlobalDialogUtils.js
CHANGED
|
@@ -1,16 +1,12 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
withSelectedEntities,
|
|
5
|
-
createCommandMenu
|
|
6
|
-
} from "@teselagen/ui";
|
|
7
|
-
import { map, get } from "lodash-es";
|
|
1
|
+
import React, { useCallback, useMemo } from "react";
|
|
2
|
+
import { DataTable, createCommandMenu } from "@teselagen/ui";
|
|
3
|
+
import { get } from "lodash-es";
|
|
8
4
|
import CutsiteFilter from "../../CutsiteFilter";
|
|
9
5
|
import { Button, ButtonGroup } from "@blueprintjs/core";
|
|
10
6
|
import { connectToEditor } from "../../withEditorProps";
|
|
11
7
|
import { compose } from "recompose";
|
|
12
8
|
import selectors from "../../selectors";
|
|
13
|
-
import
|
|
9
|
+
import _commands from "../../commands";
|
|
14
10
|
import { userDefinedHandlersAndOpts } from "../../Editor/userDefinedHandlersAndOpts";
|
|
15
11
|
import { pick } from "lodash-es";
|
|
16
12
|
import SingleEnzymeCutsiteInfo from "./SingleEnzymeCutsiteInfo";
|
|
@@ -18,105 +14,107 @@ import { withRestrictionEnzymes } from "../../CutsiteFilter/withRestrictionEnzym
|
|
|
18
14
|
import { cutsitesSubmenu } from "../../MenuBar/viewSubmenu";
|
|
19
15
|
import { getVisFilter } from "./GenericAnnotationProperties";
|
|
20
16
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
17
|
+
const schema = {
|
|
18
|
+
fields: [
|
|
19
|
+
{ path: "name", type: "string" },
|
|
20
|
+
{ path: "numberOfCuts", type: "number" },
|
|
21
|
+
{ path: "groups", type: "string" }
|
|
22
|
+
]
|
|
23
|
+
};
|
|
26
24
|
|
|
27
|
-
|
|
28
|
-
return (
|
|
29
|
-
<SingleEnzymeCutsiteInfo
|
|
30
|
-
{...{
|
|
31
|
-
allRestrictionEnzymes: this.props.allRestrictionEnzymes,
|
|
32
|
-
allCutsites: this.props.allCutsites,
|
|
33
|
-
filteredCutsites: this.props.filteredCutsites,
|
|
34
|
-
editorName: this.props.editorName,
|
|
35
|
-
dispatch: this.props.dispatch,
|
|
36
|
-
selectedAnnotationId: this.props.selectedAnnotationId,
|
|
37
|
-
cutsiteGroup: row.original.cutsiteGroup,
|
|
38
|
-
enzyme: row.original.enzyme
|
|
39
|
-
}}
|
|
40
|
-
></SingleEnzymeCutsiteInfo>
|
|
41
|
-
);
|
|
42
|
-
};
|
|
25
|
+
const defaultValues = { order: ["numberOfCuts"] };
|
|
43
26
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
27
|
+
const CutsiteProperties = props => {
|
|
28
|
+
const commands = _commands({ props });
|
|
29
|
+
const {
|
|
30
|
+
allRestrictionEnzymes,
|
|
31
|
+
allCutsites,
|
|
32
|
+
annotationVisibilityShow,
|
|
33
|
+
createNewDigest,
|
|
34
|
+
dispatch,
|
|
35
|
+
editorName,
|
|
36
|
+
filteredCutsites,
|
|
37
|
+
selectedAnnotationId
|
|
38
|
+
} = props;
|
|
51
39
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
40
|
+
const SubComponent = useCallback(
|
|
41
|
+
row => (
|
|
42
|
+
<SingleEnzymeCutsiteInfo
|
|
43
|
+
allRestrictionEnzymes={allRestrictionEnzymes}
|
|
44
|
+
allCutsites={allCutsites}
|
|
45
|
+
filteredCutsites={filteredCutsites}
|
|
46
|
+
editorName={editorName}
|
|
47
|
+
dispatch={dispatch}
|
|
48
|
+
selectedAnnotationId={selectedAnnotationId}
|
|
49
|
+
cutsiteGroup={row.original.cutsiteGroup}
|
|
50
|
+
enzyme={row.original.enzyme}
|
|
51
|
+
/>
|
|
52
|
+
),
|
|
53
|
+
[
|
|
54
|
+
allCutsites,
|
|
55
|
+
allRestrictionEnzymes,
|
|
56
|
+
dispatch,
|
|
57
57
|
editorName,
|
|
58
|
-
|
|
59
|
-
filteredCutsites: allCutsites,
|
|
58
|
+
filteredCutsites,
|
|
60
59
|
selectedAnnotationId
|
|
61
|
-
|
|
60
|
+
]
|
|
61
|
+
);
|
|
62
62
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
let groups = "";
|
|
67
|
-
const exisitingEnzymeGroups = window.getExistingEnzymeGroups();
|
|
63
|
+
const onChangeHook = useCallback(() => {
|
|
64
|
+
annotationVisibilityShow("cutsites");
|
|
65
|
+
}, [annotationVisibilityShow]);
|
|
68
66
|
|
|
69
|
-
|
|
70
|
-
if (exisitingEnzymeGroups[key].includes(name)) groups += key;
|
|
71
|
-
groups += " ";
|
|
72
|
-
});
|
|
67
|
+
const { cutsitesByName, cutsitesById } = filteredCutsites;
|
|
73
68
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
name
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
69
|
+
const cutsitesToUse = useMemo(
|
|
70
|
+
() =>
|
|
71
|
+
Object.values(cutsitesByName || {}).map(cutsiteGroup => {
|
|
72
|
+
const name = cutsiteGroup[0].restrictionEnzyme.name;
|
|
73
|
+
let groups = "";
|
|
74
|
+
const exisitingEnzymeGroups = window.getExistingEnzymeGroups();
|
|
75
|
+
|
|
76
|
+
Object.keys(exisitingEnzymeGroups).forEach(key => {
|
|
77
|
+
if (exisitingEnzymeGroups[key].includes(name)) groups += key;
|
|
78
|
+
groups += " ";
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
return {
|
|
82
|
+
cutsiteGroup,
|
|
83
|
+
id: name,
|
|
84
|
+
name,
|
|
85
|
+
numberOfCuts: cutsiteGroup.length,
|
|
86
|
+
enzyme: cutsiteGroup[0].restrictionEnzyme,
|
|
87
|
+
groups
|
|
88
|
+
};
|
|
89
|
+
}),
|
|
90
|
+
[cutsitesByName]
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
const selectedIds = useMemo(
|
|
94
|
+
() => get(cutsitesById[selectedAnnotationId], "restrictionEnzyme.name"),
|
|
95
|
+
[cutsitesById, selectedAnnotationId]
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
return (
|
|
99
|
+
<>
|
|
100
|
+
<div
|
|
101
|
+
style={{
|
|
102
|
+
marginBottom: 10,
|
|
103
|
+
paddingTop: 3,
|
|
104
|
+
display: "flex",
|
|
105
|
+
// flexWrap: 'wrap',
|
|
106
|
+
width: "100%",
|
|
107
|
+
// justifyContent: "space-between",
|
|
108
|
+
alignItems: "center"
|
|
109
|
+
}}
|
|
110
|
+
>
|
|
111
|
+
{getVisFilter(
|
|
112
|
+
createCommandMenu(cutsitesSubmenu, commands, {
|
|
113
|
+
useTicks: true
|
|
114
|
+
})
|
|
115
|
+
)}
|
|
116
|
+
<ButtonGroup>
|
|
98
117
|
<Button
|
|
99
|
-
style={{ marginLeft: 10, cursor: "auto" }}
|
|
100
|
-
disabled
|
|
101
|
-
minimal
|
|
102
|
-
icon="filter"
|
|
103
|
-
/> */}
|
|
104
|
-
{getVisFilter(
|
|
105
|
-
createCommandMenu(cutsitesSubmenu, this.commands, {
|
|
106
|
-
useTicks: true
|
|
107
|
-
})
|
|
108
|
-
)}
|
|
109
|
-
<ButtonGroup>
|
|
110
|
-
<Button
|
|
111
|
-
intent="success"
|
|
112
|
-
data-tip="Virtual Digest"
|
|
113
|
-
icon="cut"
|
|
114
|
-
style={{ marginLeft: 15, flexGrow: -1 }}
|
|
115
|
-
onClick={() => {
|
|
116
|
-
createNewDigest();
|
|
117
|
-
}}
|
|
118
|
-
></Button>
|
|
119
|
-
{/* <Button
|
|
120
118
|
intent="success"
|
|
121
119
|
data-tip="Virtual Digest"
|
|
122
120
|
icon="cut"
|
|
@@ -124,43 +122,37 @@ class CutsiteProperties extends React.Component {
|
|
|
124
122
|
onClick={() => {
|
|
125
123
|
createNewDigest();
|
|
126
124
|
}}
|
|
127
|
-
>
|
|
128
|
-
</Button> */}
|
|
129
|
-
</ButtonGroup>
|
|
130
|
-
|
|
131
|
-
<CutsiteFilter
|
|
132
|
-
{...pick(this.props, userDefinedHandlersAndOpts)}
|
|
133
|
-
style={{ marginLeft: "auto", marginRight: 3 }}
|
|
134
|
-
editorName={editorName}
|
|
135
|
-
manageEnzymesToLeft
|
|
136
|
-
onChangeHook={this.onChangeHook}
|
|
137
125
|
/>
|
|
138
|
-
</
|
|
139
|
-
<
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
noSelect
|
|
146
|
-
noHeader
|
|
147
|
-
noFooter
|
|
148
|
-
withExpandAndCollapseAllButton
|
|
149
|
-
noFullscreenButton
|
|
150
|
-
noPadding
|
|
151
|
-
defaults={{ order: ["numberOfCuts"] }}
|
|
152
|
-
formName="cutsiteProperties"
|
|
153
|
-
noRouter
|
|
154
|
-
withSearch={false}
|
|
155
|
-
SubComponent={this.SubComponent}
|
|
156
|
-
isInfinite
|
|
157
|
-
schema={this.schema}
|
|
158
|
-
entities={cutsitesToUse}
|
|
126
|
+
</ButtonGroup>
|
|
127
|
+
<CutsiteFilter
|
|
128
|
+
{...pick(props, userDefinedHandlersAndOpts)}
|
|
129
|
+
style={{ marginLeft: "auto", marginRight: 3 }}
|
|
130
|
+
editorName={editorName}
|
|
131
|
+
manageEnzymesToLeft
|
|
132
|
+
onChangeHook={onChangeHook}
|
|
159
133
|
/>
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
134
|
+
</div>
|
|
135
|
+
<DataTable
|
|
136
|
+
selectedIds={selectedIds}
|
|
137
|
+
compact
|
|
138
|
+
noSelect
|
|
139
|
+
noHeader
|
|
140
|
+
noFooter
|
|
141
|
+
withExpandAndCollapseAllButton
|
|
142
|
+
noFullscreenButton
|
|
143
|
+
noPadding
|
|
144
|
+
defaults={defaultValues}
|
|
145
|
+
formName="cutsiteProperties"
|
|
146
|
+
noRouter
|
|
147
|
+
withSearch={false}
|
|
148
|
+
SubComponent={SubComponent}
|
|
149
|
+
isInfinite
|
|
150
|
+
schema={schema}
|
|
151
|
+
entities={cutsitesToUse}
|
|
152
|
+
/>
|
|
153
|
+
</>
|
|
154
|
+
);
|
|
155
|
+
};
|
|
164
156
|
|
|
165
157
|
export default compose(
|
|
166
158
|
connectToEditor((editorState, ownProps) => {
|
|
@@ -180,6 +172,5 @@ export default compose(
|
|
|
180
172
|
cutsites: cutsites.cutsitesArray
|
|
181
173
|
};
|
|
182
174
|
}),
|
|
183
|
-
withRestrictionEnzymes
|
|
184
|
-
withSelectedEntities("cutsiteProperties")
|
|
175
|
+
withRestrictionEnzymes
|
|
185
176
|
)(CutsiteProperties);
|
|
@@ -1,11 +1,17 @@
|
|
|
1
|
-
import React from "react";
|
|
1
|
+
import React, { useCallback, useMemo } from "react";
|
|
2
2
|
import { DataTable } from "@teselagen/ui";
|
|
3
|
-
|
|
4
3
|
import { CutsiteTag } from "../../CutsiteFilter/AdditionalCutsiteInfoDialog";
|
|
5
|
-
|
|
6
4
|
import EnzymeViewer from "../../EnzymeViewer";
|
|
7
5
|
import { getEnzymeAliases } from "../../utils/editorUtils";
|
|
8
6
|
|
|
7
|
+
const schema = {
|
|
8
|
+
fields: [
|
|
9
|
+
{ path: "topSnipPosition", displayName: "Top Snip", type: "string" },
|
|
10
|
+
{ path: "position", type: "string" },
|
|
11
|
+
{ path: "strand", type: "string" }
|
|
12
|
+
]
|
|
13
|
+
};
|
|
14
|
+
|
|
9
15
|
export default function SingleEnzymeCutsiteInfo({
|
|
10
16
|
cutsiteGroup,
|
|
11
17
|
enzyme,
|
|
@@ -16,40 +22,52 @@ export default function SingleEnzymeCutsiteInfo({
|
|
|
16
22
|
allCutsites,
|
|
17
23
|
filteredCutsites: { cutsitesByName: cutsitesByNameActive }
|
|
18
24
|
}) {
|
|
19
|
-
const onRowSelect = (
|
|
20
|
-
|
|
25
|
+
const onRowSelect = useCallback(
|
|
26
|
+
([record]) => {
|
|
27
|
+
if (!record) return;
|
|
21
28
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
29
|
+
dispatch({
|
|
30
|
+
type: "CARET_POSITION_UPDATE",
|
|
31
|
+
payload: record.topSnipPosition,
|
|
32
|
+
meta: {
|
|
33
|
+
editorName
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
},
|
|
37
|
+
[dispatch, editorName]
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
const aliases = useMemo(() => getEnzymeAliases(enzyme), [enzyme]);
|
|
41
|
+
const entities = useMemo(
|
|
42
|
+
() =>
|
|
43
|
+
cutsiteGroup
|
|
44
|
+
.sort((a, b) => a.topSnipPosition - b.topSnipPosition)
|
|
45
|
+
.map(
|
|
46
|
+
({
|
|
47
|
+
restrictionEnzyme: { forwardRegex, reverseRegex } = {},
|
|
48
|
+
forward,
|
|
49
|
+
id,
|
|
50
|
+
topSnipBeforeBottom,
|
|
51
|
+
topSnipPosition,
|
|
52
|
+
bottomSnipPosition
|
|
53
|
+
}) => {
|
|
54
|
+
return {
|
|
55
|
+
id,
|
|
56
|
+
topSnipPosition,
|
|
57
|
+
position: topSnipBeforeBottom
|
|
58
|
+
? topSnipPosition + " - " + bottomSnipPosition
|
|
59
|
+
: bottomSnipPosition + " - " + topSnipPosition,
|
|
60
|
+
strand:
|
|
61
|
+
forwardRegex === reverseRegex
|
|
62
|
+
? "Palindromic"
|
|
63
|
+
: forward
|
|
64
|
+
? "1"
|
|
65
|
+
: "-1"
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
),
|
|
69
|
+
[cutsiteGroup]
|
|
70
|
+
);
|
|
53
71
|
|
|
54
72
|
return (
|
|
55
73
|
<div>
|
|
@@ -61,14 +79,12 @@ export default function SingleEnzymeCutsiteInfo({
|
|
|
61
79
|
>
|
|
62
80
|
{enzyme && (
|
|
63
81
|
<EnzymeViewer
|
|
64
|
-
{
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
forwardSnipPosition: enzyme.topSnipOffset
|
|
68
|
-
}}
|
|
82
|
+
sequence={enzyme.site}
|
|
83
|
+
reverseSnipPosition={enzyme.bottomSnipOffset}
|
|
84
|
+
forwardSnipPosition={enzyme.topSnipOffset}
|
|
69
85
|
/>
|
|
70
86
|
)}
|
|
71
|
-
<br
|
|
87
|
+
<br />
|
|
72
88
|
{entities && !!entities.length && (
|
|
73
89
|
<div>
|
|
74
90
|
<DataTable
|
|
@@ -106,7 +122,7 @@ export default function SingleEnzymeCutsiteInfo({
|
|
|
106
122
|
key={i}
|
|
107
123
|
name={n}
|
|
108
124
|
doNotShowCuts
|
|
109
|
-
|
|
125
|
+
/>
|
|
110
126
|
);
|
|
111
127
|
})}
|
|
112
128
|
</div>
|
|
@@ -117,14 +133,6 @@ export default function SingleEnzymeCutsiteInfo({
|
|
|
117
133
|
);
|
|
118
134
|
}
|
|
119
135
|
|
|
120
|
-
const schema = {
|
|
121
|
-
fields: [
|
|
122
|
-
{ path: "topSnipPosition", displayName: "Top Snip", type: "string" },
|
|
123
|
-
{ path: "position", type: "string" },
|
|
124
|
-
{ path: "strand", type: "string" }
|
|
125
|
-
]
|
|
126
|
-
};
|
|
127
|
-
|
|
128
136
|
// export default compose(
|
|
129
137
|
// withEditorProps,
|
|
130
138
|
// withRestrictionEnzymes
|