jbrowse-plugin-msaview 2.3.5 → 2.4.0

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 (148) hide show
  1. package/README.md +15 -216
  2. package/dist/AddHighlightModel/GenomeMouseoverHighlight.js +4 -15
  3. package/dist/AddHighlightModel/GenomeMouseoverHighlight.js.map +1 -1
  4. package/dist/AddHighlightModel/MsaToGenomeHighlight.js +5 -8
  5. package/dist/AddHighlightModel/MsaToGenomeHighlight.js.map +1 -1
  6. package/dist/AddHighlightModel/util.d.ts +3 -0
  7. package/dist/AddHighlightModel/util.js +3 -0
  8. package/dist/AddHighlightModel/util.js.map +1 -1
  9. package/dist/LaunchMsaView/components/LaunchMsaViewDialog.js +3 -8
  10. package/dist/LaunchMsaView/components/LaunchMsaViewDialog.js.map +1 -1
  11. package/dist/LaunchMsaView/components/ManualMSALoader/ManualMSALoader.js +26 -14
  12. package/dist/LaunchMsaView/components/ManualMSALoader/ManualMSALoader.js.map +1 -1
  13. package/dist/LaunchMsaView/components/NCBIBlastQuery/CachedBlastResults.js +16 -7
  14. package/dist/LaunchMsaView/components/NCBIBlastQuery/CachedBlastResults.js.map +1 -1
  15. package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastAutomaticPanel.js +6 -7
  16. package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastAutomaticPanel.js.map +1 -1
  17. package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastManualPanel.js +4 -4
  18. package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastManualPanel.js.map +1 -1
  19. package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastPanel.js +8 -1
  20. package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastPanel.js.map +1 -1
  21. package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastRIDPanel.js +15 -7
  22. package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastRIDPanel.js.map +1 -1
  23. package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBISettingsDialog.js +8 -1
  24. package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBISettingsDialog.js.map +1 -1
  25. package/dist/LaunchMsaView/components/NCBIBlastQuery/blastLaunchView.d.ts +4 -4
  26. package/dist/LaunchMsaView/components/NCBIBlastQuery/blastLaunchView.js +2 -2
  27. package/dist/LaunchMsaView/components/NCBIBlastQuery/blastLaunchView.js.map +1 -1
  28. package/dist/LaunchMsaView/components/NCBIBlastQuery/consts.d.ts +4 -0
  29. package/dist/LaunchMsaView/components/NCBIBlastQuery/consts.js +2 -0
  30. package/dist/LaunchMsaView/components/NCBIBlastQuery/consts.js.map +1 -1
  31. package/dist/LaunchMsaView/components/NCBIBlastQuery/useCachedBlastResults.js +3 -0
  32. package/dist/LaunchMsaView/components/NCBIBlastQuery/useCachedBlastResults.js.map +1 -1
  33. package/dist/LaunchMsaView/components/PreLoadedMSA/PreLoadedMSADataPanel.js +17 -23
  34. package/dist/LaunchMsaView/components/PreLoadedMSA/PreLoadedMSADataPanel.js.map +1 -1
  35. package/dist/LaunchMsaView/components/PreLoadedMSA/types.d.ts +1 -0
  36. package/dist/LaunchMsaView/components/PreLoadedMSA/types.js +4 -1
  37. package/dist/LaunchMsaView/components/PreLoadedMSA/types.js.map +1 -1
  38. package/dist/LaunchMsaView/components/TabPanel.js +1 -1
  39. package/dist/LaunchMsaView/components/TabPanel.js.map +1 -1
  40. package/dist/LaunchMsaView/components/TranscriptSelector.js +7 -3
  41. package/dist/LaunchMsaView/components/TranscriptSelector.js.map +1 -1
  42. package/dist/LaunchMsaView/components/types.d.ts +0 -3
  43. package/dist/LaunchMsaView/components/useFeatureSequence.d.ts +4 -4
  44. package/dist/LaunchMsaView/components/useFeatureSequence.js +2 -4
  45. package/dist/LaunchMsaView/components/useFeatureSequence.js.map +1 -1
  46. package/dist/LaunchMsaView/components/useSWRFeatureSequence.d.ts +4 -5
  47. package/dist/LaunchMsaView/components/useSWRFeatureSequence.js +11 -30
  48. package/dist/LaunchMsaView/components/useSWRFeatureSequence.js.map +1 -1
  49. package/dist/MsaViewPanel/afterCreateAutoruns.js +10 -25
  50. package/dist/MsaViewPanel/afterCreateAutoruns.js.map +1 -1
  51. package/dist/MsaViewPanel/components/ConnectStructureDialog.js +15 -10
  52. package/dist/MsaViewPanel/components/ConnectStructureDialog.js.map +1 -1
  53. package/dist/MsaViewPanel/components/LoadingBLAST.js +2 -3
  54. package/dist/MsaViewPanel/components/LoadingBLAST.js.map +1 -1
  55. package/dist/MsaViewPanel/components/MsaViewPanel.js +8 -1
  56. package/dist/MsaViewPanel/components/MsaViewPanel.js.map +1 -1
  57. package/dist/MsaViewPanel/model.d.ts +6 -13
  58. package/dist/MsaViewPanel/model.js +15 -26
  59. package/dist/MsaViewPanel/model.js.map +1 -1
  60. package/dist/MsaViewPanel/msaDataStore.d.ts +0 -1
  61. package/dist/MsaViewPanel/msaDataStore.js +0 -9
  62. package/dist/MsaViewPanel/msaDataStore.js.map +1 -1
  63. package/dist/MsaViewPanel/pairwiseAlignment.js +6 -6
  64. package/dist/MsaViewPanel/pairwiseAlignment.js.map +1 -1
  65. package/dist/MsaViewPanel/structureConnection.d.ts +28 -4
  66. package/dist/MsaViewPanel/structureConnection.js +10 -6
  67. package/dist/MsaViewPanel/structureConnection.js.map +1 -1
  68. package/dist/MsaViewPanel/structureConnection.test.js +1 -19
  69. package/dist/MsaViewPanel/structureConnection.test.js.map +1 -1
  70. package/dist/jbrowse-plugin-msaview.umd.production.min.js +25 -27
  71. package/dist/jbrowse-plugin-msaview.umd.production.min.js.map +4 -4
  72. package/dist/utils/blastCache.d.ts +7 -13
  73. package/dist/utils/blastCache.js +0 -12
  74. package/dist/utils/blastCache.js.map +1 -1
  75. package/dist/utils/msa.d.ts +2 -1
  76. package/dist/utils/msa.js +0 -3
  77. package/dist/utils/msa.js.map +1 -1
  78. package/dist/utils/ncbiBlast.d.ts +3 -2
  79. package/dist/utils/ncbiBlast.js +1 -1
  80. package/dist/utils/ncbiBlast.js.map +1 -1
  81. package/dist/utils/taxonomyNames.js +9 -4
  82. package/dist/utils/taxonomyNames.js.map +1 -1
  83. package/dist/version.d.ts +1 -1
  84. package/dist/version.js +1 -1
  85. package/package.json +19 -19
  86. package/src/AddHighlightModel/GenomeMouseoverHighlight.tsx +7 -22
  87. package/src/AddHighlightModel/MsaToGenomeHighlight.tsx +10 -10
  88. package/src/AddHighlightModel/util.ts +6 -0
  89. package/src/LaunchMsaView/components/LaunchMsaViewDialog.tsx +3 -16
  90. package/src/LaunchMsaView/components/ManualMSALoader/ManualMSALoader.tsx +30 -19
  91. package/src/LaunchMsaView/components/NCBIBlastQuery/CachedBlastResults.tsx +17 -9
  92. package/src/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastAutomaticPanel.tsx +14 -18
  93. package/src/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastManualPanel.tsx +4 -10
  94. package/src/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastPanel.tsx +9 -1
  95. package/src/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastRIDPanel.tsx +15 -8
  96. package/src/LaunchMsaView/components/NCBIBlastQuery/NCBISettingsDialog.tsx +9 -1
  97. package/src/LaunchMsaView/components/NCBIBlastQuery/blastLaunchView.ts +6 -6
  98. package/src/LaunchMsaView/components/NCBIBlastQuery/consts.ts +7 -0
  99. package/src/LaunchMsaView/components/NCBIBlastQuery/useCachedBlastResults.ts +3 -0
  100. package/src/LaunchMsaView/components/PreLoadedMSA/PreLoadedMSADataPanel.tsx +23 -29
  101. package/src/LaunchMsaView/components/PreLoadedMSA/types.ts +6 -0
  102. package/src/LaunchMsaView/components/TabPanel.tsx +1 -1
  103. package/src/LaunchMsaView/components/TranscriptSelector.tsx +7 -3
  104. package/src/LaunchMsaView/components/types.ts +0 -3
  105. package/src/LaunchMsaView/components/useFeatureSequence.ts +1 -7
  106. package/src/LaunchMsaView/components/useSWRFeatureSequence.ts +10 -37
  107. package/src/MsaViewPanel/afterCreateAutoruns.ts +13 -39
  108. package/src/MsaViewPanel/components/ConnectStructureDialog.tsx +23 -25
  109. package/src/MsaViewPanel/components/LoadingBLAST.tsx +4 -3
  110. package/src/MsaViewPanel/components/MsaViewPanel.tsx +9 -1
  111. package/src/MsaViewPanel/model.ts +31 -39
  112. package/src/MsaViewPanel/msaDataStore.ts +0 -9
  113. package/src/MsaViewPanel/pairwiseAlignment.ts +6 -6
  114. package/src/MsaViewPanel/structureConnection.test.ts +0 -21
  115. package/src/MsaViewPanel/structureConnection.ts +30 -7
  116. package/src/utils/blastCache.ts +14 -37
  117. package/src/utils/msa.ts +5 -6
  118. package/src/utils/ncbiBlast.ts +9 -5
  119. package/src/utils/taxonomyNames.ts +13 -4
  120. package/src/version.ts +1 -1
  121. package/dist/LaunchMsaView/components/EnsemblGeneTree/EnsemblGeneTree.d.ts +0 -8
  122. package/dist/LaunchMsaView/components/EnsemblGeneTree/EnsemblGeneTree.js +0 -70
  123. package/dist/LaunchMsaView/components/EnsemblGeneTree/EnsemblGeneTree.js.map +0 -1
  124. package/dist/LaunchMsaView/components/EnsemblGeneTree/ensemblGeneTreeLaunchView.d.ts +0 -13
  125. package/dist/LaunchMsaView/components/EnsemblGeneTree/ensemblGeneTreeLaunchView.js +0 -12
  126. package/dist/LaunchMsaView/components/EnsemblGeneTree/ensemblGeneTreeLaunchView.js.map +0 -1
  127. package/dist/LaunchMsaView/components/EnsemblGeneTree/ensemblGeneTreeUtils.d.ts +0 -6
  128. package/dist/LaunchMsaView/components/EnsemblGeneTree/ensemblGeneTreeUtils.js +0 -25
  129. package/dist/LaunchMsaView/components/EnsemblGeneTree/ensemblGeneTreeUtils.js.map +0 -1
  130. package/dist/LaunchMsaView/components/EnsemblGeneTree/gatherSequencesFromTree.d.ts +0 -2
  131. package/dist/LaunchMsaView/components/EnsemblGeneTree/gatherSequencesFromTree.js +0 -20
  132. package/dist/LaunchMsaView/components/EnsemblGeneTree/gatherSequencesFromTree.js.map +0 -1
  133. package/dist/LaunchMsaView/components/EnsemblGeneTree/types.d.ts +0 -24
  134. package/dist/LaunchMsaView/components/EnsemblGeneTree/types.js +0 -2
  135. package/dist/LaunchMsaView/components/EnsemblGeneTree/types.js.map +0 -1
  136. package/dist/LaunchMsaView/components/EnsemblGeneTree/useGeneTree.d.ts +0 -10
  137. package/dist/LaunchMsaView/components/EnsemblGeneTree/useGeneTree.js +0 -11
  138. package/dist/LaunchMsaView/components/EnsemblGeneTree/useGeneTree.js.map +0 -1
  139. package/dist/LaunchMsaView/components/EnsemblGeneTree/util.d.ts +0 -1
  140. package/dist/LaunchMsaView/components/EnsemblGeneTree/util.js +0 -2
  141. package/dist/LaunchMsaView/components/EnsemblGeneTree/util.js.map +0 -1
  142. package/src/LaunchMsaView/components/EnsemblGeneTree/EnsemblGeneTree.tsx +0 -123
  143. package/src/LaunchMsaView/components/EnsemblGeneTree/ensemblGeneTreeLaunchView.ts +0 -30
  144. package/src/LaunchMsaView/components/EnsemblGeneTree/ensemblGeneTreeUtils.ts +0 -47
  145. package/src/LaunchMsaView/components/EnsemblGeneTree/gatherSequencesFromTree.ts +0 -22
  146. package/src/LaunchMsaView/components/EnsemblGeneTree/types.ts +0 -28
  147. package/src/LaunchMsaView/components/EnsemblGeneTree/useGeneTree.ts +0 -17
  148. package/src/LaunchMsaView/components/EnsemblGeneTree/util.ts +0 -6
@@ -8,27 +8,14 @@ import {
8
8
  retrieveMsaData,
9
9
  storeMsaData,
10
10
  } from './msaDataStore'
11
- import { gappedToUngappedPosition } from './structureConnection'
11
+ import {
12
+ gappedToUngappedPosition,
13
+ getProteinViews,
14
+ } from './structureConnection'
12
15
  import { getUniprotIdFromAlphaFoldUrl } from './util'
13
16
 
14
17
  import type { JBrowsePluginMsaViewModel } from './model'
15
18
 
16
- interface ProteinView {
17
- type: 'ProteinView'
18
- id: string
19
- structures: {
20
- connectedViewId?: string
21
- uniprotId?: string
22
- structureSequences?: unknown[]
23
- hoverGenomeHighlights?: { start: number; end: number }[]
24
- }[]
25
- }
26
-
27
- function isProteinView(view: unknown): view is ProteinView {
28
- const v = view as Record<string, unknown>
29
- return v.type === 'ProteinView' && Array.isArray(v.structures)
30
- }
31
-
32
19
  export function loadStoredData(self: JBrowsePluginMsaViewModel) {
33
20
  const { dataStoreId, rows } = self
34
21
  if (dataStoreId && rows.length === 0) {
@@ -57,8 +44,7 @@ export function loadStoredData(self: JBrowsePluginMsaViewModel) {
57
44
  export function storeDataToIndexedDB(self: JBrowsePluginMsaViewModel) {
58
45
  const { rows, dataStoreId } = self
59
46
  if (rows.length > 0 && !dataStoreId) {
60
- const hasFilehandle = !!(self.msaFilehandle ?? self.treeFilehandle)
61
- if (hasFilehandle) {
47
+ if (self.msaFilehandle || self.treeFilehandle) {
62
48
  return
63
49
  }
64
50
 
@@ -179,7 +165,7 @@ export function highlightConnectedStructures(self: JBrowsePluginMsaViewModel) {
179
165
  }
180
166
 
181
167
  for (const conn of connectedProteinViews) {
182
- const structure = conn.proteinView?.structures?.[conn.structureIdx]
168
+ const structure = conn.proteinView.structures[conn.structureIdx]
183
169
  if (!structure) {
184
170
  continue
185
171
  }
@@ -210,25 +196,19 @@ export function highlightConnectedStructures(self: JBrowsePluginMsaViewModel) {
210
196
  }
211
197
 
212
198
  export function autoConnectStructures(self: JBrowsePluginMsaViewModel) {
213
- const { views } = getSession(self)
214
199
  const { connectedViewId, uniprotId, rows, connectedStructures } = self
215
200
 
216
201
  if (!uniprotId || rows.length === 0) {
217
202
  return
218
203
  }
219
204
 
220
- for (const view of views) {
221
- if (!isProteinView(view)) {
222
- continue
223
- }
224
- const v = view
225
-
205
+ for (const view of getProteinViews(getSession(self).views)) {
226
206
  for (
227
207
  let structureIdx = 0;
228
- structureIdx < v.structures.length;
208
+ structureIdx < view.structures.length;
229
209
  structureIdx++
230
210
  ) {
231
- const structure = v.structures[structureIdx]
211
+ const structure = view.structures[structureIdx]
232
212
  if (!structure) {
233
213
  continue
234
214
  }
@@ -242,7 +222,7 @@ export function autoConnectStructures(self: JBrowsePluginMsaViewModel) {
242
222
  }
243
223
 
244
224
  const alreadyConnected = connectedStructures.some(
245
- c => c.proteinViewId === v.id && c.structureIdx === structureIdx,
225
+ c => c.proteinViewId === view.id && c.structureIdx === structureIdx,
246
226
  )
247
227
  if (alreadyConnected) {
248
228
  continue
@@ -253,7 +233,7 @@ export function autoConnectStructures(self: JBrowsePluginMsaViewModel) {
253
233
  }
254
234
 
255
235
  try {
256
- self.connectToStructure(v.id, structureIdx)
236
+ self.connectToStructure(view.id, structureIdx)
257
237
  } catch (e) {
258
238
  console.error('Failed to auto-connect to ProteinView:', e)
259
239
  }
@@ -262,7 +242,6 @@ export function autoConnectStructures(self: JBrowsePluginMsaViewModel) {
262
242
  }
263
243
 
264
244
  export function observeProteinHighlights(self: JBrowsePluginMsaViewModel) {
265
- const { views } = getSession(self)
266
245
  const { connectedViewId, transcriptToMsaMap, querySeqName } = self
267
246
 
268
247
  if (!connectedViewId || !transcriptToMsaMap) {
@@ -271,13 +250,8 @@ export function observeProteinHighlights(self: JBrowsePluginMsaViewModel) {
271
250
 
272
251
  const columns = new Set<number>()
273
252
 
274
- for (const view of views) {
275
- if (!isProteinView(view)) {
276
- continue
277
- }
278
- const v = view
279
-
280
- for (const structure of v.structures) {
253
+ for (const view of getProteinViews(getSession(self).views)) {
254
+ for (const structure of view.structures) {
281
255
  if (structure.connectedViewId !== connectedViewId) {
282
256
  continue
283
257
  }
@@ -1,6 +1,6 @@
1
1
  import React, { useState } from 'react'
2
2
 
3
- import { Dialog } from '@jbrowse/core/ui'
3
+ import { Dialog, ErrorMessage } from '@jbrowse/core/ui'
4
4
  import { getSession } from '@jbrowse/core/util'
5
5
  import {
6
6
  Button,
@@ -13,9 +13,18 @@ import {
13
13
  Typography,
14
14
  } from '@mui/material'
15
15
  import { observer } from 'mobx-react'
16
+ import { makeStyles } from 'tss-react/mui'
17
+
18
+ import { getProteinViews } from '../structureConnection'
16
19
 
17
20
  import type { JBrowsePluginMsaViewModel } from '../model'
18
21
 
22
+ const useStyles = makeStyles()(theme => ({
23
+ formControl: {
24
+ marginBottom: theme.spacing(2),
25
+ },
26
+ }))
27
+
19
28
  const ConnectStructureDialog = observer(function ConnectStructureDialog({
20
29
  model,
21
30
  handleClose,
@@ -23,23 +32,18 @@ const ConnectStructureDialog = observer(function ConnectStructureDialog({
23
32
  model: JBrowsePluginMsaViewModel
24
33
  handleClose: () => void
25
34
  }) {
35
+ const { classes } = useStyles()
26
36
  const session = getSession(model)
27
37
  const [selectedViewId, setSelectedViewId] = useState('')
28
38
  const [selectedStructureIdx, setSelectedStructureIdx] = useState(0)
29
39
  const [selectedMsaRow, setSelectedMsaRow] = useState(model.querySeqName)
30
40
  const [error, setError] = useState<string>()
31
41
 
32
- // Find all ProteinViews in the session
33
-
34
- const proteinViews = session.views.filter(
35
- (v: any) => v.type === 'ProteinView',
36
- ) as any[]
42
+ const proteinViews = getProteinViews(session.views)
37
43
 
38
- // Get structures for the selected view
39
44
  const selectedView = proteinViews.find(v => v.id === selectedViewId)
40
45
  const structures = selectedView?.structures ?? []
41
46
 
42
- // Get MSA row names
43
47
  const msaRowNames = model.rows.map(r => r[0])
44
48
 
45
49
  const handleConnect = () => {
@@ -75,7 +79,7 @@ const ConnectStructureDialog = observer(function ConnectStructureDialog({
75
79
  </Typography>
76
80
  ) : (
77
81
  <>
78
- <FormControl fullWidth sx={{ mb: 2 }}>
82
+ <FormControl fullWidth className={classes.formControl}>
79
83
  <InputLabel>Protein View</InputLabel>
80
84
  <Select
81
85
  value={selectedViewId}
@@ -93,8 +97,8 @@ const ConnectStructureDialog = observer(function ConnectStructureDialog({
93
97
  </Select>
94
98
  </FormControl>
95
99
 
96
- {structures.length > 1 && (
97
- <FormControl fullWidth sx={{ mb: 2 }}>
100
+ {structures.length > 1 ? (
101
+ <FormControl fullWidth className={classes.formControl}>
98
102
  <InputLabel>Structure</InputLabel>
99
103
  <Select
100
104
  value={selectedStructureIdx}
@@ -103,18 +107,16 @@ const ConnectStructureDialog = observer(function ConnectStructureDialog({
103
107
  setSelectedStructureIdx(e.target.value)
104
108
  }}
105
109
  >
106
- {structures.map(
107
- (structure: { url?: string }, idx: number) => (
108
- <MenuItem key={idx} value={idx}>
109
- {structure.url ?? `Structure ${idx + 1}`}
110
- </MenuItem>
111
- ),
112
- )}
110
+ {structures.map((structure, idx) => (
111
+ <MenuItem key={idx} value={idx}>
112
+ {structure.url ?? `Structure ${idx + 1}`}
113
+ </MenuItem>
114
+ ))}
113
115
  </Select>
114
116
  </FormControl>
115
- )}
117
+ ) : null}
116
118
 
117
- <FormControl fullWidth sx={{ mb: 2 }}>
119
+ <FormControl fullWidth className={classes.formControl}>
118
120
  <InputLabel>MSA Row</InputLabel>
119
121
  <Select
120
122
  value={selectedMsaRow}
@@ -131,11 +133,7 @@ const ConnectStructureDialog = observer(function ConnectStructureDialog({
131
133
  </Select>
132
134
  </FormControl>
133
135
 
134
- {error && (
135
- <Typography color="error" sx={{ mt: 1 }}>
136
- {error}
137
- </Typography>
138
- )}
136
+ {error ? <ErrorMessage error={error} /> : null}
139
137
  </>
140
138
  )}
141
139
  </DialogContent>
@@ -60,7 +60,7 @@ const LoadingBLAST = observer(function LoadingBLAST2({
60
60
  model: JBrowsePluginMsaViewModel
61
61
  baseUrl: string
62
62
  }) {
63
- const { progress, rid, error, processing } = model
63
+ const { progress, rid, error } = model
64
64
  const { classes } = useStyles()
65
65
  return (
66
66
  <div className={classes.margin}>
@@ -69,8 +69,9 @@ const LoadingBLAST = observer(function LoadingBLAST2({
69
69
  <RIDError baseUrl={baseUrl} rid={rid} error={error} />
70
70
  ) : rid ? (
71
71
  <RIDProgress baseUrl={baseUrl} rid={rid} progress={progress} />
72
- ) : null}
73
- <Typography>{processing || 'Initializing BLAST query'}</Typography>
72
+ ) : (
73
+ <Typography>{progress || 'Initializing BLAST query'}</Typography>
74
+ )}
74
75
  </div>
75
76
  )
76
77
  })
@@ -3,17 +3,25 @@ import React from 'react'
3
3
  import { LoadingEllipses } from '@jbrowse/core/ui'
4
4
  import { observer } from 'mobx-react'
5
5
  import { MSAView } from 'react-msaview'
6
+ import { makeStyles } from 'tss-react/mui'
6
7
 
7
8
  import { ErrorBoundary } from './ErrorBoundary'
8
9
  import LoadingBLAST from './LoadingBLAST'
9
10
 
10
11
  import type { JBrowsePluginMsaViewModel } from '../model'
11
12
 
13
+ const useStyles = makeStyles()({
14
+ loadingContainer: {
15
+ padding: 20,
16
+ },
17
+ })
18
+
12
19
  const MsaViewPanel = observer(function MsaViewPanel2({
13
20
  model,
14
21
  }: {
15
22
  model: JBrowsePluginMsaViewModel
16
23
  }) {
24
+ const { classes } = useStyles()
17
25
  const { blastParams, loadingStoredData } = model
18
26
  return (
19
27
  <ErrorBoundary>
@@ -21,7 +29,7 @@ const MsaViewPanel = observer(function MsaViewPanel2({
21
29
  {blastParams ? (
22
30
  <LoadingBLAST model={model} baseUrl={blastParams.baseUrl} />
23
31
  ) : loadingStoredData ? (
24
- <div style={{ padding: 20 }}>
32
+ <div className={classes.loadingContainer}>
25
33
  <LoadingEllipses message="Loading MSA data" variant="h6" />
26
34
  </div>
27
35
  ) : (
@@ -21,10 +21,18 @@ import {
21
21
  import { genomeToMSA } from './genomeToMSA'
22
22
  import { msaCoordToGenomeCoord } from './msaCoordToGenomeCoord'
23
23
  import { buildAlignmentMaps, runPairwiseAlignment } from './pairwiseAlignment'
24
- import { mapToRecord, ungappedToGappedPosition } from './structureConnection'
24
+ import {
25
+ getProteinViews,
26
+ ungappedToGappedPosition,
27
+ } from './structureConnection'
25
28
 
26
- import type { StructureConnection } from './structureConnection'
29
+ import type { ProteinView, StructureConnection } from './structureConnection'
27
30
  import type { MafRegion, MsaViewInitState } from './types'
31
+ import type {
32
+ BlastDatabase,
33
+ BlastProgram,
34
+ MsaAlgorithm,
35
+ } from '../LaunchMsaView/components/NCBIBlastQuery/consts'
28
36
  import type { Feature } from '@jbrowse/core/util'
29
37
  import type { Instance } from '@jbrowse/mobx-state-tree'
30
38
  import type { LinearGenomeViewModel } from '@jbrowse/plugin-linear-genome-view'
@@ -45,9 +53,9 @@ export interface IRegion {
45
53
 
46
54
  export interface BlastParams {
47
55
  baseUrl: string
48
- blastDatabase: string
49
- msaAlgorithm: string
50
- blastProgram: string
56
+ blastDatabase: BlastDatabase
57
+ msaAlgorithm: MsaAlgorithm
58
+ blastProgram: BlastProgram
51
59
  selectedTranscript?: Feature
52
60
  proteinSequence: string
53
61
  rid?: string
@@ -175,13 +183,6 @@ export default function stateModelFactory() {
175
183
  : undefined
176
184
  },
177
185
 
178
- /**
179
- * #getter
180
- */
181
- get processing() {
182
- return !!self.progress
183
- },
184
-
185
186
  /**
186
187
  * #getter
187
188
  */
@@ -194,19 +195,18 @@ export default function stateModelFactory() {
194
195
  * #getter
195
196
  */
196
197
  get connectedProteinViews() {
197
- const { views } = getSession(self)
198
- return self.connectedStructures
199
- .map(conn => {
200
- const proteinView = views.find(
201
- (v: unknown) =>
202
- (v as Record<string, unknown>).id === conn.proteinViewId,
203
- )
204
- return proteinView ? { ...conn, proteinView } : undefined
205
- })
206
- .filter(
207
- (c): c is StructureConnection & { proteinView: any } =>
208
- c !== undefined,
198
+ const proteinViews = getProteinViews(getSession(self).views)
199
+ const result: (StructureConnection & { proteinView: ProteinView })[] =
200
+ []
201
+ for (const conn of self.connectedStructures) {
202
+ const proteinView = proteinViews.find(
203
+ v => v.id === conn.proteinViewId,
209
204
  )
205
+ if (proteinView) {
206
+ result.push({ ...conn, proteinView })
207
+ }
208
+ }
209
+ return result
210
210
  },
211
211
  }))
212
212
 
@@ -216,7 +216,7 @@ export default function stateModelFactory() {
216
216
  */
217
217
  get structureHoverCol(): number | undefined {
218
218
  for (const conn of self.connectedProteinViews) {
219
- const structure = conn.proteinView?.structures?.[conn.structureIdx]
219
+ const structure = conn.proteinView.structures[conn.structureIdx]
220
220
  const structurePos = structure?.hoverPosition?.structureSeqPos
221
221
  if (structurePos !== undefined) {
222
222
  const msaUngapped = conn.structureToMsa[structurePos]
@@ -246,12 +246,6 @@ export default function stateModelFactory() {
246
246
  }
247
247
  return genomeToMSA({ model: self as JBrowsePluginMsaViewModel })
248
248
  },
249
- /**
250
- * #getter
251
- */
252
- get clickCol2() {
253
- return undefined
254
- },
255
249
  }))
256
250
 
257
251
  .actions(self => ({
@@ -378,16 +372,14 @@ export default function stateModelFactory() {
378
372
 
379
373
  const ungappedMsaSequence = msaSequence.replaceAll('-', '')
380
374
 
381
- const { views } = getSession(self)
382
-
383
- const proteinView = views.find(
384
- (v: any) => v.id === proteinViewId,
385
- ) as any
375
+ const proteinView = getProteinViews(getSession(self).views).find(
376
+ v => v.id === proteinViewId,
377
+ )
386
378
  if (!proteinView) {
387
379
  throw new Error(`ProteinView "${proteinViewId}" not found`)
388
380
  }
389
381
 
390
- const structure = proteinView.structures?.[structureIdx]
382
+ const structure = proteinView.structures[structureIdx]
391
383
  if (!structure) {
392
384
  throw new Error(`Structure at index ${structureIdx} not found`)
393
385
  }
@@ -407,8 +399,8 @@ export default function stateModelFactory() {
407
399
  proteinViewId,
408
400
  structureIdx,
409
401
  msaRowName: rowName,
410
- msaToStructure: mapToRecord(seq1ToSeq2),
411
- structureToMsa: mapToRecord(seq2ToSeq1),
402
+ msaToStructure: Object.fromEntries(seq1ToSeq2),
403
+ structureToMsa: Object.fromEntries(seq2ToSeq1),
412
404
  }
413
405
 
414
406
  self.connectedStructures.push(connection)
@@ -66,15 +66,6 @@ export async function retrieveMsaData(id: string) {
66
66
  }
67
67
  }
68
68
 
69
- export async function deleteMsaData(id: string) {
70
- try {
71
- const db = await getDB()
72
- await db.delete(STORE_NAME, id)
73
- } catch (e) {
74
- console.warn('Failed to delete MSA data:', e)
75
- }
76
- }
77
-
78
69
  export async function cleanupOldData(maxAgeMs = 7 * 24 * 60 * 60 * 1000) {
79
70
  try {
80
71
  const db = await getDB()
@@ -1,9 +1,7 @@
1
1
  import BLOSUM62 from './blosum62'
2
2
 
3
3
  function getScore(a: string, b: string) {
4
- const upper_a = a.toUpperCase()
5
- const upper_b = b.toUpperCase()
6
- return BLOSUM62[upper_a]?.[upper_b] ?? -4
4
+ return BLOSUM62[a.toUpperCase()]?.[b.toUpperCase()] ?? -4
7
5
  }
8
6
 
9
7
  const GAP_OPEN = -10
@@ -75,10 +73,12 @@ export function needlemanWunsch(
75
73
  let i = m
76
74
  let j = n
77
75
 
78
- const finalScores = [M[m]![n]!, Ix[m]![n]!, Iy[m]![n]!]
79
- const score = Math.max(...finalScores)
76
+ const mScore = M[m]![n]!
77
+ const ixScore = Ix[m]![n]!
78
+ const iyScore = Iy[m]![n]!
79
+ const score = Math.max(mScore, ixScore, iyScore)
80
80
  let currentMatrix: 'M' | 'Ix' | 'Iy' =
81
- score === M[m]![n]! ? 'M' : score === Ix[m]![n]! ? 'Ix' : 'Iy'
81
+ score === mScore ? 'M' : score === ixScore ? 'Ix' : 'Iy'
82
82
 
83
83
  while (i > 0 || j > 0) {
84
84
  if (currentMatrix === 'M' && i > 0 && j > 0) {
@@ -2,7 +2,6 @@ import { describe, expect, test } from 'vitest'
2
2
 
3
3
  import {
4
4
  gappedToUngappedPosition,
5
- mapToRecord,
6
5
  ungappedToGappedPosition,
7
6
  } from './structureConnection'
8
7
 
@@ -121,23 +120,3 @@ describe('gappedToUngappedPosition and ungappedToGappedPosition are inverses', (
121
120
  }
122
121
  })
123
122
  })
124
-
125
- describe('mapToRecord', () => {
126
- test('converts Map to Record', () => {
127
- const map = new Map<number, number>([
128
- [0, 5],
129
- [1, 10],
130
- [2, 15],
131
- ])
132
- const record = mapToRecord(map)
133
- expect(record[0]).toBe(5)
134
- expect(record[1]).toBe(10)
135
- expect(record[2]).toBe(15)
136
- })
137
-
138
- test('handles empty Map', () => {
139
- const map = new Map<number, number>()
140
- const record = mapToRecord(map)
141
- expect(Object.keys(record)).toHaveLength(0)
142
- })
143
- })
@@ -1,3 +1,33 @@
1
+ export interface ProteinViewStructure {
2
+ url?: string
3
+ connectedViewId?: string
4
+ uniprotId?: string
5
+ structureSequences?: string[]
6
+ hoverGenomeHighlights?: { start: number; end: number }[]
7
+ hoverPosition?: { structureSeqPos?: number }
8
+ clearHighlightFromExternal?: () => void
9
+ highlightFromExternal?: (pos: number) => void
10
+ }
11
+
12
+ export interface ProteinView {
13
+ type: 'ProteinView'
14
+ id: string
15
+ displayName?: string
16
+ structures: ProteinViewStructure[]
17
+ }
18
+
19
+ export function isProteinView(view: unknown): view is ProteinView {
20
+ const v = view as Record<string, unknown>
21
+ return v.type === 'ProteinView' && Array.isArray(v.structures)
22
+ }
23
+
24
+ /**
25
+ * Extract all ProteinView instances from a session's views array.
26
+ */
27
+ export function getProteinViews(views: { type: string }[]): ProteinView[] {
28
+ return (views as unknown[]).filter(isProteinView)
29
+ }
30
+
1
31
  /**
2
32
  * Represents a connection between the MSA view and a protein structure
3
33
  */
@@ -59,10 +89,3 @@ export function ungappedToGappedPosition(
59
89
  }
60
90
  return undefined
61
91
  }
62
-
63
- /**
64
- * Convert Map to plain object for MST frozen storage
65
- */
66
- export function mapToRecord(map: Map<number, number>): Record<number, number> {
67
- return Object.fromEntries(map)
68
- }
@@ -1,5 +1,11 @@
1
1
  import { openDB } from 'idb'
2
2
 
3
+ import type {
4
+ BlastDatabase,
5
+ BlastProgram,
6
+ MsaAlgorithm,
7
+ } from '../LaunchMsaView/components/NCBIBlastQuery/consts'
8
+
3
9
  const DB_NAME = 'jbrowse-msaview-blast-cache'
4
10
  const STORE_NAME = 'blast-results'
5
11
  const DB_VERSION = 2
@@ -7,9 +13,9 @@ const DB_VERSION = 2
7
13
  export interface CachedBlastResult {
8
14
  id: string
9
15
  proteinSequence: string
10
- blastDatabase: string
11
- blastProgram: string
12
- msaAlgorithm: string
16
+ blastDatabase: BlastDatabase
17
+ blastProgram: BlastProgram
18
+ msaAlgorithm: MsaAlgorithm
13
19
  msa: string
14
20
  tree: string
15
21
  treeMetadata: string
@@ -36,8 +42,8 @@ async function getDB() {
36
42
 
37
43
  function createCacheKey(
38
44
  proteinSequence: string,
39
- blastDatabase: string,
40
- blastProgram: string,
45
+ blastDatabase: BlastDatabase,
46
+ blastProgram: BlastProgram,
41
47
  transcriptId?: string,
42
48
  ) {
43
49
  if (transcriptId) {
@@ -46,27 +52,6 @@ function createCacheKey(
46
52
  return `${blastDatabase}:${blastProgram}:${proteinSequence}`
47
53
  }
48
54
 
49
- export async function getCachedBlastResult({
50
- proteinSequence,
51
- blastDatabase,
52
- blastProgram,
53
- transcriptId,
54
- }: {
55
- proteinSequence: string
56
- blastDatabase: string
57
- blastProgram: string
58
- transcriptId?: string
59
- }) {
60
- const db = await getDB()
61
- const id = createCacheKey(
62
- proteinSequence,
63
- blastDatabase,
64
- blastProgram,
65
- transcriptId,
66
- )
67
- return db.get(STORE_NAME, id)
68
- }
69
-
70
55
  export async function saveBlastResult({
71
56
  proteinSequence,
72
57
  blastDatabase,
@@ -82,9 +67,9 @@ export async function saveBlastResult({
82
67
  geneName,
83
68
  }: {
84
69
  proteinSequence: string
85
- blastDatabase: string
86
- blastProgram: string
87
- msaAlgorithm: string
70
+ blastDatabase: BlastDatabase
71
+ blastProgram: BlastProgram
72
+ msaAlgorithm: MsaAlgorithm
88
73
  msa: string
89
74
  tree: string
90
75
  treeMetadata: string
@@ -127,14 +112,6 @@ export async function getAllCachedResults() {
127
112
  return results.toSorted((a, b) => b.timestamp - a.timestamp)
128
113
  }
129
114
 
130
- export async function getCachedResultsByGeneId(geneId: string) {
131
- const db = await getDB()
132
- const results = await db.getAll(STORE_NAME)
133
- return results
134
- .filter(r => r.geneId === geneId)
135
- .toSorted((a, b) => b.timestamp - a.timestamp)
136
- }
137
-
138
115
  export async function deleteCachedResult(id: string) {
139
116
  const db = await getDB()
140
117
  await db.delete(STORE_NAME, id)
package/src/utils/msa.ts CHANGED
@@ -1,9 +1,11 @@
1
1
  import { textfetch, timeout } from './fetch'
2
2
 
3
+ import type { MsaAlgorithm } from '../LaunchMsaView/components/NCBIBlastQuery/consts'
4
+
3
5
  const base = `https://www.ebi.ac.uk/Tools/services/rest`
4
6
 
5
7
  const algorithms: Record<
6
- string,
8
+ MsaAlgorithm,
7
9
  {
8
10
  params: Record<string, string>
9
11
  msaResult: string
@@ -38,7 +40,7 @@ async function wait({
38
40
  algorithm,
39
41
  }: {
40
42
  jobId: string
41
- algorithm: string
43
+ algorithm: MsaAlgorithm
42
44
  onProgress: (arg: string) => void
43
45
  }) {
44
46
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
@@ -62,14 +64,11 @@ export async function launchMSA({
62
64
  sequence,
63
65
  onProgress,
64
66
  }: {
65
- algorithm: string
67
+ algorithm: MsaAlgorithm
66
68
  sequence: string
67
69
  onProgress: (arg: string) => void
68
70
  }) {
69
71
  const config = algorithms[algorithm]
70
- if (!config) {
71
- throw new Error(`unknown algorithm: ${algorithm}`)
72
- }
73
72
 
74
73
  onProgress(`Launching ${algorithm} MSA...`)
75
74