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

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 (136) hide show
  1. package/dist/index.esm.js +6964 -4598
  2. package/dist/index.esm.js.map +1 -1
  3. package/dist/jbrowse-plugin-apollo.cjs.development.js +6610 -4261
  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 +11563 -7493
  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/ApolloInternetAccount/addMenuItems.ts +23 -2
  13. package/src/ApolloInternetAccount/components/AuthTypeSelector.tsx +1 -0
  14. package/src/ApolloInternetAccount/components/LoginButtons.tsx +1 -1
  15. package/src/ApolloInternetAccount/components/LoginIcons.tsx +1 -1
  16. package/src/ApolloInternetAccount/configSchema.ts +1 -1
  17. package/src/ApolloInternetAccount/model.ts +11 -10
  18. package/src/ApolloJobModel.ts +1 -1
  19. package/src/ApolloRefNameAliasAdapter/ApolloRefNameAliasAdapter.ts +8 -6
  20. package/src/ApolloRefNameAliasAdapter/index.ts +2 -2
  21. package/src/ApolloSequenceAdapter/ApolloSequenceAdapter.ts +4 -4
  22. package/src/ApolloSequenceAdapter/index.ts +1 -1
  23. package/src/ApolloTextSearchAdapter/ApolloTextSearchAdapter.ts +8 -7
  24. package/src/ApolloTextSearchAdapter/index.ts +1 -1
  25. package/src/BackendDrivers/BackendDriver.ts +7 -7
  26. package/src/BackendDrivers/CollaborationServerDriver.ts +14 -10
  27. package/src/BackendDrivers/DesktopFileDriver.ts +11 -10
  28. package/src/BackendDrivers/InMemoryFileDriver.ts +10 -6
  29. package/src/ChangeManager.ts +15 -11
  30. package/src/FeatureDetailsWidget/ApolloFeatureDetailsWidget.tsx +8 -7
  31. package/src/FeatureDetailsWidget/ApolloTranscriptDetailsWidget.tsx +35 -14
  32. package/src/FeatureDetailsWidget/AttributeKey.tsx +50 -0
  33. package/src/FeatureDetailsWidget/AttributeKeySelector.tsx +104 -0
  34. package/src/FeatureDetailsWidget/Attributes.tsx +215 -367
  35. package/src/FeatureDetailsWidget/BasicInformation.tsx +6 -5
  36. package/src/FeatureDetailsWidget/DefaultAttributeEditor.tsx +104 -0
  37. package/src/FeatureDetailsWidget/DefaultAttributeViewer.tsx +22 -0
  38. package/src/FeatureDetailsWidget/FeatureDetailsNavigation.tsx +4 -4
  39. package/src/FeatureDetailsWidget/NumberTextField.tsx +1 -1
  40. package/src/FeatureDetailsWidget/Sequence.tsx +2 -2
  41. package/src/FeatureDetailsWidget/StringTextField.tsx +1 -1
  42. package/src/FeatureDetailsWidget/TranscriptSequence.tsx +15 -23
  43. package/src/FeatureDetailsWidget/TranscriptWidgetEditLocation.tsx +950 -196
  44. package/src/FeatureDetailsWidget/TranscriptWidgetSummary.tsx +8 -4
  45. package/src/FeatureDetailsWidget/model.ts +8 -3
  46. package/src/LinearApolloDisplay/components/LinearApolloDisplay.tsx +7 -7
  47. package/src/LinearApolloDisplay/glyphs/BoxGlyph.ts +59 -72
  48. package/src/LinearApolloDisplay/glyphs/GeneGlyph.ts +253 -60
  49. package/src/LinearApolloDisplay/glyphs/GenericChildGlyph.ts +52 -6
  50. package/src/LinearApolloDisplay/glyphs/Glyph.ts +16 -8
  51. package/src/LinearApolloDisplay/stateModel/base.ts +81 -10
  52. package/src/LinearApolloDisplay/stateModel/index.ts +4 -3
  53. package/src/LinearApolloDisplay/stateModel/layouts.ts +8 -39
  54. package/src/LinearApolloDisplay/stateModel/mouseEvents.ts +63 -46
  55. package/src/LinearApolloDisplay/stateModel/rendering.ts +60 -31
  56. package/src/LinearApolloSixFrameDisplay/components/LinearApolloSixFrameDisplay.tsx +226 -0
  57. package/src/LinearApolloSixFrameDisplay/components/TrackLines.tsx +32 -0
  58. package/src/LinearApolloSixFrameDisplay/components/index.ts +2 -0
  59. package/src/LinearApolloSixFrameDisplay/configSchema.ts +7 -0
  60. package/src/LinearApolloSixFrameDisplay/glyphs/GeneGlyph.ts +940 -0
  61. package/src/LinearApolloSixFrameDisplay/glyphs/Glyph.ts +63 -0
  62. package/src/LinearApolloSixFrameDisplay/glyphs/index.ts +1 -0
  63. package/src/LinearApolloSixFrameDisplay/index.ts +2 -0
  64. package/src/LinearApolloSixFrameDisplay/stateModel/base.ts +302 -0
  65. package/src/LinearApolloSixFrameDisplay/stateModel/index.ts +27 -0
  66. package/src/LinearApolloSixFrameDisplay/stateModel/layouts.ts +252 -0
  67. package/src/LinearApolloSixFrameDisplay/stateModel/mouseEvents.ts +368 -0
  68. package/src/LinearApolloSixFrameDisplay/stateModel/rendering.ts +201 -0
  69. package/src/LinearApolloSixFrameDisplay/types.ts +1 -0
  70. package/src/OntologyManager/OntologyStore/fulltext.test.ts +1 -1
  71. package/src/OntologyManager/OntologyStore/fulltext.ts +8 -3
  72. package/src/OntologyManager/OntologyStore/index.test.ts +3 -1
  73. package/src/OntologyManager/OntologyStore/index.ts +19 -14
  74. package/src/OntologyManager/OntologyStore/indexeddb-schema.ts +6 -5
  75. package/src/OntologyManager/OntologyStore/indexeddb-storage.ts +11 -5
  76. package/src/OntologyManager/index.ts +12 -7
  77. package/src/OntologyManager/util.ts +3 -2
  78. package/src/TabularEditor/HybridGrid/ChangeHandling.ts +2 -2
  79. package/src/TabularEditor/HybridGrid/Feature.tsx +13 -7
  80. package/src/TabularEditor/HybridGrid/FeatureAttributes.tsx +1 -1
  81. package/src/TabularEditor/HybridGrid/HybridGrid.tsx +3 -2
  82. package/src/TabularEditor/HybridGrid/ToolBar.tsx +1 -1
  83. package/src/TabularEditor/HybridGrid/featureContextMenuItems.ts +114 -22
  84. package/src/TabularEditor/TabularEditorPane.tsx +1 -1
  85. package/src/TabularEditor/model.ts +2 -2
  86. package/src/TabularEditor/types.ts +5 -2
  87. package/src/components/AddAssembly.tsx +182 -179
  88. package/src/components/AddAssemblyAliases.tsx +114 -0
  89. package/src/components/AddChildFeature.tsx +8 -10
  90. package/src/components/AddFeature.tsx +216 -44
  91. package/src/components/AddRefSeqAliases.tsx +14 -12
  92. package/src/components/CopyFeature.tsx +10 -11
  93. package/src/components/CreateApolloAnnotation.tsx +342 -158
  94. package/src/components/DeleteAssembly.tsx +9 -8
  95. package/src/components/DeleteFeature.tsx +362 -14
  96. package/src/components/Dialog.tsx +1 -1
  97. package/src/components/DownloadGFF3.tsx +31 -11
  98. package/src/components/FilterFeatures.tsx +6 -4
  99. package/src/components/FilterTranscripts.tsx +86 -0
  100. package/src/components/ImportFeatures.tsx +7 -6
  101. package/src/components/LogOut.tsx +5 -4
  102. package/src/components/ManageChecks.tsx +9 -8
  103. package/src/components/ManageUsers.tsx +11 -10
  104. package/src/components/MergeExons.tsx +193 -0
  105. package/src/components/MergeTranscripts.tsx +185 -0
  106. package/src/components/OntologyTermAutocomplete.tsx +5 -5
  107. package/src/components/OntologyTermMultiSelect.tsx +6 -6
  108. package/src/components/OpenLocalFile.tsx +4 -3
  109. package/src/components/SplitExon.tsx +134 -0
  110. package/src/components/ViewChangeLog.tsx +7 -6
  111. package/src/components/ViewCheckResults.tsx +8 -7
  112. package/src/components/index.ts +3 -0
  113. package/src/config.ts +5 -0
  114. package/src/extensions/annotationFromJBrowseFeature.test.ts +1 -0
  115. package/src/extensions/annotationFromJBrowseFeature.ts +13 -10
  116. package/src/extensions/annotationFromPileup.ts +104 -94
  117. package/src/index.ts +33 -50
  118. package/src/makeDisplayComponent.tsx +90 -37
  119. package/src/session/ClientDataStore.ts +21 -17
  120. package/src/session/session.ts +46 -39
  121. package/src/types.ts +4 -4
  122. package/src/util/annotationFeatureUtils.ts +66 -1
  123. package/src/util/copyToClipboard.ts +21 -0
  124. package/src/util/glyphUtils.ts +49 -0
  125. package/src/util/index.ts +5 -3
  126. package/src/util/loadAssemblyIntoClient.ts +10 -3
  127. package/src/util/mouseEventsUtils.ts +113 -0
  128. package/src/ApolloSixFrameRenderer/ApolloSixFrameRenderer.tsx +0 -13
  129. package/src/ApolloSixFrameRenderer/components/ApolloRendering.tsx +0 -707
  130. package/src/ApolloSixFrameRenderer/configSchema.ts +0 -7
  131. package/src/ApolloSixFrameRenderer/index.ts +0 -3
  132. package/src/SixFrameFeatureDisplay/components/TrackLines.tsx +0 -19
  133. package/src/SixFrameFeatureDisplay/components/index.ts +0 -1
  134. package/src/SixFrameFeatureDisplay/configSchema.ts +0 -21
  135. package/src/SixFrameFeatureDisplay/index.ts +0 -2
  136. package/src/SixFrameFeatureDisplay/stateModel.ts +0 -443
@@ -0,0 +1,63 @@
1
+ import { type AnnotationFeature } from '@apollo-annotation/mst'
2
+ import { type MenuItem } from '@jbrowse/core/ui'
3
+
4
+ import {
5
+ type LinearApolloSixFrameDisplayMouseEvents,
6
+ type MousePositionWithFeatureAndGlyph,
7
+ } from '../stateModel/mouseEvents'
8
+ import { type LinearApolloSixFrameDisplayRendering } from '../stateModel/rendering'
9
+ import { type CanvasMouseEvent } from '../types'
10
+
11
+ export interface Glyph {
12
+ /** draw the feature's primary rendering on the canvas */
13
+ draw(
14
+ ctx: CanvasRenderingContext2D,
15
+ feature: AnnotationFeature,
16
+ row: number,
17
+ stateModel: LinearApolloSixFrameDisplayRendering,
18
+ displayedRegionIndex: number,
19
+ ): void
20
+
21
+ drawHover(
22
+ display: LinearApolloSixFrameDisplayMouseEvents,
23
+ overlayCtx: CanvasRenderingContext2D,
24
+ ): void
25
+
26
+ drawDragPreview(
27
+ display: LinearApolloSixFrameDisplayMouseEvents,
28
+ ctx: CanvasRenderingContext2D,
29
+ ): void
30
+
31
+ onMouseDown(
32
+ display: LinearApolloSixFrameDisplayMouseEvents,
33
+ currentMousePosition: MousePositionWithFeatureAndGlyph,
34
+ event: CanvasMouseEvent,
35
+ ): void
36
+
37
+ onMouseMove(
38
+ display: LinearApolloSixFrameDisplayMouseEvents,
39
+ currentMousePosition: MousePositionWithFeatureAndGlyph,
40
+ event: CanvasMouseEvent,
41
+ ): void
42
+
43
+ onMouseLeave(
44
+ display: LinearApolloSixFrameDisplayMouseEvents,
45
+ currentMousePosition: MousePositionWithFeatureAndGlyph,
46
+ event: CanvasMouseEvent,
47
+ ): void
48
+
49
+ onMouseUp(
50
+ display: LinearApolloSixFrameDisplayMouseEvents,
51
+ currentMousePosition: MousePositionWithFeatureAndGlyph,
52
+ event: CanvasMouseEvent,
53
+ ): void
54
+
55
+ drawTooltip(
56
+ display: LinearApolloSixFrameDisplayMouseEvents,
57
+ context: CanvasRenderingContext2D,
58
+ ): void
59
+
60
+ getContextMenuItems(
61
+ display: LinearApolloSixFrameDisplayMouseEvents,
62
+ ): MenuItem[]
63
+ }
@@ -0,0 +1 @@
1
+ export * from './GeneGlyph'
@@ -0,0 +1,2 @@
1
+ export { configSchema } from './configSchema'
2
+ export { stateModelFactory } from './stateModel'
@@ -0,0 +1,302 @@
1
+ /* eslint-disable @typescript-eslint/unbound-method */
2
+ /* eslint-disable @typescript-eslint/no-unsafe-return */
3
+ /* eslint-disable @typescript-eslint/no-unsafe-assignment */
4
+ /* eslint-disable @typescript-eslint/no-unsafe-member-access */
5
+ /* eslint-disable @typescript-eslint/no-unnecessary-condition */
6
+ import { type AnnotationFeature } from '@apollo-annotation/mst'
7
+ import type PluginManager from '@jbrowse/core/PluginManager'
8
+ import { ConfigurationReference, getConf } from '@jbrowse/core/configuration'
9
+ import { type AnyConfigurationSchemaType } from '@jbrowse/core/configuration/configurationSchema'
10
+ import { BaseDisplay } from '@jbrowse/core/pluggableElementTypes'
11
+ import {
12
+ type AbstractSessionModel,
13
+ type SessionWithWidgets,
14
+ getContainingView,
15
+ getSession,
16
+ } from '@jbrowse/core/util'
17
+ import { getParentRenderProps } from '@jbrowse/core/util/tracks'
18
+ // import type LinearGenomeViewPlugin from '@jbrowse/plugin-linear-genome-view'
19
+ import { type LinearGenomeViewModel } from '@jbrowse/plugin-linear-genome-view'
20
+ import { autorun } from 'mobx'
21
+ import { addDisposer, cast, getRoot, getSnapshot, types } from 'mobx-state-tree'
22
+
23
+ import { type ApolloInternetAccountModel } from '../../ApolloInternetAccount/model'
24
+ import { FilterFeatures } from '../../components/FilterFeatures'
25
+ import { type ApolloSessionModel } from '../../session'
26
+ import { type ApolloRootModel } from '../../types'
27
+
28
+ const minDisplayHeight = 20
29
+
30
+ export function baseModelFactory(
31
+ _pluginManager: PluginManager,
32
+ configSchema: AnyConfigurationSchemaType,
33
+ ) {
34
+ return BaseDisplay.named('BaseLinearApolloSixFrameDisplay')
35
+ .props({
36
+ type: types.literal('LinearApolloSixFrameDisplay'),
37
+ configuration: ConfigurationReference(configSchema),
38
+ graphical: true,
39
+ table: false,
40
+ showFeatureLabels: true,
41
+ heightPreConfig: types.maybe(
42
+ types.refinement(
43
+ 'displayHeight',
44
+ types.number,
45
+ (n) => n >= minDisplayHeight,
46
+ ),
47
+ ),
48
+ filteredFeatureTypes: types.array(types.string),
49
+ })
50
+ .views((self) => {
51
+ const { configuration, renderProps: superRenderProps } = self
52
+ return {
53
+ renderProps() {
54
+ return {
55
+ ...superRenderProps(),
56
+ ...getParentRenderProps(self),
57
+ config: configuration.renderer,
58
+ }
59
+ },
60
+ }
61
+ })
62
+ .volatile(() => ({
63
+ scrollTop: 0,
64
+ }))
65
+ .views((self) => ({
66
+ get lgv() {
67
+ return getContainingView(self) as unknown as LinearGenomeViewModel
68
+ },
69
+ get height() {
70
+ if (self.heightPreConfig) {
71
+ return self.heightPreConfig
72
+ }
73
+ if (self.graphical && self.table) {
74
+ return 500
75
+ }
76
+ if (self.graphical) {
77
+ return 200
78
+ }
79
+ return 300
80
+ },
81
+ }))
82
+ .views((self) => ({
83
+ get rendererTypeName() {
84
+ return self.configuration.renderer.type
85
+ },
86
+ get session() {
87
+ return getSession(self) as unknown as ApolloSessionModel
88
+ },
89
+ get regions() {
90
+ const regions = self.lgv.dynamicBlocks.contentBlocks.map(
91
+ ({ assemblyName, end, refName, start }) => ({
92
+ assemblyName,
93
+ refName,
94
+ start: Math.round(start),
95
+ end: Math.round(end),
96
+ }),
97
+ )
98
+ return regions
99
+ },
100
+ regionCannotBeRendered(/* region */) {
101
+ if (self.lgv && self.lgv.bpPerPx >= 200) {
102
+ return 'Zoom in to see annotations'
103
+ }
104
+ return
105
+ },
106
+ }))
107
+ .views((self) => ({
108
+ get apolloInternetAccount() {
109
+ const [region] = self.regions
110
+ const { internetAccounts } = getRoot<ApolloRootModel>(self)
111
+ const { assemblyName } = region
112
+ const { assemblyManager } =
113
+ self.session as unknown as AbstractSessionModel
114
+ const assembly = assemblyManager.get(assemblyName)
115
+ if (!assembly) {
116
+ throw new Error(`No assembly found with name ${assemblyName}`)
117
+ }
118
+ const { internetAccountConfigId } = getConf(assembly, [
119
+ 'sequence',
120
+ 'metadata',
121
+ ]) as { internetAccountConfigId: string }
122
+ return internetAccounts.find(
123
+ (ia) => getConf(ia, 'internetAccountId') === internetAccountConfigId,
124
+ ) as ApolloInternetAccountModel | undefined
125
+ },
126
+ get changeManager() {
127
+ return (self.session as unknown as ApolloSessionModel).apolloDataStore
128
+ .changeManager
129
+ },
130
+ getAssemblyId(assemblyName: string) {
131
+ const { assemblyManager } =
132
+ self.session as unknown as AbstractSessionModel
133
+ const assembly = assemblyManager.get(assemblyName)
134
+ if (!assembly) {
135
+ throw new Error(`Could not find assembly named ${assemblyName}`)
136
+ }
137
+ return assembly.name
138
+ },
139
+ get selectedFeature(): AnnotationFeature | undefined {
140
+ return (self.session as unknown as ApolloSessionModel)
141
+ .apolloSelectedFeature
142
+ },
143
+ }))
144
+ .actions((self) => ({
145
+ setScrollTop(scrollTop: number) {
146
+ self.scrollTop = scrollTop
147
+ },
148
+ setHeight(displayHeight: number) {
149
+ self.heightPreConfig = Math.max(displayHeight, minDisplayHeight)
150
+ return self.height
151
+ },
152
+ resizeHeight(distance: number) {
153
+ const oldHeight = self.height
154
+ const newHeight = this.setHeight(self.height + distance)
155
+ return newHeight - oldHeight
156
+ },
157
+ showGraphicalOnly() {
158
+ self.graphical = true
159
+ self.table = false
160
+ },
161
+ showTableOnly() {
162
+ self.graphical = false
163
+ self.table = true
164
+ },
165
+ showGraphicalAndTable() {
166
+ self.graphical = true
167
+ self.table = true
168
+ },
169
+ toggleShowFeatureLabels() {
170
+ self.showFeatureLabels = !self.showFeatureLabels
171
+ },
172
+ updateFilteredFeatureTypes(types: string[]) {
173
+ self.filteredFeatureTypes = cast(types)
174
+ },
175
+ }))
176
+ .views((self) => {
177
+ const { filteredFeatureTypes, trackMenuItems: superTrackMenuItems } = self
178
+ return {
179
+ trackMenuItems() {
180
+ const { graphical, table, showFeatureLabels } = self
181
+ return [
182
+ ...superTrackMenuItems(),
183
+ {
184
+ type: 'subMenu',
185
+ label: 'Appearance',
186
+ subMenu: [
187
+ {
188
+ label: 'Show graphical display',
189
+ type: 'radio',
190
+ checked: graphical && !table,
191
+ onClick: () => {
192
+ self.showGraphicalOnly()
193
+ },
194
+ },
195
+ {
196
+ label: 'Show table display',
197
+ type: 'radio',
198
+ checked: table && !graphical,
199
+ onClick: () => {
200
+ self.showTableOnly()
201
+ },
202
+ },
203
+ {
204
+ label: 'Show both graphical and table display',
205
+ type: 'radio',
206
+ checked: table && graphical,
207
+ onClick: () => {
208
+ self.showGraphicalAndTable()
209
+ },
210
+ },
211
+ {
212
+ label: 'Feature Labels',
213
+ type: 'checkbox',
214
+ checked: showFeatureLabels,
215
+ onClick: () => {
216
+ self.toggleShowFeatureLabels()
217
+ },
218
+ },
219
+ ],
220
+ },
221
+ {
222
+ label: 'Filter features by type',
223
+ onClick: () => {
224
+ const session = self.session as unknown as ApolloSessionModel
225
+ ;(self.session as unknown as AbstractSessionModel).queueDialog(
226
+ (doneCallback) => [
227
+ FilterFeatures,
228
+ {
229
+ session,
230
+ handleClose: () => {
231
+ doneCallback()
232
+ },
233
+ featureTypes: getSnapshot(filteredFeatureTypes),
234
+ onUpdate: (types: string[]) => {
235
+ self.updateFilteredFeatureTypes(types)
236
+ },
237
+ },
238
+ ],
239
+ )
240
+ },
241
+ },
242
+ ]
243
+ },
244
+ }
245
+ })
246
+ .actions((self) => ({
247
+ setSelectedFeature(feature?: AnnotationFeature) {
248
+ ;(
249
+ self.session as unknown as ApolloSessionModel
250
+ ).apolloSetSelectedFeature(feature)
251
+ },
252
+ showFeatureDetailsWidget(
253
+ feature: AnnotationFeature,
254
+ customWidgetNameAndId?: [string, string],
255
+ ) {
256
+ const [region] = self.regions
257
+ const { assemblyName, refName } = region
258
+ const assembly = self.getAssemblyId(assemblyName)
259
+ if (!assembly) {
260
+ return
261
+ }
262
+ const { session } = self
263
+ const { changeManager } = session.apolloDataStore
264
+ const [widgetName, widgetId] = customWidgetNameAndId ?? [
265
+ 'ApolloFeatureDetailsWidget',
266
+ 'apolloFeatureDetailsWidget',
267
+ ]
268
+ const apolloFeatureWidget = (
269
+ session as unknown as SessionWithWidgets
270
+ ).addWidget(widgetName, widgetId, {
271
+ feature,
272
+ assembly,
273
+ refName,
274
+ changeManager,
275
+ })
276
+ ;(session as unknown as SessionWithWidgets).showWidget(
277
+ apolloFeatureWidget,
278
+ )
279
+ },
280
+ afterAttach() {
281
+ addDisposer(
282
+ self,
283
+ autorun(
284
+ () => {
285
+ if (!self.lgv.initialized || self.regionCannotBeRendered()) {
286
+ return
287
+ }
288
+ void (
289
+ self.session as unknown as ApolloSessionModel
290
+ ).apolloDataStore.loadFeatures(self.regions)
291
+ if (self.lgv.bpPerPx <= 3) {
292
+ void (
293
+ self.session as unknown as ApolloSessionModel
294
+ ).apolloDataStore.loadRefSeq(self.regions)
295
+ }
296
+ },
297
+ { name: 'LinearApolloSixFrameDisplayLoadFeatures', delay: 1000 },
298
+ ),
299
+ )
300
+ },
301
+ }))
302
+ }
@@ -0,0 +1,27 @@
1
+ import type PluginManager from '@jbrowse/core/PluginManager'
2
+ import { type AnyConfigurationSchemaType } from '@jbrowse/core/configuration/configurationSchema'
3
+ import { type Instance, types } from 'mobx-state-tree'
4
+
5
+ import { TabularEditorStateModelType } from '../../TabularEditor'
6
+
7
+ import { mouseEventsModelFactory } from './mouseEvents'
8
+
9
+ export function stateModelFactory(
10
+ pluginManager: PluginManager,
11
+ configSchema: AnyConfigurationSchemaType,
12
+ ) {
13
+ // TODO: this needs to be refactored so that the final composition of the
14
+ // state model mixins happens here in one central place
15
+ return mouseEventsModelFactory(pluginManager, configSchema)
16
+ .props({ tabularEditor: types.optional(TabularEditorStateModelType, {}) })
17
+ .named('LinearApolloSixFrameDisplay')
18
+ }
19
+
20
+ export type LinearApolloSixFrameDisplayStateModel = ReturnType<
21
+ typeof stateModelFactory
22
+ >
23
+ // eslint disable because of
24
+ // https://mobx-state-tree.js.org/tips/typescript#using-a-mst-type-at-design-time
25
+ // eslint-disable-next-line @typescript-eslint/no-empty-object-type
26
+ export interface LinearApolloSixFrameDisplay
27
+ extends Instance<LinearApolloSixFrameDisplayStateModel> {}
@@ -0,0 +1,252 @@
1
+ /* eslint-disable @typescript-eslint/no-unnecessary-condition */
2
+
3
+ import {
4
+ type AnnotationFeature,
5
+ type TranscriptPartCoding,
6
+ } from '@apollo-annotation/mst'
7
+ import type PluginManager from '@jbrowse/core/PluginManager'
8
+ import { type AnyConfigurationSchemaType } from '@jbrowse/core/configuration/configurationSchema'
9
+ import {
10
+ type AbstractSessionModel,
11
+ doesIntersect2,
12
+ getFrame,
13
+ } from '@jbrowse/core/util'
14
+ import { autorun, observable } from 'mobx'
15
+ import { addDisposer, isAlive } from 'mobx-state-tree'
16
+
17
+ import { type ApolloSessionModel } from '../../session'
18
+ import { geneGlyph } from '../glyphs'
19
+
20
+ import { baseModelFactory } from './base'
21
+
22
+ export interface LayoutRow {
23
+ rowNum: number
24
+ feature: AnnotationFeature
25
+ cds: TranscriptPartCoding | null
26
+ }
27
+
28
+ export function layoutsModelFactory(
29
+ pluginManager: PluginManager,
30
+ configSchema: AnyConfigurationSchemaType,
31
+ ) {
32
+ const BaseLinearApolloSixFrameDisplay = baseModelFactory(
33
+ pluginManager,
34
+ configSchema,
35
+ )
36
+
37
+ return BaseLinearApolloSixFrameDisplay.named(
38
+ 'LinearApolloSixFrameDisplayLayouts',
39
+ )
40
+ .props({
41
+ featuresMinMaxLimit: 500_000,
42
+ })
43
+ .volatile(() => ({
44
+ seenFeatures: observable.map<string, AnnotationFeature>(),
45
+ }))
46
+ .views((self) => ({
47
+ get featuresMinMax() {
48
+ const { assemblyManager } =
49
+ self.session as unknown as AbstractSessionModel
50
+ return self.lgv.displayedRegions.map((region) => {
51
+ const assembly = assemblyManager.get(region.assemblyName)
52
+ let min: number | undefined
53
+ let max: number | undefined
54
+ const { end, refName, start } = region
55
+ for (const [, feature] of self.seenFeatures) {
56
+ if (
57
+ refName !== assembly?.getCanonicalRefName(feature.refSeq) ||
58
+ !doesIntersect2(start, end, feature.min, feature.max) ||
59
+ feature.length > self.featuresMinMaxLimit
60
+ ) {
61
+ continue
62
+ }
63
+ if (min === undefined) {
64
+ ;({ min } = feature)
65
+ }
66
+ if (max === undefined) {
67
+ ;({ max } = feature)
68
+ }
69
+ if (feature.minWithChildren < min) {
70
+ ;({ min } = feature)
71
+ }
72
+ if (feature.maxWithChildren > max) {
73
+ ;({ max } = feature)
74
+ }
75
+ }
76
+ if (min !== undefined && max !== undefined) {
77
+ return [min, max]
78
+ }
79
+ return
80
+ })
81
+ },
82
+ getGlyph(_feature: AnnotationFeature) {
83
+ return geneGlyph
84
+ },
85
+ featureLabelSpacer(elem: number): number {
86
+ return self.showFeatureLabels ? elem * 2 - 1 : elem
87
+ },
88
+ }))
89
+ .actions((self) => ({
90
+ addSeenFeature(feature: AnnotationFeature) {
91
+ self.seenFeatures.set(feature._id, feature)
92
+ },
93
+ deleteSeenFeature(featureId: string) {
94
+ self.seenFeatures.delete(featureId)
95
+ },
96
+ }))
97
+ .views((self) => ({
98
+ get geneTrackRowNums() {
99
+ return [4, 5].map((elem) => self.featureLabelSpacer(elem))
100
+ },
101
+ }))
102
+ .views((self) => ({
103
+ get featureLayouts() {
104
+ const { assemblyManager } =
105
+ self.session as unknown as AbstractSessionModel
106
+ return self.lgv.displayedRegions.map((region, idx) => {
107
+ const assembly = assemblyManager.get(region.assemblyName)
108
+ const featureLayout = new Map<number, LayoutRow[]>()
109
+ const minMax = self.featuresMinMax[idx]
110
+ if (!minMax) {
111
+ return featureLayout
112
+ }
113
+ const { end, refName, start } = region
114
+ for (const [id, feature] of self.seenFeatures.entries()) {
115
+ if (!isAlive(feature)) {
116
+ self.deleteSeenFeature(id)
117
+ continue
118
+ }
119
+ if (
120
+ refName !== assembly?.getCanonicalRefName(feature.refSeq) ||
121
+ !doesIntersect2(start, end, feature.min, feature.max)
122
+ ) {
123
+ continue
124
+ }
125
+ const { featureTypeOntology } =
126
+ self.session.apolloDataStore.ontologyManager
127
+ if (!featureTypeOntology) {
128
+ throw new Error('featureTypeOntology is undefined')
129
+ }
130
+ if (feature.looksLikeGene) {
131
+ const rowNum =
132
+ feature.strand == 1
133
+ ? self.geneTrackRowNums[0]
134
+ : self.geneTrackRowNums[1]
135
+ if (!featureLayout.get(rowNum)) {
136
+ featureLayout.set(rowNum, [])
137
+ }
138
+ const layoutRow = featureLayout.get(rowNum)
139
+ layoutRow?.push({ rowNum, feature, cds: null })
140
+ const { children } = feature
141
+ if (!children) {
142
+ continue
143
+ }
144
+ for (const [, child] of children) {
145
+ if (featureTypeOntology.isTypeOf(child.type, 'transcript')) {
146
+ const {
147
+ cdsLocations,
148
+ strand,
149
+ children: childrenOfmRNA,
150
+ } = child
151
+ if (childrenOfmRNA) {
152
+ for (const [, exon] of childrenOfmRNA) {
153
+ if (!featureTypeOntology.isTypeOf(exon.type, 'exon')) {
154
+ continue
155
+ }
156
+ const rowNum =
157
+ exon.strand == 1
158
+ ? self.geneTrackRowNums[0]
159
+ : self.geneTrackRowNums[1]
160
+ const layoutRow = featureLayout.get(rowNum)
161
+ layoutRow?.push({ rowNum, feature: exon, cds: null })
162
+ }
163
+ }
164
+ for (const cdsRow of cdsLocations) {
165
+ for (const cds of cdsRow) {
166
+ let rowNum: number = getFrame(
167
+ cds.min,
168
+ cds.max,
169
+ strand ?? 1,
170
+ cds.phase,
171
+ )
172
+ rowNum = self.featureLabelSpacer(
173
+ rowNum < 0 ? -1 * rowNum + 5 : rowNum,
174
+ )
175
+ if (!featureLayout.get(rowNum)) {
176
+ featureLayout.set(rowNum, [])
177
+ }
178
+ const layoutRow = featureLayout.get(rowNum)
179
+ layoutRow?.push({ rowNum, feature: child, cds })
180
+ }
181
+ }
182
+ }
183
+ }
184
+ } else {
185
+ continue
186
+ }
187
+ }
188
+ return featureLayout
189
+ })
190
+ },
191
+ getFeatureLayoutPosition(feature: AnnotationFeature) {
192
+ const { featureLayouts } = this
193
+ for (const [idx, layout] of featureLayouts.entries()) {
194
+ for (const [, layoutRow] of layout) {
195
+ for (const { feature: layoutFeature } of layoutRow) {
196
+ if (feature._id === layoutFeature._id) {
197
+ return {
198
+ layoutIndex: idx,
199
+ layoutRow: 0,
200
+ featureRow: 0,
201
+ }
202
+ }
203
+ }
204
+ }
205
+ }
206
+ return
207
+ },
208
+ }))
209
+ .views((_self) => ({
210
+ get highestRow() {
211
+ return 5
212
+ },
213
+ }))
214
+ .actions((self) => ({
215
+ afterAttach() {
216
+ addDisposer(
217
+ self,
218
+ autorun(
219
+ () => {
220
+ if (!self.lgv.initialized || self.regionCannotBeRendered()) {
221
+ return
222
+ }
223
+ for (const region of self.regions) {
224
+ const assembly = (
225
+ self.session as unknown as ApolloSessionModel
226
+ ).apolloDataStore.assemblies.get(region.assemblyName)
227
+ const ref = assembly?.getByRefName(region.refName)
228
+ const features = ref?.features
229
+ if (!features) {
230
+ continue
231
+ }
232
+ for (const [, feature] of features) {
233
+ if (
234
+ doesIntersect2(
235
+ region.start,
236
+ region.end,
237
+ feature.min,
238
+ feature.max,
239
+ ) &&
240
+ !self.seenFeatures.has(feature._id)
241
+ ) {
242
+ self.addSeenFeature(feature)
243
+ }
244
+ }
245
+ }
246
+ },
247
+ { name: 'LinearApolloSixFrameDisplaySetSeenFeatures', delay: 1000 },
248
+ ),
249
+ )
250
+ },
251
+ }))
252
+ }