@apollo-annotation/jbrowse-plugin-apollo 0.3.4 → 0.3.5

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.
Files changed (44) hide show
  1. package/dist/index.esm.js +1513 -1074
  2. package/dist/index.esm.js.map +1 -1
  3. package/dist/jbrowse-plugin-apollo.cjs.development.js +1510 -1065
  4. package/dist/jbrowse-plugin-apollo.cjs.development.js.map +1 -1
  5. package/dist/jbrowse-plugin-apollo.cjs.production.min.js +1 -1
  6. package/dist/jbrowse-plugin-apollo.cjs.production.min.js.map +1 -1
  7. package/dist/jbrowse-plugin-apollo.umd.development.js +4681 -2097
  8. package/dist/jbrowse-plugin-apollo.umd.development.js.map +1 -1
  9. package/dist/jbrowse-plugin-apollo.umd.production.min.js +1 -1
  10. package/dist/jbrowse-plugin-apollo.umd.production.min.js.map +1 -1
  11. package/package.json +4 -4
  12. package/src/ApolloSequenceAdapter/ApolloSequenceAdapter.ts +13 -0
  13. package/src/FeatureDetailsWidget/ApolloFeatureDetailsWidget.tsx +88 -17
  14. package/src/FeatureDetailsWidget/ApolloTranscriptDetailsWidget.tsx +144 -22
  15. package/src/FeatureDetailsWidget/Attributes.tsx +93 -43
  16. package/src/FeatureDetailsWidget/BasicInformation.tsx +2 -4
  17. package/src/FeatureDetailsWidget/FeatureDetailsNavigation.tsx +6 -4
  18. package/src/FeatureDetailsWidget/Sequence.tsx +16 -33
  19. package/src/FeatureDetailsWidget/TranscriptSequence.tsx +137 -92
  20. package/src/FeatureDetailsWidget/TranscriptWidgetEditLocation.tsx +600 -0
  21. package/src/FeatureDetailsWidget/TranscriptWidgetSummary.tsx +54 -0
  22. package/src/LinearApolloDisplay/components/LinearApolloDisplay.tsx +13 -6
  23. package/src/LinearApolloDisplay/glyphs/BoxGlyph.ts +6 -27
  24. package/src/LinearApolloDisplay/glyphs/GeneGlyph.ts +35 -13
  25. package/src/LinearApolloDisplay/stateModel/layouts.ts +7 -2
  26. package/src/LinearApolloDisplay/stateModel/rendering.ts +4 -0
  27. package/src/OntologyManager/OntologyStore/fulltext-stopwords.ts +10 -1
  28. package/src/OntologyManager/OntologyStore/index.test.ts +1 -0
  29. package/src/OntologyManager/index.ts +2 -0
  30. package/src/SixFrameFeatureDisplay/stateModel.ts +5 -1
  31. package/src/TabularEditor/HybridGrid/Feature.tsx +0 -1
  32. package/src/TabularEditor/HybridGrid/NumberCell.tsx +8 -1
  33. package/src/TabularEditor/HybridGrid/ToolBar.tsx +14 -12
  34. package/src/TabularEditor/HybridGrid/featureContextMenuItems.ts +3 -27
  35. package/src/components/AddAssembly.tsx +608 -291
  36. package/src/components/CreateApolloAnnotation.tsx +144 -37
  37. package/src/components/OntologyTermMultiSelect.tsx +3 -0
  38. package/src/components/index.ts +0 -1
  39. package/src/extensions/annotationFromJBrowseFeature.ts +3 -2
  40. package/src/makeDisplayComponent.tsx +3 -4
  41. package/src/util/annotationFeatureUtils.ts +53 -0
  42. package/src/util/index.ts +1 -0
  43. package/src/FeatureDetailsWidget/TranscriptBasic.tsx +0 -200
  44. package/src/components/ModifyFeatureAttribute.tsx +0 -460
@@ -8,12 +8,7 @@ import {
8
8
  SessionWithWidgets,
9
9
  } from '@jbrowse/core/util'
10
10
 
11
- import {
12
- AddChildFeature,
13
- CopyFeature,
14
- DeleteFeature,
15
- ModifyFeatureAttribute,
16
- } from '../../components'
11
+ import { AddChildFeature, CopyFeature, DeleteFeature } from '../../components'
17
12
 
18
13
  import { LinearApolloDisplay } from '../stateModel'
19
14
  import {
@@ -349,26 +344,6 @@ function getContextMenuItems(
349
344
  )
350
345
  },
351
346
  },
352
- {
353
- label: 'Modify feature attribute',
354
- disabled: readOnly,
355
- onClick: () => {
356
- ;(session as unknown as AbstractSessionModel).queueDialog(
357
- (doneCallback) => [
358
- ModifyFeatureAttribute,
359
- {
360
- session,
361
- handleClose: () => {
362
- doneCallback()
363
- },
364
- changeManager,
365
- sourceFeature,
366
- sourceAssemblyId: currentAssemblyId,
367
- },
368
- ],
369
- )
370
- },
371
- },
372
347
  {
373
348
  label: 'Edit feature details',
374
349
  onClick: () => {
@@ -394,7 +369,11 @@ function getContextMenuItems(
394
369
  throw new Error('featureTypeOntology is undefined')
395
370
  }
396
371
  if (
397
- featureTypeOntology.isTypeOf(sourceFeature.type, 'transcript') &&
372
+ (featureTypeOntology.isTypeOf(sourceFeature.type, 'transcript') ||
373
+ featureTypeOntology.isTypeOf(
374
+ sourceFeature.type,
375
+ 'pseudogenic_transcript',
376
+ )) &&
398
377
  isSessionModelWithWidgets(session)
399
378
  ) {
400
379
  menuItems.push({
@@ -112,10 +112,9 @@ function draw(
112
112
  // Draw lines on different rows for each transcript
113
113
  let currentRow = 0
114
114
  for (const [, transcript] of children) {
115
- const isTranscript = featureTypeOntology.isTypeOf(
116
- transcript.type,
117
- 'transcript',
118
- )
115
+ const isTranscript =
116
+ featureTypeOntology.isTypeOf(transcript.type, 'transcript') ||
117
+ featureTypeOntology.isTypeOf(transcript.type, 'pseudogenic_transcript')
119
118
  if (!isTranscript) {
120
119
  currentRow += 1
121
120
  continue
@@ -161,7 +160,12 @@ function draw(
161
160
  // Draw exon and CDS for each transcript
162
161
  currentRow = 0
163
162
  for (const [, child] of children) {
164
- if (!featureTypeOntology.isTypeOf(child.type, 'transcript')) {
163
+ if (
164
+ !(
165
+ featureTypeOntology.isTypeOf(child.type, 'transcript') ||
166
+ featureTypeOntology.isTypeOf(child.type, 'pseudogenic_transcript')
167
+ )
168
+ ) {
165
169
  boxGlyph.draw(ctx, child, row, stateModel, displayedRegionIndex)
166
170
  currentRow += 1
167
171
  continue
@@ -455,7 +459,11 @@ function getFeatureFromLayout(
455
459
  if (
456
460
  featureTypeOntology.isTypeOf(featureObj.type, 'CDS') &&
457
461
  featureObj.parent &&
458
- featureTypeOntology.isTypeOf(featureObj.parent.type, 'transcript')
462
+ (featureTypeOntology.isTypeOf(featureObj.parent.type, 'transcript') ||
463
+ featureTypeOntology.isTypeOf(
464
+ featureObj.parent.type,
465
+ 'pseudogenic_transcript',
466
+ ))
459
467
  ) {
460
468
  const { cdsLocations } = featureObj.parent
461
469
  for (const cdsLoc of cdsLocations) {
@@ -483,7 +491,7 @@ function getCDSCount(
483
491
  if (!children) {
484
492
  return 0
485
493
  }
486
- const isMrna = featureTypeOntology.isTypeOf(type, 'mRNA')
494
+ const isMrna = featureTypeOntology.isTypeOf(type, 'transcript')
487
495
  let cdsCount = 0
488
496
  if (isMrna) {
489
497
  for (const [, child] of children) {
@@ -504,7 +512,9 @@ function getRowCount(
504
512
  if (!children) {
505
513
  return 1
506
514
  }
507
- const isTranscript = featureTypeOntology.isTypeOf(type, 'transcript')
515
+ const isTranscript =
516
+ featureTypeOntology.isTypeOf(type, 'transcript') ||
517
+ featureTypeOntology.isTypeOf(type, 'pseudogenic_transcript')
508
518
  let rowCount = 0
509
519
  if (isTranscript) {
510
520
  for (const [, child] of children) {
@@ -532,7 +542,9 @@ function featuresForRow(
532
542
  feature: AnnotationFeature,
533
543
  featureTypeOntology: OntologyRecord,
534
544
  ): AnnotationFeature[][] {
535
- const isGene = featureTypeOntology.isTypeOf(feature.type, 'gene')
545
+ const isGene =
546
+ featureTypeOntology.isTypeOf(feature.type, 'gene') ||
547
+ featureTypeOntology.isTypeOf(feature.type, 'pseudogene')
536
548
  if (!isGene) {
537
549
  throw new Error('Top level feature for GeneGlyph must have type "gene"')
538
550
  }
@@ -542,7 +554,12 @@ function featuresForRow(
542
554
  }
543
555
  const features: AnnotationFeature[][] = []
544
556
  for (const [, child] of children) {
545
- if (!featureTypeOntology.isTypeOf(child.type, 'transcript')) {
557
+ if (
558
+ !(
559
+ featureTypeOntology.isTypeOf(child.type, 'transcript') ||
560
+ featureTypeOntology.isTypeOf(child.type, 'pseudogenic_transcript')
561
+ )
562
+ ) {
546
563
  features.push([child, feature])
547
564
  continue
548
565
  }
@@ -651,8 +668,12 @@ function getDraggableFeatureInfo(
651
668
  if (!featureTypeOntology) {
652
669
  throw new Error('featureTypeOntology is undefined')
653
670
  }
654
- const isGene = featureTypeOntology.isTypeOf(feature.type, 'gene')
655
- const isTranscript = featureTypeOntology.isTypeOf(feature.type, 'transcript')
671
+ const isGene =
672
+ featureTypeOntology.isTypeOf(feature.type, 'gene') ||
673
+ featureTypeOntology.isTypeOf(feature.type, 'pseudogene')
674
+ const isTranscript =
675
+ featureTypeOntology.isTypeOf(feature.type, 'transcript') ||
676
+ featureTypeOntology.isTypeOf(feature.type, 'pseudogenic_transcript')
656
677
  const isCds = featureTypeOntology.isTypeOf(feature.type, 'CDS')
657
678
  if (isGene || isTranscript) {
658
679
  return
@@ -691,9 +712,10 @@ function getDraggableFeatureInfo(
691
712
  }
692
713
 
693
714
  const overlappingExon = exonChildren.find((child) => {
694
- const [start, end] = intersection2(bp, bp + 1, child.min, child.max)
715
+ const [start, end] = intersection2(bp - 1, bp, child.min, child.max)
695
716
  return start !== undefined && end !== undefined
696
717
  })
718
+
697
719
  if (!overlappingExon) {
698
720
  return
699
721
  }
@@ -80,12 +80,17 @@ export function layoutsModelFactory(
80
80
  if (!children?.size) {
81
81
  return false
82
82
  }
83
- const isGene = featureTypeOntology.isTypeOf(feature.type, 'gene')
83
+ const isGene =
84
+ featureTypeOntology.isTypeOf(feature.type, 'gene') ||
85
+ featureTypeOntology.isTypeOf(feature.type, 'pseudogene')
84
86
  if (!isGene) {
85
87
  return false
86
88
  }
87
89
  for (const [, child] of children) {
88
- if (featureTypeOntology.isTypeOf(child.type, 'transcript')) {
90
+ if (
91
+ featureTypeOntology.isTypeOf(child.type, 'transcript') ||
92
+ featureTypeOntology.isTypeOf(child.type, 'pseudogenic_transcript')
93
+ ) {
89
94
  const { children: grandChildren } = child
90
95
  if (!grandChildren?.size) {
91
96
  return false
@@ -155,6 +155,8 @@ function codonColorCode(letter: string) {
155
155
  }
156
156
 
157
157
  function reverseCodonSeq(seq: string): string {
158
+ // disable because sequence is all ascii
159
+ // eslint-disable-next-line @typescript-eslint/no-misused-spread
158
160
  return [...seq]
159
161
  .map((c) => revcom(c))
160
162
  .reverse()
@@ -272,6 +274,8 @@ export function sequenceRenderingModelFactory(
272
274
  if (!seq) {
273
275
  return
274
276
  }
277
+ // disable because sequence is all ascii
278
+ // eslint-disable-next-line @typescript-eslint/no-misused-spread
275
279
  for (const [i, letter] of [...seq].entries()) {
276
280
  const trnslXOffset =
277
281
  (self.lgv.bpToPx({
@@ -127,7 +127,16 @@ export const genericEnglishStopwords = new Set([
127
127
  'don',
128
128
  'should',
129
129
  'now',
130
- ...'1234567890',
130
+ '0',
131
+ '1',
132
+ '2',
133
+ '3',
134
+ '4',
135
+ '5',
136
+ '6',
137
+ '7',
138
+ '8',
139
+ '9',
131
140
  ])
132
141
 
133
142
  /**
@@ -25,6 +25,7 @@ jest.mock('jsonpath', () => {
25
25
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
26
26
  query: jest.fn((obj: any, pathExpression: string, count?: number) => {
27
27
  const newObj =
28
+ // eslint-disable-next-line unicorn/prefer-structured-clone
28
29
  obj instanceof Object ? obj : JSON.parse(JSON.stringify(obj))
29
30
  return original.query(newObj, pathExpression, count)
30
31
  }),
@@ -87,7 +87,9 @@ export const OntologyRecordType = types
87
87
  return
88
88
  }
89
89
  void self.loadEquivalentTypes('gene')
90
+ void self.loadEquivalentTypes('pseudogene')
90
91
  void self.loadEquivalentTypes('transcript')
92
+ void self.loadEquivalentTypes('pseudogenic_transcript')
91
93
  void self.loadEquivalentTypes('CDS')
92
94
  void self.loadEquivalentTypes('mRNA')
93
95
  reaction.dispose()
@@ -301,7 +301,11 @@ export function stateModelFactory(
301
301
  )) {
302
302
  for (const [, childFeature] of feature.children ?? new Map()) {
303
303
  if (
304
- featureTypeOntology.isTypeOf(childFeature.type, 'transcript')
304
+ featureTypeOntology.isTypeOf(childFeature.type, 'transcript') ||
305
+ featureTypeOntology.isTypeOf(
306
+ feature.type,
307
+ 'pseudogenic_transcript',
308
+ )
305
309
  ) {
306
310
  for (const [, grandChildFeature] of childFeature.children ||
307
311
  new Map()) {
@@ -1,4 +1,3 @@
1
- /* eslint-disable @typescript-eslint/use-unknown-in-catch-callback-variable */
2
1
  /* eslint-disable unicorn/no-nested-ternary */
3
2
  /* eslint-disable @typescript-eslint/unbound-method */
4
3
 
@@ -1,5 +1,4 @@
1
1
  /* eslint-disable @typescript-eslint/unbound-method */
2
- /* eslint-disable @typescript-eslint/use-unknown-in-catch-callback-variable */
3
2
  import { observer } from 'mobx-react'
4
3
  import React, { useEffect, useState } from 'react'
5
4
  import { makeStyles } from 'tss-react/mui'
@@ -37,6 +36,14 @@ export const NumberCell = observer(function NumberCell({
37
36
  const [blur, setBlur] = useState(false)
38
37
  const [inputNode, setInputNode] = useState<HTMLInputElement | null>(null)
39
38
  const { classes } = useStyles()
39
+
40
+ useEffect(() => {
41
+ if (initialValue !== value) {
42
+ setValue(initialValue)
43
+ }
44
+ // eslint-disable-next-line react-hooks/exhaustive-deps
45
+ }, [initialValue])
46
+
40
47
  useEffect(() => {
41
48
  if (blur) {
42
49
  inputNode?.blur()
@@ -47,18 +47,20 @@ export const ToolBar = observer(function ToolBar({
47
47
  onChange={(event) => {
48
48
  model.setFilterText(event.target.value)
49
49
  }}
50
- InputProps={{
51
- endAdornment: (
52
- <InputAdornment position="end">
53
- <IconButton
54
- onClick={() => {
55
- model.clearFilterText()
56
- }}
57
- >
58
- <ClearIcon />
59
- </IconButton>
60
- </InputAdornment>
61
- ),
50
+ slotProps={{
51
+ input: {
52
+ endAdornment: (
53
+ <InputAdornment position="end">
54
+ <IconButton
55
+ onClick={() => {
56
+ model.clearFilterText()
57
+ }}
58
+ >
59
+ <ClearIcon />
60
+ </IconButton>
61
+ </InputAdornment>
62
+ ),
63
+ },
62
64
  }}
63
65
  />
64
66
  </div>
@@ -7,12 +7,7 @@ import {
7
7
  } from '@jbrowse/core/util'
8
8
 
9
9
  import { ChangeManager } from '../../ChangeManager'
10
- import {
11
- AddChildFeature,
12
- CopyFeature,
13
- DeleteFeature,
14
- ModifyFeatureAttribute,
15
- } from '../../components'
10
+ import { AddChildFeature, CopyFeature, DeleteFeature } from '../../components'
16
11
  import { ApolloSessionModel } from '../../session'
17
12
  import { getApolloInternetAccount } from '../../util'
18
13
 
@@ -116,33 +111,14 @@ export function featureContextMenuItems(
116
111
  )
117
112
  },
118
113
  },
119
- {
120
- label: 'Edit attributes',
121
- disabled: readOnly,
122
- onClick: () => {
123
- ;(session as unknown as AbstractSessionModel).queueDialog(
124
- (doneCallback) => [
125
- ModifyFeatureAttribute,
126
- {
127
- session,
128
- handleClose: () => {
129
- doneCallback()
130
- },
131
- changeManager,
132
- sourceFeature: feature,
133
- sourceAssemblyId: currentAssemblyId,
134
- },
135
- ],
136
- )
137
- },
138
- },
139
114
  )
140
115
  const { featureTypeOntology } = session.apolloDataStore.ontologyManager
141
116
  if (!featureTypeOntology) {
142
117
  throw new Error('featureTypeOntology is undefined')
143
118
  }
144
119
  if (
145
- featureTypeOntology.isTypeOf(feature.type, 'transcript') &&
120
+ (featureTypeOntology.isTypeOf(feature.type, 'transcript') ||
121
+ featureTypeOntology.isTypeOf(feature.type, 'pseudogenic_transcript')) &&
146
122
  isSessionModelWithWidgets(session)
147
123
  ) {
148
124
  menuItems.push({