@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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@teselagen/ove",
3
- "version": "0.7.3-beta.6",
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.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,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
- this.copyAllAlignmentsFastaClipboardHelper =
1217
- new ClipboardJS(
1218
- `.copyAllAlignmentsFastaClipboardHelper`,
1219
- {
1220
- action: "copyAllAlignmentsFasta",
1221
- text: () => {
1222
- return this.getAllAlignmentsFastaText();
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
- this.copySpecificAlignmentFastaClipboardHelper =
1242
- new ClipboardJS(
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;
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
- this.copySpecificAlignmentAsPlainClipboardHelper =
1281
- new ClipboardJS(
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;
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
  }
@@ -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