@apollo-annotation/jbrowse-plugin-apollo 0.3.4 → 0.3.6

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 (131) hide show
  1. package/dist/index.esm.js +5466 -4490
  2. package/dist/index.esm.js.map +1 -1
  3. package/dist/jbrowse-plugin-apollo.cjs.development.js +5283 -4318
  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 +6806 -4088
  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 +5 -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 +17 -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 +5 -5
  30. package/src/FeatureDetailsWidget/ApolloFeatureDetailsWidget.tsx +92 -20
  31. package/src/FeatureDetailsWidget/ApolloTranscriptDetailsWidget.tsx +170 -27
  32. package/src/FeatureDetailsWidget/AttributeKey.tsx +50 -0
  33. package/src/FeatureDetailsWidget/AttributeKeySelector.tsx +104 -0
  34. package/src/FeatureDetailsWidget/Attributes.tsx +213 -320
  35. package/src/FeatureDetailsWidget/BasicInformation.tsx +8 -9
  36. package/src/FeatureDetailsWidget/DefaultAttributeEditor.tsx +104 -0
  37. package/src/FeatureDetailsWidget/DefaultAttributeViewer.tsx +22 -0
  38. package/src/FeatureDetailsWidget/FeatureDetailsNavigation.tsx +10 -8
  39. package/src/FeatureDetailsWidget/NumberTextField.tsx +1 -1
  40. package/src/FeatureDetailsWidget/Sequence.tsx +18 -35
  41. package/src/FeatureDetailsWidget/StringTextField.tsx +1 -1
  42. package/src/FeatureDetailsWidget/TranscriptSequence.tsx +140 -95
  43. package/src/FeatureDetailsWidget/TranscriptWidgetEditLocation.tsx +600 -0
  44. package/src/FeatureDetailsWidget/TranscriptWidgetSummary.tsx +54 -0
  45. package/src/FeatureDetailsWidget/model.ts +8 -3
  46. package/src/LinearApolloDisplay/components/LinearApolloDisplay.tsx +19 -12
  47. package/src/LinearApolloDisplay/glyphs/BoxGlyph.ts +19 -41
  48. package/src/LinearApolloDisplay/glyphs/GeneGlyph.ts +44 -22
  49. package/src/LinearApolloDisplay/glyphs/GenericChildGlyph.ts +6 -5
  50. package/src/LinearApolloDisplay/glyphs/Glyph.ts +7 -7
  51. package/src/LinearApolloDisplay/stateModel/base.ts +52 -10
  52. package/src/LinearApolloDisplay/stateModel/index.ts +4 -3
  53. package/src/LinearApolloDisplay/stateModel/layouts.ts +8 -34
  54. package/src/LinearApolloDisplay/stateModel/mouseEvents.ts +13 -12
  55. package/src/LinearApolloDisplay/stateModel/rendering.ts +63 -31
  56. package/src/LinearApolloSixFrameDisplay/components/LinearApolloSixFrameDisplay.tsx +221 -0
  57. package/src/LinearApolloSixFrameDisplay/components/TrackLines.tsx +40 -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 +821 -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 +261 -0
  65. package/src/LinearApolloSixFrameDisplay/stateModel/index.ts +27 -0
  66. package/src/LinearApolloSixFrameDisplay/stateModel/layouts.ts +236 -0
  67. package/src/LinearApolloSixFrameDisplay/stateModel/mouseEvents.ts +349 -0
  68. package/src/LinearApolloSixFrameDisplay/stateModel/rendering.ts +199 -0
  69. package/src/LinearApolloSixFrameDisplay/types.ts +1 -0
  70. package/src/OntologyManager/OntologyStore/fulltext-stopwords.ts +10 -1
  71. package/src/OntologyManager/OntologyStore/fulltext.test.ts +1 -1
  72. package/src/OntologyManager/OntologyStore/fulltext.ts +8 -3
  73. package/src/OntologyManager/OntologyStore/index.test.ts +4 -1
  74. package/src/OntologyManager/OntologyStore/index.ts +19 -14
  75. package/src/OntologyManager/OntologyStore/indexeddb-schema.ts +6 -5
  76. package/src/OntologyManager/OntologyStore/indexeddb-storage.ts +11 -5
  77. package/src/OntologyManager/index.ts +10 -6
  78. package/src/OntologyManager/util.ts +3 -2
  79. package/src/TabularEditor/HybridGrid/ChangeHandling.ts +2 -2
  80. package/src/TabularEditor/HybridGrid/Feature.tsx +9 -8
  81. package/src/TabularEditor/HybridGrid/FeatureAttributes.tsx +1 -1
  82. package/src/TabularEditor/HybridGrid/HybridGrid.tsx +3 -2
  83. package/src/TabularEditor/HybridGrid/NumberCell.tsx +8 -1
  84. package/src/TabularEditor/HybridGrid/ToolBar.tsx +15 -13
  85. package/src/TabularEditor/HybridGrid/featureContextMenuItems.ts +9 -33
  86. package/src/TabularEditor/TabularEditorPane.tsx +1 -1
  87. package/src/TabularEditor/model.ts +2 -2
  88. package/src/TabularEditor/types.ts +5 -2
  89. package/src/components/AddAssembly.tsx +611 -291
  90. package/src/components/AddChildFeature.tsx +6 -5
  91. package/src/components/AddFeature.tsx +211 -38
  92. package/src/components/AddRefSeqAliases.tsx +14 -12
  93. package/src/components/CopyFeature.tsx +8 -7
  94. package/src/components/CreateApolloAnnotation.tsx +154 -46
  95. package/src/components/DeleteAssembly.tsx +9 -8
  96. package/src/components/DeleteFeature.tsx +5 -4
  97. package/src/components/Dialog.tsx +1 -1
  98. package/src/components/DownloadGFF3.tsx +11 -10
  99. package/src/components/FilterFeatures.tsx +6 -4
  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/OntologyTermAutocomplete.tsx +5 -5
  105. package/src/components/OntologyTermMultiSelect.tsx +9 -6
  106. package/src/components/OpenLocalFile.tsx +4 -3
  107. package/src/components/ViewChangeLog.tsx +7 -6
  108. package/src/components/ViewCheckResults.tsx +8 -7
  109. package/src/components/index.ts +0 -1
  110. package/src/extensions/annotationFromJBrowseFeature.test.ts +1 -0
  111. package/src/extensions/annotationFromJBrowseFeature.ts +14 -12
  112. package/src/extensions/annotationFromPileup.ts +6 -6
  113. package/src/index.ts +33 -50
  114. package/src/makeDisplayComponent.tsx +93 -41
  115. package/src/session/ClientDataStore.ts +21 -17
  116. package/src/session/session.ts +20 -26
  117. package/src/types.ts +4 -4
  118. package/src/util/annotationFeatureUtils.ts +53 -0
  119. package/src/util/index.ts +4 -3
  120. package/src/util/loadAssemblyIntoClient.ts +10 -3
  121. package/src/ApolloSixFrameRenderer/ApolloSixFrameRenderer.tsx +0 -13
  122. package/src/ApolloSixFrameRenderer/components/ApolloRendering.tsx +0 -707
  123. package/src/ApolloSixFrameRenderer/configSchema.ts +0 -7
  124. package/src/ApolloSixFrameRenderer/index.ts +0 -3
  125. package/src/FeatureDetailsWidget/TranscriptBasic.tsx +0 -200
  126. package/src/SixFrameFeatureDisplay/components/TrackLines.tsx +0 -19
  127. package/src/SixFrameFeatureDisplay/components/index.ts +0 -1
  128. package/src/SixFrameFeatureDisplay/configSchema.ts +0 -21
  129. package/src/SixFrameFeatureDisplay/index.ts +0 -2
  130. package/src/SixFrameFeatureDisplay/stateModel.ts +0 -439
  131. package/src/components/ModifyFeatureAttribute.tsx +0 -460
@@ -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,261 @@
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
+ getContainingView,
14
+ getSession,
15
+ } from '@jbrowse/core/util'
16
+ import { getParentRenderProps } from '@jbrowse/core/util/tracks'
17
+ // import type LinearGenomeViewPlugin from '@jbrowse/plugin-linear-genome-view'
18
+ import { type LinearGenomeViewModel } from '@jbrowse/plugin-linear-genome-view'
19
+ import { autorun } from 'mobx'
20
+ import { addDisposer, cast, getRoot, getSnapshot, types } from 'mobx-state-tree'
21
+
22
+ import { type ApolloInternetAccountModel } from '../../ApolloInternetAccount/model'
23
+ import { FilterFeatures } from '../../components/FilterFeatures'
24
+ import { type ApolloSessionModel } from '../../session'
25
+ import { type ApolloRootModel } from '../../types'
26
+
27
+ const minDisplayHeight = 20
28
+
29
+ export function baseModelFactory(
30
+ _pluginManager: PluginManager,
31
+ configSchema: AnyConfigurationSchemaType,
32
+ ) {
33
+ return BaseDisplay.named('BaseLinearApolloSixFrameDisplay')
34
+ .props({
35
+ type: types.literal('LinearApolloSixFrameDisplay'),
36
+ configuration: ConfigurationReference(configSchema),
37
+ graphical: true,
38
+ table: false,
39
+ heightPreConfig: types.maybe(
40
+ types.refinement(
41
+ 'displayHeight',
42
+ types.number,
43
+ (n) => n >= minDisplayHeight,
44
+ ),
45
+ ),
46
+ filteredFeatureTypes: types.array(types.string),
47
+ })
48
+ .views((self) => {
49
+ const { configuration, renderProps: superRenderProps } = self
50
+ return {
51
+ renderProps() {
52
+ return {
53
+ ...superRenderProps(),
54
+ ...getParentRenderProps(self),
55
+ config: configuration.renderer,
56
+ }
57
+ },
58
+ }
59
+ })
60
+ .volatile(() => ({
61
+ scrollTop: 0,
62
+ }))
63
+ .views((self) => ({
64
+ get lgv() {
65
+ return getContainingView(self) as unknown as LinearGenomeViewModel
66
+ },
67
+ get height() {
68
+ if (self.heightPreConfig) {
69
+ return self.heightPreConfig
70
+ }
71
+ if (self.graphical && self.table) {
72
+ return 500
73
+ }
74
+ if (self.graphical) {
75
+ return 200
76
+ }
77
+ return 300
78
+ },
79
+ }))
80
+ .views((self) => ({
81
+ get rendererTypeName() {
82
+ return self.configuration.renderer.type
83
+ },
84
+ get session() {
85
+ return getSession(self) as unknown as ApolloSessionModel
86
+ },
87
+ get regions() {
88
+ const regions = self.lgv.dynamicBlocks.contentBlocks.map(
89
+ ({ assemblyName, end, refName, start }) => ({
90
+ assemblyName,
91
+ refName,
92
+ start: Math.round(start),
93
+ end: Math.round(end),
94
+ }),
95
+ )
96
+ return regions
97
+ },
98
+ regionCannotBeRendered(/* region */) {
99
+ if (self.lgv && self.lgv.bpPerPx >= 200) {
100
+ return 'Zoom in to see annotations'
101
+ }
102
+ return
103
+ },
104
+ }))
105
+ .views((self) => ({
106
+ get apolloInternetAccount() {
107
+ const [region] = self.regions
108
+ const { internetAccounts } = getRoot<ApolloRootModel>(self)
109
+ const { assemblyName } = region
110
+ const { assemblyManager } =
111
+ self.session as unknown as AbstractSessionModel
112
+ const assembly = assemblyManager.get(assemblyName)
113
+ if (!assembly) {
114
+ throw new Error(`No assembly found with name ${assemblyName}`)
115
+ }
116
+ const { internetAccountConfigId } = getConf(assembly, [
117
+ 'sequence',
118
+ 'metadata',
119
+ ]) as { internetAccountConfigId: string }
120
+ return internetAccounts.find(
121
+ (ia) => getConf(ia, 'internetAccountId') === internetAccountConfigId,
122
+ ) as ApolloInternetAccountModel | undefined
123
+ },
124
+ get changeManager() {
125
+ return (self.session as unknown as ApolloSessionModel).apolloDataStore
126
+ .changeManager
127
+ },
128
+ getAssemblyId(assemblyName: string) {
129
+ const { assemblyManager } =
130
+ self.session as unknown as AbstractSessionModel
131
+ const assembly = assemblyManager.get(assemblyName)
132
+ if (!assembly) {
133
+ throw new Error(`Could not find assembly named ${assemblyName}`)
134
+ }
135
+ return assembly.name
136
+ },
137
+ get selectedFeature(): AnnotationFeature | undefined {
138
+ return (self.session as unknown as ApolloSessionModel)
139
+ .apolloSelectedFeature
140
+ },
141
+ }))
142
+ .actions((self) => ({
143
+ setScrollTop(scrollTop: number) {
144
+ self.scrollTop = scrollTop
145
+ },
146
+ setHeight(displayHeight: number) {
147
+ self.heightPreConfig = Math.max(displayHeight, minDisplayHeight)
148
+ return self.height
149
+ },
150
+ resizeHeight(distance: number) {
151
+ const oldHeight = self.height
152
+ const newHeight = this.setHeight(self.height + distance)
153
+ return newHeight - oldHeight
154
+ },
155
+ showGraphicalOnly() {
156
+ self.graphical = true
157
+ self.table = false
158
+ },
159
+ showTableOnly() {
160
+ self.graphical = false
161
+ self.table = true
162
+ },
163
+ showGraphicalAndTable() {
164
+ self.graphical = true
165
+ self.table = true
166
+ },
167
+ updateFilteredFeatureTypes(types: string[]) {
168
+ self.filteredFeatureTypes = cast(types)
169
+ },
170
+ }))
171
+ .views((self) => {
172
+ const { filteredFeatureTypes, trackMenuItems: superTrackMenuItems } = self
173
+ return {
174
+ trackMenuItems() {
175
+ const { graphical, table } = self
176
+ return [
177
+ ...superTrackMenuItems(),
178
+ {
179
+ type: 'subMenu',
180
+ label: 'Appearance',
181
+ subMenu: [
182
+ {
183
+ label: 'Show graphical display',
184
+ type: 'radio',
185
+ checked: graphical && !table,
186
+ onClick: () => {
187
+ self.showGraphicalOnly()
188
+ },
189
+ },
190
+ {
191
+ label: 'Show table display',
192
+ type: 'radio',
193
+ checked: table && !graphical,
194
+ onClick: () => {
195
+ self.showTableOnly()
196
+ },
197
+ },
198
+ {
199
+ label: 'Show both graphical and table display',
200
+ type: 'radio',
201
+ checked: table && graphical,
202
+ onClick: () => {
203
+ self.showGraphicalAndTable()
204
+ },
205
+ },
206
+ ],
207
+ },
208
+ {
209
+ label: 'Filter features by type',
210
+ onClick: () => {
211
+ const session = self.session as unknown as ApolloSessionModel
212
+ ;(self.session as unknown as AbstractSessionModel).queueDialog(
213
+ (doneCallback) => [
214
+ FilterFeatures,
215
+ {
216
+ session,
217
+ handleClose: () => {
218
+ doneCallback()
219
+ },
220
+ featureTypes: getSnapshot(filteredFeatureTypes),
221
+ onUpdate: (types: string[]) => {
222
+ self.updateFilteredFeatureTypes(types)
223
+ },
224
+ },
225
+ ],
226
+ )
227
+ },
228
+ },
229
+ ]
230
+ },
231
+ }
232
+ })
233
+ .actions((self) => ({
234
+ setSelectedFeature(feature?: AnnotationFeature) {
235
+ ;(
236
+ self.session as unknown as ApolloSessionModel
237
+ ).apolloSetSelectedFeature(feature)
238
+ },
239
+ afterAttach() {
240
+ addDisposer(
241
+ self,
242
+ autorun(
243
+ () => {
244
+ if (!self.lgv.initialized || self.regionCannotBeRendered()) {
245
+ return
246
+ }
247
+ void (
248
+ self.session as unknown as ApolloSessionModel
249
+ ).apolloDataStore.loadFeatures(self.regions)
250
+ if (self.lgv.bpPerPx <= 3) {
251
+ void (
252
+ self.session as unknown as ApolloSessionModel
253
+ ).apolloDataStore.loadRefSeq(self.regions)
254
+ }
255
+ },
256
+ { name: 'LinearApolloSixFrameDisplayLoadFeatures', delay: 1000 },
257
+ ),
258
+ )
259
+ },
260
+ }))
261
+ }
@@ -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,236 @@
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
+ }))
86
+ .actions((self) => ({
87
+ addSeenFeature(feature: AnnotationFeature) {
88
+ self.seenFeatures.set(feature._id, feature)
89
+ },
90
+ deleteSeenFeature(featureId: string) {
91
+ self.seenFeatures.delete(featureId)
92
+ },
93
+ }))
94
+ .views((self) => ({
95
+ get featureLayouts() {
96
+ const { assemblyManager } =
97
+ self.session as unknown as AbstractSessionModel
98
+ return self.lgv.displayedRegions.map((region, idx) => {
99
+ const assembly = assemblyManager.get(region.assemblyName)
100
+ const featureLayout = new Map<number, LayoutRow[]>()
101
+ const minMax = self.featuresMinMax[idx]
102
+ if (!minMax) {
103
+ return featureLayout
104
+ }
105
+ const { end, refName, start } = region
106
+ for (const [id, feature] of self.seenFeatures.entries()) {
107
+ if (!isAlive(feature)) {
108
+ self.deleteSeenFeature(id)
109
+ continue
110
+ }
111
+ if (
112
+ refName !== assembly?.getCanonicalRefName(feature.refSeq) ||
113
+ !doesIntersect2(start, end, feature.min, feature.max)
114
+ ) {
115
+ continue
116
+ }
117
+ const { featureTypeOntology } =
118
+ self.session.apolloDataStore.ontologyManager
119
+ if (!featureTypeOntology) {
120
+ throw new Error('featureTypeOntology is undefined')
121
+ }
122
+ if (feature.looksLikeGene) {
123
+ const rowNum = feature.strand == 1 ? 4 : 5
124
+ if (!featureLayout.get(rowNum)) {
125
+ featureLayout.set(rowNum, [])
126
+ }
127
+ const layoutRow = featureLayout.get(rowNum)
128
+ layoutRow?.push({ rowNum, feature, cds: null })
129
+ const { children } = feature
130
+ if (!children) {
131
+ continue
132
+ }
133
+ for (const [, child] of children) {
134
+ if (featureTypeOntology.isTypeOf(child.type, 'transcript')) {
135
+ const {
136
+ cdsLocations,
137
+ strand,
138
+ children: childrenOfmRNA,
139
+ } = child
140
+ if (childrenOfmRNA) {
141
+ for (const [, exon] of childrenOfmRNA) {
142
+ if (!featureTypeOntology.isTypeOf(exon.type, 'exon')) {
143
+ continue
144
+ }
145
+ const rowNum = exon.strand == 1 ? 4 : 5
146
+ const layoutRow = featureLayout.get(rowNum)
147
+ layoutRow?.push({ rowNum, feature: exon, cds: null })
148
+ }
149
+ }
150
+ for (const cdsRow of cdsLocations) {
151
+ for (const cds of cdsRow) {
152
+ let rowNum: number = getFrame(
153
+ cds.min,
154
+ cds.max,
155
+ strand ?? 1,
156
+ cds.phase,
157
+ )
158
+ rowNum = rowNum < 0 ? -1 * rowNum + 5 : rowNum
159
+ if (!featureLayout.get(rowNum)) {
160
+ featureLayout.set(rowNum, [])
161
+ }
162
+ const layoutRow = featureLayout.get(rowNum)
163
+ layoutRow?.push({ rowNum, feature: child, cds })
164
+ }
165
+ }
166
+ }
167
+ }
168
+ } else {
169
+ continue
170
+ }
171
+ }
172
+ return featureLayout
173
+ })
174
+ },
175
+ getFeatureLayoutPosition(feature: AnnotationFeature) {
176
+ const { featureLayouts } = this
177
+ for (const [idx, layout] of featureLayouts.entries()) {
178
+ for (const [, layoutRow] of layout) {
179
+ for (const { feature: layoutFeature } of layoutRow) {
180
+ if (feature._id === layoutFeature._id) {
181
+ return {
182
+ layoutIndex: idx,
183
+ layoutRow: 0,
184
+ featureRow: 0,
185
+ }
186
+ }
187
+ }
188
+ }
189
+ }
190
+ return
191
+ },
192
+ }))
193
+ .views((_self) => ({
194
+ get highestRow() {
195
+ return 5
196
+ },
197
+ }))
198
+ .actions((self) => ({
199
+ afterAttach() {
200
+ addDisposer(
201
+ self,
202
+ autorun(
203
+ () => {
204
+ if (!self.lgv.initialized || self.regionCannotBeRendered()) {
205
+ return
206
+ }
207
+ for (const region of self.regions) {
208
+ const assembly = (
209
+ self.session as unknown as ApolloSessionModel
210
+ ).apolloDataStore.assemblies.get(region.assemblyName)
211
+ const ref = assembly?.getByRefName(region.refName)
212
+ const features = ref?.features
213
+ if (!features) {
214
+ continue
215
+ }
216
+ for (const [, feature] of features) {
217
+ if (
218
+ doesIntersect2(
219
+ region.start,
220
+ region.end,
221
+ feature.min,
222
+ feature.max,
223
+ ) &&
224
+ !self.seenFeatures.has(feature._id)
225
+ ) {
226
+ self.addSeenFeature(feature)
227
+ }
228
+ }
229
+ }
230
+ },
231
+ { name: 'LinearApolloSixFrameDisplaySetSeenFeatures', delay: 1000 },
232
+ ),
233
+ )
234
+ },
235
+ }))
236
+ }