@teselagen/ove 0.7.3-beta.7 → 0.7.4
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/AlignmentView/index.d.ts +4 -0
- package/DigestTool/DigestTool.d.ts +1 -1
- package/helperComponents/PropertiesDialog/index.d.ts +2 -7
- package/index.cjs.js +7219 -581
- package/index.es.js +7208 -570
- package/index.umd.js +7216 -560
- package/package.json +3 -2
- package/src/AlignmentView/index.js +45 -83
- 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 +18 -20
- 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
|
+
"version": "0.7.4",
|
|
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",
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
"buffer": "5.7.1",
|
|
35
35
|
"bufferpack": "0.0.6",
|
|
36
36
|
"classnames": "^2.3.2",
|
|
37
|
+
"clipboard": "2.0.11",
|
|
37
38
|
"color": "^3.2.1",
|
|
38
39
|
"combokeys": "^3.0.1",
|
|
39
40
|
"copy-to-clipboard": "^3.3.1",
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
Droppable,
|
|
5
5
|
Draggable as DndDraggable
|
|
6
6
|
} from "@hello-pangea/dnd";
|
|
7
|
+
import Clipboard from "clipboard";
|
|
7
8
|
import React from "react";
|
|
8
9
|
import { connect } from "react-redux";
|
|
9
10
|
import {
|
|
@@ -1212,30 +1213,16 @@ export class AlignmentView extends React.Component {
|
|
|
1212
1213
|
this.copyAllAlignmentsFastaClipboardHelper.destroy();
|
|
1213
1214
|
},
|
|
1214
1215
|
didMount: () => {
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
async () => {
|
|
1223
|
-
const textToCopy =
|
|
1224
|
-
this.getAllAlignmentsFastaText();
|
|
1225
|
-
|
|
1226
|
-
try {
|
|
1227
|
-
await navigator.clipboard.writeText(
|
|
1228
|
-
textToCopy
|
|
1229
|
-
);
|
|
1230
|
-
} catch (err) {
|
|
1231
|
-
console.error(
|
|
1232
|
-
"Failed to copy text:",
|
|
1233
|
-
err
|
|
1234
|
-
);
|
|
1216
|
+
this.copyAllAlignmentsFastaClipboardHelper =
|
|
1217
|
+
new Clipboard(
|
|
1218
|
+
`.copyAllAlignmentsFastaClipboardHelper`,
|
|
1219
|
+
{
|
|
1220
|
+
action: "copyAllAlignmentsFasta",
|
|
1221
|
+
text: () => {
|
|
1222
|
+
return this.getAllAlignmentsFastaText();
|
|
1235
1223
|
}
|
|
1236
1224
|
}
|
|
1237
1225
|
);
|
|
1238
|
-
});
|
|
1239
1226
|
},
|
|
1240
1227
|
onClick: () => {
|
|
1241
1228
|
window.toastr.success("Selection Copied");
|
|
@@ -1251,42 +1238,29 @@ export class AlignmentView extends React.Component {
|
|
|
1251
1238
|
this.copySpecificAlignmentFastaClipboardHelper.destroy();
|
|
1252
1239
|
},
|
|
1253
1240
|
didMount: () => {
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
const seqDataToCopyAsFasta = `>${name}\r\n${seqDataToCopy}\r\n`;
|
|
1274
|
-
|
|
1275
|
-
try {
|
|
1276
|
-
await navigator.clipboard.writeText(
|
|
1277
|
-
seqDataToCopyAsFasta
|
|
1278
|
-
);
|
|
1279
|
-
} catch (err) {
|
|
1280
|
-
console.error(
|
|
1281
|
-
"Failed to copy text:",
|
|
1282
|
-
err
|
|
1283
|
-
);
|
|
1241
|
+
this.copySpecificAlignmentFastaClipboardHelper =
|
|
1242
|
+
new Clipboard(
|
|
1243
|
+
`.copySpecificAlignmentFastaClipboardHelper`,
|
|
1244
|
+
{
|
|
1245
|
+
action: "copySpecificAlignmentFasta",
|
|
1246
|
+
text: () => {
|
|
1247
|
+
const { selectionLayer } =
|
|
1248
|
+
this.props.store.getState()
|
|
1249
|
+
.VectorEditor
|
|
1250
|
+
.__allEditorsOptions.alignments[
|
|
1251
|
+
this.props.id
|
|
1252
|
+
] || {};
|
|
1253
|
+
const seqDataToCopy =
|
|
1254
|
+
getSequenceDataBetweenRange(
|
|
1255
|
+
alignmentData,
|
|
1256
|
+
selectionLayer
|
|
1257
|
+
).sequence;
|
|
1258
|
+
const seqDataToCopyAsFasta = `>${name}\r\n${seqDataToCopy}\r\n`;
|
|
1259
|
+
return seqDataToCopyAsFasta;
|
|
1284
1260
|
}
|
|
1285
1261
|
}
|
|
1286
1262
|
);
|
|
1287
|
-
});
|
|
1288
1263
|
},
|
|
1289
|
-
|
|
1290
1264
|
onClick: () => {
|
|
1291
1265
|
window.toastr.success(
|
|
1292
1266
|
"Selection Copied As Fasta"
|
|
@@ -1303,40 +1277,28 @@ export class AlignmentView extends React.Component {
|
|
|
1303
1277
|
this.copySpecificAlignmentAsPlainClipboardHelper.destroy();
|
|
1304
1278
|
},
|
|
1305
1279
|
didMount: () => {
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
try {
|
|
1326
|
-
await navigator.clipboard.writeText(
|
|
1327
|
-
seqDataToCopy
|
|
1328
|
-
);
|
|
1329
|
-
} catch (err) {
|
|
1330
|
-
console.error(
|
|
1331
|
-
"Failed to copy text:",
|
|
1332
|
-
err
|
|
1333
|
-
);
|
|
1280
|
+
this.copySpecificAlignmentAsPlainClipboardHelper =
|
|
1281
|
+
new Clipboard(
|
|
1282
|
+
`.copySpecificAlignmentAsPlainClipboardHelper`,
|
|
1283
|
+
{
|
|
1284
|
+
action: "copySpecificAlignmentFasta",
|
|
1285
|
+
text: () => {
|
|
1286
|
+
const { selectionLayer } =
|
|
1287
|
+
this.props.store.getState()
|
|
1288
|
+
.VectorEditor
|
|
1289
|
+
.__allEditorsOptions.alignments[
|
|
1290
|
+
this.props.id
|
|
1291
|
+
] || {};
|
|
1292
|
+
const seqDataToCopy =
|
|
1293
|
+
getSequenceDataBetweenRange(
|
|
1294
|
+
alignmentData,
|
|
1295
|
+
selectionLayer
|
|
1296
|
+
).sequence;
|
|
1297
|
+
return seqDataToCopy;
|
|
1334
1298
|
}
|
|
1335
1299
|
}
|
|
1336
1300
|
);
|
|
1337
|
-
});
|
|
1338
1301
|
},
|
|
1339
|
-
|
|
1340
1302
|
onClick: () => {
|
|
1341
1303
|
window.toastr.success("Selection Copied");
|
|
1342
1304
|
}
|
|
@@ -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