@apollo-annotation/jbrowse-plugin-apollo 0.3.7 → 0.3.9
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 +11212 -10483
- package/dist/index.esm.js.map +1 -1
- package/dist/jbrowse-plugin-apollo.cjs.development.js +11251 -10509
- 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 +7726 -9014
- 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 +18 -18
- package/src/ApolloInternetAccount/model.ts +123 -70
- package/src/ApolloRefNameAliasAdapter/ApolloRefNameAliasAdapter.ts +4 -4
- package/src/ApolloSequenceAdapter/ApolloSequenceAdapter.ts +9 -7
- package/src/BackendDrivers/CollaborationServerDriver.ts +72 -20
- package/src/BackendDrivers/DesktopFileDriver.ts +2 -2
- package/src/ChangeManager.ts +36 -14
- package/src/FeatureDetailsWidget/ApolloTranscriptDetailsWidget.tsx +64 -5
- package/src/FeatureDetailsWidget/BasicInformation.tsx +6 -4
- package/src/FeatureDetailsWidget/NumberTextField.tsx +5 -2
- package/src/FeatureDetailsWidget/TranscriptSequence.tsx +70 -73
- package/src/FeatureDetailsWidget/TranscriptWidgetEditLocation.tsx +72 -234
- package/src/LinearApolloDisplay/components/CheckResultWarnings.tsx +92 -0
- package/src/LinearApolloDisplay/components/LinearApolloDisplay.tsx +23 -131
- package/src/LinearApolloDisplay/glyphs/BoxGlyph.ts +50 -194
- package/src/LinearApolloDisplay/glyphs/GeneGlyph.ts +279 -217
- package/src/LinearApolloDisplay/glyphs/GenericChildGlyph.ts +53 -34
- package/src/LinearApolloDisplay/glyphs/Glyph.ts +7 -9
- package/src/LinearApolloDisplay/glyphs/util.ts +19 -0
- package/src/LinearApolloDisplay/stateModel/base.ts +34 -43
- package/src/LinearApolloDisplay/stateModel/layouts.ts +3 -2
- package/src/LinearApolloDisplay/stateModel/mouseEvents.ts +32 -261
- package/src/LinearApolloDisplay/stateModel/rendering.ts +43 -343
- 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/drawSequenceOverlay.ts +181 -0
- package/src/LinearApolloReferenceSequenceDisplay/drawSequenceTrack.ts +218 -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 +157 -0
- package/src/LinearApolloSixFrameDisplay/components/LinearApolloSixFrameDisplay.tsx +101 -38
- package/src/LinearApolloSixFrameDisplay/glyphs/GeneGlyph.ts +334 -262
- package/src/LinearApolloSixFrameDisplay/glyphs/Glyph.ts +12 -8
- package/src/LinearApolloSixFrameDisplay/stateModel/base.ts +42 -4
- package/src/LinearApolloSixFrameDisplay/stateModel/layouts.ts +4 -8
- package/src/LinearApolloSixFrameDisplay/stateModel/mouseEvents.ts +73 -97
- package/src/LinearApolloSixFrameDisplay/stateModel/rendering.ts +49 -61
- package/src/TabularEditor/HybridGrid/Feature.tsx +16 -14
- package/src/TabularEditor/HybridGrid/HybridGrid.tsx +7 -5
- package/src/components/AddAssembly.tsx +34 -38
- package/src/components/AddAssemblyAliases.tsx +1 -1
- package/src/components/AddChildFeature.tsx +5 -2
- package/src/components/AddFeature.tsx +30 -21
- package/src/components/AddRefSeqAliases.tsx +64 -50
- package/src/components/CopyFeature.tsx +4 -2
- package/src/components/CreateApolloAnnotation.tsx +22 -9
- package/src/components/DeleteAssembly.tsx +3 -10
- package/src/components/DownloadGFF3.tsx +2 -2
- package/src/components/EditZoomThresholdDialog.tsx +69 -0
- package/src/components/FilterFeatures.tsx +7 -7
- package/src/components/FilterTranscripts.tsx +6 -6
- package/src/components/ImportFeatures.tsx +1 -1
- package/src/components/ManageChecks.tsx +3 -10
- package/src/components/ManageUsers.tsx +23 -22
- package/src/components/MergeTranscripts.tsx +12 -15
- package/src/components/OntologyTermAutocomplete.tsx +1 -8
- package/src/components/OntologyTermMultiSelect.tsx +11 -11
- package/src/components/OpenLocalFile.tsx +11 -7
- package/src/components/ViewChangeLog.tsx +25 -50
- package/src/components/ViewCheckResults.tsx +2 -8
- package/src/components/index.ts +1 -0
- package/src/config.ts +6 -0
- package/src/index.ts +53 -115
- package/src/makeDisplayComponent.tsx +9 -14
- package/src/menus/index.ts +1 -0
- package/src/{ApolloInternetAccount/addMenuItems.ts → menus/topLevelMenu.ts} +56 -47
- package/src/menus/topLevelMenuAdmin.ts +154 -0
- package/src/session/ClientDataStore.ts +32 -14
- package/src/session/session.ts +159 -121
- package/src/util/annotationFeatureUtils.ts +15 -21
- package/src/util/displayUtils.ts +149 -0
- package/src/util/glyphUtils.ts +329 -0
- package/src/util/loadAssemblyIntoClient.ts +3 -2
- package/src/util/mouseEventsUtils.ts +32 -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
|
+
}
|
|
@@ -33,6 +33,7 @@ import {
|
|
|
33
33
|
|
|
34
34
|
import {
|
|
35
35
|
type ApolloInternetAccount,
|
|
36
|
+
type BackendDriver,
|
|
36
37
|
CollaborationServerDriver,
|
|
37
38
|
DesktopFileDriver,
|
|
38
39
|
InMemoryFileDriver,
|
|
@@ -86,18 +87,38 @@ export function clientDataStoreFactory(
|
|
|
86
87
|
}
|
|
87
88
|
return self.assemblies.put(assemblySnapshot)
|
|
88
89
|
},
|
|
90
|
+
}))
|
|
91
|
+
.actions((self) => ({
|
|
89
92
|
addFeature(assemblyId: string, feature: AnnotationFeatureSnapshot) {
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
93
|
+
const session = getSession(self)
|
|
94
|
+
const { assemblyManager } = session
|
|
95
|
+
let apolloAssembly = self.assemblies.get(assemblyId)
|
|
96
|
+
if (!apolloAssembly) {
|
|
97
|
+
// maybe it's a valid assembly that we haven't loaded yet
|
|
98
|
+
const assembly = assemblyManager.get(assemblyId)
|
|
99
|
+
if (!assembly) {
|
|
100
|
+
throw new Error(
|
|
101
|
+
`Could not find assembly "${assemblyId}" to add feature "${feature._id}"`,
|
|
102
|
+
)
|
|
103
|
+
}
|
|
104
|
+
apolloAssembly = self.addAssembly(assemblyId)
|
|
95
105
|
}
|
|
96
|
-
|
|
106
|
+
let ref = apolloAssembly.refSeqs.get(feature.refSeq)
|
|
97
107
|
if (!ref) {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
)
|
|
108
|
+
// maybe it's a valid refName that we haven't loaded yet
|
|
109
|
+
const assembly = assemblyManager.get(assemblyId)
|
|
110
|
+
if (!assembly) {
|
|
111
|
+
throw new Error(
|
|
112
|
+
`Could not find assembly "${assemblyId}" to add feature "${feature._id}"`,
|
|
113
|
+
)
|
|
114
|
+
}
|
|
115
|
+
const canonicalRefName = assembly.getCanonicalRefName(feature.refSeq)
|
|
116
|
+
if (!canonicalRefName) {
|
|
117
|
+
throw new Error(
|
|
118
|
+
`Could not find refSeq "${feature.refSeq}" to add feature "${feature._id}"`,
|
|
119
|
+
)
|
|
120
|
+
}
|
|
121
|
+
ref = apolloAssembly.addRefSeq(feature.refSeq, canonicalRefName)
|
|
101
122
|
}
|
|
102
123
|
ref.features.put(feature)
|
|
103
124
|
},
|
|
@@ -212,15 +233,12 @@ export function clientDataStoreFactory(
|
|
|
212
233
|
},
|
|
213
234
|
}))
|
|
214
235
|
.views((self) => ({
|
|
215
|
-
getBackendDriver(assemblyId: string) {
|
|
216
|
-
if (!assemblyId) {
|
|
217
|
-
return self.collaborationServerDriver
|
|
218
|
-
}
|
|
236
|
+
getBackendDriver(assemblyId: string): BackendDriver | undefined {
|
|
219
237
|
const session = getSession(self)
|
|
220
238
|
const { assemblyManager } = session
|
|
221
239
|
const assembly = assemblyManager.get(assemblyId)
|
|
222
240
|
if (!assembly) {
|
|
223
|
-
return
|
|
241
|
+
return
|
|
224
242
|
}
|
|
225
243
|
const { file, internetAccountConfigId } = getConf(assembly, [
|
|
226
244
|
'sequence',
|
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,
|
|
@@ -54,12 +54,15 @@ export interface Collaborator {
|
|
|
54
54
|
locations: UserLocation[]
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
+
export interface HoveredFeature {
|
|
58
|
+
feature: AnnotationFeature
|
|
59
|
+
bp: number
|
|
60
|
+
}
|
|
61
|
+
|
|
57
62
|
export function extendSession(
|
|
58
63
|
pluginManager: PluginManager,
|
|
59
64
|
sessionModel: ReturnType<typeof types.model>,
|
|
60
65
|
) {
|
|
61
|
-
const aborter = new AbortController()
|
|
62
|
-
const { signal } = aborter
|
|
63
66
|
const AnnotationFeatureExtended = pluginManager.evaluateExtensionPoint(
|
|
64
67
|
'Apollo-extendAnnotationFeature',
|
|
65
68
|
AnnotationFeatureModel,
|
|
@@ -70,7 +73,12 @@ export function extendSession(
|
|
|
70
73
|
apolloDataStore: types.optional(ClientDataStore, { typeName: 'Client' }),
|
|
71
74
|
apolloSelectedFeature: types.safeReference(AnnotationFeatureExtended),
|
|
72
75
|
jobsManager: types.optional(ApolloJobModel, {}),
|
|
76
|
+
isLocked: types.optional(types.boolean, false),
|
|
73
77
|
})
|
|
78
|
+
.volatile(() => ({
|
|
79
|
+
apolloHoveredFeature: undefined as HoveredFeature | undefined,
|
|
80
|
+
abortController: new AbortController(),
|
|
81
|
+
}))
|
|
74
82
|
.extend(() => {
|
|
75
83
|
const collabs = observable.array<Collaborator>([])
|
|
76
84
|
|
|
@@ -95,10 +103,13 @@ export function extendSession(
|
|
|
95
103
|
}
|
|
96
104
|
})
|
|
97
105
|
.actions((self) => ({
|
|
98
|
-
apolloSetSelectedFeature(feature?: AnnotationFeature) {
|
|
106
|
+
apolloSetSelectedFeature(feature?: AnnotationFeature | string) {
|
|
99
107
|
// @ts-expect-error Not sure why TS thinks these MST types don't match
|
|
100
108
|
self.apolloSelectedFeature = feature
|
|
101
109
|
},
|
|
110
|
+
apolloSetHoveredFeature(feature?: HoveredFeature) {
|
|
111
|
+
self.apolloHoveredFeature = feature
|
|
112
|
+
},
|
|
102
113
|
addApolloTrackConfig(assembly: AssemblyModel, baseURL?: string) {
|
|
103
114
|
const trackId = `apollo_track_${assembly.name}`
|
|
104
115
|
const hasTrack = (self as unknown as AbstractSessionModel).tracks.some(
|
|
@@ -127,6 +138,18 @@ export function extendSession(
|
|
|
127
138
|
})
|
|
128
139
|
}
|
|
129
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
|
+
},
|
|
130
153
|
broadcastLocations() {
|
|
131
154
|
const { internetAccounts } = getRoot<ApolloRootModel>(self)
|
|
132
155
|
const locations: {
|
|
@@ -142,20 +165,16 @@ export function extendSession(
|
|
|
142
165
|
const lgv = view as unknown as LinearGenomeViewModel
|
|
143
166
|
if (lgv.initialized) {
|
|
144
167
|
const { dynamicBlocks } = lgv
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
assembly.backendDriverType === 'CollaborationServerDriver'
|
|
154
|
-
) {
|
|
155
|
-
locations.push({ assemblyName, refName, start, end })
|
|
156
|
-
}
|
|
168
|
+
for (const block of dynamicBlocks.contentBlocks) {
|
|
169
|
+
const { assemblyName, end, refName, start } = block
|
|
170
|
+
const assembly = self.apolloDataStore.assemblies.get(assemblyName)
|
|
171
|
+
if (
|
|
172
|
+
assembly &&
|
|
173
|
+
assembly.backendDriverType === 'CollaborationServerDriver'
|
|
174
|
+
) {
|
|
175
|
+
locations.push({ assemblyName, refName, start, end })
|
|
157
176
|
}
|
|
158
|
-
}
|
|
177
|
+
}
|
|
159
178
|
}
|
|
160
179
|
}
|
|
161
180
|
if (locations.length === 0) {
|
|
@@ -184,28 +203,35 @@ export function extendSession(
|
|
|
184
203
|
}
|
|
185
204
|
},
|
|
186
205
|
}))
|
|
206
|
+
.volatile((self) => ({
|
|
207
|
+
previousSnapshot: getSnapshot(self),
|
|
208
|
+
}))
|
|
187
209
|
.actions((self) => ({
|
|
188
|
-
afterCreate
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
210
|
+
afterCreate() {
|
|
211
|
+
applySnapshot(self, { name: self.name, id: self.id })
|
|
212
|
+
// @ts-expect-error type is missing on ApolloRootModel
|
|
213
|
+
const { internetAccounts, jbrowse, reloadPluginManagerCallback } =
|
|
214
|
+
getRoot<ApolloRootModel>(self)
|
|
215
|
+
addDisposer(
|
|
216
|
+
self,
|
|
217
|
+
autorun(
|
|
218
|
+
() => {
|
|
219
|
+
// broadcastLocations() // **** This is not working and therefore we need to duplicate broadcastLocations() -method code here because autorun() does not observe changes otherwise
|
|
220
|
+
const locations: {
|
|
221
|
+
assemblyName: string
|
|
222
|
+
refName: string
|
|
223
|
+
start: number
|
|
224
|
+
end: number
|
|
225
|
+
}[] = []
|
|
226
|
+
for (const view of (self as unknown as AbstractSessionModel)
|
|
227
|
+
.views) {
|
|
228
|
+
if (view.type !== 'LinearGenomeView') {
|
|
229
|
+
return
|
|
230
|
+
}
|
|
231
|
+
const lgv = view as unknown as LinearGenomeViewModel
|
|
232
|
+
if (lgv.initialized) {
|
|
233
|
+
const { dynamicBlocks } = lgv
|
|
234
|
+
for (const block of dynamicBlocks.contentBlocks) {
|
|
209
235
|
const { assemblyName, end, refName, start } = block
|
|
210
236
|
const assembly =
|
|
211
237
|
self.apolloDataStore.assemblies.get(assemblyName)
|
|
@@ -216,100 +242,112 @@ export function extendSession(
|
|
|
216
242
|
locations.push({ assemblyName, refName, start, end })
|
|
217
243
|
}
|
|
218
244
|
}
|
|
219
|
-
}
|
|
245
|
+
}
|
|
220
246
|
}
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
247
|
+
if (locations.length === 0) {
|
|
248
|
+
for (const internetAccount of internetAccounts) {
|
|
249
|
+
if ('baseURL' in internetAccount) {
|
|
250
|
+
internetAccount.postUserLocation([])
|
|
251
|
+
}
|
|
226
252
|
}
|
|
253
|
+
return
|
|
227
254
|
}
|
|
228
|
-
return
|
|
229
|
-
}
|
|
230
255
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
256
|
+
const allLocations: UserLocation[] = []
|
|
257
|
+
for (const internetAccount of internetAccounts) {
|
|
258
|
+
if ('baseURL' in internetAccount) {
|
|
259
|
+
for (const location of locations) {
|
|
260
|
+
const tmpLoc: UserLocation = {
|
|
261
|
+
assemblyId: location.assemblyName,
|
|
262
|
+
refSeq: location.refName,
|
|
263
|
+
start: location.start,
|
|
264
|
+
end: location.end,
|
|
265
|
+
}
|
|
266
|
+
allLocations.push(tmpLoc)
|
|
240
267
|
}
|
|
241
|
-
|
|
268
|
+
internetAccount.postUserLocation(allLocations)
|
|
242
269
|
}
|
|
243
|
-
internetAccount.postUserLocation(allLocations)
|
|
244
270
|
}
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
|
|
271
|
+
},
|
|
272
|
+
{ name: 'ApolloSessionBroadcastLocations' },
|
|
273
|
+
),
|
|
248
274
|
)
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
275
|
+
addDisposer(
|
|
276
|
+
self,
|
|
277
|
+
autorun(
|
|
278
|
+
async (reaction) => {
|
|
279
|
+
// When the initial config.json loads, it doesn't include the Apollo
|
|
280
|
+
// tracks, which would result in a potentially invalid session snapshot
|
|
281
|
+
// if any tracks are open. Here we copy the session snapshot, apply an
|
|
282
|
+
// empty session snapshot, and then restore the original session
|
|
283
|
+
// snapshot after the updated config.json loads.
|
|
284
|
+
const pluginConfiguration =
|
|
285
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
286
|
+
jbrowse.configuration.ApolloPlugin as Instance<
|
|
287
|
+
typeof ApolloPluginConfigurationSchema
|
|
288
|
+
>
|
|
289
|
+
const hasRole = readConfObject(
|
|
290
|
+
pluginConfiguration,
|
|
291
|
+
'hasRole',
|
|
292
|
+
) as boolean
|
|
293
|
+
if (hasRole) {
|
|
294
|
+
// @ts-expect-error not sure why snapshot type is wrong for snapshot
|
|
295
|
+
applySnapshot(self, self.previousSnapshot)
|
|
296
|
+
reaction.dispose()
|
|
297
|
+
return
|
|
298
|
+
}
|
|
272
299
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
300
|
+
const { signal } = self.abortController
|
|
301
|
+
// fetch and initialize assemblies for each of our Apollo internet accounts
|
|
302
|
+
for (const internetAccount of internetAccounts as ApolloInternetAccountModel[]) {
|
|
303
|
+
if (internetAccount.type !== 'ApolloInternetAccount') {
|
|
304
|
+
continue
|
|
305
|
+
}
|
|
278
306
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
307
|
+
const { baseURL } = internetAccount
|
|
308
|
+
const uri = new URL('jbrowse/config.json', baseURL).href
|
|
309
|
+
const fetch = internetAccount.getFetcher({
|
|
310
|
+
locationType: 'UriLocation',
|
|
311
|
+
uri,
|
|
312
|
+
})
|
|
313
|
+
let response: Response
|
|
314
|
+
try {
|
|
315
|
+
response = await fetch(uri, { signal })
|
|
316
|
+
} catch (error) {
|
|
317
|
+
if (!self.abortController.signal.aborted) {
|
|
318
|
+
console.error(error)
|
|
319
|
+
}
|
|
320
|
+
continue
|
|
321
|
+
}
|
|
322
|
+
if (!response.ok) {
|
|
323
|
+
const errorMessage = await createFetchErrorMessage(
|
|
324
|
+
response,
|
|
325
|
+
'Failed to fetch assemblies',
|
|
326
|
+
)
|
|
327
|
+
console.error(errorMessage)
|
|
328
|
+
continue
|
|
329
|
+
}
|
|
330
|
+
let jbrowseConfig
|
|
331
|
+
try {
|
|
332
|
+
jbrowseConfig = await response.json()
|
|
333
|
+
} catch (error) {
|
|
334
|
+
console.error(error)
|
|
335
|
+
continue
|
|
336
|
+
}
|
|
337
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
|
338
|
+
reloadPluginManagerCallback(
|
|
339
|
+
jbrowseConfig,
|
|
340
|
+
self.previousSnapshot,
|
|
341
|
+
)
|
|
342
|
+
reaction.dispose()
|
|
343
|
+
}
|
|
344
|
+
},
|
|
345
|
+
{ name: 'ApolloSessionLoadConfig' },
|
|
346
|
+
),
|
|
347
|
+
)
|
|
348
|
+
},
|
|
311
349
|
beforeDestroy() {
|
|
312
|
-
|
|
350
|
+
self.abortController.abort('destroying session model')
|
|
313
351
|
},
|
|
314
352
|
}))
|
|
315
353
|
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import { type AnnotationFeature } from '@apollo-annotation/mst'
|
|
2
2
|
|
|
3
|
-
import { type MousePosition } from '../LinearApolloDisplay/stateModel/mouseEvents'
|
|
4
|
-
|
|
5
3
|
export function getFeatureName(feature: AnnotationFeature) {
|
|
6
4
|
const { attributes } = feature
|
|
7
5
|
const name = attributes.get('gff_name')
|
|
@@ -75,44 +73,40 @@ function getParents(feature: AnnotationFeature): AnnotationFeature[] {
|
|
|
75
73
|
return parents
|
|
76
74
|
}
|
|
77
75
|
|
|
78
|
-
export function
|
|
79
|
-
|
|
76
|
+
export function getRelatedFeatures(
|
|
77
|
+
feature: AnnotationFeature,
|
|
78
|
+
bp: number,
|
|
80
79
|
includeSiblings = false,
|
|
81
80
|
): AnnotationFeature[] {
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
clickedFeatures.push(mousePosition.featureAndGlyphUnderMouse.feature)
|
|
87
|
-
for (const x of getParents(mousePosition.featureAndGlyphUnderMouse.feature)) {
|
|
88
|
-
clickedFeatures.push(x)
|
|
81
|
+
const relatedFeatures: AnnotationFeature[] = []
|
|
82
|
+
relatedFeatures.push(feature)
|
|
83
|
+
for (const x of getParents(feature)) {
|
|
84
|
+
relatedFeatures.push(x)
|
|
89
85
|
}
|
|
90
|
-
const
|
|
91
|
-
const children = getChildren(mousePosition.featureAndGlyphUnderMouse.feature)
|
|
86
|
+
const children = getChildren(feature)
|
|
92
87
|
for (const child of children) {
|
|
93
88
|
if (child.min < bp && child.max >= bp) {
|
|
94
|
-
|
|
89
|
+
relatedFeatures.push(child)
|
|
95
90
|
}
|
|
96
91
|
}
|
|
97
92
|
if (!includeSiblings) {
|
|
98
|
-
return
|
|
93
|
+
return relatedFeatures
|
|
99
94
|
}
|
|
100
95
|
|
|
101
96
|
// Also add siblings , i.e. features having the same parent as the clicked
|
|
102
97
|
// one and intersecting the click position
|
|
103
|
-
if (
|
|
104
|
-
const siblings =
|
|
105
|
-
mousePosition.featureAndGlyphUnderMouse.feature.parent.children
|
|
98
|
+
if (feature.parent) {
|
|
99
|
+
const siblings = feature.parent.children
|
|
106
100
|
if (siblings) {
|
|
107
101
|
for (const [, sib] of siblings) {
|
|
108
|
-
if (sib._id ==
|
|
102
|
+
if (sib._id == feature._id) {
|
|
109
103
|
continue
|
|
110
104
|
}
|
|
111
105
|
if (sib.min < bp && sib.max >= bp) {
|
|
112
|
-
|
|
106
|
+
relatedFeatures.push(sib)
|
|
113
107
|
}
|
|
114
108
|
}
|
|
115
109
|
}
|
|
116
110
|
}
|
|
117
|
-
return
|
|
111
|
+
return relatedFeatures
|
|
118
112
|
}
|