@apollo-annotation/jbrowse-plugin-apollo 0.3.6 → 0.3.8
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 +4603 -2045
- package/dist/index.esm.js.map +1 -1
- package/dist/jbrowse-plugin-apollo.cjs.development.js +4611 -2039
- 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 +9387 -4016
- 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 +15 -15
- package/src/ApolloInternetAccount/model.ts +48 -13
- package/src/BackendDrivers/CollaborationServerDriver.ts +23 -2
- package/src/ChangeManager.ts +42 -18
- package/src/FeatureDetailsWidget/ApolloTranscriptDetailsWidget.tsx +64 -5
- package/src/FeatureDetailsWidget/Attributes.tsx +8 -3
- package/src/FeatureDetailsWidget/TranscriptSequence.tsx +70 -81
- package/src/FeatureDetailsWidget/TranscriptWidgetEditLocation.tsx +946 -190
- package/src/FeatureDetailsWidget/TranscriptWidgetSummary.tsx +4 -0
- package/src/LinearApolloDisplay/components/LinearApolloDisplay.tsx +61 -73
- package/src/LinearApolloDisplay/glyphs/BoxGlyph.ts +55 -211
- package/src/LinearApolloDisplay/glyphs/GeneGlyph.ts +562 -108
- package/src/LinearApolloDisplay/glyphs/GenericChildGlyph.ts +78 -14
- package/src/LinearApolloDisplay/glyphs/Glyph.ts +15 -9
- package/src/LinearApolloDisplay/stateModel/base.ts +63 -43
- package/src/LinearApolloDisplay/stateModel/layouts.ts +3 -2
- package/src/LinearApolloDisplay/stateModel/mouseEvents.ts +79 -292
- package/src/LinearApolloDisplay/stateModel/rendering.ts +45 -344
- package/src/LinearApolloReferenceSequenceDisplay/components/LinearApolloReferenceSequenceDisplay.tsx +87 -0
- package/src/LinearApolloReferenceSequenceDisplay/components/index.ts +1 -0
- package/src/LinearApolloReferenceSequenceDisplay/configSchema.ts +7 -0
- package/src/LinearApolloReferenceSequenceDisplay/index.ts +3 -0
- package/src/LinearApolloReferenceSequenceDisplay/stateModel/base.ts +227 -0
- package/src/LinearApolloReferenceSequenceDisplay/stateModel/index.ts +25 -0
- package/src/LinearApolloReferenceSequenceDisplay/stateModel/rendering.ts +481 -0
- package/src/LinearApolloSixFrameDisplay/components/LinearApolloSixFrameDisplay.tsx +102 -40
- package/src/LinearApolloSixFrameDisplay/components/TrackLines.tsx +12 -20
- package/src/LinearApolloSixFrameDisplay/glyphs/GeneGlyph.ts +382 -243
- package/src/LinearApolloSixFrameDisplay/glyphs/Glyph.ts +12 -8
- package/src/LinearApolloSixFrameDisplay/stateModel/base.ts +83 -4
- package/src/LinearApolloSixFrameDisplay/stateModel/layouts.ts +23 -11
- package/src/LinearApolloSixFrameDisplay/stateModel/mouseEvents.ts +118 -123
- package/src/LinearApolloSixFrameDisplay/stateModel/rendering.ts +53 -63
- package/src/OntologyManager/index.ts +4 -1
- package/src/TabularEditor/HybridGrid/Feature.tsx +20 -14
- package/src/TabularEditor/HybridGrid/HybridGrid.tsx +7 -5
- package/src/TabularEditor/HybridGrid/featureContextMenuItems.ts +108 -16
- package/src/components/AddAssembly.tsx +1 -1
- package/src/components/AddAssemblyAliases.tsx +114 -0
- package/src/components/AddChildFeature.tsx +7 -7
- package/src/components/AddFeature.tsx +20 -15
- package/src/components/AddRefSeqAliases.tsx +9 -9
- package/src/components/CopyFeature.tsx +4 -4
- package/src/components/CreateApolloAnnotation.tsx +335 -151
- package/src/components/DeleteAssembly.tsx +1 -1
- package/src/components/DeleteFeature.tsx +358 -11
- package/src/components/DownloadGFF3.tsx +20 -1
- package/src/components/EditZoomThresholdDialog.tsx +69 -0
- package/src/components/FilterFeatures.tsx +7 -7
- package/src/components/FilterTranscripts.tsx +86 -0
- package/src/components/ImportFeatures.tsx +1 -1
- package/src/components/ManageChecks.tsx +1 -1
- package/src/components/MergeExons.tsx +193 -0
- package/src/components/MergeTranscripts.tsx +182 -0
- package/src/components/OntologyTermMultiSelect.tsx +11 -11
- package/src/components/OpenLocalFile.tsx +11 -7
- package/src/components/SplitExon.tsx +134 -0
- package/src/components/ViewCheckResults.tsx +1 -1
- package/src/components/index.ts +4 -0
- package/src/config.ts +11 -0
- package/src/extensions/annotationFromJBrowseFeature.ts +2 -0
- package/src/extensions/annotationFromPileup.ts +99 -89
- package/src/index.ts +42 -105
- package/src/makeDisplayComponent.tsx +0 -1
- package/src/menus/index.ts +1 -0
- package/src/{ApolloInternetAccount/addMenuItems.ts → menus/topLevelMenu.ts} +60 -33
- package/src/menus/topLevelMenuAdmin.ts +154 -0
- package/src/session/session.ts +163 -104
- package/src/util/annotationFeatureUtils.ts +59 -0
- package/src/util/copyToClipboard.ts +21 -0
- package/src/util/displayUtils.ts +149 -0
- package/src/util/glyphUtils.ts +201 -0
- package/src/util/index.ts +2 -0
- package/src/util/mouseEventsUtils.ts +145 -0
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type AbstractMenuManager,
|
|
3
|
+
type AbstractSessionModel,
|
|
4
|
+
} from '@jbrowse/core/util'
|
|
5
|
+
import AddIcon from '@mui/icons-material/Add'
|
|
6
|
+
import AdminPanelSettingsIcon from '@mui/icons-material/AdminPanelSettings'
|
|
7
|
+
import DeleteIcon from '@mui/icons-material/Delete'
|
|
8
|
+
import InputIcon from '@mui/icons-material/Input'
|
|
9
|
+
import PersonIcon from '@mui/icons-material/Person'
|
|
10
|
+
import RuleIcon from '@mui/icons-material/Rule'
|
|
11
|
+
|
|
12
|
+
import {
|
|
13
|
+
AddAssembly,
|
|
14
|
+
AddAssemblyAliases,
|
|
15
|
+
AddRefSeqAliases,
|
|
16
|
+
DeleteAssembly,
|
|
17
|
+
ImportFeatures,
|
|
18
|
+
ManageChecks,
|
|
19
|
+
ManageUsers,
|
|
20
|
+
} from '../components'
|
|
21
|
+
import { type ApolloSessionModel } from '../session'
|
|
22
|
+
|
|
23
|
+
export function addTopLevelAdminMenus(rootModel: AbstractMenuManager) {
|
|
24
|
+
rootModel.appendToMenu('Apollo', {
|
|
25
|
+
label: 'Admin',
|
|
26
|
+
type: 'subMenu',
|
|
27
|
+
icon: AdminPanelSettingsIcon,
|
|
28
|
+
subMenu: [
|
|
29
|
+
{
|
|
30
|
+
label: 'Add Assembly',
|
|
31
|
+
icon: AddIcon,
|
|
32
|
+
onClick: (session: ApolloSessionModel) => {
|
|
33
|
+
;(session as unknown as AbstractSessionModel).queueDialog(
|
|
34
|
+
(doneCallback) => [
|
|
35
|
+
AddAssembly,
|
|
36
|
+
{
|
|
37
|
+
session,
|
|
38
|
+
handleClose: () => {
|
|
39
|
+
doneCallback()
|
|
40
|
+
},
|
|
41
|
+
changeManager: session.apolloDataStore.changeManager,
|
|
42
|
+
},
|
|
43
|
+
],
|
|
44
|
+
)
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
label: 'Delete Assembly',
|
|
49
|
+
icon: DeleteIcon,
|
|
50
|
+
onClick: (session: ApolloSessionModel) => {
|
|
51
|
+
;(session as unknown as AbstractSessionModel).queueDialog(
|
|
52
|
+
(doneCallback) => [
|
|
53
|
+
DeleteAssembly,
|
|
54
|
+
{
|
|
55
|
+
session,
|
|
56
|
+
handleClose: () => {
|
|
57
|
+
doneCallback()
|
|
58
|
+
},
|
|
59
|
+
changeManager: session.apolloDataStore.changeManager,
|
|
60
|
+
},
|
|
61
|
+
],
|
|
62
|
+
)
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
label: 'Import Features',
|
|
67
|
+
icon: InputIcon,
|
|
68
|
+
onClick: (session: ApolloSessionModel) => {
|
|
69
|
+
;(session as unknown as AbstractSessionModel).queueDialog(
|
|
70
|
+
(doneCallback) => [
|
|
71
|
+
ImportFeatures,
|
|
72
|
+
{
|
|
73
|
+
session,
|
|
74
|
+
handleClose: () => {
|
|
75
|
+
doneCallback()
|
|
76
|
+
},
|
|
77
|
+
changeManager: session.apolloDataStore.changeManager,
|
|
78
|
+
},
|
|
79
|
+
],
|
|
80
|
+
)
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
label: 'Add reference sequence aliases',
|
|
85
|
+
onClick: (session: ApolloSessionModel) => {
|
|
86
|
+
;(session as unknown as AbstractSessionModel).queueDialog(
|
|
87
|
+
(doneCallback) => [
|
|
88
|
+
AddRefSeqAliases,
|
|
89
|
+
{
|
|
90
|
+
session,
|
|
91
|
+
handleClose: () => {
|
|
92
|
+
doneCallback()
|
|
93
|
+
},
|
|
94
|
+
changeManager: session.apolloDataStore.changeManager,
|
|
95
|
+
},
|
|
96
|
+
],
|
|
97
|
+
)
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
label: 'Add Assembly aliases',
|
|
102
|
+
onClick: (session: ApolloSessionModel) => {
|
|
103
|
+
;(session as unknown as AbstractSessionModel).queueDialog(
|
|
104
|
+
(doneCallback) => [
|
|
105
|
+
AddAssemblyAliases,
|
|
106
|
+
{
|
|
107
|
+
session,
|
|
108
|
+
handleClose: () => {
|
|
109
|
+
doneCallback()
|
|
110
|
+
},
|
|
111
|
+
changeManager: session.apolloDataStore.changeManager,
|
|
112
|
+
},
|
|
113
|
+
],
|
|
114
|
+
)
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
label: 'Manage Users',
|
|
119
|
+
icon: PersonIcon,
|
|
120
|
+
onClick: (session: ApolloSessionModel) => {
|
|
121
|
+
;(session as unknown as AbstractSessionModel).queueDialog(
|
|
122
|
+
(doneCallback) => [
|
|
123
|
+
ManageUsers,
|
|
124
|
+
{
|
|
125
|
+
session,
|
|
126
|
+
handleClose: () => {
|
|
127
|
+
doneCallback()
|
|
128
|
+
},
|
|
129
|
+
changeManager: session.apolloDataStore.changeManager,
|
|
130
|
+
},
|
|
131
|
+
],
|
|
132
|
+
)
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
label: 'Manage Checks',
|
|
137
|
+
icon: RuleIcon,
|
|
138
|
+
onClick: (session: ApolloSessionModel) => {
|
|
139
|
+
;(session as unknown as AbstractSessionModel).queueDialog(
|
|
140
|
+
(doneCallback) => [
|
|
141
|
+
ManageChecks,
|
|
142
|
+
{
|
|
143
|
+
session,
|
|
144
|
+
handleClose: () => {
|
|
145
|
+
doneCallback()
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
],
|
|
149
|
+
)
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
|
+
],
|
|
153
|
+
})
|
|
154
|
+
}
|
package/src/session/session.ts
CHANGED
|
@@ -26,8 +26,8 @@ import { autorun, observable } from 'mobx'
|
|
|
26
26
|
import {
|
|
27
27
|
type Instance,
|
|
28
28
|
type SnapshotOut,
|
|
29
|
+
addDisposer,
|
|
29
30
|
applySnapshot,
|
|
30
|
-
flow,
|
|
31
31
|
getRoot,
|
|
32
32
|
getSnapshot,
|
|
33
33
|
types,
|
|
@@ -36,6 +36,7 @@ import {
|
|
|
36
36
|
import { type ApolloInternetAccountModel } from '../ApolloInternetAccount/model'
|
|
37
37
|
import { ApolloJobModel } from '../ApolloJobModel'
|
|
38
38
|
import { type ChangeManager } from '../ChangeManager'
|
|
39
|
+
import type ApolloPluginConfigurationSchema from '../config'
|
|
39
40
|
import { type ApolloRootModel } from '../types'
|
|
40
41
|
import { createFetchErrorMessage } from '../util'
|
|
41
42
|
|
|
@@ -53,12 +54,15 @@ export interface Collaborator {
|
|
|
53
54
|
locations: UserLocation[]
|
|
54
55
|
}
|
|
55
56
|
|
|
57
|
+
export interface HoveredFeature {
|
|
58
|
+
feature: AnnotationFeature
|
|
59
|
+
bp: number
|
|
60
|
+
}
|
|
61
|
+
|
|
56
62
|
export function extendSession(
|
|
57
63
|
pluginManager: PluginManager,
|
|
58
64
|
sessionModel: ReturnType<typeof types.model>,
|
|
59
65
|
) {
|
|
60
|
-
const aborter = new AbortController()
|
|
61
|
-
const { signal } = aborter
|
|
62
66
|
const AnnotationFeatureExtended = pluginManager.evaluateExtensionPoint(
|
|
63
67
|
'Apollo-extendAnnotationFeature',
|
|
64
68
|
AnnotationFeatureModel,
|
|
@@ -69,7 +73,12 @@ export function extendSession(
|
|
|
69
73
|
apolloDataStore: types.optional(ClientDataStore, { typeName: 'Client' }),
|
|
70
74
|
apolloSelectedFeature: types.safeReference(AnnotationFeatureExtended),
|
|
71
75
|
jobsManager: types.optional(ApolloJobModel, {}),
|
|
76
|
+
isLocked: types.optional(types.boolean, false),
|
|
72
77
|
})
|
|
78
|
+
.volatile(() => ({
|
|
79
|
+
apolloHoveredFeature: undefined as HoveredFeature | undefined,
|
|
80
|
+
abortController: new AbortController(),
|
|
81
|
+
}))
|
|
73
82
|
.extend(() => {
|
|
74
83
|
const collabs = observable.array<Collaborator>([])
|
|
75
84
|
|
|
@@ -94,10 +103,13 @@ export function extendSession(
|
|
|
94
103
|
}
|
|
95
104
|
})
|
|
96
105
|
.actions((self) => ({
|
|
97
|
-
apolloSetSelectedFeature(feature?: AnnotationFeature) {
|
|
106
|
+
apolloSetSelectedFeature(feature?: AnnotationFeature | string) {
|
|
98
107
|
// @ts-expect-error Not sure why TS thinks these MST types don't match
|
|
99
108
|
self.apolloSelectedFeature = feature
|
|
100
109
|
},
|
|
110
|
+
apolloSetHoveredFeature(feature?: HoveredFeature) {
|
|
111
|
+
self.apolloHoveredFeature = feature
|
|
112
|
+
},
|
|
101
113
|
addApolloTrackConfig(assembly: AssemblyModel, baseURL?: string) {
|
|
102
114
|
const trackId = `apollo_track_${assembly.name}`
|
|
103
115
|
const hasTrack = (self as unknown as AbstractSessionModel).tracks.some(
|
|
@@ -126,6 +138,18 @@ export function extendSession(
|
|
|
126
138
|
})
|
|
127
139
|
}
|
|
128
140
|
},
|
|
141
|
+
toggleLocked() {
|
|
142
|
+
self.isLocked = !self.isLocked
|
|
143
|
+
},
|
|
144
|
+
getPluginConfiguration() {
|
|
145
|
+
const { jbrowse } = getRoot<ApolloRootModel>(self)
|
|
146
|
+
const pluginConfiguration =
|
|
147
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
148
|
+
jbrowse.configuration.ApolloPlugin as Instance<
|
|
149
|
+
typeof ApolloPluginConfigurationSchema
|
|
150
|
+
>
|
|
151
|
+
return pluginConfiguration
|
|
152
|
+
},
|
|
129
153
|
broadcastLocations() {
|
|
130
154
|
const { internetAccounts } = getRoot<ApolloRootModel>(self)
|
|
131
155
|
const locations: {
|
|
@@ -183,120 +207,155 @@ export function extendSession(
|
|
|
183
207
|
}
|
|
184
208
|
},
|
|
185
209
|
}))
|
|
210
|
+
.volatile((self) => ({
|
|
211
|
+
previousSnapshot: getSnapshot(self),
|
|
212
|
+
}))
|
|
186
213
|
.actions((self) => ({
|
|
187
|
-
afterCreate
|
|
188
|
-
|
|
189
|
-
//
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
locations.push({ assemblyName, refName, start, end })
|
|
214
|
+
afterCreate() {
|
|
215
|
+
applySnapshot(self, { name: self.name, id: self.id })
|
|
216
|
+
// @ts-expect-error type is missing on ApolloRootModel
|
|
217
|
+
const { internetAccounts, jbrowse, reloadPluginManagerCallback } =
|
|
218
|
+
getRoot<ApolloRootModel>(self)
|
|
219
|
+
addDisposer(
|
|
220
|
+
self,
|
|
221
|
+
autorun(
|
|
222
|
+
() => {
|
|
223
|
+
// broadcastLocations() // **** This is not working and therefore we need to duplicate broadcastLocations() -method code here because autorun() does not observe changes otherwise
|
|
224
|
+
const locations: {
|
|
225
|
+
assemblyName: string
|
|
226
|
+
refName: string
|
|
227
|
+
start: number
|
|
228
|
+
end: number
|
|
229
|
+
}[] = []
|
|
230
|
+
for (const view of (self as unknown as AbstractSessionModel)
|
|
231
|
+
.views) {
|
|
232
|
+
if (view.type !== 'LinearGenomeView') {
|
|
233
|
+
return
|
|
234
|
+
}
|
|
235
|
+
const lgv = view as unknown as LinearGenomeViewModel
|
|
236
|
+
if (lgv.initialized) {
|
|
237
|
+
const { dynamicBlocks } = lgv
|
|
238
|
+
// eslint-disable-next-line unicorn/no-array-for-each
|
|
239
|
+
dynamicBlocks.forEach((block) => {
|
|
240
|
+
if (block.regionNumber !== undefined) {
|
|
241
|
+
const { assemblyName, end, refName, start } = block
|
|
242
|
+
const assembly =
|
|
243
|
+
self.apolloDataStore.assemblies.get(assemblyName)
|
|
244
|
+
if (
|
|
245
|
+
assembly &&
|
|
246
|
+
assembly.backendDriverType ===
|
|
247
|
+
'CollaborationServerDriver'
|
|
248
|
+
) {
|
|
249
|
+
locations.push({ assemblyName, refName, start, end })
|
|
250
|
+
}
|
|
225
251
|
}
|
|
252
|
+
})
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
if (locations.length === 0) {
|
|
256
|
+
for (const internetAccount of internetAccounts) {
|
|
257
|
+
if ('baseURL' in internetAccount) {
|
|
258
|
+
internetAccount.postUserLocation([])
|
|
226
259
|
}
|
|
227
|
-
}
|
|
260
|
+
}
|
|
261
|
+
return
|
|
228
262
|
}
|
|
229
|
-
|
|
230
|
-
|
|
263
|
+
|
|
264
|
+
const allLocations: UserLocation[] = []
|
|
231
265
|
for (const internetAccount of internetAccounts) {
|
|
232
266
|
if ('baseURL' in internetAccount) {
|
|
233
|
-
|
|
267
|
+
for (const location of locations) {
|
|
268
|
+
const tmpLoc: UserLocation = {
|
|
269
|
+
assemblyId: location.assemblyName,
|
|
270
|
+
refSeq: location.refName,
|
|
271
|
+
start: location.start,
|
|
272
|
+
end: location.end,
|
|
273
|
+
}
|
|
274
|
+
allLocations.push(tmpLoc)
|
|
275
|
+
}
|
|
276
|
+
internetAccount.postUserLocation(allLocations)
|
|
234
277
|
}
|
|
235
278
|
}
|
|
236
|
-
|
|
237
|
-
}
|
|
279
|
+
},
|
|
280
|
+
{ name: 'ApolloSessionBroadcastLocations' },
|
|
281
|
+
),
|
|
282
|
+
)
|
|
283
|
+
addDisposer(
|
|
284
|
+
self,
|
|
285
|
+
autorun(
|
|
286
|
+
async (reaction) => {
|
|
287
|
+
// When the initial config.json loads, it doesn't include the Apollo
|
|
288
|
+
// tracks, which would result in a potentially invalid session snapshot
|
|
289
|
+
// if any tracks are open. Here we copy the session snapshot, apply an
|
|
290
|
+
// empty session snapshot, and then restore the original session
|
|
291
|
+
// snapshot after the updated config.json loads.
|
|
292
|
+
const pluginConfiguration =
|
|
293
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
294
|
+
jbrowse.configuration.ApolloPlugin as Instance<
|
|
295
|
+
typeof ApolloPluginConfigurationSchema
|
|
296
|
+
>
|
|
297
|
+
const hasRole = readConfObject(
|
|
298
|
+
pluginConfiguration,
|
|
299
|
+
'hasRole',
|
|
300
|
+
) as boolean
|
|
301
|
+
if (hasRole) {
|
|
302
|
+
// @ts-expect-error not sure why snapshot type is wrong for snapshot
|
|
303
|
+
applySnapshot(self, self.previousSnapshot)
|
|
304
|
+
reaction.dispose()
|
|
305
|
+
return
|
|
306
|
+
}
|
|
238
307
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
308
|
+
const { signal } = self.abortController
|
|
309
|
+
// fetch and initialize assemblies for each of our Apollo internet accounts
|
|
310
|
+
for (const internetAccount of internetAccounts as ApolloInternetAccountModel[]) {
|
|
311
|
+
if (internetAccount.type !== 'ApolloInternetAccount') {
|
|
312
|
+
continue
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
const { baseURL } = internetAccount
|
|
316
|
+
const uri = new URL('jbrowse/config.json', baseURL).href
|
|
317
|
+
const fetch = internetAccount.getFetcher({
|
|
318
|
+
locationType: 'UriLocation',
|
|
319
|
+
uri,
|
|
320
|
+
})
|
|
321
|
+
let response: Response
|
|
322
|
+
try {
|
|
323
|
+
response = await fetch(uri, { signal })
|
|
324
|
+
} catch (error) {
|
|
325
|
+
if (!self.abortController.signal.aborted) {
|
|
326
|
+
console.error(error)
|
|
248
327
|
}
|
|
249
|
-
|
|
328
|
+
continue
|
|
250
329
|
}
|
|
251
|
-
|
|
330
|
+
if (!response.ok) {
|
|
331
|
+
const errorMessage = await createFetchErrorMessage(
|
|
332
|
+
response,
|
|
333
|
+
'Failed to fetch assemblies',
|
|
334
|
+
)
|
|
335
|
+
console.error(errorMessage)
|
|
336
|
+
continue
|
|
337
|
+
}
|
|
338
|
+
let jbrowseConfig
|
|
339
|
+
try {
|
|
340
|
+
jbrowseConfig = await response.json()
|
|
341
|
+
} catch (error) {
|
|
342
|
+
console.error(error)
|
|
343
|
+
continue
|
|
344
|
+
}
|
|
345
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
|
346
|
+
reloadPluginManagerCallback(
|
|
347
|
+
jbrowseConfig,
|
|
348
|
+
self.previousSnapshot,
|
|
349
|
+
)
|
|
350
|
+
reaction.dispose()
|
|
252
351
|
}
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
|
|
352
|
+
},
|
|
353
|
+
{ name: 'ApolloSessionLoadConfig' },
|
|
354
|
+
),
|
|
256
355
|
)
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
// fetch and initialize assemblies for each of our Apollo internet accounts
|
|
260
|
-
for (const internetAccount of internetAccounts as ApolloInternetAccountModel[]) {
|
|
261
|
-
if (internetAccount.type !== 'ApolloInternetAccount') {
|
|
262
|
-
continue
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
const { baseURL } = internetAccount
|
|
266
|
-
const uri = new URL('jbrowse/config.json', baseURL).href
|
|
267
|
-
const fetch = internetAccount.getFetcher({
|
|
268
|
-
locationType: 'UriLocation',
|
|
269
|
-
uri,
|
|
270
|
-
})
|
|
271
|
-
let response: Response
|
|
272
|
-
try {
|
|
273
|
-
response = yield fetch(uri, { signal })
|
|
274
|
-
} catch (error) {
|
|
275
|
-
console.error(error)
|
|
276
|
-
continue
|
|
277
|
-
}
|
|
278
|
-
if (!response.ok) {
|
|
279
|
-
const errorMessage = yield createFetchErrorMessage(
|
|
280
|
-
response,
|
|
281
|
-
'Failed to fetch assemblies',
|
|
282
|
-
)
|
|
283
|
-
console.error(errorMessage)
|
|
284
|
-
continue
|
|
285
|
-
}
|
|
286
|
-
let jbrowseConfig
|
|
287
|
-
try {
|
|
288
|
-
jbrowseConfig = yield response.json()
|
|
289
|
-
} catch (error) {
|
|
290
|
-
console.error(error)
|
|
291
|
-
continue
|
|
292
|
-
}
|
|
293
|
-
applySnapshot(jbrowse, jbrowseConfig)
|
|
294
|
-
// @ts-expect-error snapshot seems to get wrong type?
|
|
295
|
-
applySnapshot(self, sessionSnapshot)
|
|
296
|
-
}
|
|
297
|
-
}),
|
|
356
|
+
},
|
|
298
357
|
beforeDestroy() {
|
|
299
|
-
|
|
358
|
+
self.abortController.abort('destroying session model')
|
|
300
359
|
},
|
|
301
360
|
}))
|
|
302
361
|
|
|
@@ -51,3 +51,62 @@ export function getStrand(strand: number | undefined) {
|
|
|
51
51
|
}
|
|
52
52
|
return ''
|
|
53
53
|
}
|
|
54
|
+
|
|
55
|
+
function getChildren(feature: AnnotationFeature): AnnotationFeature[] {
|
|
56
|
+
const children: AnnotationFeature[] = []
|
|
57
|
+
//
|
|
58
|
+
if (feature.children) {
|
|
59
|
+
for (const [, ff] of feature.children) {
|
|
60
|
+
children.push(ff)
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return children
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function getParents(feature: AnnotationFeature): AnnotationFeature[] {
|
|
67
|
+
const parents: AnnotationFeature[] = []
|
|
68
|
+
let { parent } = feature
|
|
69
|
+
while (parent) {
|
|
70
|
+
parents.push(parent)
|
|
71
|
+
;({ parent } = parent)
|
|
72
|
+
}
|
|
73
|
+
return parents
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function getRelatedFeatures(
|
|
77
|
+
feature: AnnotationFeature,
|
|
78
|
+
bp: number,
|
|
79
|
+
includeSiblings = false,
|
|
80
|
+
): AnnotationFeature[] {
|
|
81
|
+
const relatedFeatures: AnnotationFeature[] = []
|
|
82
|
+
relatedFeatures.push(feature)
|
|
83
|
+
for (const x of getParents(feature)) {
|
|
84
|
+
relatedFeatures.push(x)
|
|
85
|
+
}
|
|
86
|
+
const children = getChildren(feature)
|
|
87
|
+
for (const child of children) {
|
|
88
|
+
if (child.min < bp && child.max >= bp) {
|
|
89
|
+
relatedFeatures.push(child)
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
if (!includeSiblings) {
|
|
93
|
+
return relatedFeatures
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Also add siblings , i.e. features having the same parent as the clicked
|
|
97
|
+
// one and intersecting the click position
|
|
98
|
+
if (feature.parent) {
|
|
99
|
+
const siblings = feature.parent.children
|
|
100
|
+
if (siblings) {
|
|
101
|
+
for (const [, sib] of siblings) {
|
|
102
|
+
if (sib._id == feature._id) {
|
|
103
|
+
continue
|
|
104
|
+
}
|
|
105
|
+
if (sib.min < bp && sib.max >= bp) {
|
|
106
|
+
relatedFeatures.push(sib)
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return relatedFeatures
|
|
112
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export async function copyToClipboard(element: HTMLElement) {
|
|
2
|
+
if (isSecureContext) {
|
|
3
|
+
const textBlob = new Blob([element.outerText], { type: 'text/plain' })
|
|
4
|
+
const htmlBlob = new Blob([element.outerHTML], { type: 'text/html' })
|
|
5
|
+
const clipboardItem = new ClipboardItem({
|
|
6
|
+
[textBlob.type]: textBlob,
|
|
7
|
+
[htmlBlob.type]: htmlBlob,
|
|
8
|
+
})
|
|
9
|
+
return navigator.clipboard.write([clipboardItem])
|
|
10
|
+
}
|
|
11
|
+
const copyCallback = (event: ClipboardEvent) => {
|
|
12
|
+
event.clipboardData?.setData('text/plain', element.outerText)
|
|
13
|
+
event.clipboardData?.setData('text/html', element.outerHTML)
|
|
14
|
+
event.preventDefault()
|
|
15
|
+
}
|
|
16
|
+
document.addEventListener('copy', copyCallback)
|
|
17
|
+
// fall back to deprecated only in non-secure contexts
|
|
18
|
+
// eslint-disable-next-line @typescript-eslint/no-deprecated
|
|
19
|
+
document.execCommand('copy')
|
|
20
|
+
document.removeEventListener('copy', copyCallback)
|
|
21
|
+
}
|