@teselagen/ove 0.8.22 → 0.8.25

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,8 +1,9 @@
1
1
  {
2
2
  "name": "@teselagen/ove",
3
- "version": "0.8.22",
3
+ "version": "0.8.25",
4
4
  "main": "./src/index.js",
5
5
  "type": "module",
6
+ "repository": "https://github.com/TeselaGen/tg-oss",
6
7
  "exports": {
7
8
  ".": {
8
9
  "import": "./index.es.js",
@@ -14,12 +15,12 @@
14
15
  "@blueprintjs/core": "3.54.0",
15
16
  "@hello-pangea/dnd": "16.2.0",
16
17
  "@risingstack/react-easy-state": "^6.3.0",
17
- "@teselagen/bio-parsers": "0.4.32",
18
+ "@teselagen/bio-parsers": "0.4.33",
18
19
  "@teselagen/file-utils": "0.3.20",
19
- "@teselagen/range-utils": "0.3.13",
20
+ "@teselagen/range-utils": "0.3.19",
20
21
  "@teselagen/react-list": "0.8.18",
21
- "@teselagen/sequence-utils": "0.3.36",
22
- "@teselagen/ui": "0.10.10",
22
+ "@teselagen/sequence-utils": "0.3.41",
23
+ "@teselagen/ui": "0.10.16",
23
24
  "@use-gesture/react": "10.3.0",
24
25
  "biomsa": "^0.2.4",
25
26
  "classnames": "^2.3.2",
@@ -62,6 +63,5 @@
62
63
  "to-regex-range": "5.0.1",
63
64
  "use-debounce": "^8.0.4",
64
65
  "validate.io-nonnegative-integer-array": "^1.0.1"
65
- },
66
- "license": "MIT"
67
- }
66
+ }
67
+ }
@@ -8,7 +8,7 @@ declare const _default: ((state: any) => {
8
8
  annotationTypePlural: string;
9
9
  isOrf: boolean;
10
10
  id: any;
11
- }[]) & import('reselect').OutputSelectorFields<(args_0: any, args_1: any, args_2: any, args_3: any) => {
11
+ }[]) & import('reselect').OutputSelectorFields<(args_0: any, args_1: any, args_2: any, args_3: any, args_4: any) => {
12
12
  start: number;
13
13
  end: number;
14
14
  length: number;
@@ -104,32 +104,34 @@ class _LinearView extends React.Component {
104
104
  } = this.props;
105
105
  // if (!isEqual(sequenceData, this.oldSeqData)) {
106
106
  this.paredDownMessages = [];
107
- const paredDownSeqData = ["parts", "features", "cutsites"].reduce(
108
- (acc, type) => {
109
- const nameUpper = startCase(type);
110
- const maxToShow =
111
- (maxAnnotationsToDisplay
112
- ? maxAnnotationsToDisplay[type]
113
- : limits[type]) || 50;
114
- const [annotations, paredDown] = pareDownAnnotations(
115
- sequenceData["filtered" + nameUpper] || sequenceData[type] || {},
116
- maxToShow
117
- );
107
+ const paredDownSeqData = [
108
+ "parts",
109
+ "features",
110
+ "cutsites",
111
+ "primers"
112
+ ].reduce((acc, type) => {
113
+ const nameUpper = startCase(type);
114
+ const maxToShow =
115
+ (maxAnnotationsToDisplay
116
+ ? maxAnnotationsToDisplay[type]
117
+ : limits[type]) || 50;
118
+ const [annotations, paredDown] = pareDownAnnotations(
119
+ sequenceData["filtered" + nameUpper] || sequenceData[type] || {},
120
+ maxToShow
121
+ );
118
122
 
119
- if (paredDown) {
120
- this.paredDownMessages.push(
121
- getParedDownWarning({
122
- nameUpper,
123
- isAdjustable: !maxAnnotationsToDisplay,
124
- maxToShow
125
- })
126
- );
127
- }
128
- acc[type] = annotations;
129
- return acc;
130
- },
131
- {}
132
- );
123
+ if (paredDown) {
124
+ this.paredDownMessages.push(
125
+ getParedDownWarning({
126
+ nameUpper,
127
+ isAdjustable: !maxAnnotationsToDisplay,
128
+ maxToShow
129
+ })
130
+ );
131
+ }
132
+ acc[type] = annotations;
133
+ return acc;
134
+ }, {});
133
135
  this.rowData = prepareRowData(
134
136
  {
135
137
  ...sequenceData,
@@ -8,7 +8,8 @@ import {
8
8
  DropdownButton,
9
9
  createCommandMenu,
10
10
  popoverOverflowModifiers,
11
- removeDuplicatesIcon
11
+ removeDuplicatesIcon,
12
+ useMemoDeepEqual
12
13
  } from "@teselagen/ui";
13
14
  import { map, upperFirst, pick, startCase, isFunction } from "lodash-es";
14
15
  import {
@@ -41,69 +42,79 @@ const genericAnnotationProperties = ({
41
42
  additionalFooterEls
42
43
  }) => {
43
44
  const annotationTypeUpper = upperFirst(annotationType);
44
- class AnnotationProperties extends React.Component {
45
- constructor(props) {
46
- super(props);
47
- this.commands = commands(this);
48
- }
49
- onRowSelect = ([record]) => {
50
- if (!record) return;
51
- const { dispatch, editorName } = this.props;
52
- dispatch({
53
- type: "SELECTION_LAYER_UPDATE",
54
- payload: record,
55
- meta: {
56
- editorName
57
- }
58
- });
59
- };
60
- render() {
61
- const {
62
- readOnly,
63
- annotations = {},
64
- annotationVisibility,
65
- sequenceLength,
66
- selectionLayer,
67
- sequence,
68
- isProtein,
69
- allPartTags,
70
- annotationPropertiesSelectedEntities:
71
- _annotationPropertiesSelectedEntities,
72
- selectedAnnotationId,
73
- PropertiesProps
74
- } = this.props;
75
- const annotationPropertiesSelectedEntities =
76
- _annotationPropertiesSelectedEntities.filter(a => annotations[a.id]);
45
+ const AnnotationProperties = props => {
46
+ const {
47
+ readOnly,
48
+ annotations = {},
49
+ annotationVisibility,
50
+ sequenceLength,
51
+ selectionLayer,
52
+ sequence,
53
+ isProtein,
54
+ allPartTags,
55
+ annotationPropertiesSelectedEntities:
56
+ _annotationPropertiesSelectedEntities,
57
+ selectedAnnotationId,
58
+ PropertiesProps,
59
+ dispatch,
60
+ editorName
61
+ } = props;
77
62
 
78
- const deleteAnnotation = this.props[`delete${annotationTypeUpper}`];
63
+ // We need to keep a ref to the props so that the commands factory (old code) works
64
+ const instanceRef = React.useRef({ props });
65
+ instanceRef.current.props = props;
66
+ const cmds = React.useMemo(() => commands(instanceRef.current), []);
79
67
 
80
- const annotationsToUse = map(annotations, annotation => {
81
- return {
82
- ...annotation,
83
- ...(annotation.strand === undefined && {
84
- strand: annotation.forward ? 1 : -1
85
- }),
86
- size: getRangeLength(annotation, sequenceLength)
87
- };
88
- });
68
+ const onRowSelect = React.useCallback(
69
+ ([record]) => {
70
+ if (!record) return;
71
+ dispatch({
72
+ type: "SELECTION_LAYER_UPDATE",
73
+ payload: record,
74
+ meta: {
75
+ editorName
76
+ }
77
+ });
78
+ },
79
+ [dispatch, editorName]
80
+ );
81
+
82
+ const annotationPropertiesSelectedEntities =
83
+ _annotationPropertiesSelectedEntities.filter(a => annotations[a.id]);
89
84
 
90
- const keyedPartTags = getKeyedTagsAndTagOptions(allPartTags) ?? {};
91
- const additionalColumns =
92
- PropertiesProps?.propertiesList?.find(
93
- p => (p.name || p) === (pluralize(annotationType) || "")
94
- )?.additionalColumns || [];
85
+ const deleteAnnotation = props[`delete${annotationTypeUpper}`];
95
86
 
96
- this.schema = {
87
+ const annotationsToUse = React.useMemo(
88
+ () =>
89
+ map(annotations, annotation => {
90
+ return {
91
+ ...annotation,
92
+ ...(annotation.strand === undefined && {
93
+ strand: annotation.forward ? 1 : -1
94
+ }),
95
+ size: getRangeLength(annotation, sequenceLength)
96
+ };
97
+ }),
98
+ [annotations, sequenceLength]
99
+ );
100
+
101
+ const keyedPartTags = getKeyedTagsAndTagOptions(allPartTags) ?? {};
102
+ const additionalColumns =
103
+ PropertiesProps?.propertiesList?.find(
104
+ p => (p.name || p) === (pluralize(annotationType) || "")
105
+ )?.additionalColumns || [];
106
+
107
+ const schema = useMemoDeepEqual(
108
+ () => ({
97
109
  fields: [
98
110
  {
99
111
  path: "name",
100
112
  type: "string",
101
-
102
113
  render: (name, ann) => {
103
114
  const checked =
104
- !this.props.annotationVisibility[
105
- `${annotationType}IndividualToHide`
106
- ][ann.id];
115
+ !annotationVisibility[`${annotationType}IndividualToHide`][
116
+ ann.id
117
+ ];
107
118
 
108
119
  return (
109
120
  <>
@@ -113,9 +124,9 @@ const genericAnnotationProperties = ({
113
124
  e.stopPropagation();
114
125
  const upperType = startCase(annotationType);
115
126
  if (checked) {
116
- this.props[`hide${upperType}Individual`]([ann.id]);
127
+ props[`hide${upperType}Individual`]([ann.id]);
117
128
  } else {
118
- this.props[`show${upperType}Individual`]([ann.id]);
129
+ props[`show${upperType}Individual`]([ann.id]);
119
130
  }
120
131
  }}
121
132
  style={{
@@ -131,7 +142,6 @@ const genericAnnotationProperties = ({
131
142
  );
132
143
  }
133
144
  },
134
-
135
145
  ...(!withBases
136
146
  ? []
137
147
  : [
@@ -141,7 +151,7 @@ const genericAnnotationProperties = ({
141
151
  render: (bases, primer) => {
142
152
  let bps = bases;
143
153
  if (!bases) {
144
- bps = getSequenceWithinRange(primer, this.props.sequence);
154
+ bps = getSequenceWithinRange(primer, sequence);
145
155
  if (!primer.forward) {
146
156
  bps = getReverseComplementSequenceString(bps);
147
157
  }
@@ -170,8 +180,8 @@ const genericAnnotationProperties = ({
170
180
  }
171
181
  }
172
182
  ]),
173
- sizeSchema(this.props.isProtein),
174
- ...(withTags && this.props.allPartTags
183
+ sizeSchema(isProtein),
184
+ ...(withTags && allPartTags
175
185
  ? [
176
186
  {
177
187
  path: "tags",
@@ -203,159 +213,163 @@ const genericAnnotationProperties = ({
203
213
  { path: "strand", type: "number" },
204
214
  ...additionalColumns
205
215
  ]
206
- };
216
+ }),
217
+ [
218
+ additionalColumns,
219
+ allPartTags,
220
+ annotationVisibility,
221
+ isProtein,
222
+ keyedPartTags,
223
+ sequence
224
+ ]
225
+ );
207
226
 
208
- return (
209
- <DataTable
210
- topLeftItems={getVisFilter(
211
- createCommandMenu(
212
- isFunction(visSubmenu) ? visSubmenu(this.props) : visSubmenu,
213
- this.commands,
214
- {
215
- useTicks: true
216
- }
217
- )
218
- )}
219
- annotationPropertiesSelectedEntities={
220
- annotationPropertiesSelectedEntities
221
- }
222
- leftOfSearchBarItems={
223
- <>
224
- {!readOnly && (
225
- <ButtonGroup style={{ marginTop: 3, marginRight: 4 }}>
226
- <Tooltip
227
- position="top"
228
- modifiers={popoverOverflowModifiers}
229
- content="New"
230
- >
231
- <AnchorButton
232
- disabled={!sequenceLength}
233
- icon="plus"
234
- className="tgNewAnnBtn"
235
- onClick={() => {
236
- showAddOrEditAnnotationDialog({
237
- type: annotationType,
238
- annotation: pick(
239
- selectionLayer,
240
- "start",
241
- "end",
242
- "forward"
243
- )
244
- });
245
- }}
246
- ></AnchorButton>
247
- </Tooltip>
248
- <Tooltip
249
- position="top"
250
- modifiers={popoverOverflowModifiers}
251
- content="Edit"
252
- >
253
- <AnchorButton
254
- onClick={() => {
255
- showAddOrEditAnnotationDialog({
256
- type: annotationType,
257
- annotation: annotationPropertiesSelectedEntities[0]
258
- });
259
- }}
260
- disabled={
261
- annotationPropertiesSelectedEntities.length !== 1
262
- }
263
- icon="edit"
264
- ></AnchorButton>
265
- </Tooltip>
227
+ return (
228
+ <DataTable
229
+ topLeftItems={getVisFilter(
230
+ createCommandMenu(
231
+ isFunction(visSubmenu) ? visSubmenu(props) : visSubmenu,
232
+ cmds,
233
+ {
234
+ useTicks: true
235
+ }
236
+ )
237
+ )}
238
+ annotationPropertiesSelectedEntities={
239
+ annotationPropertiesSelectedEntities
240
+ }
241
+ leftOfSearchBarItems={
242
+ <>
243
+ {!readOnly && (
244
+ <ButtonGroup style={{ marginTop: 3, marginRight: 4 }}>
245
+ <Tooltip
246
+ position="top"
247
+ modifiers={popoverOverflowModifiers}
248
+ content="New"
249
+ >
250
+ <AnchorButton
251
+ disabled={!sequenceLength}
252
+ icon="plus"
253
+ className="tgNewAnnBtn"
254
+ onClick={() => {
255
+ showAddOrEditAnnotationDialog({
256
+ type: annotationType,
257
+ annotation: pick(
258
+ selectionLayer,
259
+ "start",
260
+ "end",
261
+ "forward"
262
+ )
263
+ });
264
+ }}
265
+ ></AnchorButton>
266
+ </Tooltip>
267
+ <Tooltip
268
+ position="top"
269
+ modifiers={popoverOverflowModifiers}
270
+ content="Edit"
271
+ >
272
+ <AnchorButton
273
+ onClick={() => {
274
+ showAddOrEditAnnotationDialog({
275
+ type: annotationType,
276
+ annotation: annotationPropertiesSelectedEntities[0]
277
+ });
278
+ }}
279
+ disabled={annotationPropertiesSelectedEntities.length !== 1}
280
+ icon="edit"
281
+ ></AnchorButton>
282
+ </Tooltip>
266
283
 
267
- {["feature"].includes(annotationType) && (
268
- <CmdButton
269
- text=""
270
- icon="cog"
271
- data-tip="Configure Feature Types"
272
- cmd={this.commands.onConfigureFeatureTypesClick}
273
- />
274
- )}
275
- {["part", "primer", "feature"].includes(annotationType) && (
276
- <CmdButton
277
- text=""
278
- icon={removeDuplicatesIcon}
279
- data-tip="Remove Duplicates"
280
- cmd={
281
- this.commands[
282
- `showRemoveDuplicatesDialog${
283
- annotationTypeUpper + "s"
284
- }`
285
- ]
286
- }
287
- />
288
- )}
284
+ {["feature"].includes(annotationType) && (
285
+ <CmdButton
286
+ text=""
287
+ icon="cog"
288
+ data-tip="Configure Feature Types"
289
+ cmd={cmds.onConfigureFeatureTypesClick}
290
+ />
291
+ )}
292
+ {["part", "primer", "feature"].includes(annotationType) && (
293
+ <CmdButton
294
+ text=""
295
+ icon={removeDuplicatesIcon}
296
+ data-tip="Remove Duplicates"
297
+ cmd={
298
+ cmds[
299
+ `showRemoveDuplicatesDialog${annotationTypeUpper + "s"}`
300
+ ]
301
+ }
302
+ />
303
+ )}
289
304
 
290
- {additionalFooterEls && additionalFooterEls(this.props)}
291
- <Tooltip
292
- position="top"
293
- modifiers={popoverOverflowModifiers}
294
- content="Delete"
295
- >
296
- <AnchorButton
297
- onClick={() => {
298
- deleteAnnotation(annotationPropertiesSelectedEntities);
299
- }}
300
- className="tgDeleteAnnsBtn"
301
- intent="danger"
302
- disabled={!annotationPropertiesSelectedEntities.length}
303
- icon="trash"
304
- ></AnchorButton>
305
- </Tooltip>
306
- </ButtonGroup>
307
- )}
308
- {/* {createCommandMenu(
309
- {
310
- cmd: "featureFilterIndividualCmd",
311
- // text: 'hahah',
312
- shouldDismissPopover: false
313
- },
314
- this.commands,
315
- {
316
- useTicks: true
317
- }
318
- )} */}
319
- {/* <CmdCheckbox
320
- prefix="Show "
321
- cmd={this.commands.featureFilterIndividualCmd}
322
- /> */}
323
- </>
324
- }
325
- onDoubleClick={annotation => {
326
- showAddOrEditAnnotationDialog({
327
- type: annotationType,
328
- annotation
329
- });
330
- }}
331
- withCheckboxes
332
- showFeatureIndividual={this.props.showFeatureIndividual} //we need to pass this in order to force the DT to rerenderannotationVisibility={annotationVisibility}
333
- hideFeatureIndividual={this.props.hideFeatureIndividual} //we need to pass this in order to force the DT to rerenderannotationVisibility={annotationVisibility}
334
- showPartIndividual={this.props.showPartIndividual} //we need to pass this in order to force the DT to rerenderannotationVisibility={annotationVisibility}
335
- hidePartIndividual={this.props.hidePartIndividual} //we need to pass this in order to force the DT to rerenderannotationVisibility={annotationVisibility}
336
- showPrimerIndividual={this.props.showPrimerIndividual} //we need to pass this in order to force the DT to rerenderannotationVisibility={annotationVisibility}
337
- hidePrimerIndividual={this.props.hidePrimerIndividual} //we need to pass this in order to force the DT to rerenderannotationVisibility={annotationVisibility}
338
- annotationVisibility={annotationVisibility} //we need to pass this in order to force the DT to rerenderannotationVisibility={annotationVisibility}
339
- featureLengthsToHide={this.props.featureLengthsToHide} //we need to pass this in order to force the DT to rerenderannotationVisibility={annotationVisibility}
340
- primerLengthsToHide={this.props.primerLengthsToHide} //we need to pass this in order to force the DT to rerenderannotationVisibility={annotationVisibility}
341
- partLengthsToHide={this.props.partLengthsToHide} //we need to pass this in order to force the DT to rerenderannotationVisibility={annotationVisibility}
342
- sequence={sequence} //we need to pass this in order to force the DT to rerenderannotationVisibility={annotationVisibility}
343
- noPadding
344
- noFullscreenButton
345
- onRowSelect={this.onRowSelect}
346
- selectedIds={selectedAnnotationId}
347
- formName="annotationProperties"
348
- noRouter
349
- isProtein={isProtein}
350
- compact
351
- isInfinite
352
- withDisplayOptions
353
- schema={this.schema}
354
- entities={annotationsToUse}
355
- />
356
- );
357
- }
358
- }
305
+ {additionalFooterEls && additionalFooterEls(props)}
306
+ <Tooltip
307
+ position="top"
308
+ modifiers={popoverOverflowModifiers}
309
+ content="Delete"
310
+ >
311
+ <AnchorButton
312
+ onClick={() => {
313
+ deleteAnnotation(annotationPropertiesSelectedEntities);
314
+ }}
315
+ className="tgDeleteAnnsBtn"
316
+ intent="danger"
317
+ disabled={!annotationPropertiesSelectedEntities.length}
318
+ icon="trash"
319
+ ></AnchorButton>
320
+ </Tooltip>
321
+ </ButtonGroup>
322
+ )}
323
+ {/* {createCommandMenu(
324
+ {
325
+ cmd: "featureFilterIndividualCmd",
326
+ // text: 'hahah',
327
+ shouldDismissPopover: false
328
+ },
329
+ cmds,
330
+ {
331
+ useTicks: true
332
+ }
333
+ )} */}
334
+ {/* <CmdCheckbox
335
+ prefix="Show "
336
+ cmd={cmds.featureFilterIndividualCmd}
337
+ /> */}
338
+ </>
339
+ }
340
+ onDoubleClick={annotation => {
341
+ showAddOrEditAnnotationDialog({
342
+ type: annotationType,
343
+ annotation
344
+ });
345
+ }}
346
+ withCheckboxes
347
+ showFeatureIndividual={props.showFeatureIndividual} //we need to pass this in order to force the DT to rerenderannotationVisibility={annotationVisibility}
348
+ hideFeatureIndividual={props.hideFeatureIndividual} //we need to pass this in order to force the DT to rerenderannotationVisibility={annotationVisibility}
349
+ showPartIndividual={props.showPartIndividual} //we need to pass this in order to force the DT to rerenderannotationVisibility={annotationVisibility}
350
+ hidePartIndividual={props.hidePartIndividual} //we need to pass this in order to force the DT to rerenderannotationVisibility={annotationVisibility}
351
+ showPrimerIndividual={props.showPrimerIndividual} //we need to pass this in order to force the DT to rerenderannotationVisibility={annotationVisibility}
352
+ hidePrimerIndividual={props.hidePrimerIndividual} //we need to pass this in order to force the DT to rerenderannotationVisibility={annotationVisibility}
353
+ annotationVisibility={annotationVisibility} //we need to pass this in order to force the DT to rerenderannotationVisibility={annotationVisibility}
354
+ featureLengthsToHide={props.featureLengthsToHide} //we need to pass this in order to force the DT to rerenderannotationVisibility={annotationVisibility}
355
+ primerLengthsToHide={props.primerLengthsToHide} //we need to pass this in order to force the DT to rerenderannotationVisibility={annotationVisibility}
356
+ partLengthsToHide={props.partLengthsToHide} //we need to pass this in order to force the DT to rerenderannotationVisibility={annotationVisibility}
357
+ sequence={sequence} //we need to pass this in order to force the DT to rerenderannotationVisibility={annotationVisibility}
358
+ noPadding
359
+ noFullscreenButton
360
+ onRowSelect={onRowSelect}
361
+ selectedIds={selectedAnnotationId}
362
+ formName="annotationProperties"
363
+ noRouter
364
+ isProtein={isProtein}
365
+ compact
366
+ isInfinite
367
+ withDisplayOptions
368
+ schema={schema}
369
+ entities={annotationsToUse}
370
+ />
371
+ );
372
+ };
359
373
 
360
374
  return compose(
361
375
  connectToEditor(
@@ -9,6 +9,7 @@ export default createSelector(
9
9
  circularSelector,
10
10
  minimumOrfSizeSelector,
11
11
  state => state.useAdditionalOrfStartCodons,
12
+ state => state.sequenceData?.isProtein || state.sequenceData?.isOligo,
12
13
  findOrfsInPlasmid
13
14
  );
14
15