@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.
Files changed (84) hide show
  1. package/dist/index.esm.js +4603 -2045
  2. package/dist/index.esm.js.map +1 -1
  3. package/dist/jbrowse-plugin-apollo.cjs.development.js +4611 -2039
  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 +9387 -4016
  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 +15 -15
  12. package/src/ApolloInternetAccount/model.ts +48 -13
  13. package/src/BackendDrivers/CollaborationServerDriver.ts +23 -2
  14. package/src/ChangeManager.ts +42 -18
  15. package/src/FeatureDetailsWidget/ApolloTranscriptDetailsWidget.tsx +64 -5
  16. package/src/FeatureDetailsWidget/Attributes.tsx +8 -3
  17. package/src/FeatureDetailsWidget/TranscriptSequence.tsx +70 -81
  18. package/src/FeatureDetailsWidget/TranscriptWidgetEditLocation.tsx +946 -190
  19. package/src/FeatureDetailsWidget/TranscriptWidgetSummary.tsx +4 -0
  20. package/src/LinearApolloDisplay/components/LinearApolloDisplay.tsx +61 -73
  21. package/src/LinearApolloDisplay/glyphs/BoxGlyph.ts +55 -211
  22. package/src/LinearApolloDisplay/glyphs/GeneGlyph.ts +562 -108
  23. package/src/LinearApolloDisplay/glyphs/GenericChildGlyph.ts +78 -14
  24. package/src/LinearApolloDisplay/glyphs/Glyph.ts +15 -9
  25. package/src/LinearApolloDisplay/stateModel/base.ts +63 -43
  26. package/src/LinearApolloDisplay/stateModel/layouts.ts +3 -2
  27. package/src/LinearApolloDisplay/stateModel/mouseEvents.ts +79 -292
  28. package/src/LinearApolloDisplay/stateModel/rendering.ts +45 -344
  29. package/src/LinearApolloReferenceSequenceDisplay/components/LinearApolloReferenceSequenceDisplay.tsx +87 -0
  30. package/src/LinearApolloReferenceSequenceDisplay/components/index.ts +1 -0
  31. package/src/LinearApolloReferenceSequenceDisplay/configSchema.ts +7 -0
  32. package/src/LinearApolloReferenceSequenceDisplay/index.ts +3 -0
  33. package/src/LinearApolloReferenceSequenceDisplay/stateModel/base.ts +227 -0
  34. package/src/LinearApolloReferenceSequenceDisplay/stateModel/index.ts +25 -0
  35. package/src/LinearApolloReferenceSequenceDisplay/stateModel/rendering.ts +481 -0
  36. package/src/LinearApolloSixFrameDisplay/components/LinearApolloSixFrameDisplay.tsx +102 -40
  37. package/src/LinearApolloSixFrameDisplay/components/TrackLines.tsx +12 -20
  38. package/src/LinearApolloSixFrameDisplay/glyphs/GeneGlyph.ts +382 -243
  39. package/src/LinearApolloSixFrameDisplay/glyphs/Glyph.ts +12 -8
  40. package/src/LinearApolloSixFrameDisplay/stateModel/base.ts +83 -4
  41. package/src/LinearApolloSixFrameDisplay/stateModel/layouts.ts +23 -11
  42. package/src/LinearApolloSixFrameDisplay/stateModel/mouseEvents.ts +118 -123
  43. package/src/LinearApolloSixFrameDisplay/stateModel/rendering.ts +53 -63
  44. package/src/OntologyManager/index.ts +4 -1
  45. package/src/TabularEditor/HybridGrid/Feature.tsx +20 -14
  46. package/src/TabularEditor/HybridGrid/HybridGrid.tsx +7 -5
  47. package/src/TabularEditor/HybridGrid/featureContextMenuItems.ts +108 -16
  48. package/src/components/AddAssembly.tsx +1 -1
  49. package/src/components/AddAssemblyAliases.tsx +114 -0
  50. package/src/components/AddChildFeature.tsx +7 -7
  51. package/src/components/AddFeature.tsx +20 -15
  52. package/src/components/AddRefSeqAliases.tsx +9 -9
  53. package/src/components/CopyFeature.tsx +4 -4
  54. package/src/components/CreateApolloAnnotation.tsx +335 -151
  55. package/src/components/DeleteAssembly.tsx +1 -1
  56. package/src/components/DeleteFeature.tsx +358 -11
  57. package/src/components/DownloadGFF3.tsx +20 -1
  58. package/src/components/EditZoomThresholdDialog.tsx +69 -0
  59. package/src/components/FilterFeatures.tsx +7 -7
  60. package/src/components/FilterTranscripts.tsx +86 -0
  61. package/src/components/ImportFeatures.tsx +1 -1
  62. package/src/components/ManageChecks.tsx +1 -1
  63. package/src/components/MergeExons.tsx +193 -0
  64. package/src/components/MergeTranscripts.tsx +182 -0
  65. package/src/components/OntologyTermMultiSelect.tsx +11 -11
  66. package/src/components/OpenLocalFile.tsx +11 -7
  67. package/src/components/SplitExon.tsx +134 -0
  68. package/src/components/ViewCheckResults.tsx +1 -1
  69. package/src/components/index.ts +4 -0
  70. package/src/config.ts +11 -0
  71. package/src/extensions/annotationFromJBrowseFeature.ts +2 -0
  72. package/src/extensions/annotationFromPileup.ts +99 -89
  73. package/src/index.ts +42 -105
  74. package/src/makeDisplayComponent.tsx +0 -1
  75. package/src/menus/index.ts +1 -0
  76. package/src/{ApolloInternetAccount/addMenuItems.ts → menus/topLevelMenu.ts} +60 -33
  77. package/src/menus/topLevelMenuAdmin.ts +154 -0
  78. package/src/session/session.ts +163 -104
  79. package/src/util/annotationFeatureUtils.ts +59 -0
  80. package/src/util/copyToClipboard.ts +21 -0
  81. package/src/util/displayUtils.ts +149 -0
  82. package/src/util/glyphUtils.ts +201 -0
  83. package/src/util/index.ts +2 -0
  84. package/src/util/mouseEventsUtils.ts +145 -0
@@ -4,21 +4,30 @@
4
4
  /* eslint-disable @typescript-eslint/no-unsafe-call */
5
5
  /* eslint-disable @typescript-eslint/no-unsafe-return */
6
6
  import { type AnnotationFeatureSnapshot } from '@apollo-annotation/mst'
7
- import { AddFeatureChange } from '@apollo-annotation/shared'
8
7
  import { type Assembly } from '@jbrowse/core/assemblyManager/assembly'
9
8
  import { type DisplayType } from '@jbrowse/core/pluggableElementTypes'
10
9
  import type PluggableElementBase from '@jbrowse/core/pluggableElementTypes/PluggableElementBase'
11
- import { getContainingView, getSession } from '@jbrowse/core/util'
10
+ import {
11
+ type AbstractSessionModel,
12
+ getContainingView,
13
+ getSession,
14
+ } from '@jbrowse/core/util'
12
15
  import { type LinearGenomeViewModel } from '@jbrowse/plugin-linear-genome-view'
13
16
  import AddIcon from '@mui/icons-material/Add'
14
17
  import ObjectID from 'bson-objectid'
15
18
 
16
- import { type ApolloSessionModel } from '../session'
19
+ import { CreateApolloAnnotation } from '../components/CreateApolloAnnotation'
17
20
 
18
- function parseCigar(cigar: string): [string | undefined, number][] {
19
- return (cigar.toUpperCase().match(/\d+\D/g) ?? []).map((op) => {
20
- return [(/\D/.exec(op) ?? [])[0], Number.parseInt(op, 10)]
21
- })
21
+ function parseCigar(cigar: string): [string, number][] {
22
+ const regex = /(\d+)([MIDNSHPX=])/g
23
+ const result: [string, number][] = []
24
+ let match
25
+
26
+ while ((match = regex.exec(cigar)) !== null) {
27
+ result.push([match[2], Number.parseInt(match[1], 10)])
28
+ }
29
+
30
+ return result
22
31
  }
23
32
 
24
33
  export function annotationFromPileup(pluggableElement: PluggableElementBase) {
@@ -62,55 +71,87 @@ export function annotationFromPileup(pluggableElement: PluggableElementBase) {
62
71
  }
63
72
  return refSeqId
64
73
  },
65
- createFeature() {
74
+ getAnnotationFeature() {
66
75
  const feature = self.contextMenuFeature
67
76
  const assembly = self.getAssembly()
68
77
  const refSeqId = self.getRefSeqId(assembly)
78
+ const start: number = feature.get('start')
79
+ const end: number = feature.get('end')
80
+ const strand = feature.get('strand')
81
+ const name = feature.get('name')
82
+
69
83
  const cigarData: string = feature.get('CIGAR')
70
84
  const ops = parseCigar(cigarData)
71
- let currOffset = 0
72
- const start: number = feature.get('start')
73
- let openStart: number | undefined
85
+ let position = start
86
+ let currentExonStart: number | undefined
74
87
  const exons: {
75
88
  start: number
76
89
  end: number
77
90
  }[] = []
91
+
92
+ // Example: [[96,S], [4,M], [4216,N], [357,M], [1,I], [628,M], [94,S]]
93
+ // Results in 2 exons
94
+ // M, = and X are matches -> exon
95
+ // N is a gap in the reference sequence -> intron
96
+ // I, S, H and P -> not counted in reference position
78
97
  for (const [op, len] of ops) {
79
- // open or continue open
80
- if (op === 'M' || op === '=') {
81
- // if it was closed, then open with start, strand, type
82
- if (openStart === undefined) {
83
- // add subfeature
84
- openStart = currOffset + start
98
+ switch (op) {
99
+ case 'M':
100
+ case '=':
101
+ case 'X': {
102
+ if (currentExonStart === undefined) {
103
+ currentExonStart = position
104
+ }
105
+ position += len
106
+ break
107
+ }
108
+
109
+ case 'N': {
110
+ if (currentExonStart !== undefined) {
111
+ exons.push({
112
+ start: currentExonStart,
113
+ end: position,
114
+ })
115
+ currentExonStart = undefined
116
+ }
117
+ position += len
118
+ break
119
+ }
120
+ case 'D': {
121
+ position += len
122
+ break
123
+ }
124
+ case 'I':
125
+ case 'S':
126
+ case 'H':
127
+ case 'P': {
128
+ // These operations do not affect the position in the reference sequence
129
+ break
130
+ }
131
+ default: {
132
+ throw new Error(`Unknown CIGAR operation: ${op}`)
85
133
  }
86
- } else if (op === 'N' && openStart !== undefined) {
87
- // if it was open, then close and add the subfeature
88
- exons.push({
89
- start: openStart,
90
- end: currOffset + openStart,
91
- })
92
- openStart = undefined
93
- }
94
- if (op !== 'I') {
95
- // we ignore insertions when calculating potential exon length
96
- currOffset += len
97
134
  }
98
135
  }
99
- // if we are still open, then close with the final length and add subfeature
100
- if (openStart !== undefined) {
136
+
137
+ // If still in exon at end
138
+ if (currentExonStart !== undefined) {
101
139
  exons.push({
102
- start: openStart,
103
- end: currOffset + start,
140
+ start: currentExonStart,
141
+ end: position,
104
142
  })
105
143
  }
106
144
 
107
145
  const newFeature: AnnotationFeatureSnapshot = {
108
146
  _id: ObjectID().toHexString(),
109
147
  refSeq: refSeqId,
110
- min: feature.get('start'),
111
- max: feature.get('end'),
148
+ min: start,
149
+ max: end,
112
150
  type: 'mRNA',
113
- strand: feature.get('strand'),
151
+ strand,
152
+ attributes: {
153
+ name: [name],
154
+ },
114
155
  }
115
156
  if (exons.length === 0) {
116
157
  return newFeature
@@ -118,75 +159,28 @@ export function annotationFromPileup(pluggableElement: PluggableElementBase) {
118
159
 
119
160
  const children: Record<string, AnnotationFeatureSnapshot> = {}
120
161
  newFeature.children = children
121
- const [firstExon] = exons
122
- const cdsFeature: AnnotationFeatureSnapshot = {
123
- _id: ObjectID().toHexString(),
124
- refSeq: refSeqId,
125
- min: firstExon.start,
126
- max: firstExon.end,
127
- type: 'CDS',
128
- strand: feature.get('strand'),
129
- }
130
- newFeature.children[cdsFeature._id] = cdsFeature
131
- if (exons.length === 1) {
132
- const exon: AnnotationFeatureSnapshot = {
133
- _id: ObjectID().toHexString(),
134
- refSeq: refSeqId,
135
- min: firstExon.start,
136
- max: firstExon.end,
137
- type: 'exon',
138
- strand: feature.get('strand'),
139
- }
140
- newFeature.children[exon._id] = exon
141
- return newFeature
142
- }
143
162
 
144
- const discontinuousLocations: {
145
- start: number
146
- end: number
147
- phase: 0 | 1 | 2
148
- }[] = []
149
- let phase: 0 | 1 | 2 = 0
150
163
  for (const exon of exons) {
151
- cdsFeature.min = Math.min(cdsFeature.min, exon.start)
152
- cdsFeature.max = Math.max(cdsFeature.max, exon.end)
153
- const { end, start } = exon
154
- discontinuousLocations.push({ start, end, phase })
155
- const localPhase = (end - start) % 3
156
- phase = ((phase + localPhase) % 3) as 0 | 1 | 2
157
164
  const newExon: AnnotationFeatureSnapshot = {
158
165
  _id: ObjectID().toHexString(),
159
166
  refSeq: refSeqId,
160
- min: start,
161
- max: end,
167
+ min: exon.start,
168
+ max: exon.end,
162
169
  type: 'exon',
163
- strand: feature.get('strand'),
170
+ strand,
164
171
  }
165
172
  newFeature.children[newExon._id] = newExon
166
173
  }
167
174
  return newFeature
168
175
  },
169
- async onPileupFeatureContext() {
170
- const newFeature = self.createFeature()
171
- const assembly = self.getAssembly()
172
- const assemblyId = assembly.name
173
- const change = new AddFeatureChange({
174
- changedIds: [newFeature._id],
175
- typeName: 'AddFeatureChange',
176
- assembly: assemblyId,
177
- addedFeature: newFeature,
178
- })
179
- const session = getSession(self)
180
- await (
181
- session as unknown as ApolloSessionModel
182
- ).apolloDataStore.changeManager.submit(change)
183
- session.notify('Annotation added successfully', 'success')
184
- },
185
176
  }))
186
177
  .views((self) => {
187
178
  const superContextMenuItems = self.contextMenuItems
188
179
  return {
189
180
  contextMenuItems() {
181
+ const session = getSession(self)
182
+ const assembly = self.getAssembly()
183
+ const region = self.getFirstRegion()
190
184
  const feature = self.contextMenuFeature
191
185
  if (!feature) {
192
186
  return superContextMenuItems()
@@ -196,7 +190,23 @@ export function annotationFromPileup(pluggableElement: PluggableElementBase) {
196
190
  {
197
191
  label: 'Create Apollo annotation',
198
192
  icon: AddIcon,
199
- onClick: self.onPileupFeatureContext,
193
+ onClick: () => {
194
+ ;(session as unknown as AbstractSessionModel).queueDialog(
195
+ (doneCallback) => [
196
+ CreateApolloAnnotation,
197
+ {
198
+ session,
199
+ handleClose: () => {
200
+ doneCallback()
201
+ },
202
+ annotationFeature: self.getAnnotationFeature(assembly),
203
+ assembly,
204
+ refSeqId: self.getRefSeqId(assembly),
205
+ region,
206
+ },
207
+ ],
208
+ )
209
+ },
200
210
  },
201
211
  ]
202
212
  },
package/src/index.ts CHANGED
@@ -6,6 +6,7 @@ import {
6
6
  CDSCheck,
7
7
  CoreValidation,
8
8
  ParentChildValidation,
9
+ TranscriptCheck,
9
10
  changes,
10
11
  validationRegistry,
11
12
  } from '@apollo-annotation/shared'
@@ -30,6 +31,7 @@ import {
30
31
  } from '@jbrowse/core/util'
31
32
  import { type LinearGenomeViewStateModel } from '@jbrowse/plugin-linear-genome-view'
32
33
  import AddIcon from '@mui/icons-material/Add'
34
+ import { alpha } from '@mui/material'
33
35
 
34
36
  import { version } from '../package.json'
35
37
 
@@ -51,19 +53,16 @@ import {
51
53
  configSchema as linearApolloDisplayConfigSchema,
52
54
  stateModelFactory as LinearApolloDisplayStateModelFactory,
53
55
  } from './LinearApolloDisplay'
56
+ import {
57
+ LinearApolloReferenceSequenceDisplay,
58
+ configSchema as linearApolloReferenceSequenceDisplayConfigSchema,
59
+ stateModelFactory as LinearApolloReferenceSequenceDisplayStateModelFactory,
60
+ } from './LinearApolloReferenceSequenceDisplay'
54
61
  import {
55
62
  configSchema as linearApolloSixFrameDisplayConfigSchema,
56
63
  stateModelFactory as LinearApolloSixFrameDisplayStateModelFactory,
57
64
  } from './LinearApolloSixFrameDisplay'
58
- import {
59
- AddFeature,
60
- DownloadGFF3,
61
- LogOut,
62
- ManageChecks,
63
- OpenLocalFile,
64
- ViewChangeLog,
65
- ViewCheckResults,
66
- } from './components'
65
+ import { AddFeature } from './components'
67
66
  import ApolloPluginConfigurationSchema from './config'
68
67
  import {
69
68
  annotationFromJBrowseFeature,
@@ -73,6 +72,7 @@ import {
73
72
  LinearApolloDisplayComponent,
74
73
  LinearApolloSixFrameDisplayComponent,
75
74
  } from './makeDisplayComponent'
75
+ import { addTopLevelMenus } from './menus'
76
76
  import { type ApolloSessionModel, extendSession } from './session'
77
77
 
78
78
  interface RpcHandle {
@@ -106,6 +106,10 @@ for (const [changeName, change] of Object.entries(changes)) {
106
106
 
107
107
  const cdsCheck = new CDSCheck()
108
108
  checkRegistry.registerCheck(cdsCheck.name, cdsCheck)
109
+
110
+ const transcriptCheck = new TranscriptCheck()
111
+ checkRegistry.registerCheck(transcriptCheck.name, transcriptCheck)
112
+
109
113
  validationRegistry.registerValidation(new CoreValidation())
110
114
  validationRegistry.registerValidation(new ParentChildValidation())
111
115
 
@@ -201,6 +205,22 @@ export default class ApolloPlugin extends Plugin {
201
205
  })
202
206
  })
203
207
 
208
+ pluginManager.addDisplayType(() => {
209
+ const configSchema = linearApolloReferenceSequenceDisplayConfigSchema
210
+ return new DisplayType({
211
+ name: 'LinearApolloReferenceSequenceDisplay',
212
+ configSchema,
213
+ stateModel: LinearApolloReferenceSequenceDisplayStateModelFactory(
214
+ pluginManager,
215
+ configSchema,
216
+ ),
217
+ displayName: 'Apollo reference sequence display',
218
+ trackType: 'ReferenceSequenceTrack',
219
+ viewType: 'LinearGenomeView',
220
+ ReactComponent: LinearApolloReferenceSequenceDisplay,
221
+ })
222
+ })
223
+
204
224
  pluginManager.addToExtensionPoint(
205
225
  'Core-extendSession',
206
226
  // @ts-expect-error not sure how to deal with snapshot model types
@@ -357,103 +377,20 @@ export default class ApolloPlugin extends Plugin {
357
377
 
358
378
  configure(pluginManager: PluginManager) {
359
379
  if (isAbstractMenuManager(pluginManager.rootModel)) {
360
- pluginManager.rootModel.appendToMenu('Apollo', {
361
- label: 'Download GFF3',
362
- onClick: (session: ApolloSessionModel) => {
363
- ;(session as unknown as AbstractSessionModel).queueDialog(
364
- (doneCallback) => [
365
- DownloadGFF3,
366
- {
367
- session,
368
- handleClose: () => {
369
- doneCallback()
370
- },
371
- },
372
- ],
373
- )
374
- },
375
- })
376
- pluginManager.rootModel.appendToMenu('Apollo', {
377
- label: 'Manage Checks',
378
- onClick: (session: ApolloSessionModel) => {
379
- ;(session as unknown as AbstractSessionModel).queueDialog(
380
- (doneCallback) => [
381
- ManageChecks,
382
- {
383
- session,
384
- handleClose: () => {
385
- doneCallback()
386
- },
387
- },
388
- ],
389
- )
390
- },
391
- })
392
- pluginManager.rootModel.appendToMenu('Apollo', {
393
- label: 'View Change Log',
394
- onClick: (session: ApolloSessionModel) => {
395
- ;(session as unknown as AbstractSessionModel).queueDialog(
396
- (doneCallback) => [
397
- ViewChangeLog,
398
- {
399
- session,
400
- handleClose: () => {
401
- doneCallback()
402
- },
403
- },
404
- ],
405
- )
406
- },
407
- })
408
- pluginManager.rootModel.appendToMenu('Apollo', {
409
- label: 'Open local GFF3 file',
410
- onClick: (session: ApolloSessionModel) => {
411
- ;(session as unknown as AbstractSessionModel).queueDialog(
412
- (doneCallback) => [
413
- OpenLocalFile,
414
- {
415
- session,
416
- handleClose: () => {
417
- doneCallback()
418
- },
419
- inMemoryFileDriver: session.apolloDataStore.inMemoryFileDriver,
420
- },
421
- ],
422
- )
423
- },
424
- })
425
- pluginManager.rootModel.appendToMenu('Apollo', {
426
- label: 'View check results',
427
- onClick: (session: ApolloSessionModel) => {
428
- ;(session as unknown as AbstractSessionModel).queueDialog(
429
- (doneCallback) => [
430
- ViewCheckResults,
431
- {
432
- session,
433
- handleClose: () => {
434
- doneCallback()
435
- },
436
- },
437
- ],
438
- )
439
- },
440
- })
441
- pluginManager.rootModel.appendToMenu('Apollo', {
442
- label: 'Log out',
443
- onClick: (session: ApolloSessionModel) => {
444
- ;(session as unknown as AbstractSessionModel).queueDialog(
445
- (doneCallback) => [
446
- LogOut,
447
- {
448
- session,
449
- handleClose: () => {
450
- doneCallback()
451
- },
452
- },
453
- ],
454
- )
380
+ pluginManager.jexl.addFunction(
381
+ 'colorFeature',
382
+ (featureType: 'pseudogenic_transcript' | 'nonCodingTranscript') => {
383
+ if (featureType === 'pseudogenic_transcript') {
384
+ return alpha('rgb(148, 203, 236)', 0.6)
385
+ }
386
+ if (featureType === 'nonCodingTranscript') {
387
+ return alpha('rgb(194, 106, 119)', 0.6)
388
+ }
389
+ throw new Error('Invalid type')
455
390
  },
456
- })
391
+ )
392
+
393
+ addTopLevelMenus(pluginManager.rootModel)
457
394
  }
458
395
  }
459
396
  }
@@ -19,7 +19,6 @@ const accordionControlHeight = 12
19
19
  const useStyles = makeStyles()((theme) => ({
20
20
  shading: {
21
21
  background: alpha(theme.palette.primary.main, 0.2),
22
- overflowY: 'scroll',
23
22
  overflowX: 'hidden',
24
23
  },
25
24
  details: {
@@ -0,0 +1 @@
1
+ export { addTopLevelMenus } from './topLevelMenu'
@@ -2,112 +2,139 @@ import {
2
2
  type AbstractMenuManager,
3
3
  type AbstractSessionModel,
4
4
  } from '@jbrowse/core/util'
5
+ import DownloadIcon from '@mui/icons-material/Download'
6
+ import FactCheckIcon from '@mui/icons-material/FactCheck'
7
+ import FileOpenIcon from '@mui/icons-material/FileOpen'
8
+ import LogoutIcon from '@mui/icons-material/Logout'
9
+ import RedoIcon from '@mui/icons-material/Redo'
10
+ import TrackChangesIcon from '@mui/icons-material/TrackChanges'
11
+ import UndoIcon from '@mui/icons-material/Undo'
5
12
 
6
13
  import {
7
- AddAssembly,
8
- AddRefSeqAliases,
9
- DeleteAssembly,
10
- ImportFeatures,
11
- ManageUsers,
14
+ DownloadGFF3,
15
+ LogOut,
16
+ OpenLocalFile,
17
+ ViewChangeLog,
18
+ ViewCheckResults,
12
19
  } from '../components'
13
20
  import { type ApolloSessionModel } from '../session'
14
21
 
15
- export function addMenuItems(rootModel: AbstractMenuManager) {
22
+ export function addTopLevelMenus(rootModel: AbstractMenuManager) {
23
+ rootModel.insertInMenu(
24
+ 'Apollo',
25
+ {
26
+ label: 'Redo',
27
+ icon: RedoIcon,
28
+ onClick(session: ApolloSessionModel) {
29
+ const { apolloDataStore } = session
30
+ void apolloDataStore.changeManager.redoLastChange()
31
+ },
32
+ },
33
+ 0,
34
+ )
35
+ rootModel.insertInMenu(
36
+ 'Apollo',
37
+ {
38
+ label: 'Undo',
39
+ icon: UndoIcon,
40
+ onClick(session: ApolloSessionModel) {
41
+ const { apolloDataStore } = session
42
+ void apolloDataStore.changeManager.undoLastChange()
43
+ },
44
+ },
45
+ 0,
46
+ )
47
+
16
48
  rootModel.appendToMenu('Apollo', {
17
- label: 'Add Assembly',
49
+ label: 'Download GFF3',
50
+ icon: DownloadIcon,
18
51
  onClick: (session: ApolloSessionModel) => {
19
52
  ;(session as unknown as AbstractSessionModel).queueDialog(
20
53
  (doneCallback) => [
21
- AddAssembly,
54
+ DownloadGFF3,
22
55
  {
23
56
  session,
24
57
  handleClose: () => {
25
58
  doneCallback()
26
59
  },
27
- changeManager: session.apolloDataStore.changeManager,
28
60
  },
29
61
  ],
30
62
  )
31
63
  },
32
64
  })
33
65
  rootModel.appendToMenu('Apollo', {
34
- label: 'Delete Assembly',
66
+ label: 'View Change Log',
67
+ icon: TrackChangesIcon,
35
68
  onClick: (session: ApolloSessionModel) => {
36
69
  ;(session as unknown as AbstractSessionModel).queueDialog(
37
70
  (doneCallback) => [
38
- DeleteAssembly,
71
+ ViewChangeLog,
39
72
  {
40
73
  session,
41
74
  handleClose: () => {
42
75
  doneCallback()
43
76
  },
44
- changeManager: session.apolloDataStore.changeManager,
45
77
  },
46
78
  ],
47
79
  )
48
80
  },
49
81
  })
50
82
  rootModel.appendToMenu('Apollo', {
51
- label: 'Import Features',
83
+ label: 'Open local GFF3 file',
84
+ icon: FileOpenIcon,
52
85
  onClick: (session: ApolloSessionModel) => {
53
86
  ;(session as unknown as AbstractSessionModel).queueDialog(
54
87
  (doneCallback) => [
55
- ImportFeatures,
88
+ OpenLocalFile,
56
89
  {
57
90
  session,
58
91
  handleClose: () => {
59
92
  doneCallback()
60
93
  },
61
- changeManager: session.apolloDataStore.changeManager,
94
+ inMemoryFileDriver: session.apolloDataStore.inMemoryFileDriver,
62
95
  },
63
96
  ],
64
97
  )
65
98
  },
66
99
  })
67
100
  rootModel.appendToMenu('Apollo', {
68
- label: 'Add reference sequence aliases',
101
+ label: 'View check results',
102
+ icon: FactCheckIcon,
69
103
  onClick: (session: ApolloSessionModel) => {
70
104
  ;(session as unknown as AbstractSessionModel).queueDialog(
71
105
  (doneCallback) => [
72
- AddRefSeqAliases,
106
+ ViewCheckResults,
73
107
  {
74
108
  session,
75
109
  handleClose: () => {
76
110
  doneCallback()
77
111
  },
78
- changeManager: session.apolloDataStore.changeManager,
79
112
  },
80
113
  ],
81
114
  )
82
115
  },
83
116
  })
84
117
  rootModel.appendToMenu('Apollo', {
85
- label: 'Manage Users',
118
+ label: 'Lock/Unlock session',
119
+ onClick: (session: ApolloSessionModel) => {
120
+ session.toggleLocked()
121
+ },
122
+ })
123
+ rootModel.appendToMenu('Apollo', {
124
+ label: 'Log out',
125
+ icon: LogoutIcon,
86
126
  onClick: (session: ApolloSessionModel) => {
87
127
  ;(session as unknown as AbstractSessionModel).queueDialog(
88
128
  (doneCallback) => [
89
- ManageUsers,
129
+ LogOut,
90
130
  {
91
131
  session,
92
132
  handleClose: () => {
93
133
  doneCallback()
94
134
  },
95
- changeManager: session.apolloDataStore.changeManager,
96
135
  },
97
136
  ],
98
137
  )
99
138
  },
100
139
  })
101
- rootModel.appendToMenu('Apollo', {
102
- label: 'Undo',
103
- onClick: (session: ApolloSessionModel) => {
104
- const { apolloDataStore } = session
105
- const { notify } = session as unknown as AbstractSessionModel
106
- if (apolloDataStore.changeManager.recentChanges.length > 0) {
107
- void apolloDataStore.changeManager.revertLastChange()
108
- } else {
109
- notify('No changes to undo', 'info')
110
- }
111
- },
112
- })
113
140
  }