@teselagen/ove 0.7.3-beta.6 → 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/AlignmentView/index.d.ts +0 -4
- package/DigestTool/DigestTool.d.ts +1 -1
- package/helperComponents/PropertiesDialog/index.d.ts +2 -7
- package/index.cjs.js +6573 -1325
- package/index.es.js +6574 -1326
- package/index.umd.js +6565 -1306
- package/package.json +2 -3
- package/src/AlignmentView/index.js +83 -45
- 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/Keyboard.js +2 -2
- package/src/withEditorInteractions/index.js +18 -10
- package/utils/useFormValue.d.ts +1 -0
- package/withEditorInteractions/Keyboard.d.ts +2 -2
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",
|
|
@@ -34,7 +34,6 @@
|
|
|
34
34
|
"buffer": "5.7.1",
|
|
35
35
|
"bufferpack": "0.0.6",
|
|
36
36
|
"classnames": "^2.3.2",
|
|
37
|
-
"clipboard": "2.0.8",
|
|
38
37
|
"color": "^3.2.1",
|
|
39
38
|
"combokeys": "^3.0.1",
|
|
40
39
|
"copy-to-clipboard": "^3.3.1",
|
|
@@ -4,7 +4,6 @@ import {
|
|
|
4
4
|
Droppable,
|
|
5
5
|
Draggable as DndDraggable
|
|
6
6
|
} from "@hello-pangea/dnd";
|
|
7
|
-
import * as ClipboardJS from "clipboard";
|
|
8
7
|
import React from "react";
|
|
9
8
|
import { connect } from "react-redux";
|
|
10
9
|
import {
|
|
@@ -1213,16 +1212,30 @@ export class AlignmentView extends React.Component {
|
|
|
1213
1212
|
this.copyAllAlignmentsFastaClipboardHelper.destroy();
|
|
1214
1213
|
},
|
|
1215
1214
|
didMount: () => {
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1215
|
+
const elements = document.querySelectorAll(
|
|
1216
|
+
`.copyAllAlignmentsFastaClipboardHelper`
|
|
1217
|
+
);
|
|
1218
|
+
|
|
1219
|
+
elements.forEach(element => {
|
|
1220
|
+
element.addEventListener(
|
|
1221
|
+
"click",
|
|
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
|
+
);
|
|
1223
1235
|
}
|
|
1224
1236
|
}
|
|
1225
1237
|
);
|
|
1238
|
+
});
|
|
1226
1239
|
},
|
|
1227
1240
|
onClick: () => {
|
|
1228
1241
|
window.toastr.success("Selection Copied");
|
|
@@ -1238,29 +1251,42 @@ export class AlignmentView extends React.Component {
|
|
|
1238
1251
|
this.copySpecificAlignmentFastaClipboardHelper.destroy();
|
|
1239
1252
|
},
|
|
1240
1253
|
didMount: () => {
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
] || {};
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1254
|
+
const elements = document.querySelectorAll(
|
|
1255
|
+
`.copySpecificAlignmentFastaClipboardHelper`
|
|
1256
|
+
);
|
|
1257
|
+
|
|
1258
|
+
elements.forEach(element => {
|
|
1259
|
+
element.addEventListener(
|
|
1260
|
+
"click",
|
|
1261
|
+
async () => {
|
|
1262
|
+
const { selectionLayer } =
|
|
1263
|
+
this.props.store.getState()
|
|
1264
|
+
.VectorEditor.__allEditorsOptions
|
|
1265
|
+
.alignments[this.props.id] || {};
|
|
1266
|
+
|
|
1267
|
+
const seqDataToCopy =
|
|
1268
|
+
getSequenceDataBetweenRange(
|
|
1269
|
+
alignmentData,
|
|
1270
|
+
selectionLayer
|
|
1271
|
+
).sequence;
|
|
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
|
+
);
|
|
1260
1284
|
}
|
|
1261
1285
|
}
|
|
1262
1286
|
);
|
|
1287
|
+
});
|
|
1263
1288
|
},
|
|
1289
|
+
|
|
1264
1290
|
onClick: () => {
|
|
1265
1291
|
window.toastr.success(
|
|
1266
1292
|
"Selection Copied As Fasta"
|
|
@@ -1277,28 +1303,40 @@ export class AlignmentView extends React.Component {
|
|
|
1277
1303
|
this.copySpecificAlignmentAsPlainClipboardHelper.destroy();
|
|
1278
1304
|
},
|
|
1279
1305
|
didMount: () => {
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
] || {};
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1306
|
+
const elements = document.querySelectorAll(
|
|
1307
|
+
`.copySpecificAlignmentAsPlainClipboardHelper`
|
|
1308
|
+
);
|
|
1309
|
+
|
|
1310
|
+
elements.forEach(element => {
|
|
1311
|
+
element.addEventListener(
|
|
1312
|
+
"click",
|
|
1313
|
+
async () => {
|
|
1314
|
+
const { selectionLayer } =
|
|
1315
|
+
this.props.store.getState()
|
|
1316
|
+
.VectorEditor.__allEditorsOptions
|
|
1317
|
+
.alignments[this.props.id] || {};
|
|
1318
|
+
|
|
1319
|
+
const seqDataToCopy =
|
|
1320
|
+
getSequenceDataBetweenRange(
|
|
1321
|
+
alignmentData,
|
|
1322
|
+
selectionLayer
|
|
1323
|
+
).sequence;
|
|
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
|
+
);
|
|
1298
1334
|
}
|
|
1299
1335
|
}
|
|
1300
1336
|
);
|
|
1337
|
+
});
|
|
1301
1338
|
},
|
|
1339
|
+
|
|
1302
1340
|
onClick: () => {
|
|
1303
1341
|
window.toastr.success("Selection Copied");
|
|
1304
1342
|
}
|
|
@@ -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