@apollo-annotation/jbrowse-plugin-apollo 0.3.6 → 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 (56) hide show
  1. package/dist/index.esm.js +2679 -850
  2. package/dist/index.esm.js.map +1 -1
  3. package/dist/jbrowse-plugin-apollo.cjs.development.js +2676 -847
  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 +5194 -1258
  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 +18 -0
  13. package/src/ChangeManager.ts +10 -6
  14. package/src/FeatureDetailsWidget/Attributes.tsx +8 -3
  15. package/src/FeatureDetailsWidget/TranscriptSequence.tsx +12 -20
  16. package/src/FeatureDetailsWidget/TranscriptWidgetEditLocation.tsx +929 -175
  17. package/src/FeatureDetailsWidget/TranscriptWidgetSummary.tsx +4 -0
  18. package/src/LinearApolloDisplay/components/LinearApolloDisplay.tsx +1 -1
  19. package/src/LinearApolloDisplay/glyphs/BoxGlyph.ts +48 -60
  20. package/src/LinearApolloDisplay/glyphs/GeneGlyph.ts +244 -51
  21. package/src/LinearApolloDisplay/glyphs/GenericChildGlyph.ts +46 -1
  22. package/src/LinearApolloDisplay/glyphs/Glyph.ts +9 -1
  23. package/src/LinearApolloDisplay/stateModel/base.ts +29 -0
  24. package/src/LinearApolloDisplay/stateModel/mouseEvents.ts +51 -35
  25. package/src/LinearApolloDisplay/stateModel/rendering.ts +2 -1
  26. package/src/LinearApolloSixFrameDisplay/components/LinearApolloSixFrameDisplay.tsx +7 -2
  27. package/src/LinearApolloSixFrameDisplay/components/TrackLines.tsx +12 -20
  28. package/src/LinearApolloSixFrameDisplay/glyphs/GeneGlyph.ts +243 -124
  29. package/src/LinearApolloSixFrameDisplay/stateModel/base.ts +42 -1
  30. package/src/LinearApolloSixFrameDisplay/stateModel/layouts.ts +19 -3
  31. package/src/LinearApolloSixFrameDisplay/stateModel/mouseEvents.ts +53 -34
  32. package/src/LinearApolloSixFrameDisplay/stateModel/rendering.ts +4 -2
  33. package/src/OntologyManager/index.ts +4 -1
  34. package/src/TabularEditor/HybridGrid/Feature.tsx +4 -0
  35. package/src/TabularEditor/HybridGrid/featureContextMenuItems.ts +108 -16
  36. package/src/components/AddAssemblyAliases.tsx +114 -0
  37. package/src/components/AddChildFeature.tsx +3 -6
  38. package/src/components/AddFeature.tsx +14 -15
  39. package/src/components/CopyFeature.tsx +2 -4
  40. package/src/components/CreateApolloAnnotation.tsx +334 -151
  41. package/src/components/DeleteFeature.tsx +358 -11
  42. package/src/components/DownloadGFF3.tsx +20 -1
  43. package/src/components/FilterTranscripts.tsx +86 -0
  44. package/src/components/MergeExons.tsx +193 -0
  45. package/src/components/MergeTranscripts.tsx +185 -0
  46. package/src/components/SplitExon.tsx +134 -0
  47. package/src/components/index.ts +3 -0
  48. package/src/config.ts +5 -0
  49. package/src/extensions/annotationFromJBrowseFeature.ts +2 -0
  50. package/src/extensions/annotationFromPileup.ts +99 -89
  51. package/src/session/session.ts +26 -13
  52. package/src/util/annotationFeatureUtils.ts +65 -0
  53. package/src/util/copyToClipboard.ts +21 -0
  54. package/src/util/glyphUtils.ts +49 -0
  55. package/src/util/index.ts +2 -0
  56. package/src/util/mouseEventsUtils.ts +113 -0
@@ -82,6 +82,9 @@ export function layoutsModelFactory(
82
82
  getGlyph(_feature: AnnotationFeature) {
83
83
  return geneGlyph
84
84
  },
85
+ featureLabelSpacer(elem: number): number {
86
+ return self.showFeatureLabels ? elem * 2 - 1 : elem
87
+ },
85
88
  }))
86
89
  .actions((self) => ({
87
90
  addSeenFeature(feature: AnnotationFeature) {
@@ -91,6 +94,11 @@ export function layoutsModelFactory(
91
94
  self.seenFeatures.delete(featureId)
92
95
  },
93
96
  }))
97
+ .views((self) => ({
98
+ get geneTrackRowNums() {
99
+ return [4, 5].map((elem) => self.featureLabelSpacer(elem))
100
+ },
101
+ }))
94
102
  .views((self) => ({
95
103
  get featureLayouts() {
96
104
  const { assemblyManager } =
@@ -120,7 +128,10 @@ export function layoutsModelFactory(
120
128
  throw new Error('featureTypeOntology is undefined')
121
129
  }
122
130
  if (feature.looksLikeGene) {
123
- const rowNum = feature.strand == 1 ? 4 : 5
131
+ const rowNum =
132
+ feature.strand == 1
133
+ ? self.geneTrackRowNums[0]
134
+ : self.geneTrackRowNums[1]
124
135
  if (!featureLayout.get(rowNum)) {
125
136
  featureLayout.set(rowNum, [])
126
137
  }
@@ -142,7 +153,10 @@ export function layoutsModelFactory(
142
153
  if (!featureTypeOntology.isTypeOf(exon.type, 'exon')) {
143
154
  continue
144
155
  }
145
- const rowNum = exon.strand == 1 ? 4 : 5
156
+ const rowNum =
157
+ exon.strand == 1
158
+ ? self.geneTrackRowNums[0]
159
+ : self.geneTrackRowNums[1]
146
160
  const layoutRow = featureLayout.get(rowNum)
147
161
  layoutRow?.push({ rowNum, feature: exon, cds: null })
148
162
  }
@@ -155,7 +169,9 @@ export function layoutsModelFactory(
155
169
  strand ?? 1,
156
170
  cds.phase,
157
171
  )
158
- rowNum = rowNum < 0 ? -1 * rowNum + 5 : rowNum
172
+ rowNum = self.featureLabelSpacer(
173
+ rowNum < 0 ? -1 * rowNum + 5 : rowNum,
174
+ )
159
175
  if (!featureLayout.get(rowNum)) {
160
176
  featureLayout.set(rowNum, [])
161
177
  }
@@ -11,9 +11,10 @@ import { type AnyConfigurationSchemaType } from '@jbrowse/core/configuration/con
11
11
  import { type MenuItem } from '@jbrowse/core/ui'
12
12
  import { type LinearGenomeViewModel } from '@jbrowse/plugin-linear-genome-view'
13
13
  import { autorun } from 'mobx'
14
- import { type Instance, addDisposer } from 'mobx-state-tree'
14
+ import { type Instance, addDisposer, cast } from 'mobx-state-tree'
15
15
  import { type CSSProperties } from 'react'
16
16
 
17
+ import { type Edge, getPropagatedLocationChanges } from '../../util'
17
18
  import { type Coord } from '../components'
18
19
  import { type Glyph } from '../glyphs/Glyph'
19
20
  import { type CanvasMouseEvent } from '../types'
@@ -75,7 +76,8 @@ export function mouseEventsModelIntermediateFactory(
75
76
  start: MousePosition
76
77
  current: MousePosition
77
78
  feature: AnnotationFeature
78
- edge: 'min' | 'max'
79
+ edge: Edge
80
+ shrinkParent: boolean
79
81
  } | null,
80
82
  cursor: undefined as CSSProperties['cursor'] | undefined,
81
83
  apolloHover: undefined as FeatureAndGlyphUnderMouse | undefined,
@@ -91,7 +93,7 @@ export function mouseEventsModelIntermediateFactory(
91
93
  return mousePosition
92
94
  }
93
95
  let foundFeature
94
- if ([4, 5].includes(row)) {
96
+ if (self.geneTrackRowNums.includes(row)) {
95
97
  foundFeature = layoutRow.find(
96
98
  (f) =>
97
99
  f.feature.type == 'exon' &&
@@ -104,9 +106,16 @@ export function mouseEventsModelIntermediateFactory(
104
106
  )
105
107
  }
106
108
  } else {
107
- foundFeature = layoutRow.find(
108
- (f) => f.cds != null && bp >= f.cds.min && bp <= f.cds.max,
109
- )
109
+ foundFeature = layoutRow.find((f) => {
110
+ const featureID = f.feature.attributes.get('gff_id')?.toString()
111
+ return (
112
+ f.cds != null &&
113
+ bp >= f.cds.min &&
114
+ bp <= f.cds.max &&
115
+ (featureID === undefined ||
116
+ !self.filteredTranscripts.includes(featureID))
117
+ )
118
+ })
110
119
  }
111
120
  if (!foundFeature) {
112
121
  return mousePosition
@@ -143,6 +152,9 @@ export function mouseEventsModelIntermediateFactory(
143
152
  self.cursor = cursor
144
153
  }
145
154
  },
155
+ updateFilteredTranscripts(forms: string[]): void {
156
+ self.filteredTranscripts = cast(forms)
157
+ },
146
158
  }))
147
159
  .actions(() => ({
148
160
  // onClick(event: CanvasMouseEvent) {
@@ -176,20 +188,23 @@ export function mouseEventsModelFactory(
176
188
  startDrag(
177
189
  mousePosition: MousePositionWithFeatureAndGlyph,
178
190
  feature: AnnotationFeature,
179
- edge: 'min' | 'max',
191
+ edge: Edge,
192
+ shrinkParent = false,
180
193
  ) {
181
194
  self.apolloDragging = {
182
195
  start: mousePosition,
183
196
  current: mousePosition,
184
197
  feature,
185
198
  edge,
199
+ shrinkParent,
186
200
  }
187
201
  },
188
202
  endDrag() {
189
203
  if (!self.apolloDragging) {
190
204
  throw new Error('endDrag() called with no current drag in progress')
191
205
  }
192
- const { current, edge, feature, start } = self.apolloDragging
206
+ const { current, edge, feature, start, shrinkParent } =
207
+ self.apolloDragging
193
208
  // don't do anything if it was only dragged a tiny bit
194
209
  if (Math.abs(current.x - start.x) <= 4) {
195
210
  self.setDragging()
@@ -199,33 +214,35 @@ export function mouseEventsModelFactory(
199
214
  const { displayedRegions } = self.lgv
200
215
  const region = displayedRegions[start.regionNumber]
201
216
  const assembly = self.getAssemblyId(region.assemblyName)
217
+ const changes = getPropagatedLocationChanges(
218
+ feature,
219
+ current.bp,
220
+ edge,
221
+ shrinkParent,
222
+ )
202
223
 
203
- let change: LocationEndChange | LocationStartChange
204
- if (edge === 'max') {
205
- const featureId = feature._id
206
- const oldEnd = feature.max
207
- const newEnd = current.bp
208
- change = new LocationEndChange({
209
- typeName: 'LocationEndChange',
210
- changedIds: [featureId],
211
- featureId,
212
- oldEnd,
213
- newEnd,
214
- assembly,
215
- })
216
- } else {
217
- const featureId = feature._id
218
- const oldStart = feature.min
219
- const newStart = current.bp
220
- change = new LocationStartChange({
221
- typeName: 'LocationStartChange',
222
- changedIds: [featureId],
223
- featureId,
224
- oldStart,
225
- newStart,
226
- assembly,
227
- })
228
- }
224
+ const change: LocationEndChange | LocationStartChange =
225
+ edge === 'max'
226
+ ? new LocationEndChange({
227
+ typeName: 'LocationEndChange',
228
+ changedIds: changes.map((c) => c.featureId),
229
+ changes: changes.map((c) => ({
230
+ featureId: c.featureId,
231
+ oldEnd: c.oldLocation,
232
+ newEnd: c.newLocation,
233
+ })),
234
+ assembly,
235
+ })
236
+ : new LocationStartChange({
237
+ typeName: 'LocationStartChange',
238
+ changedIds: changes.map((c) => c.featureId),
239
+ changes: changes.map((c) => ({
240
+ featureId: c.featureId,
241
+ oldStart: c.oldLocation,
242
+ newStart: c.newLocation,
243
+ })),
244
+ assembly,
245
+ })
229
246
  void self.changeManager.submit(change)
230
247
  self.setDragging()
231
248
  self.setCursor()
@@ -281,6 +298,8 @@ export function mouseEventsModelFactory(
281
298
  mousePosition,
282
299
  event,
283
300
  )
301
+ } else {
302
+ self.setSelectedFeature()
284
303
  }
285
304
 
286
305
  if (self.apolloDragging) {
@@ -4,7 +4,7 @@ import { type AnyConfigurationSchemaType } from '@jbrowse/core/configuration/con
4
4
  import { doesIntersect2 } from '@jbrowse/core/util'
5
5
  import { type Theme } from '@mui/material'
6
6
  import { autorun } from 'mobx'
7
- import { type Instance, addDisposer } from 'mobx-state-tree'
7
+ import { type Instance, addDisposer, types } from 'mobx-state-tree'
8
8
 
9
9
  import { type ApolloSessionModel } from '../../session'
10
10
 
@@ -29,6 +29,7 @@ export function renderingModelIntermediateFactory(
29
29
  detailsHeight: 200,
30
30
  lastRowTooltipBufferHeight: 80,
31
31
  isShown: true,
32
+ filteredTranscripts: types.array(types.string),
32
33
  })
33
34
  .volatile(() => ({
34
35
  canvas: null as HTMLCanvasElement | null,
@@ -38,8 +39,9 @@ export function renderingModelIntermediateFactory(
38
39
  }))
39
40
  .views((self) => ({
40
41
  get featuresHeight() {
42
+ const featureLabelSpacer = self.showFeatureLabels ? 2 : 1
41
43
  return (
42
- (self.highestRow + 1) * self.apolloRowHeight +
44
+ featureLabelSpacer * ((self.highestRow + 1) * self.apolloRowHeight) +
43
45
  self.lastRowTooltipBufferHeight
44
46
  )
45
47
  },
@@ -15,6 +15,7 @@ import {
15
15
  flow,
16
16
  getRoot,
17
17
  getSnapshot,
18
+ isAlive,
18
19
  types,
19
20
  } from 'mobx-state-tree'
20
21
 
@@ -79,7 +80,9 @@ export const OntologyRecordType = types
79
80
  const equivalents: string[] = terms
80
81
  .map((term) => term.lbl)
81
82
  .filter((term) => term != undefined)
82
- self.setEquivalentTypes(type, equivalents)
83
+ if (isAlive(self)) {
84
+ self.setEquivalentTypes(type, equivalents)
85
+ }
83
86
  }),
84
87
  }))
85
88
  .actions((self) => ({
@@ -68,6 +68,8 @@ function makeContextMenuItems(
68
68
  selectedFeature,
69
69
  session,
70
70
  setSelectedFeature,
71
+ filteredTranscripts,
72
+ updateFilteredTranscripts,
71
73
  } = display
72
74
  return featureContextMenuItems(
73
75
  feature,
@@ -77,6 +79,8 @@ function makeContextMenuItems(
77
79
  setSelectedFeature,
78
80
  session,
79
81
  changeManager,
82
+ filteredTranscripts,
83
+ updateFilteredTranscripts,
80
84
  )
81
85
  }
82
86
 
@@ -7,7 +7,14 @@ import {
7
7
  } from '@jbrowse/core/util'
8
8
 
9
9
  import { type ChangeManager } from '../../ChangeManager'
10
- import { AddChildFeature, CopyFeature, DeleteFeature } from '../../components'
10
+ import {
11
+ AddChildFeature,
12
+ CopyFeature,
13
+ DeleteFeature,
14
+ MergeExons,
15
+ MergeTranscripts,
16
+ SplitExon,
17
+ } from '../../components'
11
18
  import { type ApolloSessionModel } from '../../session'
12
19
  import { getApolloInternetAccount } from '../../util'
13
20
 
@@ -19,6 +26,8 @@ export function featureContextMenuItems(
19
26
  setSelectedFeature: (f: AnnotationFeature | undefined) => void,
20
27
  session: ApolloSessionModel,
21
28
  changeManager: ChangeManager,
29
+ filteredTranscripts: string[],
30
+ updateFilteredTranscripts: (forms: string[]) => void,
22
31
  ) {
23
32
  const internetAccount = getApolloInternetAccount(session)
24
33
  const role = internetAccount ? internetAccount.role : 'admin'
@@ -26,6 +35,7 @@ export function featureContextMenuItems(
26
35
  const readOnly = !(role && ['admin', 'user'].includes(role))
27
36
  const menuItems: MenuItem[] = []
28
37
  if (feature) {
38
+ const featureID = feature.attributes.get('gff_id')?.toString()
29
39
  const sourceAssemblyId = getAssemblyId(region.assemblyName)
30
40
  const currentAssemblyId = getAssemblyId(region.assemblyName)
31
41
  menuItems.push(
@@ -111,6 +121,72 @@ export function featureContextMenuItems(
111
121
  )
112
122
  },
113
123
  },
124
+ {
125
+ label: 'Merge transcripts',
126
+ disabled: !admin,
127
+ onClick: () => {
128
+ ;(session as unknown as AbstractSessionModel).queueDialog(
129
+ (doneCallback) => [
130
+ MergeTranscripts,
131
+ {
132
+ session,
133
+ handleClose: () => {
134
+ doneCallback()
135
+ },
136
+ changeManager,
137
+ sourceFeature: feature,
138
+ sourceAssemblyId: currentAssemblyId,
139
+ selectedFeature,
140
+ setSelectedFeature,
141
+ },
142
+ ],
143
+ )
144
+ },
145
+ },
146
+ {
147
+ label: 'Merge exons',
148
+ disabled: !admin,
149
+ onClick: () => {
150
+ ;(session as unknown as AbstractSessionModel).queueDialog(
151
+ (doneCallback) => [
152
+ MergeExons,
153
+ {
154
+ session,
155
+ handleClose: () => {
156
+ doneCallback()
157
+ },
158
+ changeManager,
159
+ sourceFeature: feature,
160
+ sourceAssemblyId: currentAssemblyId,
161
+ selectedFeature,
162
+ setSelectedFeature,
163
+ },
164
+ ],
165
+ )
166
+ },
167
+ },
168
+ {
169
+ label: 'Split exon',
170
+ disabled: !admin,
171
+ onClick: () => {
172
+ ;(session as unknown as AbstractSessionModel).queueDialog(
173
+ (doneCallback) => [
174
+ SplitExon,
175
+ {
176
+ session,
177
+ handleClose: () => {
178
+ doneCallback()
179
+ },
180
+ changeManager,
181
+ sourceFeature: feature,
182
+ sourceAssemblyId: currentAssemblyId,
183
+ selectedFeature,
184
+ setSelectedFeature,
185
+ },
186
+ ],
187
+ )
188
+ },
189
+ },
114
190
  )
115
191
  const { featureTypeOntology } = session.apolloDataStore.ontologyManager
116
192
  if (!featureTypeOntology) {
@@ -121,22 +197,38 @@ export function featureContextMenuItems(
121
197
  featureTypeOntology.isTypeOf(feature.type, 'pseudogenic_transcript')) &&
122
198
  isSessionModelWithWidgets(session)
123
199
  ) {
124
- menuItems.push({
125
- label: 'Edit transcript details',
126
- onClick: () => {
127
- const apolloTranscriptWidget = session.addWidget(
128
- 'ApolloTranscriptDetails',
129
- 'apolloTranscriptDetails',
130
- {
131
- feature,
132
- assembly: currentAssemblyId,
133
- changeManager,
134
- refName: region.refName,
135
- },
136
- )
137
- session.showWidget(apolloTranscriptWidget)
200
+ menuItems.push(
201
+ {
202
+ label: 'Edit transcript details',
203
+ onClick: () => {
204
+ const apolloTranscriptWidget = session.addWidget(
205
+ 'ApolloTranscriptDetails',
206
+ 'apolloTranscriptDetails',
207
+ {
208
+ feature,
209
+ assembly: currentAssemblyId,
210
+ changeManager,
211
+ refName: region.refName,
212
+ },
213
+ )
214
+ session.showWidget(apolloTranscriptWidget)
215
+ },
216
+ },
217
+ {
218
+ label: 'Visible',
219
+ type: 'checkbox',
220
+ checked:
221
+ featureID && filteredTranscripts.includes(featureID) ? false : true,
222
+ onClick: () => {
223
+ if (featureID) {
224
+ const newForms = filteredTranscripts.includes(featureID)
225
+ ? filteredTranscripts.filter((form) => form !== featureID)
226
+ : [...filteredTranscripts, featureID]
227
+ updateFilteredTranscripts(newForms)
228
+ }
229
+ },
138
230
  },
139
- })
231
+ )
140
232
  }
141
233
  }
142
234
  return menuItems
@@ -0,0 +1,114 @@
1
+ import { AddAssemblyAliasesChange } from '@apollo-annotation/shared'
2
+ import { Box, DialogContent, DialogContentText } from '@mui/material'
3
+ import { DataGrid, type GridColDef, type GridRowModel } from '@mui/x-data-grid'
4
+ import React from 'react'
5
+
6
+ import {
7
+ type ApolloInternetAccount,
8
+ type CollaborationServerDriver,
9
+ } from '../BackendDrivers'
10
+ import { type ChangeManager } from '../ChangeManager'
11
+ import { type ApolloSessionModel } from '../session'
12
+
13
+ import { Dialog } from './Dialog'
14
+
15
+ interface AddAssemblyAliasProps {
16
+ session: ApolloSessionModel
17
+ handleClose: () => void
18
+ changeManager: ChangeManager
19
+ }
20
+
21
+ const columns: GridColDef[] = [
22
+ {
23
+ field: 'name',
24
+ headerName: 'Assembly Name',
25
+ width: 150,
26
+ editable: false,
27
+ },
28
+ {
29
+ field: 'aliases',
30
+ headerName: 'Aliases',
31
+ width: 300,
32
+ editable: true,
33
+ },
34
+ ]
35
+
36
+ interface AssemblyAlias {
37
+ id: string
38
+ name: string
39
+ aliases: string
40
+ }
41
+
42
+ export function AddAssemblyAliases({
43
+ changeManager,
44
+ handleClose,
45
+ session,
46
+ }: AddAssemblyAliasProps) {
47
+ const { apolloDataStore } = session
48
+ const { collaborationServerDriver } = apolloDataStore as {
49
+ collaborationServerDriver: CollaborationServerDriver
50
+ getInternetAccount(
51
+ assemblyName?: string,
52
+ internetAccountId?: string,
53
+ ): ApolloInternetAccount
54
+ }
55
+ const assemblies = collaborationServerDriver.getAssemblies()
56
+
57
+ const rows: AssemblyAlias[] = assemblies.map((assembly) => {
58
+ return {
59
+ id: assembly.name,
60
+ name: assembly.displayName ?? assembly.name,
61
+ aliases: assembly.aliases.join(', '),
62
+ } as AssemblyAlias
63
+ })
64
+
65
+ const [errorMessage, setErrorMessage] = React.useState('')
66
+
67
+ const processRowUpdate = (newRow: GridRowModel, _oldRow: GridRowModel) => {
68
+ const change = new AddAssemblyAliasesChange({
69
+ typeName: 'AddAssemblyAliasesChange',
70
+ assembly: newRow.id as string,
71
+ aliases: (newRow.aliases as string).split(','),
72
+ })
73
+ void changeManager.submit(change).catch(() => {
74
+ setErrorMessage('Error submitting change')
75
+ })
76
+ handleClose()
77
+ return newRow
78
+ }
79
+
80
+ return (
81
+ <Dialog
82
+ open
83
+ title="Add assembly aliases"
84
+ handleClose={handleClose}
85
+ maxWidth={'sm'}
86
+ data-testid="add-assembly-alias"
87
+ fullWidth
88
+ >
89
+ <DialogContent style={{ display: 'flex', flexDirection: 'column' }}>
90
+ <Box sx={{ height: 400, width: '100%' }}>
91
+ <DataGrid
92
+ rows={rows}
93
+ columns={columns}
94
+ initialState={{
95
+ pagination: {
96
+ paginationModel: {
97
+ pageSize: 5,
98
+ },
99
+ },
100
+ }}
101
+ pageSizeOptions={[5]}
102
+ processRowUpdate={processRowUpdate}
103
+ disableRowSelectionOnClick
104
+ />
105
+ </Box>
106
+ </DialogContent>
107
+ {errorMessage ? (
108
+ <DialogContent>
109
+ <DialogContentText color="error">{errorMessage}</DialogContentText>
110
+ </DialogContent>
111
+ ) : null}
112
+ </Dialog>
113
+ )
114
+ }
@@ -1,8 +1,7 @@
1
1
  /* eslint-disable @typescript-eslint/unbound-method */
2
- /* eslint-disable @typescript-eslint/no-misused-promises */
2
+
3
3
  import { type AnnotationFeature } from '@apollo-annotation/mst'
4
4
  import { AddFeatureChange } from '@apollo-annotation/shared'
5
- import { type AbstractSessionModel } from '@jbrowse/core/util'
6
5
  import {
7
6
  Button,
8
7
  DialogActions,
@@ -37,7 +36,6 @@ export function AddChildFeature({
37
36
  sourceAssemblyId,
38
37
  sourceFeature,
39
38
  }: AddChildFeatureProps) {
40
- const { notify } = session as unknown as AbstractSessionModel
41
39
  const [end, setEnd] = useState(String(sourceFeature.max))
42
40
  const [start, setStart] = useState(String(sourceFeature.min + 1))
43
41
  const [type, setType] = useState('')
@@ -63,7 +61,7 @@ export function AddChildFeature({
63
61
  return terms
64
62
  }
65
63
 
66
- async function onSubmit(event: React.FormEvent<HTMLFormElement>) {
64
+ function onSubmit(event: React.FormEvent<HTMLFormElement>) {
67
65
  event.preventDefault()
68
66
  setErrorMessage('')
69
67
  const change = new AddFeatureChange({
@@ -79,8 +77,7 @@ export function AddChildFeature({
79
77
  },
80
78
  parentFeatureId: sourceFeature._id,
81
79
  })
82
- await changeManager.submit(change)
83
- notify('Feature added successfully', 'success')
80
+ void changeManager.submit(change)
84
81
  handleClose()
85
82
  event.preventDefault()
86
83
  }
@@ -1,12 +1,9 @@
1
1
  /* eslint-disable @typescript-eslint/unbound-method */
2
2
  /* eslint-disable @typescript-eslint/no-unnecessary-condition */
3
- /* eslint-disable @typescript-eslint/no-misused-promises */
3
+
4
4
  import { type AnnotationFeatureSnapshot } from '@apollo-annotation/mst'
5
5
  import { AddFeatureChange } from '@apollo-annotation/shared'
6
- import {
7
- type AbstractSessionModel,
8
- type Region,
9
- } from '@jbrowse/core/util/types'
6
+ import { type Region } from '@jbrowse/core/util/types'
10
7
  import InfoIcon from '@mui/icons-material/Info'
11
8
  import {
12
9
  Box,
@@ -96,7 +93,6 @@ export function AddFeature({
96
93
  region,
97
94
  session,
98
95
  }: AddFeatureProps) {
99
- const { notify } = session as unknown as AbstractSessionModel
100
96
  const [end, setEnd] = useState(String(region.end))
101
97
  const [start, setStart] = useState(String(region.start + 1))
102
98
  const [type, setType] = useState<NewFeature>(NewFeature.GENE_AND_SUBFEATURES)
@@ -104,7 +100,7 @@ export function AddFeature({
104
100
  const [strand, setStrand] = useState<1 | -1 | undefined>()
105
101
  const [errorMessage, setErrorMessage] = useState('')
106
102
 
107
- async function onSubmit(event: React.FormEvent<HTMLFormElement>) {
103
+ function onSubmit(event: React.FormEvent<HTMLFormElement>) {
108
104
  event.preventDefault()
109
105
  setErrorMessage('')
110
106
 
@@ -120,7 +116,9 @@ export function AddFeature({
120
116
  }
121
117
 
122
118
  if (!refSeqId) {
123
- setErrorMessage('Invalid refseq id')
119
+ setErrorMessage(
120
+ 'Invalid refseq id. Make sure you have the Apollo annotation track open',
121
+ )
124
122
  return
125
123
  }
126
124
 
@@ -149,8 +147,7 @@ export function AddFeature({
149
147
  children,
150
148
  },
151
149
  })
152
- await changeManager.submit(change)
153
- notify('Feature added successfully', 'success')
150
+ void changeManager.submit(change)
154
151
  handleClose()
155
152
  return
156
153
  }
@@ -167,8 +164,7 @@ export function AddFeature({
167
164
  assembly: region.assemblyName,
168
165
  addedFeature: mRNA,
169
166
  })
170
- await changeManager.submit(change)
171
- notify('Feature added successfully', 'success')
167
+ void changeManager.submit(change)
172
168
  handleClose()
173
169
  return
174
170
  }
@@ -191,8 +187,7 @@ export function AddFeature({
191
187
  strand,
192
188
  },
193
189
  })
194
- await changeManager.submit(change)
195
- notify('Feature added successfully', 'success')
190
+ void changeManager.submit(change)
196
191
  handleClose()
197
192
  return
198
193
  }
@@ -231,7 +226,11 @@ export function AddFeature({
231
226
  }
232
227
 
233
228
  let submitDisabled: boolean = Boolean(error) || !(start && end && type)
234
- if (type === NewFeature.CUSTOM && !customType) {
229
+ if (
230
+ (type === NewFeature.CUSTOM && !customType) ||
231
+ (!strand && type === NewFeature.GENE_AND_SUBFEATURES) ||
232
+ (!strand && type === NewFeature.TRANSCRIPT_AND_SUBFEATURES)
233
+ ) {
235
234
  submitDisabled = true
236
235
  }
237
236