@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.
- package/dist/index.esm.js +1513 -1074
- package/dist/index.esm.js.map +1 -1
- package/dist/jbrowse-plugin-apollo.cjs.development.js +1510 -1065
- package/dist/jbrowse-plugin-apollo.cjs.development.js.map +1 -1
- package/dist/jbrowse-plugin-apollo.cjs.production.min.js +1 -1
- package/dist/jbrowse-plugin-apollo.cjs.production.min.js.map +1 -1
- package/dist/jbrowse-plugin-apollo.umd.development.js +4681 -2097
- package/dist/jbrowse-plugin-apollo.umd.development.js.map +1 -1
- package/dist/jbrowse-plugin-apollo.umd.production.min.js +1 -1
- package/dist/jbrowse-plugin-apollo.umd.production.min.js.map +1 -1
- package/package.json +4 -4
- package/src/ApolloSequenceAdapter/ApolloSequenceAdapter.ts +13 -0
- package/src/FeatureDetailsWidget/ApolloFeatureDetailsWidget.tsx +88 -17
- package/src/FeatureDetailsWidget/ApolloTranscriptDetailsWidget.tsx +144 -22
- package/src/FeatureDetailsWidget/Attributes.tsx +93 -43
- package/src/FeatureDetailsWidget/BasicInformation.tsx +2 -4
- package/src/FeatureDetailsWidget/FeatureDetailsNavigation.tsx +6 -4
- package/src/FeatureDetailsWidget/Sequence.tsx +16 -33
- package/src/FeatureDetailsWidget/TranscriptSequence.tsx +137 -92
- package/src/FeatureDetailsWidget/TranscriptWidgetEditLocation.tsx +600 -0
- package/src/FeatureDetailsWidget/TranscriptWidgetSummary.tsx +54 -0
- package/src/LinearApolloDisplay/components/LinearApolloDisplay.tsx +13 -6
- package/src/LinearApolloDisplay/glyphs/BoxGlyph.ts +6 -27
- package/src/LinearApolloDisplay/glyphs/GeneGlyph.ts +35 -13
- package/src/LinearApolloDisplay/stateModel/layouts.ts +7 -2
- package/src/LinearApolloDisplay/stateModel/rendering.ts +4 -0
- package/src/OntologyManager/OntologyStore/fulltext-stopwords.ts +10 -1
- package/src/OntologyManager/OntologyStore/index.test.ts +1 -0
- package/src/OntologyManager/index.ts +2 -0
- package/src/SixFrameFeatureDisplay/stateModel.ts +5 -1
- package/src/TabularEditor/HybridGrid/Feature.tsx +0 -1
- package/src/TabularEditor/HybridGrid/NumberCell.tsx +8 -1
- package/src/TabularEditor/HybridGrid/ToolBar.tsx +14 -12
- package/src/TabularEditor/HybridGrid/featureContextMenuItems.ts +3 -27
- package/src/components/AddAssembly.tsx +608 -291
- package/src/components/CreateApolloAnnotation.tsx +144 -37
- package/src/components/OntologyTermMultiSelect.tsx +3 -0
- package/src/components/index.ts +0 -1
- package/src/extensions/annotationFromJBrowseFeature.ts +3 -2
- package/src/makeDisplayComponent.tsx +3 -4
- package/src/util/annotationFeatureUtils.ts +53 -0
- package/src/util/index.ts +1 -0
- package/src/FeatureDetailsWidget/TranscriptBasic.tsx +0 -200
- 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 =
|
|
116
|
-
transcript.type,
|
|
117
|
-
|
|
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 (
|
|
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, '
|
|
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 =
|
|
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 =
|
|
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 (
|
|
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 =
|
|
655
|
-
|
|
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
|
|
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 =
|
|
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 (
|
|
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({
|
|
@@ -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,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
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
<
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
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({
|