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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/dist/index.esm.js +11212 -10483
  2. package/dist/index.esm.js.map +1 -1
  3. package/dist/jbrowse-plugin-apollo.cjs.development.js +11251 -10509
  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 +7726 -9014
  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 +18 -18
  12. package/src/ApolloInternetAccount/model.ts +123 -70
  13. package/src/ApolloRefNameAliasAdapter/ApolloRefNameAliasAdapter.ts +4 -4
  14. package/src/ApolloSequenceAdapter/ApolloSequenceAdapter.ts +9 -7
  15. package/src/BackendDrivers/CollaborationServerDriver.ts +72 -20
  16. package/src/BackendDrivers/DesktopFileDriver.ts +2 -2
  17. package/src/ChangeManager.ts +36 -14
  18. package/src/FeatureDetailsWidget/ApolloTranscriptDetailsWidget.tsx +64 -5
  19. package/src/FeatureDetailsWidget/BasicInformation.tsx +6 -4
  20. package/src/FeatureDetailsWidget/NumberTextField.tsx +5 -2
  21. package/src/FeatureDetailsWidget/TranscriptSequence.tsx +70 -73
  22. package/src/FeatureDetailsWidget/TranscriptWidgetEditLocation.tsx +72 -234
  23. package/src/LinearApolloDisplay/components/CheckResultWarnings.tsx +92 -0
  24. package/src/LinearApolloDisplay/components/LinearApolloDisplay.tsx +23 -131
  25. package/src/LinearApolloDisplay/glyphs/BoxGlyph.ts +50 -194
  26. package/src/LinearApolloDisplay/glyphs/GeneGlyph.ts +279 -217
  27. package/src/LinearApolloDisplay/glyphs/GenericChildGlyph.ts +53 -34
  28. package/src/LinearApolloDisplay/glyphs/Glyph.ts +7 -9
  29. package/src/LinearApolloDisplay/glyphs/util.ts +19 -0
  30. package/src/LinearApolloDisplay/stateModel/base.ts +34 -43
  31. package/src/LinearApolloDisplay/stateModel/layouts.ts +3 -2
  32. package/src/LinearApolloDisplay/stateModel/mouseEvents.ts +32 -261
  33. package/src/LinearApolloDisplay/stateModel/rendering.ts +43 -343
  34. package/src/LinearApolloReferenceSequenceDisplay/components/LinearApolloReferenceSequenceDisplay.tsx +87 -0
  35. package/src/LinearApolloReferenceSequenceDisplay/components/index.ts +1 -0
  36. package/src/LinearApolloReferenceSequenceDisplay/configSchema.ts +7 -0
  37. package/src/LinearApolloReferenceSequenceDisplay/drawSequenceOverlay.ts +181 -0
  38. package/src/LinearApolloReferenceSequenceDisplay/drawSequenceTrack.ts +218 -0
  39. package/src/LinearApolloReferenceSequenceDisplay/index.ts +3 -0
  40. package/src/LinearApolloReferenceSequenceDisplay/stateModel/base.ts +227 -0
  41. package/src/LinearApolloReferenceSequenceDisplay/stateModel/index.ts +25 -0
  42. package/src/LinearApolloReferenceSequenceDisplay/stateModel/rendering.ts +157 -0
  43. package/src/LinearApolloSixFrameDisplay/components/LinearApolloSixFrameDisplay.tsx +101 -38
  44. package/src/LinearApolloSixFrameDisplay/glyphs/GeneGlyph.ts +334 -262
  45. package/src/LinearApolloSixFrameDisplay/glyphs/Glyph.ts +12 -8
  46. package/src/LinearApolloSixFrameDisplay/stateModel/base.ts +42 -4
  47. package/src/LinearApolloSixFrameDisplay/stateModel/layouts.ts +4 -8
  48. package/src/LinearApolloSixFrameDisplay/stateModel/mouseEvents.ts +73 -97
  49. package/src/LinearApolloSixFrameDisplay/stateModel/rendering.ts +49 -61
  50. package/src/TabularEditor/HybridGrid/Feature.tsx +16 -14
  51. package/src/TabularEditor/HybridGrid/HybridGrid.tsx +7 -5
  52. package/src/components/AddAssembly.tsx +34 -38
  53. package/src/components/AddAssemblyAliases.tsx +1 -1
  54. package/src/components/AddChildFeature.tsx +5 -2
  55. package/src/components/AddFeature.tsx +30 -21
  56. package/src/components/AddRefSeqAliases.tsx +64 -50
  57. package/src/components/CopyFeature.tsx +4 -2
  58. package/src/components/CreateApolloAnnotation.tsx +22 -9
  59. package/src/components/DeleteAssembly.tsx +3 -10
  60. package/src/components/DownloadGFF3.tsx +2 -2
  61. package/src/components/EditZoomThresholdDialog.tsx +69 -0
  62. package/src/components/FilterFeatures.tsx +7 -7
  63. package/src/components/FilterTranscripts.tsx +6 -6
  64. package/src/components/ImportFeatures.tsx +1 -1
  65. package/src/components/ManageChecks.tsx +3 -10
  66. package/src/components/ManageUsers.tsx +23 -22
  67. package/src/components/MergeTranscripts.tsx +12 -15
  68. package/src/components/OntologyTermAutocomplete.tsx +1 -8
  69. package/src/components/OntologyTermMultiSelect.tsx +11 -11
  70. package/src/components/OpenLocalFile.tsx +11 -7
  71. package/src/components/ViewChangeLog.tsx +25 -50
  72. package/src/components/ViewCheckResults.tsx +2 -8
  73. package/src/components/index.ts +1 -0
  74. package/src/config.ts +6 -0
  75. package/src/index.ts +53 -115
  76. package/src/makeDisplayComponent.tsx +9 -14
  77. package/src/menus/index.ts +1 -0
  78. package/src/{ApolloInternetAccount/addMenuItems.ts → menus/topLevelMenu.ts} +56 -47
  79. package/src/menus/topLevelMenuAdmin.ts +154 -0
  80. package/src/session/ClientDataStore.ts +32 -14
  81. package/src/session/session.ts +159 -121
  82. package/src/util/annotationFeatureUtils.ts +15 -21
  83. package/src/util/displayUtils.ts +149 -0
  84. package/src/util/glyphUtils.ts +329 -0
  85. package/src/util/loadAssemblyIntoClient.ts +3 -2
  86. package/src/util/mouseEventsUtils.ts +32 -0
@@ -193,11 +193,8 @@ export function CreateApolloAnnotation({
193
193
  continue
194
194
  }
195
195
 
196
- // Destination feature should be of type gene amd should be on the same strand as the source feature
197
- if (
198
- featureTypeOntology?.isTypeOf(f.type, 'gene') &&
199
- f.strand === annotationFeature.strand
200
- ) {
196
+ // Destination feature should be of type gene
197
+ if (featureTypeOntology?.isTypeOf(f.type, 'gene')) {
201
198
  const featureSnapshot = getSnapshot(f)
202
199
  filteredFeatures.push(featureSnapshot)
203
200
  }
@@ -373,7 +370,7 @@ export function CreateApolloAnnotation({
373
370
  })
374
371
  }
375
372
 
376
- await submitChange(change)
373
+ await submitChange(change, annotationFeature._id)
377
374
  }
378
375
 
379
376
  const copyTranscriptsToDestinationGene = async (
@@ -384,6 +381,15 @@ export function CreateApolloAnnotation({
384
381
  }
385
382
  for (const transcriptId of Object.keys(transcripts)) {
386
383
  const transcript = transcripts[transcriptId]
384
+ transcript.strand = selectedDestinationFeature.strand
385
+
386
+ // update strand of transcript children if they exist
387
+ if (transcript.children) {
388
+ for (const childId of Object.keys(transcript.children)) {
389
+ transcript.children[childId].strand =
390
+ selectedDestinationFeature.strand
391
+ }
392
+ }
387
393
  const change = new AddFeatureChange({
388
394
  parentFeatureId: selectedDestinationFeature._id,
389
395
  changedIds: [selectedDestinationFeature._id],
@@ -391,7 +397,8 @@ export function CreateApolloAnnotation({
391
397
  assembly: assembly.name,
392
398
  addedFeature: transcript,
393
399
  })
394
- await submitChange(change)
400
+ // selects the last added transcript
401
+ await submitChange(change, transcriptId)
395
402
  }
396
403
  }
397
404
 
@@ -419,7 +426,7 @@ export function CreateApolloAnnotation({
419
426
  },
420
427
  },
421
428
  })
422
- await submitChange(change)
429
+ await submitChange(change, newGeneId)
423
430
  }
424
431
 
425
432
  const extendSelectedDestinationFeatureLocation = async (
@@ -461,8 +468,14 @@ export function CreateApolloAnnotation({
461
468
 
462
469
  const submitChange = async (
463
470
  change: AddFeatureChange | LocationStartChange | LocationEndChange,
471
+ selectedFeatureId?: string,
464
472
  ) => {
465
- await apolloSessionModel.apolloDataStore.changeManager.submit(change)
473
+ await apolloSessionModel.apolloDataStore.changeManager
474
+ .submit(change)
475
+ .then(() => {
476
+ // Selects the newly added/modified feature
477
+ apolloSessionModel.apolloSetSelectedFeature(selectedFeatureId)
478
+ })
466
479
  }
467
480
 
468
481
  const handleCreateNewGeneChange = (
@@ -1,7 +1,6 @@
1
1
  /* eslint-disable @typescript-eslint/unbound-method */
2
2
  /* eslint-disable @typescript-eslint/no-misused-promises */
3
3
  import { DeleteAssemblyChange } from '@apollo-annotation/shared'
4
- import { type Assembly } from '@jbrowse/core/assemblyManager/assembly'
5
4
  import {
6
5
  Button,
7
6
  Checkbox,
@@ -15,7 +14,7 @@ import {
15
14
  type SelectChangeEvent,
16
15
  } from '@mui/material'
17
16
  import { getRoot } from 'mobx-state-tree'
18
- import React, { useEffect, useState } from 'react'
17
+ import React, { useState } from 'react'
19
18
 
20
19
  import { type ApolloInternetAccountModel } from '../ApolloInternetAccount/model'
21
20
  import {
@@ -40,7 +39,6 @@ export function DeleteAssembly({
40
39
  session,
41
40
  }: DeleteAssemblyProps) {
42
41
  const { internetAccounts } = getRoot<ApolloRootModel>(session)
43
- const [selectedAssembly, setSelectedAssembly] = useState<Assembly>()
44
42
  const [errorMessage, setErrorMessage] = useState('')
45
43
  const [confirmDelete, setconfirmDelete] = useState(false)
46
44
  const [submitted, setSubmitted] = useState(false)
@@ -63,12 +61,7 @@ export function DeleteAssembly({
63
61
  }
64
62
 
65
63
  const assemblies = collaborationServerDriver.getAssemblies()
66
-
67
- useEffect(() => {
68
- if (assemblies.length > 0 && selectedAssembly === undefined) {
69
- setSelectedAssembly(assemblies[0])
70
- }
71
- }, [assemblies, selectedAssembly])
64
+ const [selectedAssembly, setSelectedAssembly] = useState(assemblies.at(0))
72
65
 
73
66
  function handleChangeInternetAccount(e: SelectChangeEvent) {
74
67
  setSubmitted(false)
@@ -142,7 +135,7 @@ export function DeleteAssembly({
142
135
  >
143
136
  {assemblies.map((option) => (
144
137
  <MenuItem key={option.name} value={option.name}>
145
- {option.displayName ?? option.name}
138
+ {option.displayName}
146
139
  </MenuItem>
147
140
  ))}
148
141
  </Select>
@@ -5,7 +5,7 @@
5
5
  /* eslint-disable @typescript-eslint/no-misused-promises */
6
6
  import { type ApolloAssembly } from '@apollo-annotation/mst'
7
7
  import { annotationFeatureToGFF3 } from '@apollo-annotation/shared'
8
- import gff, { type GFF3Item } from '@gmod/gff'
8
+ import { type GFF3Item, formatSync } from '@gmod/gff'
9
9
  import { type Assembly } from '@jbrowse/core/assemblyManager/assembly'
10
10
  import { getConf } from '@jbrowse/core/configuration'
11
11
  import {
@@ -169,7 +169,7 @@ export function DownloadGFF3({ handleClose, session }: DownloadGFF3Props) {
169
169
  const { refName, seq } = sequenceFeature
170
170
  gff3Items.push({ id: refName, description: '', sequence: seq })
171
171
  }
172
- const gff3 = gff.formatSync(gff3Items)
172
+ const gff3 = formatSync(gff3Items)
173
173
  const gff3Blob = new Blob([gff3], { type: 'text/plain;charset=utf-8' })
174
174
  saveAs(
175
175
  gff3Blob,
@@ -0,0 +1,69 @@
1
+ import { Dialog } from '@jbrowse/core/ui'
2
+ import {
3
+ Button,
4
+ DialogActions,
5
+ DialogContent,
6
+ TextField,
7
+ Typography,
8
+ } from '@mui/material'
9
+ import { observer } from 'mobx-react'
10
+ import React, { useState } from 'react'
11
+
12
+ const EditZoomThresholdDialog = observer(function ({
13
+ model,
14
+ handleClose,
15
+ }: {
16
+ model: {
17
+ zoomThresholdSetting: number
18
+ setZoomThresholdSetting: (a: { zoomThreshold: number }) => void
19
+ }
20
+ handleClose: () => void
21
+ }) {
22
+ const [zoomThreshold, setZoomThreshold] = useState(
23
+ `${model.zoomThresholdSetting}`,
24
+ )
25
+
26
+ return (
27
+ <Dialog open onClose={handleClose} title="Edit zoom threshold setting">
28
+ <DialogContent>
29
+ <Typography>
30
+ The zoom level in base pairs (bp) per pixel at which features are
31
+ rendered in this Annotations track. Increasing the value will allow
32
+ features to render when zooming out, but might impact performance.
33
+ </Typography>
34
+ <TextField
35
+ label="Threshold value (bpPerPx)"
36
+ value={zoomThreshold}
37
+ onChange={(event) => {
38
+ setZoomThreshold(event.target.value)
39
+ }}
40
+ />
41
+
42
+ <DialogActions>
43
+ <Button
44
+ variant="contained"
45
+ onClick={() => {
46
+ model.setZoomThresholdSetting({
47
+ zoomThreshold: +zoomThreshold,
48
+ })
49
+ handleClose()
50
+ }}
51
+ >
52
+ Submit
53
+ </Button>
54
+ <Button
55
+ variant="contained"
56
+ color="secondary"
57
+ onClick={() => {
58
+ handleClose()
59
+ }}
60
+ >
61
+ Cancel
62
+ </Button>
63
+ </DialogActions>
64
+ </DialogContent>
65
+ </Dialog>
66
+ )
67
+ })
68
+
69
+ export default EditZoomThresholdDialog
@@ -4,7 +4,7 @@ import {
4
4
  Chip,
5
5
  DialogContent,
6
6
  DialogContentText,
7
- Grid2,
7
+ Grid,
8
8
  TextField,
9
9
  } from '@mui/material'
10
10
  import { observer } from 'mobx-react'
@@ -62,8 +62,8 @@ export const FilterFeatures = observer(function FilterFeatures({
62
62
  <DialogContentText>
63
63
  Select the feature types you want to display in the apollo track
64
64
  </DialogContentText>
65
- <Grid2 container spacing={2}>
66
- <Grid2 size={8}>
65
+ <Grid container spacing={2}>
66
+ <Grid size={8}>
67
67
  <OntologyTermAutocomplete
68
68
  session={session}
69
69
  ontologyName="Sequence Ontology"
@@ -84,8 +84,8 @@ export const FilterFeatures = observer(function FilterFeatures({
84
84
  }
85
85
  }}
86
86
  />
87
- </Grid2>
88
- <Grid2 size={4}>
87
+ </Grid>
88
+ <Grid size={4}>
89
89
  <Button
90
90
  variant="contained"
91
91
  onClick={handleAddFeatureType}
@@ -95,8 +95,8 @@ export const FilterFeatures = observer(function FilterFeatures({
95
95
  >
96
96
  Add
97
97
  </Button>
98
- </Grid2>
99
- </Grid2>
98
+ </Grid>
99
+ </Grid>
100
100
  {selectedFeatureTypes.length > 0 && (
101
101
  <div>
102
102
  <hr />
@@ -5,7 +5,7 @@ import {
5
5
  DialogContentText,
6
6
  FormControlLabel,
7
7
  FormGroup,
8
- Grid2,
8
+ Grid,
9
9
  } from '@mui/material'
10
10
  import { observer } from 'mobx-react'
11
11
  import React, { useState } from 'react'
@@ -59,8 +59,8 @@ export const FilterTranscripts = observer(function FilterTranscripts({
59
59
  Select the alternate transcripts you want to display in the apollo
60
60
  track
61
61
  </DialogContentText>
62
- <Grid2 container spacing={2}>
63
- <Grid2 size={8}>
62
+ <Grid container spacing={2}>
63
+ <Grid size={8}>
64
64
  <FormGroup>
65
65
  {allTranscripts.map((item) => (
66
66
  // eslint-disable-next-line react/jsx-key
@@ -71,15 +71,15 @@ export const FilterTranscripts = observer(function FilterTranscripts({
71
71
  onChange={() => {
72
72
  handleChange(item)
73
73
  }}
74
- inputProps={{ 'aria-label': 'controlled' }}
74
+ slotProps={{ input: { 'aria-label': 'controlled' } }}
75
75
  />
76
76
  }
77
77
  label={item}
78
78
  />
79
79
  ))}
80
80
  </FormGroup>
81
- </Grid2>
82
- </Grid2>
81
+ </Grid>
82
+ </Grid>
83
83
  </DialogContent>
84
84
  </Dialog>
85
85
  )
@@ -271,7 +271,7 @@ export function ImportFeatures({
271
271
  <Checkbox
272
272
  checked={deleteFeatures}
273
273
  onChange={handleDeleteFeatures}
274
- inputProps={{ 'aria-label': 'controlled' }}
274
+ slotProps={{ input: { 'aria-label': 'controlled' } }}
275
275
  color="warning"
276
276
  />
277
277
  }
@@ -1,7 +1,6 @@
1
1
  /* eslint-disable @typescript-eslint/use-unknown-in-catch-callback-variable */
2
2
  /* eslint-disable @typescript-eslint/unbound-method */
3
3
  /* eslint-disable @typescript-eslint/no-misused-promises */
4
- import { type Assembly } from '@jbrowse/core/assemblyManager/assembly'
5
4
  import { type AbstractSessionModel } from '@jbrowse/core/util'
6
5
  import {
7
6
  Button,
@@ -52,7 +51,6 @@ interface CheckDocument {
52
51
 
53
52
  export function ManageChecks({ handleClose, session }: ManageChecksProps) {
54
53
  const { internetAccounts } = getRoot<ApolloRootModel>(session)
55
- const [selectedAssembly, setSelectedAssembly] = useState<Assembly>()
56
54
  const [errorMessage, setErrorMessage] = useState('')
57
55
  const [submitted, setSubmitted] = useState(false)
58
56
  const apolloInternetAccounts = internetAccounts.filter(
@@ -76,6 +74,7 @@ export function ManageChecks({ handleClose, session }: ManageChecksProps) {
76
74
  }
77
75
 
78
76
  const assemblies = collaborationServerDriver.getAssemblies()
77
+ const [selectedAssembly, setSelectedAssembly] = useState(assemblies.at(0))
79
78
 
80
79
  useEffect(() => {
81
80
  async function getChecks() {
@@ -99,19 +98,13 @@ export function ManageChecks({ handleClose, session }: ManageChecksProps) {
99
98
  })
100
99
  }, [selectedInternetAccount])
101
100
 
102
- useEffect(() => {
103
- if (assemblies.length > 0 && selectedAssembly === undefined) {
104
- setSelectedAssembly(assemblies[0])
105
- }
106
- }, [assemblies, selectedAssembly])
107
-
108
101
  useEffect(() => {
109
102
  async function getChecks() {
110
103
  if (!selectedAssembly) {
111
104
  return
112
105
  }
113
106
  const { baseURL, getFetcher } = selectedInternetAccount
114
- const uri = new URL(`/assemblies/${selectedAssembly.name}`, baseURL).href
107
+ const uri = new URL(`assemblies/${selectedAssembly.name}`, baseURL).href
115
108
  const apolloFetch = getFetcher({ locationType: 'UriLocation', uri })
116
109
  const response = await apolloFetch(uri, { method: 'GET' })
117
110
  if (!response.ok) {
@@ -238,7 +231,7 @@ export function ManageChecks({ handleClose, session }: ManageChecksProps) {
238
231
  >
239
232
  {assemblies.map((option) => (
240
233
  <MenuItem key={option.name} value={option.name}>
241
- {option.displayName ?? option.name}
234
+ {option.displayName}
242
235
  </MenuItem>
243
236
  ))}
244
237
  </Select>
@@ -28,7 +28,7 @@ import {
28
28
  GridToolbar,
29
29
  } from '@mui/x-data-grid'
30
30
  import { getRoot } from 'mobx-state-tree'
31
- import React, { useCallback, useEffect, useState } from 'react'
31
+ import React, { useEffect, useState } from 'react'
32
32
 
33
33
  import { type ApolloInternetAccountModel } from '../ApolloInternetAccount/model'
34
34
  import { type ChangeManager } from '../ChangeManager'
@@ -72,33 +72,34 @@ export function ManageUsers({
72
72
  )
73
73
  const [users, setUsers] = useState<UserResponse[]>([])
74
74
 
75
- const getUsers = useCallback(async () => {
76
- const { baseURL } = selectedInternetAccount
77
- const uri = new URL('users', baseURL).href
78
- const apolloFetch = selectedInternetAccount.getFetcher({
79
- locationType: 'UriLocation',
80
- uri,
81
- })
82
- if (apolloFetch) {
83
- const response = await apolloFetch(uri, { method: 'GET' })
84
- if (!response.ok) {
85
- const newErrorMessage = await createFetchErrorMessage(
86
- response,
87
- 'Error when getting user data from db',
75
+ useEffect(() => {
76
+ async function getUsers() {
77
+ const { baseURL } = selectedInternetAccount
78
+ const uri = new URL('users', baseURL).href
79
+ const apolloFetch = selectedInternetAccount.getFetcher({
80
+ locationType: 'UriLocation',
81
+ uri,
82
+ })
83
+ if (apolloFetch) {
84
+ const response = await apolloFetch(uri, { method: 'GET' })
85
+ if (!response.ok) {
86
+ const newErrorMessage = await createFetchErrorMessage(
87
+ response,
88
+ 'Error when getting user data from db',
89
+ )
90
+ setErrorMessage(newErrorMessage)
91
+ return
92
+ }
93
+ const data = (await response.json()) as UserResponse[]
94
+ setUsers(
95
+ data.map((u) => (u.role === undefined ? { ...u, role: '' } : u)),
88
96
  )
89
- setErrorMessage(newErrorMessage)
90
- return
91
97
  }
92
- const data = (await response.json()) as UserResponse[]
93
- setUsers(data.map((u) => (u.role === undefined ? { ...u, role: '' } : u)))
94
98
  }
95
- }, [selectedInternetAccount])
96
-
97
- useEffect(() => {
98
99
  getUsers().catch((error) => {
99
100
  setErrorMessage(String(error))
100
101
  })
101
- }, [getUsers])
102
+ }, [selectedInternetAccount])
102
103
 
103
104
  async function deleteUser(id: GridRowId) {
104
105
  const change = new DeleteUserChange({
@@ -1,8 +1,6 @@
1
1
  /* eslint-disable @typescript-eslint/unbound-method */
2
- /* eslint-disable @typescript-eslint/no-misused-promises */
3
2
  import { type AnnotationFeature } from '@apollo-annotation/mst'
4
3
  import { MergeTranscriptsChange } from '@apollo-annotation/shared'
5
- import { type AbstractSessionModel } from '@jbrowse/core/util'
6
4
  import {
7
5
  Box,
8
6
  Button,
@@ -82,17 +80,20 @@ export function MergeTranscripts({
82
80
  sourceAssemblyId,
83
81
  sourceFeature,
84
82
  }: MergeTranscriptsProps) {
85
- const { notify } = session as unknown as AbstractSessionModel
86
83
  const [errorMessage, setErrorMessage] = useState('')
87
- const [selectedTranscript, setSelectedTranscript] =
88
- useState<AnnotationFeature>()
84
+ const transcripts = getTranscripts(sourceFeature, session)
85
+ const firstTranscript = Object.keys(transcripts).at(0)
86
+ const [selectedTranscriptId, setSelectedTranscriptId] = useState<
87
+ string | undefined
88
+ >(firstTranscript)
89
89
 
90
- async function onSubmit(event: React.FormEvent<HTMLFormElement>) {
90
+ function onSubmit(event: React.FormEvent<HTMLFormElement>) {
91
91
  event.preventDefault()
92
92
  setErrorMessage('')
93
- if (!selectedTranscript) {
93
+ if (!selectedTranscriptId) {
94
94
  return
95
95
  }
96
+ const selectedTranscript = transcripts[selectedTranscriptId]
96
97
  if (selectedFeature?._id === sourceFeature._id) {
97
98
  setSelectedFeature()
98
99
  }
@@ -109,20 +110,16 @@ export function MergeTranscripts({
109
110
  secondTranscript: getSnapshot(selectedTranscript),
110
111
  parentFeatureId: sourceFeature.parent._id,
111
112
  })
112
- await changeManager.submit(change)
113
- notify('Transcripts successfully merged', 'success')
113
+ void changeManager.submit(change)
114
114
  handleClose()
115
- event.preventDefault()
116
115
  }
117
116
 
118
117
  const handleTypeChange = (e: SelectChangeEvent) => {
119
118
  setErrorMessage('')
120
119
  const { value } = e.target
121
- setSelectedTranscript(transcripts[value])
120
+ setSelectedTranscriptId(value)
122
121
  }
123
122
 
124
- const transcripts = getTranscripts(sourceFeature, session)
125
-
126
123
  return (
127
124
  <Dialog
128
125
  open
@@ -140,7 +137,7 @@ export function MergeTranscripts({
140
137
  <RadioGroup
141
138
  aria-labelledby="demo-radio-buttons-group-label"
142
139
  name="radio-buttons-group"
143
- value={selectedTranscript}
140
+ value={selectedTranscriptId}
144
141
  onChange={handleTypeChange}
145
142
  >
146
143
  {Object.keys(transcripts).map((key) => (
@@ -165,7 +162,7 @@ export function MergeTranscripts({
165
162
  type="submit"
166
163
  disabled={
167
164
  Object.keys(transcripts).length === 0 ||
168
- selectedTranscript === undefined
165
+ selectedTranscriptId === undefined
169
166
  }
170
167
  >
171
168
  Submit
@@ -73,21 +73,14 @@ export function OntologyTermAutocomplete({
73
73
  [filterTermsProp, includeDeprecated],
74
74
  )
75
75
 
76
- // effect for clearing choices when not open
77
- useEffect(() => {
78
- if (!open) {
79
- setTermChoices(undefined)
80
- }
81
- }, [open])
82
-
83
76
  // effect for matching the current value with an ontology term
84
77
  useEffect(() => {
85
78
  const controller = new AbortController()
86
79
  const { signal } = controller
87
80
  if (needToLoadCurrentTerm) {
88
- setCurrentOntologyTermInvalid('')
89
81
  getCurrentTerm(ontologyStore, valueString, filterTerms, signal).then(
90
82
  (term) => {
83
+ setCurrentOntologyTermInvalid('')
91
84
  if (!signal.aborted) {
92
85
  setCurrentOntologyTerm(term)
93
86
  }
@@ -4,9 +4,9 @@
4
4
  import { isAbortException } from '@jbrowse/core/util/aborting'
5
5
  import {
6
6
  Autocomplete,
7
- type AutocompleteRenderGetTagProps,
7
+ type AutocompleteRenderValueGetItemProps,
8
8
  Chip,
9
- Grid2,
9
+ Grid,
10
10
  TextField,
11
11
  Tooltip,
12
12
  Typography,
@@ -49,14 +49,14 @@ interface TermValue {
49
49
  // const hiliteRegex = /(?<=<em class="hilite">)(.*?)(?=<\/em>)/g
50
50
 
51
51
  function TermTagWithTooltip({
52
- getTagProps,
52
+ getItemProps,
53
53
  index,
54
54
  ontology,
55
55
  termId,
56
56
  }: {
57
57
  termId: string
58
58
  index: number
59
- getTagProps: AutocompleteRenderGetTagProps
59
+ getItemProps: AutocompleteRenderValueGetItemProps<true>
60
60
  ontology: OntologyRecord
61
61
  }) {
62
62
  const manager = getParent<OntologyManager>(ontology, 2)
@@ -100,7 +100,7 @@ function TermTagWithTooltip({
100
100
  label={errorMessage || manager.applyPrefixes(termId)}
101
101
  color={errorMessage ? 'error' : 'default'}
102
102
  size="small"
103
- {...getTagProps({ index })}
103
+ {...getItemProps({ index })}
104
104
  />
105
105
  </div>
106
106
  </Tooltip>
@@ -270,13 +270,13 @@ export function OntologyTermMultiSelect({
270
270
  inputValue={inputValue}
271
271
  />
272
272
  )}
273
- renderTags={(v, getTagProps) =>
273
+ renderValue={(v, getItemProps) =>
274
274
  v.map((option, index) => (
275
275
  <TermTagWithTooltip
276
276
  termId={option.term.id}
277
277
  index={index}
278
278
  ontology={ontology}
279
- getTagProps={getTagProps}
279
+ getItemProps={getItemProps}
280
280
  key={option.term.id}
281
281
  />
282
282
  ))
@@ -336,8 +336,8 @@ function Option(props: {
336
336
  // .join(', ')
337
337
  return (
338
338
  <li {...other}>
339
- <Grid2 container>
340
- <Grid2>
339
+ <Grid container>
340
+ <Grid>
341
341
  <Typography component="span">
342
342
  {ontologyManager.applyPrefixes(option.term.id)}
343
343
  </Typography>{' '}
@@ -347,8 +347,8 @@ function Option(props: {
347
347
  />{' '}
348
348
  {/* ({lblScore}) */}
349
349
  <dl>{fields}</dl>
350
- </Grid2>
351
- </Grid2>
350
+ </Grid>
351
+ </Grid>
352
352
  </li>
353
353
  )
354
354
  }
@@ -87,6 +87,13 @@ export function OpenLocalFile({ handleClose, session }: OpenLocalFileProps) {
87
87
  return
88
88
  }
89
89
 
90
+ const fileMetadata: { file?: string } = {}
91
+ if (isElectron) {
92
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
93
+ const { webUtils } = globalThis.require('electron')
94
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
95
+ fileMetadata.file = webUtils.getPathForFile(file) as string
96
+ }
90
97
  const assemblyConfig = {
91
98
  name: assemblyId,
92
99
  aliases: [assemblyName],
@@ -95,17 +102,14 @@ export function OpenLocalFile({ handleClose, session }: OpenLocalFileProps) {
95
102
  trackId: `sequenceConfigId-${assemblyName}`,
96
103
  type: 'ReferenceSequenceTrack',
97
104
  adapter: { type: 'ApolloSequenceAdapter', assemblyId },
98
- metadata: {
99
- apollo: true,
100
- ...(isElectron
101
- ? { file: (file as File & { path: string }).path }
102
- : {}),
103
- },
105
+ metadata: { apollo: true, ...fileMetadata },
104
106
  },
105
107
  }
106
108
 
107
109
  // Save assembly into session
108
- await (addSessionAssembly || addAssembly)(assemblyConfig)
110
+ await (isElectron
111
+ ? addAssembly?.(assemblyConfig)
112
+ : (addSessionAssembly || addAssembly)(assemblyConfig))
109
113
  const a = await assemblyManager.waitForAssembly(assemblyConfig.name)
110
114
  if (a) {
111
115
  // @ts-expect-error MST type coercion problem?