@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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@teselagen/ove",
3
- "version": "0.7.3-beta.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.3-beta.5",
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
- 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
- );
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
- 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
- );
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
- 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
- );
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
  }
@@ -48,7 +48,7 @@ export default compose(
48
48
  }))}
49
49
  withCheckboxes
50
50
  schema={annotationType === "feature" ? schemaFeatures : schemaOther}
51
- ></DataTable>
51
+ />
52
52
  </div>
53
53
  <DialogFooter
54
54
  hideModal={hideDialog}
@@ -1,13 +1,8 @@
1
- // import uniqid from "shortid";
2
- // import Ladder from "./Ladder";
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={({ onFragmentSelect }) => {
141
- onFragmentSelect();
142
- }}
203
+ onSingleRowSelect={onSingleSelectRow}
143
204
  formName="digestInfoTable"
144
- entities={lanes[0].map(
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 compose(
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);
@@ -43,6 +43,7 @@ export function hideDialog() {
43
43
  delete dialogHolder.CustomModalComponent;
44
44
  delete dialogHolder.props;
45
45
  delete dialogHolder.overrideName;
46
+ delete dialogHolder.editorName;
46
47
  dialogHolder.setUniqKeyToForceRerender();
47
48
  }
48
49