jbrowse-plugin-msaview 2.4.2 → 2.4.3

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 (71) hide show
  1. package/dist/LaunchMsaView/components/LaunchMsaViewDialog.js +3 -4
  2. package/dist/LaunchMsaView/components/LaunchMsaViewDialog.js.map +1 -1
  3. package/dist/LaunchMsaView/components/LaunchPanelContent.d.ts +5 -0
  4. package/dist/LaunchMsaView/components/LaunchPanelContent.js +16 -0
  5. package/dist/LaunchMsaView/components/LaunchPanelContent.js.map +1 -0
  6. package/dist/LaunchMsaView/components/ManualMSALoader/ManualMSALoader.js +22 -25
  7. package/dist/LaunchMsaView/components/ManualMSALoader/ManualMSALoader.js.map +1 -1
  8. package/dist/LaunchMsaView/components/NCBIBlastQuery/CachedBlastResults.js +12 -24
  9. package/dist/LaunchMsaView/components/NCBIBlastQuery/CachedBlastResults.js.map +1 -1
  10. package/dist/LaunchMsaView/components/NCBIBlastQuery/MsaAlgorithmSelect.d.ts +7 -0
  11. package/dist/LaunchMsaView/components/NCBIBlastQuery/MsaAlgorithmSelect.js +10 -0
  12. package/dist/LaunchMsaView/components/NCBIBlastQuery/MsaAlgorithmSelect.js.map +1 -0
  13. package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastAutomaticPanel.js +23 -32
  14. package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastAutomaticPanel.js.map +1 -1
  15. package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastManualPanel.js +9 -15
  16. package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastManualPanel.js.map +1 -1
  17. package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastMethodSelector.d.ts +3 -2
  18. package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastMethodSelector.js.map +1 -1
  19. package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastPanel.d.ts +25 -0
  20. package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastPanel.js.map +1 -1
  21. package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastRIDPanel.js +22 -32
  22. package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastRIDPanel.js.map +1 -1
  23. package/dist/LaunchMsaView/components/NCBIBlastQuery/useCachedBlastResults.js +2 -9
  24. package/dist/LaunchMsaView/components/NCBIBlastQuery/useCachedBlastResults.js.map +1 -1
  25. package/dist/LaunchMsaView/components/PreLoadedMSA/PreLoadedMSADataPanel.js +30 -29
  26. package/dist/LaunchMsaView/components/PreLoadedMSA/PreLoadedMSADataPanel.js.map +1 -1
  27. package/dist/LaunchMsaView/components/PreLoadedMSA/fetchMSAData.js +8 -6
  28. package/dist/LaunchMsaView/components/PreLoadedMSA/fetchMSAData.js.map +1 -1
  29. package/dist/LaunchMsaView/components/SubmitCancelActions.d.ts +8 -0
  30. package/dist/LaunchMsaView/components/SubmitCancelActions.js +12 -0
  31. package/dist/LaunchMsaView/components/SubmitCancelActions.js.map +1 -0
  32. package/dist/LaunchMsaView/components/TranscriptSelector.d.ts +2 -2
  33. package/dist/LaunchMsaView/components/TranscriptSelector.js +2 -2
  34. package/dist/LaunchMsaView/components/TranscriptSelector.js.map +1 -1
  35. package/dist/LaunchMsaView/components/useSWRFeatureSequence.js +3 -13
  36. package/dist/LaunchMsaView/components/useSWRFeatureSequence.js.map +1 -1
  37. package/dist/LaunchMsaView/components/useTranscriptSelection.js +10 -12
  38. package/dist/LaunchMsaView/components/useTranscriptSelection.js.map +1 -1
  39. package/dist/LaunchMsaView/util.d.ts +4 -1
  40. package/dist/LaunchMsaView/util.js +29 -24
  41. package/dist/LaunchMsaView/util.js.map +1 -1
  42. package/dist/jbrowse-plugin-msaview.umd.production.min.js +24 -24
  43. package/dist/jbrowse-plugin-msaview.umd.production.min.js.map +4 -4
  44. package/dist/{LaunchMsaView/components/PreLoadedMSA/consts.d.ts → utils/swrConfig.d.ts} +1 -1
  45. package/dist/{LaunchMsaView/components/PreLoadedMSA/consts.js → utils/swrConfig.js} +2 -2
  46. package/dist/utils/swrConfig.js.map +1 -0
  47. package/dist/version.d.ts +1 -1
  48. package/dist/version.js +1 -1
  49. package/package.json +1 -1
  50. package/src/LaunchMsaView/components/LaunchMsaViewDialog.tsx +9 -6
  51. package/src/LaunchMsaView/components/LaunchPanelContent.tsx +27 -0
  52. package/src/LaunchMsaView/components/ManualMSALoader/ManualMSALoader.tsx +28 -60
  53. package/src/LaunchMsaView/components/NCBIBlastQuery/CachedBlastResults.tsx +21 -33
  54. package/src/LaunchMsaView/components/NCBIBlastQuery/MsaAlgorithmSelect.tsx +37 -0
  55. package/src/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastAutomaticPanel.tsx +29 -75
  56. package/src/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastManualPanel.tsx +10 -31
  57. package/src/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastMethodSelector.tsx +5 -3
  58. package/src/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastPanel.tsx +5 -2
  59. package/src/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastRIDPanel.tsx +28 -78
  60. package/src/LaunchMsaView/components/NCBIBlastQuery/useCachedBlastResults.ts +2 -10
  61. package/src/LaunchMsaView/components/PreLoadedMSA/PreLoadedMSADataPanel.tsx +34 -57
  62. package/src/LaunchMsaView/components/PreLoadedMSA/fetchMSAData.ts +17 -8
  63. package/src/LaunchMsaView/components/SubmitCancelActions.tsx +41 -0
  64. package/src/LaunchMsaView/components/TranscriptSelector.tsx +3 -3
  65. package/src/LaunchMsaView/components/useSWRFeatureSequence.ts +6 -15
  66. package/src/LaunchMsaView/components/useTranscriptSelection.ts +13 -15
  67. package/src/LaunchMsaView/util.ts +35 -25
  68. package/src/MsaViewPanel/util.ts +3 -3
  69. package/src/{LaunchMsaView/components/PreLoadedMSA/consts.ts → utils/swrConfig.ts} +1 -1
  70. package/src/version.ts +1 -1
  71. package/dist/LaunchMsaView/components/PreLoadedMSA/consts.js.map +0 -1
@@ -26,6 +26,8 @@ const panelMap = {
26
26
  manual: NCBIBlastManualPanel,
27
27
  } as const
28
28
 
29
+ export type BlastLookupMethod = keyof typeof panelMap
30
+
29
31
  export default function NCBIBlastPanel({
30
32
  handleClose,
31
33
  model,
@@ -35,7 +37,8 @@ export default function NCBIBlastPanel({
35
37
  model: AbstractTrackModel
36
38
  feature: Feature
37
39
  }) {
38
- const [lookupMethod, setLookupMethod] = useState('automatic')
40
+ const [lookupMethod, setLookupMethod] =
41
+ useState<BlastLookupMethod>('automatic')
39
42
  const [baseUrl, setBaseUrl] = useLocalStorage(
40
43
  'msa-blastRootUrl',
41
44
  BASE_BLAST_URL,
@@ -43,7 +46,7 @@ export default function NCBIBlastPanel({
43
46
  const [settingsOpen, setSettingsOpen] = useState(false)
44
47
  const { classes } = useStyles()
45
48
 
46
- const Panel = panelMap[lookupMethod as keyof typeof panelMap]
49
+ const Panel = panelMap[lookupMethod]
47
50
 
48
51
  return (
49
52
  <>
@@ -1,33 +1,23 @@
1
1
  import React, { useState } from 'react'
2
2
 
3
- import { ErrorMessage } from '@jbrowse/core/ui'
4
- import { getContainingView } from '@jbrowse/core/util'
5
- import {
6
- Button,
7
- DialogActions,
8
- DialogContent,
9
- MenuItem,
10
- Typography,
11
- } from '@mui/material'
3
+ import { Typography } from '@mui/material'
12
4
  import { observer } from 'mobx-react'
13
5
  import { makeStyles } from 'tss-react/mui'
14
6
 
7
+ import MsaAlgorithmSelect from './MsaAlgorithmSelect'
15
8
  import { blastLaunchView } from './blastLaunchView'
16
- import { msaAlgorithms } from './consts'
17
9
  import ExternalLink from '../../../components/ExternalLink'
18
10
  import TextField2 from '../../../components/TextField2'
19
- import { getGeneDisplayName, getTranscriptDisplayName } from '../../util'
11
+ import { getBlastViewTitle, getLinearGenomeView } from '../../util'
12
+ import LaunchPanelContent from '../LaunchPanelContent'
13
+ import SubmitCancelActions from '../SubmitCancelActions'
20
14
  import TranscriptSelector from '../TranscriptSelector'
21
15
  import { useTranscriptSelection } from '../useTranscriptSelection'
22
16
 
23
17
  import type { MsaAlgorithm } from './consts'
24
18
  import type { AbstractTrackModel, Feature } from '@jbrowse/core/util'
25
- import type { LinearGenomeViewModel } from '@jbrowse/plugin-linear-genome-view'
26
19
 
27
20
  const useStyles = makeStyles()({
28
- dialogContent: {
29
- width: '80em',
30
- },
31
21
  marginBottom: {
32
22
  marginBottom: 16,
33
23
  },
@@ -53,29 +43,22 @@ const NCBIBlastRIDPanel = observer(function ({
53
43
  children: React.ReactNode
54
44
  }) {
55
45
  const { classes } = useStyles()
56
- const view = getContainingView(model) as LinearGenomeViewModel
46
+ const view = getLinearGenomeView(model)
57
47
  const [launchViewError, setLaunchViewError] = useState<unknown>()
58
48
  const [rid, setRid] = useState('')
59
49
  const [selectedMsaAlgorithm, setSelectedMsaAlgorithm] =
60
50
  useState<MsaAlgorithm>('clustalo')
61
51
 
62
- const {
63
- options,
64
- selectedId,
65
- setSelectedId,
66
- selectedTranscript,
67
- proteinSequence,
68
- error: proteinSequenceError,
69
- } = useTranscriptSelection({ feature, view })
52
+ const transcriptSelection = useTranscriptSelection({ feature, view })
53
+ const { selectedTranscript, proteinSequence } = transcriptSelection
70
54
 
71
- const e = proteinSequenceError ?? launchViewError
55
+ const e = transcriptSelection.error ?? launchViewError
72
56
  const trimmedRid = rid.trim()
73
57
 
74
58
  return (
75
59
  <>
76
- <DialogContent className={classes.dialogContent}>
60
+ <LaunchPanelContent error={e}>
77
61
  {children}
78
- {e ? <ErrorMessage error={e} /> : null}
79
62
 
80
63
  <Typography variant="body2" className={classes.marginBottom}>
81
64
  Enter the RID (Request ID) from a previously submitted NCBI BLAST
@@ -104,52 +87,30 @@ const NCBIBlastRIDPanel = observer(function ({
104
87
  </Typography>
105
88
  ) : null}
106
89
 
107
- <TextField2
108
- variant="outlined"
109
- label="MSA Algorithm"
90
+ <MsaAlgorithmSelect
110
91
  className={classes.ridField}
111
- select
112
92
  value={selectedMsaAlgorithm}
113
- onChange={event => {
114
- setSelectedMsaAlgorithm(event.target.value as MsaAlgorithm)
115
- }}
116
- >
117
- {msaAlgorithms.map(val => (
118
- <MenuItem value={val} key={val}>
119
- {val}
120
- </MenuItem>
121
- ))}
122
- </TextField2>
123
-
124
- <TranscriptSelector
125
- feature={feature}
126
- options={options}
127
- selectedId={selectedId}
128
- selectedTranscript={selectedTranscript}
129
- onTranscriptChange={setSelectedId}
130
- proteinSequence={proteinSequence}
93
+ onChange={setSelectedMsaAlgorithm}
131
94
  />
132
95
 
96
+ <TranscriptSelector feature={feature} {...transcriptSelection} />
97
+
133
98
  <Typography className={classes.infoText}>
134
99
  This will fetch the BLAST results for the provided RID and run them
135
100
  through a multiple sequence alignment. The protein sequence from the
136
101
  selected transcript will be added as the query sequence in the MSA.
137
102
  </Typography>
138
- </DialogContent>
139
- <DialogActions>
140
- <Button
141
- color="primary"
142
- variant="contained"
143
- onClick={() => {
144
- try {
145
- if (!selectedTranscript || !trimmedRid) {
146
- return
147
- }
103
+ </LaunchPanelContent>
104
+ <SubmitCancelActions
105
+ submitDisabled={!proteinSequence || !trimmedRid}
106
+ onSubmit={() => {
107
+ try {
108
+ if (selectedTranscript && trimmedRid) {
148
109
  setLaunchViewError(undefined)
149
110
  blastLaunchView({
150
111
  feature: selectedTranscript,
151
112
  view,
152
- newViewTitle: `BLAST - ${getGeneDisplayName(feature)} - ${getTranscriptDisplayName(selectedTranscript)}`,
113
+ newViewTitle: getBlastViewTitle(feature, selectedTranscript),
153
114
  blastParams: {
154
115
  baseUrl,
155
116
  blastProgram: 'blastp',
@@ -161,25 +122,14 @@ const NCBIBlastRIDPanel = observer(function ({
161
122
  },
162
123
  })
163
124
  handleClose()
164
- } catch (e) {
165
- console.error(e)
166
- setLaunchViewError(e)
167
125
  }
168
- }}
169
- disabled={!proteinSequence || !trimmedRid}
170
- >
171
- Submit
172
- </Button>
173
- <Button
174
- color="secondary"
175
- variant="contained"
176
- onClick={() => {
177
- handleClose()
178
- }}
179
- >
180
- Cancel
181
- </Button>
182
- </DialogActions>
126
+ } catch (e) {
127
+ console.error(e)
128
+ setLaunchViewError(e)
129
+ }
130
+ }}
131
+ onCancel={handleClose}
132
+ />
183
133
  </>
184
134
  )
185
135
  })
@@ -5,15 +5,7 @@ import {
5
5
  deleteCachedResult,
6
6
  getAllCachedResults,
7
7
  } from '../../../utils/blastCache'
8
-
9
- const swrConfig = {
10
- revalidateOnFocus: false,
11
- revalidateOnReconnect: false,
12
- revalidateIfStale: false,
13
- refreshWhenHidden: false,
14
- refreshWhenOffline: false,
15
- shouldRetryOnError: false,
16
- }
8
+ import { staticSwrConfig } from '../../../utils/swrConfig'
17
9
 
18
10
  export function useCachedBlastResults(geneIds: string[]) {
19
11
  const {
@@ -26,7 +18,7 @@ export function useCachedBlastResults(geneIds: string[]) {
26
18
  const cached = await getAllCachedResults()
27
19
  return cached.filter(r => r.geneId && geneIds.includes(r.geneId))
28
20
  },
29
- swrConfig,
21
+ staticSwrConfig,
30
22
  )
31
23
 
32
24
  const handleDelete = async (id: string) => {
@@ -1,28 +1,26 @@
1
1
  import React, { useState } from 'react'
2
2
 
3
- import { ErrorMessage, LoadingEllipses, SanitizedHTML } from '@jbrowse/core/ui'
4
- import { getContainingView, getEnv, getSession } from '@jbrowse/core/util'
5
- import { Button, DialogActions, DialogContent, MenuItem } from '@mui/material'
3
+ import { LoadingEllipses, SanitizedHTML } from '@jbrowse/core/ui'
4
+ import { getEnv, getSession } from '@jbrowse/core/util'
5
+ import { MenuItem } from '@mui/material'
6
6
  import { observer } from 'mobx-react'
7
7
  import useSWR from 'swr'
8
8
  import { makeStyles } from 'tss-react/mui'
9
9
 
10
10
  import TextField2 from '../../../components/TextField2'
11
- import { getGeneDisplayName } from '../../util'
11
+ import { staticSwrConfig } from '../../../utils/swrConfig'
12
+ import { getGeneDisplayName, getLinearGenomeView } from '../../util'
13
+ import LaunchPanelContent from '../LaunchPanelContent'
14
+ import SubmitCancelActions from '../SubmitCancelActions'
12
15
  import TranscriptSelector from '../TranscriptSelector'
13
16
  import { useTranscriptSelection } from '../useTranscriptSelection'
14
- import { swrFlags } from './consts'
15
17
  import { fetchMSA, fetchMSAList } from './fetchMSAData'
16
18
  import { preCalculatedLaunchView } from './preCalculatedLaunchView'
17
19
  import { readMsaDatasets } from './types'
18
20
 
19
21
  import type { AbstractTrackModel, Feature } from '@jbrowse/core/util'
20
- import type { LinearGenomeViewModel } from '@jbrowse/plugin-linear-genome-view'
21
22
 
22
23
  const useStyles = makeStyles()({
23
- dialogContent: {
24
- width: '80em',
25
- },
26
24
  selectedContainer: {
27
25
  marginTop: 50,
28
26
  },
@@ -38,7 +36,7 @@ const PreLoadedMSA = observer(function ({
38
36
  handleClose: () => void
39
37
  }) {
40
38
  const session = getSession(model)
41
- const view = getContainingView(model) as LinearGenomeViewModel
39
+ const view = getLinearGenomeView(model)
42
40
  const { classes } = useStyles()
43
41
  const { pluginManager } = getEnv(model)
44
42
  const { assemblyNames } = view
@@ -56,17 +54,15 @@ const PreLoadedMSA = observer(function ({
56
54
  } = useSWR(
57
55
  selectedDataset ? `${selectedDataset.datasetId}-msa-list` : null,
58
56
  () => fetchMSAList({ config: selectedDataset!.adapter, pluginManager }),
59
- swrFlags,
57
+ staticSwrConfig,
60
58
  )
61
59
 
62
- const {
63
- options: transcripts,
64
- selectedId,
65
- setSelectedId,
66
- selectedTranscript,
67
- proteinSequence,
68
- error: proteinSequenceError,
69
- } = useTranscriptSelection({ feature, view, validIds: msaList })
60
+ const transcriptSelection = useTranscriptSelection({
61
+ feature,
62
+ view,
63
+ validIds: msaList,
64
+ })
65
+ const { selectedId, selectedTranscript } = transcriptSelection
70
66
 
71
67
  const {
72
68
  data: msaData,
@@ -82,16 +78,17 @@ const PreLoadedMSA = observer(function ({
82
78
  config: selectedDataset!.adapter,
83
79
  pluginManager,
84
80
  }),
85
- swrFlags,
81
+ staticSwrConfig,
86
82
  )
87
83
 
88
84
  const e =
89
- msaListFetchError ?? msaDataFetchError ?? proteinSequenceError ?? viewError
85
+ msaListFetchError ??
86
+ msaDataFetchError ??
87
+ transcriptSelection.error ??
88
+ viewError
90
89
  return (
91
90
  <>
92
- <DialogContent className={classes.dialogContent}>
93
- {e ? <ErrorMessage error={e} /> : null}
94
-
91
+ <LaunchPanelContent error={e}>
95
92
  <TextField2
96
93
  select
97
94
  label="Select MSA dataset"
@@ -127,29 +124,19 @@ const PreLoadedMSA = observer(function ({
127
124
  <SanitizedHTML html={selectedDataset.description} />
128
125
  <TranscriptSelector
129
126
  feature={feature}
130
- options={transcripts}
131
- selectedId={selectedId}
132
- selectedTranscript={selectedTranscript}
133
- onTranscriptChange={setSelectedId}
134
- proteinSequence={proteinSequence}
135
- validIds={msaList}
127
+ {...transcriptSelection}
136
128
  />
137
129
  </div>
138
130
  ) : null}
139
131
  </div>
140
132
  ) : null}
141
- </DialogContent>
133
+ </LaunchPanelContent>
142
134
 
143
- <DialogActions>
144
- <Button
145
- color="primary"
146
- variant="contained"
147
- disabled={!selectedTranscript || !msaData?.length}
148
- onClick={() => {
149
- try {
150
- if (!selectedTranscript || !msaData) {
151
- return
152
- }
135
+ <SubmitCancelActions
136
+ submitDisabled={!selectedTranscript || !msaData?.length}
137
+ onSubmit={() => {
138
+ try {
139
+ if (selectedTranscript && msaData) {
153
140
  const querySeqName = `${selectedId}_${assemblyNames[0]}`
154
141
  preCalculatedLaunchView({
155
142
  session,
@@ -164,23 +151,13 @@ const PreLoadedMSA = observer(function ({
164
151
  },
165
152
  })
166
153
  handleClose()
167
- } catch (e) {
168
- setViewError(e)
169
154
  }
170
- }}
171
- >
172
- Submit
173
- </Button>
174
- <Button
175
- color="secondary"
176
- variant="contained"
177
- onClick={() => {
178
- handleClose()
179
- }}
180
- >
181
- Cancel
182
- </Button>
183
- </DialogActions>
155
+ } catch (e) {
156
+ setViewError(e)
157
+ }
158
+ }}
159
+ onCancel={handleClose}
160
+ />
184
161
  </>
185
162
  )
186
163
  })
@@ -4,6 +4,19 @@ import type PluginManager from '@jbrowse/core/PluginManager'
4
4
  import type { AnyConfigurationModel } from '@jbrowse/core/configuration'
5
5
  import type { Feature } from '@jbrowse/core/util'
6
6
 
7
+ interface MsaDataAdapter {
8
+ getMSAList(): Promise<string[]>
9
+ getMSA(msaId: string): Promise<Feature[]>
10
+ }
11
+
12
+ async function getMsaAdapter(
13
+ pluginManager: PluginManager,
14
+ config: AnyConfigurationModel,
15
+ ) {
16
+ const result = await getAdapter(pluginManager, 'msa', config)
17
+ return result.dataAdapter as unknown as MsaDataAdapter
18
+ }
19
+
7
20
  export async function fetchMSAList({
8
21
  config,
9
22
  pluginManager,
@@ -11,10 +24,8 @@ export async function fetchMSAList({
11
24
  config: AnyConfigurationModel
12
25
  pluginManager: PluginManager
13
26
  }): Promise<string[]> {
14
- const result = await getAdapter(pluginManager, 'msa', config)
15
-
16
- // @ts-expect-error
17
- return result.dataAdapter.getMSAList()
27
+ const adapter = await getMsaAdapter(pluginManager, config)
28
+ return adapter.getMSAList()
18
29
  }
19
30
 
20
31
  export async function fetchMSA({
@@ -26,8 +37,6 @@ export async function fetchMSA({
26
37
  pluginManager: PluginManager
27
38
  msaId: string
28
39
  }): Promise<Feature[]> {
29
- const result = await getAdapter(pluginManager, 'msa', config)
30
-
31
- // @ts-expect-error
32
- return result.dataAdapter.getMSA(msaId)
40
+ const adapter = await getMsaAdapter(pluginManager, config)
41
+ return adapter.getMSA(msaId)
33
42
  }
@@ -0,0 +1,41 @@
1
+ import React from 'react'
2
+
3
+ import { Button, DialogActions } from '@mui/material'
4
+
5
+ export default function SubmitCancelActions({
6
+ onSubmit,
7
+ onCancel,
8
+ submitDisabled,
9
+ submitLabel = 'Submit',
10
+ cancelLabel = 'Cancel',
11
+ }: {
12
+ onSubmit: () => void
13
+ onCancel: () => void
14
+ submitDisabled?: boolean
15
+ submitLabel?: string
16
+ cancelLabel?: string
17
+ }) {
18
+ return (
19
+ <DialogActions>
20
+ <Button
21
+ color="primary"
22
+ variant="contained"
23
+ disabled={submitDisabled}
24
+ onClick={() => {
25
+ onSubmit()
26
+ }}
27
+ >
28
+ {submitLabel}
29
+ </Button>
30
+ <Button
31
+ color="secondary"
32
+ variant="contained"
33
+ onClick={() => {
34
+ onCancel()
35
+ }}
36
+ >
37
+ {cancelLabel}
38
+ </Button>
39
+ </DialogActions>
40
+ )
41
+ }
@@ -32,7 +32,7 @@ export default function TranscriptSelector({
32
32
  options,
33
33
  selectedId,
34
34
  selectedTranscript,
35
- onTranscriptChange,
35
+ setSelectedId,
36
36
  proteinSequence,
37
37
  validIds,
38
38
  }: {
@@ -40,7 +40,7 @@ export default function TranscriptSelector({
40
40
  options: Feature[]
41
41
  selectedId: string
42
42
  selectedTranscript: Feature | undefined
43
- onTranscriptChange: (transcriptId: string) => void
43
+ setSelectedId: (transcriptId: string) => void
44
44
  proteinSequence: string | undefined
45
45
  validIds?: string[]
46
46
  }) {
@@ -57,7 +57,7 @@ export default function TranscriptSelector({
57
57
  className={classes.minWidth}
58
58
  value={selectedId}
59
59
  onChange={event => {
60
- onTranscriptChange(event.target.value)
60
+ setSelectedId(event.target.value)
61
61
  }}
62
62
  >
63
63
  {options.map(val => {
@@ -2,6 +2,7 @@ import { getSession } from '@jbrowse/core/util'
2
2
  import useSWR from 'swr'
3
3
 
4
4
  import { fetchSeq } from './fetchSeq'
5
+ import { staticSwrConfig } from '../../utils/swrConfig'
5
6
 
6
7
  import type { Feature } from '@jbrowse/core/util'
7
8
 
@@ -38,22 +39,12 @@ export function useSWRFeatureSequence({
38
39
  feature?: Feature
39
40
  }) {
40
41
  const assemblyName = view?.assemblyNames?.[0]
42
+ const args =
43
+ feature && assemblyName ? { feature, assemblyName, view } : undefined
41
44
  const { data, error } = useSWR(
42
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
43
- feature && assemblyName && view
44
- ? [feature.id(), assemblyName, 'feature-sequence']
45
- : null,
46
- () =>
47
- featureSequenceFetcher({
48
- feature: feature!,
49
- assemblyName: assemblyName!,
50
- view: view!,
51
- }),
52
- {
53
- revalidateOnFocus: false,
54
- revalidateOnReconnect: false,
55
- revalidateIfStale: false,
56
- },
45
+ args ? [args.feature.id(), args.assemblyName, 'feature-sequence'] : null,
46
+ () => featureSequenceFetcher(args!),
47
+ staticSwrConfig,
57
48
  )
58
49
 
59
50
  return {
@@ -5,26 +5,24 @@ import { useFeatureSequence } from './useFeatureSequence'
5
5
 
6
6
  import type { Feature } from '@jbrowse/core/util'
7
7
 
8
- function featureInValidIds(feature: Feature, validIds: string[]): boolean {
9
- return validIds.some(id => featureMatchesId(feature, id))
10
- }
11
-
12
8
  function findValidSelection(
13
9
  currentId: string,
14
10
  options: Feature[],
15
11
  validIds: string[] | undefined,
16
12
  ): string | undefined {
17
- if (!validIds || validIds.length === 0) {
18
- return undefined
13
+ if (validIds && validIds.length > 0) {
14
+ const currentFeature = options.find(opt => getId(opt) === currentId)
15
+ const currentIsValid =
16
+ currentFeature &&
17
+ validIds.some(id => featureMatchesId(currentFeature, id))
18
+ if (currentFeature && !currentIsValid) {
19
+ const validOption = options.find(opt =>
20
+ validIds.some(id => featureMatchesId(opt, id)),
21
+ )
22
+ return validOption ? getId(validOption) : undefined
23
+ }
19
24
  }
20
-
21
- const currentFeature = options.find(opt => getId(opt) === currentId)
22
- if (!currentFeature || featureInValidIds(currentFeature, validIds)) {
23
- return undefined
24
- }
25
-
26
- const validOption = options.find(opt => featureInValidIds(opt, validIds))
27
- return validOption ? getId(validOption) : undefined
25
+ return undefined
28
26
  }
29
27
 
30
28
  export function useTranscriptSelection({
@@ -39,7 +37,7 @@ export function useTranscriptSelection({
39
37
  const options = useMemo(() => getSortedTranscriptFeatures(feature), [feature])
40
38
  const [selectedId, setSelectedId] = useState(() => getId(options[0]))
41
39
  const validatedSelectedId =
42
- findValidSelection(selectedId, options, validIds) || selectedId
40
+ findValidSelection(selectedId, options, validIds) ?? selectedId
43
41
  const selectedTranscript = options.find(
44
42
  val => getId(val) === validatedSelectedId,
45
43
  )
@@ -1,6 +1,19 @@
1
- import { sum } from '@jbrowse/core/util'
1
+ import { getContainingView, sum } from '@jbrowse/core/util'
2
2
 
3
- import type { Feature } from '@jbrowse/core/util'
3
+ import type { AbstractTrackModel, Feature } from '@jbrowse/core/util'
4
+ import type { LinearGenomeViewModel } from '@jbrowse/plugin-linear-genome-view'
5
+
6
+ export function getLinearGenomeView(model: AbstractTrackModel) {
7
+ return getContainingView(model) as LinearGenomeViewModel
8
+ }
9
+
10
+ function uniqueDefined(vals: (string | undefined)[]): string[] {
11
+ return [...new Set(vals.filter((v): v is string => !!v))]
12
+ }
13
+
14
+ function joinDefined(sep: string, parts: (string | undefined)[]): string {
15
+ return parts.filter((p): p is string => !!p).join(sep)
16
+ }
4
17
 
5
18
  export function getTranscriptFeatures(feature: Feature) {
6
19
  // check if we are looking at a 'two-level' or 'three-level' feature by
@@ -42,16 +55,14 @@ export function getId(val?: Feature): string {
42
55
  }
43
56
 
44
57
  export function getMatchableIds(val?: Feature): string[] {
45
- if (!val) {
46
- return []
47
- }
48
- const ids = [
49
- val.id(),
50
- val.get('name'),
51
- val.get('id'),
52
- val.get('transcript_id'),
53
- ].filter((id): id is string => !!id)
54
- return [...new Set(ids)]
58
+ return val
59
+ ? uniqueDefined([
60
+ val.id(),
61
+ val.get('name'),
62
+ val.get('id'),
63
+ val.get('transcript_id'),
64
+ ])
65
+ : []
55
66
  }
56
67
 
57
68
  export function featureMatchesId(feature: Feature, id: string): boolean {
@@ -59,20 +70,20 @@ export function featureMatchesId(feature: Feature, id: string): boolean {
59
70
  }
60
71
 
61
72
  export function getTranscriptDisplayName(val?: Feature) {
62
- return val === undefined
63
- ? ''
64
- : [val.get('name'), val.get('id')].filter(f => !!f).join(' ')
73
+ return val ? joinDefined(' ', [val.get('name'), val.get('id')]) : ''
65
74
  }
66
75
 
67
76
  export function getGeneDisplayName(val?: Feature) {
68
- return val === undefined
69
- ? ''
70
- : [
77
+ return val
78
+ ? joinDefined(' ', [
71
79
  val.get('gene_name') ?? val.get('name'),
72
- val.get('id') ? `(${val.get('id')})` : '',
73
- ]
74
- .filter(f => !!f)
75
- .join(' ')
80
+ val.get('id') ? `(${val.get('id')})` : undefined,
81
+ ])
82
+ : ''
83
+ }
84
+
85
+ export function getBlastViewTitle(feature: Feature, transcript: Feature) {
86
+ return `BLAST - ${getGeneDisplayName(feature)} - ${getTranscriptDisplayName(transcript)}`
76
87
  }
77
88
 
78
89
  export function getSortedTranscriptFeatures(feature: Feature) {
@@ -87,12 +98,11 @@ export function cleanProteinSequence(seq: string) {
87
98
  }
88
99
 
89
100
  export function getGeneIdentifiers(feature: Feature): string[] {
90
- const ids = [
101
+ return uniqueDefined([
91
102
  feature.id(),
92
103
  feature.get('id'),
93
104
  feature.get('name'),
94
105
  feature.get('gene_id'),
95
106
  feature.get('gene_name'),
96
- ].filter((id): id is string => !!id)
97
- return [...new Set(ids)]
107
+ ])
98
108
  }