@apollo-annotation/jbrowse-plugin-apollo 0.1.18 → 0.1.20
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 +3189 -3575
- package/dist/index.esm.js.map +1 -1
- package/dist/jbrowse-plugin-apollo.cjs.development.js +3185 -3570
- 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 +14884 -15905
- 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 +33 -33
- package/src/ApolloInternetAccount/addMenuItems.ts +18 -0
- package/src/ApolloInternetAccount/components/AuthTypeSelector.tsx +1 -0
- package/src/ApolloInternetAccount/configSchema.ts +5 -2
- package/src/ApolloInternetAccount/model.ts +14 -5
- package/src/ApolloRefNameAliasAdapter/ApolloRefNameAliasAdapter.ts +94 -0
- package/src/ApolloRefNameAliasAdapter/configSchema.ts +12 -0
- package/src/ApolloRefNameAliasAdapter/index.ts +21 -0
- package/src/ApolloSequenceAdapter/ApolloSequenceAdapter.ts +1 -0
- package/src/ApolloSixFrameRenderer/components/ApolloRendering.tsx +10 -10
- package/src/ApolloTextSearchAdapter/ApolloTextSearchAdapter.ts +35 -32
- package/src/BackendDrivers/BackendDriver.ts +8 -0
- package/src/BackendDrivers/CollaborationServerDriver.ts +49 -1
- package/src/BackendDrivers/DesktopFileDriver.ts +14 -1
- package/src/BackendDrivers/InMemoryFileDriver.ts +17 -1
- package/src/ChangeManager.ts +1 -1
- package/src/FeatureDetailsWidget/ApolloFeatureDetailsWidget.tsx +5 -25
- package/src/FeatureDetailsWidget/ApolloTranscriptDetailsWidget.tsx +82 -0
- package/src/FeatureDetailsWidget/Attributes.tsx +11 -3
- package/src/FeatureDetailsWidget/BasicInformation.tsx +38 -30
- package/src/FeatureDetailsWidget/Sequence.tsx +7 -7
- package/src/FeatureDetailsWidget/TranscriptBasic.tsx +446 -0
- package/src/FeatureDetailsWidget/TranscriptSequence.tsx +365 -0
- package/src/FeatureDetailsWidget/index.ts +2 -0
- package/src/FeatureDetailsWidget/model.ts +77 -9
- package/src/LinearApolloDisplay/components/LinearApolloDisplay.tsx +0 -2
- package/src/LinearApolloDisplay/glyphs/BoxGlyph.ts +453 -380
- package/src/LinearApolloDisplay/glyphs/GeneGlyph.ts +520 -0
- package/src/LinearApolloDisplay/glyphs/GenericChildGlyph.ts +138 -134
- package/src/LinearApolloDisplay/glyphs/Glyph.ts +38 -370
- package/src/LinearApolloDisplay/glyphs/index.ts +1 -2
- package/src/LinearApolloDisplay/stateModel/base.ts +3 -6
- package/src/LinearApolloDisplay/stateModel/getGlyph.ts +30 -30
- package/src/LinearApolloDisplay/stateModel/index.ts +5 -1
- package/src/LinearApolloDisplay/stateModel/layouts.ts +32 -24
- package/src/LinearApolloDisplay/stateModel/mouseEvents.ts +206 -217
- package/src/LinearApolloDisplay/stateModel/rendering.ts +43 -67
- package/src/OntologyManager/OntologyStore/fulltext.ts +1 -1
- package/src/OntologyManager/OntologyStore/index.ts +2 -1
- package/src/OntologyManager/index.ts +6 -2
- package/src/OntologyManager/util.ts +2 -2
- package/src/SixFrameFeatureDisplay/stateModel.ts +15 -10
- package/src/TabularEditor/HybridGrid/ChangeHandling.ts +21 -46
- package/src/TabularEditor/HybridGrid/Feature.tsx +31 -82
- package/src/TabularEditor/HybridGrid/FeatureAttributes.tsx +3 -2
- package/src/TabularEditor/HybridGrid/HybridGrid.tsx +2 -3
- package/src/TabularEditor/HybridGrid/NumberCell.tsx +1 -0
- package/src/TabularEditor/HybridGrid/featureContextMenuItems.ts +46 -5
- package/src/TabularEditor/model.ts +5 -3
- package/src/components/AddAssembly.tsx +15 -9
- package/src/components/AddChildFeature.tsx +7 -73
- package/src/components/AddFeature.tsx +2 -57
- package/src/components/AddRefSeqAliases.tsx +285 -0
- package/src/components/CopyFeature.tsx +16 -33
- package/src/components/DeleteFeature.tsx +4 -6
- package/src/components/ImportFeatures.tsx +6 -3
- package/src/components/LogOut.tsx +105 -0
- package/src/components/ManageChecks.tsx +1 -0
- package/src/components/ManageUsers.tsx +21 -1
- package/src/components/ModifyFeatureAttribute.tsx +2 -2
- package/src/components/OntologyTermAutocomplete.tsx +0 -2
- package/src/components/OntologyTermMultiSelect.tsx +1 -0
- package/src/components/OpenLocalFile.tsx +6 -5
- package/src/components/ViewChangeLog.tsx +1 -0
- package/src/components/ViewCheckResults.tsx +1 -0
- package/src/components/index.ts +4 -0
- package/src/extensions/annotationFromPileup.ts +10 -16
- package/src/index.ts +57 -3
- package/src/session/ClientDataStore.ts +49 -46
- package/src/session/session.ts +186 -114
- package/src/util/loadAssemblyIntoClient.ts +4 -210
- package/src/FeatureDetailsWidget/RelatedFeature.tsx +0 -97
- package/src/LinearApolloDisplay/glyphs/CanonicalGeneGlyph.ts +0 -1204
- package/src/LinearApolloDisplay/glyphs/ImplicitExonGeneGlyph.ts +0 -716
- package/src/LinearApolloDisplay/stateModel/glyphs.ts +0 -47
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
import { AnnotationFeature, ApolloRefSeqI } from '@apollo-annotation/mst'
|
|
2
|
+
import { splitStringIntoChunks } from '@apollo-annotation/shared'
|
|
3
|
+
import { revcom } from '@jbrowse/core/util'
|
|
4
|
+
import {
|
|
5
|
+
Button,
|
|
6
|
+
MenuItem,
|
|
7
|
+
Select,
|
|
8
|
+
SelectChangeEvent,
|
|
9
|
+
Typography,
|
|
10
|
+
} from '@mui/material'
|
|
11
|
+
import { observer } from 'mobx-react'
|
|
12
|
+
import React, { useState } from 'react'
|
|
13
|
+
|
|
14
|
+
import { ApolloSessionModel } from '../session'
|
|
15
|
+
|
|
16
|
+
export interface CDSInfo {
|
|
17
|
+
id: string
|
|
18
|
+
type: string
|
|
19
|
+
strand: number
|
|
20
|
+
min: number
|
|
21
|
+
oldMin: number
|
|
22
|
+
max: number
|
|
23
|
+
oldMax: number
|
|
24
|
+
startSeq: string
|
|
25
|
+
endSeq: string
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const getCDSInfo = (
|
|
29
|
+
feature: AnnotationFeature,
|
|
30
|
+
refData: ApolloRefSeqI,
|
|
31
|
+
): CDSInfo[] => {
|
|
32
|
+
const CDSresult: CDSInfo[] = []
|
|
33
|
+
const traverse = (
|
|
34
|
+
currentFeature: AnnotationFeature,
|
|
35
|
+
isParentMRNA: boolean,
|
|
36
|
+
) => {
|
|
37
|
+
if (
|
|
38
|
+
isParentMRNA &&
|
|
39
|
+
(currentFeature.type === 'CDS' ||
|
|
40
|
+
currentFeature.type === 'three_prime_UTR' ||
|
|
41
|
+
currentFeature.type === 'five_prime_UTR')
|
|
42
|
+
) {
|
|
43
|
+
let startSeq = refData.getSequence(
|
|
44
|
+
Number(currentFeature.min) - 2,
|
|
45
|
+
Number(currentFeature.min),
|
|
46
|
+
)
|
|
47
|
+
let endSeq = refData.getSequence(
|
|
48
|
+
Number(currentFeature.max),
|
|
49
|
+
Number(currentFeature.max) + 2,
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
if (currentFeature.strand === -1 && startSeq && endSeq) {
|
|
53
|
+
startSeq = revcom(startSeq)
|
|
54
|
+
endSeq = revcom(endSeq)
|
|
55
|
+
}
|
|
56
|
+
const oneCDS: CDSInfo = {
|
|
57
|
+
id: currentFeature._id,
|
|
58
|
+
type: currentFeature.type,
|
|
59
|
+
strand: Number(currentFeature.strand),
|
|
60
|
+
min: currentFeature.min + 1,
|
|
61
|
+
max: currentFeature.max + 1,
|
|
62
|
+
oldMin: currentFeature.min + 1,
|
|
63
|
+
oldMax: currentFeature.max + 1,
|
|
64
|
+
startSeq: startSeq || '',
|
|
65
|
+
endSeq: endSeq || '',
|
|
66
|
+
}
|
|
67
|
+
CDSresult.push(oneCDS)
|
|
68
|
+
}
|
|
69
|
+
if (currentFeature.children) {
|
|
70
|
+
for (const child of currentFeature.children) {
|
|
71
|
+
traverse(child[1], feature.type === 'mRNA')
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
traverse(feature, feature.type === 'mRNA')
|
|
76
|
+
CDSresult.sort((a, b) => {
|
|
77
|
+
return Number(a.min) - Number(b.min)
|
|
78
|
+
})
|
|
79
|
+
if (CDSresult.length > 0) {
|
|
80
|
+
CDSresult[0].startSeq = ''
|
|
81
|
+
|
|
82
|
+
// eslint-disable-next-line unicorn/prefer-at
|
|
83
|
+
CDSresult[CDSresult.length - 1].endSeq = ''
|
|
84
|
+
|
|
85
|
+
// Loop through the array and clear "startSeq" or "endSeq" based on the conditions
|
|
86
|
+
for (let i = 0; i < CDSresult.length; i++) {
|
|
87
|
+
if (i > 0 && CDSresult[i].min === CDSresult[i - 1].max) {
|
|
88
|
+
// Clear "startSeq" if the current item's "start" is equal to the previous item's "end"
|
|
89
|
+
CDSresult[i].startSeq = ''
|
|
90
|
+
}
|
|
91
|
+
if (
|
|
92
|
+
i < CDSresult.length - 1 &&
|
|
93
|
+
CDSresult[i].max === CDSresult[i + 1].min
|
|
94
|
+
) {
|
|
95
|
+
// Clear "endSeq" if the next item's "start" is equal to the current item's "end"
|
|
96
|
+
CDSresult[i].endSeq = ''
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return CDSresult
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
interface Props {
|
|
104
|
+
textSegments: { text: string; color: string }[]
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function formatSequence(
|
|
108
|
+
seq: string,
|
|
109
|
+
refName: string,
|
|
110
|
+
start: number,
|
|
111
|
+
end: number,
|
|
112
|
+
wrap?: number,
|
|
113
|
+
) {
|
|
114
|
+
const header = `>${refName}:${start + 1}–${end}\n`
|
|
115
|
+
const body =
|
|
116
|
+
wrap === undefined ? seq : splitStringIntoChunks(seq, wrap).join('\n')
|
|
117
|
+
return `${header}${body}`
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export const intronColor = 'rgb(120,120,120)' // Slightly brighter gray
|
|
121
|
+
export const utrColor = 'rgb(20,200,200)' // Slightly brighter cyan
|
|
122
|
+
export const proteinColor = 'rgb(220,70,220)' // Slightly brighter magenta
|
|
123
|
+
export const cdsColor = 'rgb(240,200,20)' // Slightly brighter yellow
|
|
124
|
+
export const updownstreamColor = 'rgb(255,130,130)' // Slightly brighter red
|
|
125
|
+
export const genomeColor = 'rgb(20,230,20)' // Slightly brighter green
|
|
126
|
+
|
|
127
|
+
let textSegments = [{ text: '', color: '' }]
|
|
128
|
+
|
|
129
|
+
export const TranscriptSequence = observer(function TranscriptSequence({
|
|
130
|
+
assembly,
|
|
131
|
+
feature,
|
|
132
|
+
refName,
|
|
133
|
+
session,
|
|
134
|
+
}: {
|
|
135
|
+
assembly: string
|
|
136
|
+
feature: AnnotationFeature
|
|
137
|
+
refName: string
|
|
138
|
+
session: ApolloSessionModel
|
|
139
|
+
}) {
|
|
140
|
+
const currentAssembly = session.apolloDataStore.assemblies.get(assembly)
|
|
141
|
+
const refData = currentAssembly?.getByRefName(refName)
|
|
142
|
+
const [showSequence, setShowSequence] = useState(false)
|
|
143
|
+
const [selectedOption, setSelectedOption] = useState('Select')
|
|
144
|
+
|
|
145
|
+
if (!(currentAssembly && refData)) {
|
|
146
|
+
return null
|
|
147
|
+
}
|
|
148
|
+
const refSeq = currentAssembly.getByRefName(refName)
|
|
149
|
+
if (!refSeq) {
|
|
150
|
+
return null
|
|
151
|
+
}
|
|
152
|
+
const transcriptItems = getCDSInfo(feature, refData)
|
|
153
|
+
const { max, min } = feature
|
|
154
|
+
let sequence = ''
|
|
155
|
+
if (showSequence) {
|
|
156
|
+
getSequenceAsString(min, max)
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function getSequenceAsString(start: number, end: number): string {
|
|
160
|
+
sequence = refSeq?.getSequence(start, end) ?? ''
|
|
161
|
+
if (sequence === '') {
|
|
162
|
+
void session.apolloDataStore.loadRefSeq([
|
|
163
|
+
{ assemblyName: assembly, refName, start, end },
|
|
164
|
+
])
|
|
165
|
+
} else {
|
|
166
|
+
sequence = formatSequence(sequence, refName, start, end)
|
|
167
|
+
}
|
|
168
|
+
getSequenceAsTextSegment(selectedOption) // For color coded sequence
|
|
169
|
+
return sequence
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const handleSeqButtonClick = () => {
|
|
173
|
+
setShowSequence(!showSequence)
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function getSequenceAsTextSegment(option: string) {
|
|
177
|
+
let seqData = ''
|
|
178
|
+
textSegments = []
|
|
179
|
+
if (!refData) {
|
|
180
|
+
return
|
|
181
|
+
}
|
|
182
|
+
switch (option) {
|
|
183
|
+
case 'CDS': {
|
|
184
|
+
textSegments.push({ text: `>${refName} : CDS\n`, color: 'black' })
|
|
185
|
+
for (const item of transcriptItems) {
|
|
186
|
+
if (item.type === 'CDS') {
|
|
187
|
+
const refSeq: string = refData.getSequence(
|
|
188
|
+
Number(item.min + 1),
|
|
189
|
+
Number(item.max),
|
|
190
|
+
)
|
|
191
|
+
seqData += item.strand === -1 && refSeq ? revcom(refSeq) : refSeq
|
|
192
|
+
textSegments.push({ text: seqData, color: cdsColor })
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
break
|
|
196
|
+
}
|
|
197
|
+
case 'cDNA': {
|
|
198
|
+
textSegments.push({ text: `>${refName} : cDNA\n`, color: 'black' })
|
|
199
|
+
for (const item of transcriptItems) {
|
|
200
|
+
if (
|
|
201
|
+
item.type === 'CDS' ||
|
|
202
|
+
item.type === 'three_prime_UTR' ||
|
|
203
|
+
item.type === 'five_prime_UTR'
|
|
204
|
+
) {
|
|
205
|
+
const refSeq: string = refData.getSequence(
|
|
206
|
+
Number(item.min + 1),
|
|
207
|
+
Number(item.max),
|
|
208
|
+
)
|
|
209
|
+
seqData += item.strand === -1 && refSeq ? revcom(refSeq) : refSeq
|
|
210
|
+
if (item.type === 'CDS') {
|
|
211
|
+
textSegments.push({ text: seqData, color: cdsColor })
|
|
212
|
+
} else {
|
|
213
|
+
textSegments.push({ text: seqData, color: utrColor })
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
break
|
|
218
|
+
}
|
|
219
|
+
case 'Full': {
|
|
220
|
+
textSegments.push({
|
|
221
|
+
text: `>${refName} : Full genomic\n`,
|
|
222
|
+
color: 'black',
|
|
223
|
+
})
|
|
224
|
+
let lastEnd = 0
|
|
225
|
+
let count = 0
|
|
226
|
+
for (const item of transcriptItems) {
|
|
227
|
+
count++
|
|
228
|
+
if (
|
|
229
|
+
lastEnd != 0 &&
|
|
230
|
+
lastEnd != Number(item.min) &&
|
|
231
|
+
count != transcriptItems.length
|
|
232
|
+
) {
|
|
233
|
+
// Intron etc. between CDS/UTRs. No need to check this on very last item
|
|
234
|
+
const refSeq: string = refData.getSequence(
|
|
235
|
+
lastEnd + 1,
|
|
236
|
+
Number(item.min) - 1,
|
|
237
|
+
)
|
|
238
|
+
seqData += item.strand === -1 && refSeq ? revcom(refSeq) : refSeq
|
|
239
|
+
textSegments.push({ text: seqData, color: 'black' })
|
|
240
|
+
}
|
|
241
|
+
if (
|
|
242
|
+
item.type === 'CDS' ||
|
|
243
|
+
item.type === 'three_prime_UTR' ||
|
|
244
|
+
item.type === 'five_prime_UTR'
|
|
245
|
+
) {
|
|
246
|
+
const refSeq: string = refData.getSequence(
|
|
247
|
+
Number(item.min + 1),
|
|
248
|
+
Number(item.max),
|
|
249
|
+
)
|
|
250
|
+
seqData += item.strand === -1 && refSeq ? revcom(refSeq) : refSeq
|
|
251
|
+
switch (item.type) {
|
|
252
|
+
case 'CDS': {
|
|
253
|
+
textSegments.push({ text: seqData, color: cdsColor })
|
|
254
|
+
break
|
|
255
|
+
}
|
|
256
|
+
case 'three_prime_UTR': {
|
|
257
|
+
textSegments.push({ text: seqData, color: utrColor })
|
|
258
|
+
break
|
|
259
|
+
}
|
|
260
|
+
case 'five_prime_UTR': {
|
|
261
|
+
textSegments.push({ text: seqData, color: utrColor })
|
|
262
|
+
break
|
|
263
|
+
}
|
|
264
|
+
default: {
|
|
265
|
+
textSegments.push({ text: seqData, color: 'black' })
|
|
266
|
+
break
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
lastEnd = Number(item.max)
|
|
271
|
+
}
|
|
272
|
+
break
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
function handleChangeSeqOption(e: SelectChangeEvent) {
|
|
278
|
+
const option = e.target.value
|
|
279
|
+
setSelectedOption(option)
|
|
280
|
+
getSequenceAsTextSegment(option)
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// Function to copy text to clipboard
|
|
284
|
+
const copyToClipboard = () => {
|
|
285
|
+
const textToCopy = textSegments.map((segment) => segment.text).join('')
|
|
286
|
+
|
|
287
|
+
if (textToCopy) {
|
|
288
|
+
navigator.clipboard
|
|
289
|
+
.writeText(textToCopy)
|
|
290
|
+
.then(() => {
|
|
291
|
+
// console.log('Text copied to clipboard!')
|
|
292
|
+
})
|
|
293
|
+
.catch((error: unknown) => {
|
|
294
|
+
console.error('Failed to copy text to clipboard', error)
|
|
295
|
+
})
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
const ColoredText: React.FC<Props> = ({ textSegments }) => {
|
|
300
|
+
return (
|
|
301
|
+
<div>
|
|
302
|
+
{textSegments.map((segment, index) => (
|
|
303
|
+
<span key={index} style={{ color: segment.color }}>
|
|
304
|
+
{splitStringIntoChunks(segment.text, 150).join('\n')}
|
|
305
|
+
</span>
|
|
306
|
+
))}
|
|
307
|
+
</div>
|
|
308
|
+
)
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
return (
|
|
312
|
+
<>
|
|
313
|
+
<Typography
|
|
314
|
+
style={{ display: 'inline', marginLeft: '15px' }}
|
|
315
|
+
variant="h5"
|
|
316
|
+
>
|
|
317
|
+
Sequence
|
|
318
|
+
</Typography>
|
|
319
|
+
<div>
|
|
320
|
+
<Button
|
|
321
|
+
variant="contained"
|
|
322
|
+
style={{ marginLeft: '15px' }}
|
|
323
|
+
onClick={handleSeqButtonClick}
|
|
324
|
+
>
|
|
325
|
+
{showSequence ? 'Hide sequence' : 'Show sequence'}
|
|
326
|
+
</Button>
|
|
327
|
+
</div>
|
|
328
|
+
<div>
|
|
329
|
+
{showSequence && (
|
|
330
|
+
<Select
|
|
331
|
+
value={selectedOption}
|
|
332
|
+
onChange={handleChangeSeqOption}
|
|
333
|
+
style={{ width: '150px', marginLeft: '15px', height: '25px' }}
|
|
334
|
+
>
|
|
335
|
+
<MenuItem value={'Select'}>Select</MenuItem>
|
|
336
|
+
<MenuItem value={'CDS'}>CDS</MenuItem>
|
|
337
|
+
<MenuItem value={'cDNA'}>cDNA</MenuItem>
|
|
338
|
+
<MenuItem value={'Full'}>Full genomics</MenuItem>
|
|
339
|
+
</Select>
|
|
340
|
+
)}
|
|
341
|
+
</div>
|
|
342
|
+
<div
|
|
343
|
+
style={{
|
|
344
|
+
width: '500px',
|
|
345
|
+
marginLeft: '15px',
|
|
346
|
+
height: '300px',
|
|
347
|
+
overflowY: 'auto',
|
|
348
|
+
border: '1px solid #ccc',
|
|
349
|
+
}}
|
|
350
|
+
>
|
|
351
|
+
{showSequence && <ColoredText textSegments={textSegments} />}
|
|
352
|
+
</div>
|
|
353
|
+
{showSequence && (
|
|
354
|
+
<Button
|
|
355
|
+
variant="contained"
|
|
356
|
+
style={{ marginLeft: '15px' }}
|
|
357
|
+
onClick={copyToClipboard}
|
|
358
|
+
>
|
|
359
|
+
Copy sequence
|
|
360
|
+
</Button>
|
|
361
|
+
)}
|
|
362
|
+
</>
|
|
363
|
+
)
|
|
364
|
+
})
|
|
365
|
+
export default TranscriptSequence
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
|
2
2
|
/* eslint-disable @typescript-eslint/no-unnecessary-condition */
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
AnnotationFeature,
|
|
5
|
+
AnnotationFeatureModel,
|
|
6
|
+
} from '@apollo-annotation/mst'
|
|
4
7
|
import { getSession } from '@jbrowse/core/util'
|
|
5
8
|
import { ElementId } from '@jbrowse/core/util/types/mst'
|
|
6
9
|
import { autorun } from 'mobx'
|
|
7
10
|
import { Instance, SnapshotIn, addDisposer, types } from 'mobx-state-tree'
|
|
8
11
|
|
|
12
|
+
import { ChangeManager } from '../ChangeManager'
|
|
9
13
|
import { ApolloSessionModel } from '../session'
|
|
10
14
|
|
|
11
15
|
export const ApolloFeatureDetailsWidgetModel = types
|
|
@@ -13,7 +17,7 @@ export const ApolloFeatureDetailsWidgetModel = types
|
|
|
13
17
|
id: ElementId,
|
|
14
18
|
type: types.literal('ApolloFeatureDetailsWidget'),
|
|
15
19
|
feature: types.maybe(
|
|
16
|
-
types.reference(
|
|
20
|
+
types.reference(AnnotationFeatureModel, {
|
|
17
21
|
onInvalidated(ev) {
|
|
18
22
|
ev.parent.setTryReload(ev.invalidId)
|
|
19
23
|
ev.removeRef()
|
|
@@ -27,7 +31,8 @@ export const ApolloFeatureDetailsWidgetModel = types
|
|
|
27
31
|
tryReload: undefined as string | undefined,
|
|
28
32
|
}))
|
|
29
33
|
.actions((self) => ({
|
|
30
|
-
setFeature(feature:
|
|
34
|
+
setFeature(feature: AnnotationFeature) {
|
|
35
|
+
// @ts-expect-error Not sure why TS thinks these MST types don't match
|
|
31
36
|
self.feature = feature
|
|
32
37
|
},
|
|
33
38
|
setTryReload(featureId?: string) {
|
|
@@ -58,9 +63,72 @@ export const ApolloFeatureDetailsWidgetModel = types
|
|
|
58
63
|
},
|
|
59
64
|
}))
|
|
60
65
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
export
|
|
65
|
-
typeof ApolloFeatureDetailsWidgetModel
|
|
66
|
-
|
|
66
|
+
// eslint disables because of
|
|
67
|
+
// https://mobx-state-tree.js.org/tips/typescript#using-a-mst-type-at-design-time
|
|
68
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
|
69
|
+
export interface ApolloFeatureDetailsWidget
|
|
70
|
+
extends Instance<typeof ApolloFeatureDetailsWidgetModel> {}
|
|
71
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
|
72
|
+
export interface ApolloFeatureDetailsWidgetSnapshot
|
|
73
|
+
extends SnapshotIn<typeof ApolloFeatureDetailsWidgetModel> {}
|
|
74
|
+
|
|
75
|
+
export const ApolloTranscriptDetailsModel = types
|
|
76
|
+
.model('ApolloTranscriptDetails', {
|
|
77
|
+
id: ElementId,
|
|
78
|
+
type: types.literal('ApolloTranscriptDetails'),
|
|
79
|
+
feature: types.maybe(
|
|
80
|
+
types.reference(AnnotationFeatureModel, {
|
|
81
|
+
onInvalidated(ev) {
|
|
82
|
+
ev.parent.setTryReload(ev.invalidId)
|
|
83
|
+
ev.removeRef()
|
|
84
|
+
},
|
|
85
|
+
}),
|
|
86
|
+
),
|
|
87
|
+
assembly: types.string,
|
|
88
|
+
refName: types.string,
|
|
89
|
+
changeManager: types.frozen<ChangeManager>(),
|
|
90
|
+
})
|
|
91
|
+
.volatile(() => ({
|
|
92
|
+
tryReload: undefined as string | undefined,
|
|
93
|
+
}))
|
|
94
|
+
.actions((self) => ({
|
|
95
|
+
setFeature(feature: AnnotationFeature) {
|
|
96
|
+
// @ts-expect-error Not sure why TS thinks these MST types don't match
|
|
97
|
+
self.feature = feature
|
|
98
|
+
},
|
|
99
|
+
setTryReload(featureId?: string) {
|
|
100
|
+
self.tryReload = featureId
|
|
101
|
+
},
|
|
102
|
+
}))
|
|
103
|
+
.actions((self) => ({
|
|
104
|
+
afterAttach() {
|
|
105
|
+
addDisposer(
|
|
106
|
+
self,
|
|
107
|
+
autorun((reaction) => {
|
|
108
|
+
if (!self.tryReload) {
|
|
109
|
+
return
|
|
110
|
+
}
|
|
111
|
+
const session = getSession(self) as unknown as ApolloSessionModel
|
|
112
|
+
const { apolloDataStore } = session
|
|
113
|
+
if (!apolloDataStore) {
|
|
114
|
+
return
|
|
115
|
+
}
|
|
116
|
+
const feature = apolloDataStore.getFeature(self.tryReload)
|
|
117
|
+
if (feature) {
|
|
118
|
+
self.setFeature(feature)
|
|
119
|
+
self.setTryReload()
|
|
120
|
+
reaction.dispose()
|
|
121
|
+
}
|
|
122
|
+
}),
|
|
123
|
+
)
|
|
124
|
+
},
|
|
125
|
+
}))
|
|
126
|
+
|
|
127
|
+
// eslint disables because of
|
|
128
|
+
// https://mobx-state-tree.js.org/tips/typescript#using-a-mst-type-at-design-time
|
|
129
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
|
130
|
+
export interface ApolloTranscriptDetailsWidget
|
|
131
|
+
extends Instance<typeof ApolloTranscriptDetailsModel> {}
|
|
132
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
|
133
|
+
export interface ApolloTranscriptDetailsWidgetSnapshot
|
|
134
|
+
extends SnapshotIn<typeof ApolloTranscriptDetailsModel> {}
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/unbound-method */
|
|
2
2
|
/* eslint-disable @typescript-eslint/no-misused-promises */
|
|
3
3
|
/* eslint-disable @typescript-eslint/no-unnecessary-condition */
|
|
4
|
-
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
|
5
|
-
/* eslint-disable @typescript-eslint/no-unsafe-argument */
|
|
6
4
|
import { Menu, MenuItem } from '@jbrowse/core/ui'
|
|
7
5
|
import {
|
|
8
6
|
AbstractSessionModel,
|