jbrowse-plugin-msaview 2.0.6 → 2.2.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 (181) hide show
  1. package/dist/AddHighlightModel/GenomeMouseoverHighlight.js +3 -3
  2. package/dist/AddHighlightModel/GenomeMouseoverHighlight.js.map +1 -1
  3. package/dist/AddHighlightModel/MsaToGenomeHighlight.js +3 -1
  4. package/dist/AddHighlightModel/MsaToGenomeHighlight.js.map +1 -1
  5. package/dist/ExternalLink.d.ts +3 -0
  6. package/dist/ExternalLink.js +11 -0
  7. package/dist/ExternalLink.js.map +1 -0
  8. package/dist/LaunchMsaView/components/{NewNCBIBlastQuery/NcbiBlastPanel.d.ts → EnsemblGeneTree/EnsemblGeneTree.d.ts} +2 -2
  9. package/dist/LaunchMsaView/components/EnsemblGeneTree/EnsemblGeneTree.js +76 -0
  10. package/dist/LaunchMsaView/components/EnsemblGeneTree/EnsemblGeneTree.js.map +1 -0
  11. package/dist/LaunchMsaView/components/EnsemblGeneTree/ensemblGeneTreeLaunchView.d.ts +13 -0
  12. package/dist/LaunchMsaView/components/EnsemblGeneTree/ensemblGeneTreeLaunchView.js +12 -0
  13. package/dist/LaunchMsaView/components/EnsemblGeneTree/ensemblGeneTreeLaunchView.js.map +1 -0
  14. package/dist/LaunchMsaView/components/EnsemblGeneTree/ensemblGeneTreeUtils.d.ts +6 -0
  15. package/dist/LaunchMsaView/components/EnsemblGeneTree/ensemblGeneTreeUtils.js +25 -0
  16. package/dist/LaunchMsaView/components/EnsemblGeneTree/ensemblGeneTreeUtils.js.map +1 -0
  17. package/dist/LaunchMsaView/components/EnsemblGeneTree/gatherSequencesFromTree.d.ts +2 -0
  18. package/dist/LaunchMsaView/components/EnsemblGeneTree/gatherSequencesFromTree.js +20 -0
  19. package/dist/LaunchMsaView/components/EnsemblGeneTree/gatherSequencesFromTree.js.map +1 -0
  20. package/dist/LaunchMsaView/components/EnsemblGeneTree/types.d.ts +24 -0
  21. package/dist/LaunchMsaView/components/EnsemblGeneTree/types.js +2 -0
  22. package/dist/LaunchMsaView/components/EnsemblGeneTree/types.js.map +1 -0
  23. package/dist/LaunchMsaView/components/EnsemblGeneTree/useGeneTree.d.ts +10 -0
  24. package/dist/LaunchMsaView/components/EnsemblGeneTree/useGeneTree.js +27 -0
  25. package/dist/LaunchMsaView/components/EnsemblGeneTree/useGeneTree.js.map +1 -0
  26. package/dist/LaunchMsaView/components/EnsemblGeneTree/util.d.ts +4 -0
  27. package/dist/LaunchMsaView/components/EnsemblGeneTree/util.js +38 -0
  28. package/dist/LaunchMsaView/components/EnsemblGeneTree/util.js.map +1 -0
  29. package/dist/LaunchMsaView/components/LaunchMsaViewDialog.js +22 -16
  30. package/dist/LaunchMsaView/components/LaunchMsaViewDialog.js.map +1 -1
  31. package/dist/LaunchMsaView/components/ManualMSALoader/ManualMSALoader.d.ts +8 -0
  32. package/dist/LaunchMsaView/components/ManualMSALoader/ManualMSALoader.js +103 -0
  33. package/dist/LaunchMsaView/components/ManualMSALoader/ManualMSALoader.js.map +1 -0
  34. package/dist/LaunchMsaView/components/ManualMSALoader/fetchGeneList.d.ts +1 -0
  35. package/dist/LaunchMsaView/components/ManualMSALoader/fetchGeneList.js +12 -0
  36. package/dist/LaunchMsaView/components/ManualMSALoader/fetchGeneList.js.map +1 -0
  37. package/dist/LaunchMsaView/components/ManualMSALoader/launchView.d.ts +14 -0
  38. package/dist/LaunchMsaView/components/ManualMSALoader/launchView.js +12 -0
  39. package/dist/LaunchMsaView/components/ManualMSALoader/launchView.js.map +1 -0
  40. package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastAutomaticPanel.d.ts +10 -0
  41. package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastAutomaticPanel.js +89 -0
  42. package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastAutomaticPanel.js.map +1 -0
  43. package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastManualPanel.d.ts +10 -0
  44. package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastManualPanel.js +55 -0
  45. package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastManualPanel.js.map +1 -0
  46. package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastMethodSelector.d.ts +5 -0
  47. package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastMethodSelector.js +11 -0
  48. package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastMethodSelector.js.map +1 -0
  49. package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastPanel.d.ts +7 -0
  50. package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastPanel.js +30 -0
  51. package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastPanel.js.map +1 -0
  52. package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBISettingsDialog.d.ts +5 -0
  53. package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBISettingsDialog.js +26 -0
  54. package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBISettingsDialog.js.map +1 -0
  55. package/dist/LaunchMsaView/components/{NewNCBIBlastQuery/ncbiBlastLaunchView.d.ts → NCBIBlastQuery/blastLaunchView.d.ts} +2 -1
  56. package/dist/LaunchMsaView/components/{NewNCBIBlastQuery/ncbiBlastLaunchView.js → NCBIBlastQuery/blastLaunchView.js} +3 -6
  57. package/dist/LaunchMsaView/components/NCBIBlastQuery/blastLaunchView.js.map +1 -0
  58. package/dist/LaunchMsaView/components/NCBIBlastQuery/consts.d.ts +1 -0
  59. package/dist/LaunchMsaView/components/NCBIBlastQuery/consts.js +2 -0
  60. package/dist/LaunchMsaView/components/NCBIBlastQuery/consts.js.map +1 -0
  61. package/dist/LaunchMsaView/components/PreLoadedMSA/PreLoadedMSADataPanel.js +18 -19
  62. package/dist/LaunchMsaView/components/PreLoadedMSA/PreLoadedMSADataPanel.js.map +1 -1
  63. package/dist/LaunchMsaView/components/TabPanel.d.ts +6 -0
  64. package/dist/LaunchMsaView/components/TabPanel.js +6 -0
  65. package/dist/LaunchMsaView/components/TabPanel.js.map +1 -0
  66. package/dist/LaunchMsaView/components/TranscriptSelector.d.ts +10 -0
  67. package/dist/LaunchMsaView/components/TranscriptSelector.js +45 -0
  68. package/dist/LaunchMsaView/components/TranscriptSelector.js.map +1 -0
  69. package/dist/LaunchMsaView/components/calculateProteinSequence.d.ts +17 -0
  70. package/dist/LaunchMsaView/components/calculateProteinSequence.js +39 -0
  71. package/dist/LaunchMsaView/components/calculateProteinSequence.js.map +1 -0
  72. package/dist/LaunchMsaView/components/fetchSeq.d.ts +8 -0
  73. package/dist/LaunchMsaView/components/fetchSeq.js +23 -0
  74. package/dist/LaunchMsaView/components/fetchSeq.js.map +1 -0
  75. package/dist/LaunchMsaView/components/types.d.ts +10 -0
  76. package/dist/LaunchMsaView/components/types.js +2 -0
  77. package/dist/LaunchMsaView/components/types.js.map +1 -0
  78. package/dist/LaunchMsaView/components/{NewNCBIBlastQuery/useFeatureSequence.d.ts → useFeatureSequence.d.ts} +3 -6
  79. package/dist/LaunchMsaView/components/{NewNCBIBlastQuery/useFeatureSequence.js → useFeatureSequence.js} +13 -23
  80. package/dist/LaunchMsaView/components/useFeatureSequence.js.map +1 -0
  81. package/dist/LaunchMsaView/components/util.js.map +1 -0
  82. package/dist/LaunchMsaView/util.d.ts +5 -1
  83. package/dist/LaunchMsaView/util.js +15 -1
  84. package/dist/LaunchMsaView/util.js.map +1 -1
  85. package/dist/MsaViewPanel/components/LoadingBLAST.d.ts +2 -1
  86. package/dist/MsaViewPanel/components/LoadingBLAST.js +6 -6
  87. package/dist/MsaViewPanel/components/LoadingBLAST.js.map +1 -1
  88. package/dist/MsaViewPanel/components/MsaViewPanel.js +1 -1
  89. package/dist/MsaViewPanel/components/MsaViewPanel.js.map +1 -1
  90. package/dist/MsaViewPanel/components/RIDLink.d.ts +2 -1
  91. package/dist/MsaViewPanel/components/RIDLink.js +6 -9
  92. package/dist/MsaViewPanel/components/RIDLink.js.map +1 -1
  93. package/dist/MsaViewPanel/doLaunchBlast.js +18 -20
  94. package/dist/MsaViewPanel/doLaunchBlast.js.map +1 -1
  95. package/dist/MsaViewPanel/model.d.ts +15 -12
  96. package/dist/MsaViewPanel/model.js.map +1 -1
  97. package/dist/ReadOnlyTextField2.d.ts +4 -0
  98. package/dist/ReadOnlyTextField2.js +20 -0
  99. package/dist/ReadOnlyTextField2.js.map +1 -0
  100. package/dist/index.d.ts +15 -0
  101. package/dist/index.js +17 -0
  102. package/dist/index.js.map +1 -1
  103. package/dist/jbrowse-plugin-msaview.umd.production.min.js +33 -31
  104. package/dist/jbrowse-plugin-msaview.umd.production.min.js.map +4 -4
  105. package/dist/utils/fetch.d.ts +1 -1
  106. package/dist/utils/fetch.js.map +1 -1
  107. package/dist/utils/ncbiBlast.d.ts +2 -2
  108. package/dist/utils/ncbiBlast.js +29 -15
  109. package/dist/utils/ncbiBlast.js.map +1 -1
  110. package/dist/utils/types.d.ts +20 -0
  111. package/dist/utils/types.js +2 -0
  112. package/dist/utils/types.js.map +1 -0
  113. package/package.json +3 -3
  114. package/src/AddHighlightModel/GenomeMouseoverHighlight.tsx +3 -3
  115. package/src/AddHighlightModel/MsaToGenomeHighlight.tsx +2 -1
  116. package/src/ExternalLink.tsx +15 -0
  117. package/src/LaunchMsaView/components/EnsemblGeneTree/EnsemblGeneTree.tsx +127 -0
  118. package/src/LaunchMsaView/components/EnsemblGeneTree/ensemblGeneTreeLaunchView.ts +30 -0
  119. package/src/LaunchMsaView/components/EnsemblGeneTree/ensemblGeneTreeUtils.ts +46 -0
  120. package/src/LaunchMsaView/components/EnsemblGeneTree/gatherSequencesFromTree.ts +22 -0
  121. package/src/LaunchMsaView/components/EnsemblGeneTree/types.ts +28 -0
  122. package/src/LaunchMsaView/components/EnsemblGeneTree/useGeneTree.ts +29 -0
  123. package/src/LaunchMsaView/components/EnsemblGeneTree/util.ts +45 -0
  124. package/src/LaunchMsaView/components/LaunchMsaViewDialog.tsx +36 -21
  125. package/src/LaunchMsaView/components/ManualMSALoader/ManualMSALoader.tsx +219 -0
  126. package/src/LaunchMsaView/components/ManualMSALoader/fetchGeneList.ts +13 -0
  127. package/src/LaunchMsaView/components/ManualMSALoader/launchView.ts +34 -0
  128. package/src/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastAutomaticPanel.tsx +226 -0
  129. package/src/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastManualPanel.tsx +111 -0
  130. package/src/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastMethodSelector.tsx +34 -0
  131. package/src/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastPanel.tsx +82 -0
  132. package/src/LaunchMsaView/components/NCBIBlastQuery/NCBISettingsDialog.tsx +75 -0
  133. package/src/LaunchMsaView/components/{NewNCBIBlastQuery/ncbiBlastLaunchView.ts → NCBIBlastQuery/blastLaunchView.ts} +4 -5
  134. package/src/LaunchMsaView/components/NCBIBlastQuery/consts.ts +1 -0
  135. package/src/LaunchMsaView/components/PreLoadedMSA/PreLoadedMSADataPanel.tsx +28 -44
  136. package/src/LaunchMsaView/components/TabPanel.tsx +19 -0
  137. package/src/LaunchMsaView/components/TranscriptSelector.tsx +99 -0
  138. package/src/LaunchMsaView/components/calculateProteinSequence.ts +68 -0
  139. package/src/LaunchMsaView/components/fetchSeq.ts +37 -0
  140. package/src/LaunchMsaView/components/types.ts +11 -0
  141. package/src/LaunchMsaView/components/{NewNCBIBlastQuery/useFeatureSequence.ts → useFeatureSequence.ts} +20 -42
  142. package/src/LaunchMsaView/util.ts +22 -2
  143. package/src/MsaViewPanel/components/LoadingBLAST.tsx +26 -8
  144. package/src/MsaViewPanel/components/MsaViewPanel.tsx +5 -1
  145. package/src/MsaViewPanel/components/RIDLink.tsx +8 -8
  146. package/src/MsaViewPanel/doLaunchBlast.ts +29 -30
  147. package/src/MsaViewPanel/model.ts +1 -0
  148. package/src/ReadOnlyTextField2.tsx +33 -0
  149. package/src/index.ts +23 -0
  150. package/src/utils/fetch.ts +2 -2
  151. package/src/utils/ncbiBlast.ts +40 -30
  152. package/src/utils/types.ts +14 -0
  153. package/dist/LaunchMsaView/components/NewNCBIBlastQuery/NcbiBlastPanel.js +0 -85
  154. package/dist/LaunchMsaView/components/NewNCBIBlastQuery/NcbiBlastPanel.js.map +0 -1
  155. package/dist/LaunchMsaView/components/NewNCBIBlastQuery/calculateProteinSequence.d.ts +0 -26
  156. package/dist/LaunchMsaView/components/NewNCBIBlastQuery/calculateProteinSequence.js +0 -48
  157. package/dist/LaunchMsaView/components/NewNCBIBlastQuery/calculateProteinSequence.js.map +0 -1
  158. package/dist/LaunchMsaView/components/NewNCBIBlastQuery/index.d.ts +0 -1
  159. package/dist/LaunchMsaView/components/NewNCBIBlastQuery/index.js +0 -2
  160. package/dist/LaunchMsaView/components/NewNCBIBlastQuery/index.js.map +0 -1
  161. package/dist/LaunchMsaView/components/NewNCBIBlastQuery/ncbiBlastLaunchView.js.map +0 -1
  162. package/dist/LaunchMsaView/components/NewNCBIBlastQuery/useFeatureSequence.js.map +0 -1
  163. package/dist/LaunchMsaView/components/NewNCBIBlastQuery/util.js.map +0 -1
  164. package/dist/LaunchMsaView/components/TabUtils.d.ts +0 -8
  165. package/dist/LaunchMsaView/components/TabUtils.js +0 -7
  166. package/dist/LaunchMsaView/components/TabUtils.js.map +0 -1
  167. package/dist/LaunchMsaView/components/tabUtil.d.ts +0 -4
  168. package/dist/LaunchMsaView/components/tabUtil.js +0 -7
  169. package/dist/LaunchMsaView/components/tabUtil.js.map +0 -1
  170. package/dist/OpenInNewIcon.d.ts +0 -3
  171. package/dist/OpenInNewIcon.js +0 -8
  172. package/dist/OpenInNewIcon.js.map +0 -1
  173. package/src/LaunchMsaView/components/NewNCBIBlastQuery/NcbiBlastPanel.tsx +0 -171
  174. package/src/LaunchMsaView/components/NewNCBIBlastQuery/calculateProteinSequence.ts +0 -92
  175. package/src/LaunchMsaView/components/NewNCBIBlastQuery/index.tsx +0 -1
  176. package/src/LaunchMsaView/components/TabUtils.tsx +0 -25
  177. package/src/LaunchMsaView/components/tabUtil.ts +0 -6
  178. package/src/OpenInNewIcon.tsx +0 -14
  179. /package/dist/LaunchMsaView/components/{NewNCBIBlastQuery/util.d.ts → util.d.ts} +0 -0
  180. /package/dist/LaunchMsaView/components/{NewNCBIBlastQuery/util.js → util.js} +0 -0
  181. /package/src/LaunchMsaView/components/{NewNCBIBlastQuery/util.ts → util.ts} +0 -0
@@ -0,0 +1,82 @@
1
+ import React, { useState } from 'react'
2
+
3
+ import { useLocalStorage } from '@jbrowse/core/util'
4
+ import SettingsIcon from '@mui/icons-material/Settings'
5
+ import { IconButton } from '@mui/material'
6
+
7
+ import NCBIBlastAutomaticPanel from './NCBIBlastAutomaticPanel'
8
+ import NCBIBlastManualPanel from './NCBIBlastManualPanel'
9
+ import NCBIBlastMethodSelector from './NCBIBlastMethodSelector'
10
+ import NCBISettingsDialog from './NCBISettingsDialog'
11
+ import { BASE_BLAST_URL } from './consts'
12
+
13
+ import type { AbstractTrackModel, Feature } from '@jbrowse/core/util'
14
+
15
+ export default function NCBIBlastPanel({
16
+ handleClose,
17
+ model,
18
+ feature,
19
+ }: {
20
+ handleClose: () => void
21
+ model: AbstractTrackModel
22
+ feature: Feature
23
+ }) {
24
+ const [lookupMethod, setLookupMethod] = useState('automatic')
25
+ const [baseUrl, setBaseUrl] = useLocalStorage(
26
+ 'msa-blastRootUrl',
27
+ BASE_BLAST_URL,
28
+ )
29
+ const [settingsOpen, setSettingsOpen] = useState(false)
30
+
31
+ return (
32
+ <>
33
+ <IconButton
34
+ style={{ float: 'right' }}
35
+ size="small"
36
+ onClick={() => {
37
+ setSettingsOpen(true)
38
+ }}
39
+ >
40
+ <SettingsIcon />
41
+ </IconButton>
42
+
43
+ {lookupMethod === 'automatic' ? (
44
+ <NCBIBlastAutomaticPanel
45
+ model={model}
46
+ feature={feature}
47
+ handleClose={handleClose}
48
+ baseUrl={baseUrl}
49
+ >
50
+ <NCBIBlastMethodSelector
51
+ lookupMethod={lookupMethod}
52
+ setLookupMethod={setLookupMethod}
53
+ />
54
+ </NCBIBlastAutomaticPanel>
55
+ ) : null}
56
+ {lookupMethod === 'manual' ? (
57
+ <NCBIBlastManualPanel
58
+ model={model}
59
+ feature={feature}
60
+ handleClose={handleClose}
61
+ baseUrl={baseUrl}
62
+ >
63
+ <NCBIBlastMethodSelector
64
+ lookupMethod={lookupMethod}
65
+ setLookupMethod={setLookupMethod}
66
+ />
67
+ </NCBIBlastManualPanel>
68
+ ) : null}
69
+ {settingsOpen ? (
70
+ <NCBISettingsDialog
71
+ baseUrl={baseUrl}
72
+ handleClose={arg => {
73
+ if (arg) {
74
+ setBaseUrl(arg)
75
+ }
76
+ setSettingsOpen(false)
77
+ }}
78
+ />
79
+ ) : null}
80
+ </>
81
+ )
82
+ }
@@ -0,0 +1,75 @@
1
+ import React, { useState } from 'react'
2
+
3
+ import {
4
+ Button,
5
+ Dialog,
6
+ DialogActions,
7
+ DialogContent,
8
+ DialogTitle,
9
+ } from '@mui/material'
10
+
11
+ import { BASE_BLAST_URL } from './consts'
12
+ import TextField2 from '../../../TextField2'
13
+
14
+ export default function NCBISettingsDialog({
15
+ handleClose,
16
+ baseUrl,
17
+ }: {
18
+ handleClose: (arg?: string) => void
19
+ baseUrl: string
20
+ }) {
21
+ const [tempBaseUrl, setTempBaseUrl] = useState(baseUrl)
22
+ return (
23
+ <Dialog
24
+ open
25
+ maxWidth="lg"
26
+ onClose={() => {
27
+ handleClose()
28
+ }}
29
+ >
30
+ <DialogTitle>BLAST Settings</DialogTitle>
31
+ <DialogContent>
32
+ <TextField2
33
+ autoFocus
34
+ margin="dense"
35
+ label="BLAST Base URL"
36
+ fullWidth
37
+ variant="outlined"
38
+ value={tempBaseUrl}
39
+ style={{ minWidth: '300px' }}
40
+ onChange={e => {
41
+ setTempBaseUrl(e.target.value)
42
+ }}
43
+ />
44
+ <Button
45
+ variant="contained"
46
+ onClick={() => {
47
+ setTempBaseUrl(BASE_BLAST_URL)
48
+ }}
49
+ >
50
+ Reset
51
+ </Button>
52
+ </DialogContent>
53
+ <DialogActions>
54
+ <Button
55
+ variant="contained"
56
+ color="secondary"
57
+ onClick={() => {
58
+ handleClose()
59
+ }}
60
+ >
61
+ Cancel
62
+ </Button>
63
+ <Button
64
+ color="primary"
65
+ variant="contained"
66
+ onClick={() => {
67
+ handleClose(tempBaseUrl)
68
+ }}
69
+ >
70
+ Save
71
+ </Button>
72
+ </DialogActions>
73
+ </Dialog>
74
+ )
75
+ }
@@ -3,26 +3,25 @@ import { Feature, getSession } from '@jbrowse/core/util'
3
3
  import type { JBrowsePluginMsaViewModel } from '../../../MsaViewPanel/model'
4
4
  import type { LinearGenomeViewModel } from '@jbrowse/plugin-linear-genome-view'
5
5
 
6
- export function ncbiBlastLaunchView({
6
+ export function blastLaunchView({
7
7
  newViewTitle,
8
8
  view,
9
9
  feature,
10
+ blastParams,
10
11
  }: {
11
12
  newViewTitle: string
12
13
  view: LinearGenomeViewModel
13
14
  feature: Feature
15
+ blastParams: Record<string, unknown>
14
16
  }) {
15
17
  return getSession(view).addView('MsaView', {
16
18
  type: 'MsaView',
17
19
  displayName: newViewTitle,
18
20
  connectedViewId: view.id,
19
21
  connectedFeature: feature.toJSON(),
20
- treeAreaWidth: 250,
21
- treeWidth: 100,
22
22
  drawNodeBubbles: true,
23
- labelsAlignRight: true,
24
23
  colWidth: 10,
25
24
  rowHeight: 12,
26
- colorSchemeName: 'percent_identity_dynamic',
25
+ blastParams,
27
26
  }) as JBrowsePluginMsaViewModel
28
27
  }
@@ -0,0 +1 @@
1
+ export const BASE_BLAST_URL = 'https://blast.ncbi.nlm.nih.gov/Blast.cgi'
@@ -7,28 +7,20 @@ import {
7
7
  getContainingView,
8
8
  getSession,
9
9
  } from '@jbrowse/core/util'
10
- import {
11
- Button,
12
- DialogActions,
13
- DialogContent,
14
- MenuItem,
15
- TextField,
16
- Typography,
17
- } from '@mui/material'
10
+ import { Button, DialogActions, DialogContent, Typography } from '@mui/material'
18
11
  import { observer } from 'mobx-react'
19
12
  import { makeStyles } from 'tss-react/mui'
20
13
 
21
14
  import { fetchGeneList } from './fetchGeneList'
22
15
  import { preCalculatedLaunchView } from './preCalculatedLaunchView'
23
- import {
24
- getGeneDisplayName,
25
- getId,
26
- getTranscriptDisplayName,
27
- getTranscriptFeatures,
28
- } from '../../util'
16
+ import ExternalLink from '../../../ExternalLink'
17
+ import { getGeneDisplayName, getId, getTranscriptFeatures } from '../../util'
18
+ import TranscriptSelector from '../TranscriptSelector'
19
+ import { useFeatureSequence } from '../useFeatureSequence'
29
20
 
30
21
  import type { LinearGenomeViewModel } from '@jbrowse/plugin-linear-genome-view'
31
22
 
23
+
32
24
  const useStyles = makeStyles()({
33
25
  dialogContent: {
34
26
  width: '80em',
@@ -47,7 +39,7 @@ const PreLoadedMSA = observer(function PreLoadedMSA2({
47
39
  const session = getSession(model)
48
40
  const view = getContainingView(model) as LinearGenomeViewModel
49
41
  const { classes } = useStyles()
50
- const [error, setError] = useState<unknown>()
42
+ const [error1, setError] = useState<unknown>()
51
43
  const [geneNameList, setGeneNameList] = useState<string[]>()
52
44
  useEffect(() => {
53
45
  // eslint-disable-next-line @typescript-eslint/no-floating-promises
@@ -67,47 +59,39 @@ const PreLoadedMSA = observer(function PreLoadedMSA2({
67
59
  }
68
60
  })()
69
61
  }, [feature])
70
- const set = new Set(geneNameList)
62
+ const validSet = new Set(geneNameList)
71
63
  const options = getTranscriptFeatures(feature)
72
- const ret = options.find(val => set.has(getId(val)))
64
+ const ret = options.find(val => validSet.has(getId(val)))
73
65
  const [userSelection, setUserSelection] = useState(getId(options[0]))
66
+ const selectedTranscript = options.find(val => getId(val) === userSelection)!
67
+ const { proteinSequence, error: error2 } = useFeatureSequence({
68
+ view,
69
+ feature: selectedTranscript,
70
+ })
71
+
72
+ const e = error1 ?? error2
74
73
 
75
74
  return (
76
75
  <>
77
76
  <DialogContent className={classes.dialogContent}>
77
+ {e ? <ErrorMessage error={e} /> : null}
78
78
  <Typography>
79
79
  The source data for these multiple sequence alignments is from{' '}
80
- <a href="https://hgdownload.soe.ucsc.edu/goldenPath/hg38/multiz100way/alignments/">
80
+ <ExternalLink href="https://hgdownload.soe.ucsc.edu/goldenPath/hg38/multiz100way/alignments/">
81
81
  knownCanonical.multiz100way.protAA.fa.gz
82
- </a>
82
+ </ExternalLink>
83
83
  </Typography>
84
- {error ? <ErrorMessage error={error} /> : null}
85
84
  {geneNameList && !ret ? (
86
- <div style={{ color: 'red' }}>No MSA data for this gene found</div>
85
+ <Typography color="error">No MSA data for this gene found</Typography>
87
86
  ) : null}
88
- <TextField
89
- value={userSelection}
90
- onChange={event => {
91
- setUserSelection(event.target.value)
92
- }}
93
- label="Choose isoform to view MSA for"
94
- select
95
- >
96
- {options
97
- .filter(val => set.has(getId(val)))
98
- .map(val => (
99
- <MenuItem value={getId(val)} key={val.id()}>
100
- {getTranscriptDisplayName(val)} (has data)
101
- </MenuItem>
102
- ))}
103
- {options
104
- .filter(val => !set.has(getId(val)))
105
- .map(val => (
106
- <MenuItem value={getId(val)} key={val.id()} disabled>
107
- {getTranscriptDisplayName(val)}
108
- </MenuItem>
109
- ))}
110
- </TextField>
87
+ <TranscriptSelector
88
+ feature={feature}
89
+ options={options}
90
+ selectedTranscriptId={userSelection}
91
+ onTranscriptChange={setUserSelection}
92
+ proteinSequence={proteinSequence}
93
+ validSet={validSet}
94
+ />
111
95
  </DialogContent>
112
96
 
113
97
  <DialogActions>
@@ -0,0 +1,19 @@
1
+ import React from 'react'
2
+
3
+ // this is from MUI example
4
+ export default function TabPanel({
5
+ children,
6
+ value,
7
+ index,
8
+ ...other
9
+ }: {
10
+ children?: React.ReactNode
11
+ index: number
12
+ value: number
13
+ }) {
14
+ return (
15
+ <div role="tabpanel" hidden={value !== index} {...other}>
16
+ {value === index && <div>{children}</div>}
17
+ </div>
18
+ )
19
+ }
@@ -0,0 +1,99 @@
1
+ import React, { useState } from 'react'
2
+
3
+ import { Feature } from '@jbrowse/core/util'
4
+ import { Button, MenuItem } from '@mui/material'
5
+ import { makeStyles } from 'tss-react/mui'
6
+
7
+ import ReadOnlyTextField2 from '../../ReadOnlyTextField2'
8
+ import TextField2 from '../../TextField2'
9
+ import {
10
+ getGeneDisplayName,
11
+ getId,
12
+ getTranscriptDisplayName,
13
+ getTranscriptLength,
14
+ } from '../util'
15
+
16
+ const useStyles = makeStyles()({
17
+ flex: {
18
+ display: 'flex',
19
+ },
20
+ minWidth: {
21
+ minWidth: 300,
22
+ },
23
+ })
24
+
25
+ export default function TranscriptSelector({
26
+ feature,
27
+ options,
28
+ selectedTranscriptId,
29
+ onTranscriptChange,
30
+ proteinSequence,
31
+ validSet,
32
+ }: {
33
+ feature: Feature
34
+ options: Feature[]
35
+ selectedTranscriptId: string
36
+ onTranscriptChange: (transcriptId: string) => void
37
+ proteinSequence: string | undefined
38
+ validSet?: Set<string>
39
+ }) {
40
+ const { classes } = useStyles()
41
+ const [showSequence, setShowSequence] = useState(false)
42
+ const selectedTranscript = options.find(
43
+ val => getId(val) === selectedTranscriptId,
44
+ )!
45
+
46
+ return (
47
+ <>
48
+ <div className={classes.flex}>
49
+ <TextField2
50
+ variant="outlined"
51
+ label={`Choose isoform of ${getGeneDisplayName(feature)}`}
52
+ select
53
+ className={classes.minWidth}
54
+ value={selectedTranscriptId}
55
+ onChange={event => {
56
+ onTranscriptChange(event.target.value)
57
+ }}
58
+ >
59
+ {options
60
+ .toSorted(
61
+ (a, b) => getTranscriptLength(b).len - getTranscriptLength(a).len,
62
+ )
63
+ .map(val => {
64
+ const inSet = validSet ? validSet.has(getId(val)) : true
65
+ const { len, mod } = getTranscriptLength(val)
66
+ return (
67
+ <MenuItem value={getId(val)} key={val.id()} disabled={!inSet}>
68
+ {getTranscriptDisplayName(val)} ({len} aa){' '}
69
+ {mod ? ` (possible fragment)` : ''}
70
+ {validSet ? (inSet ? ' (has data)' : ' (no data)') : ''}
71
+ </MenuItem>
72
+ )
73
+ })}
74
+ </TextField2>
75
+ <div style={{ alignContent: 'center', marginLeft: 20 }}>
76
+ <Button
77
+ variant="contained"
78
+ color="primary"
79
+ onClick={() => {
80
+ setShowSequence(!showSequence)
81
+ }}
82
+ >
83
+ {showSequence ? 'Hide sequence' : 'Show sequence'}
84
+ </Button>
85
+ </div>
86
+ </div>
87
+
88
+ {showSequence && (
89
+ <ReadOnlyTextField2
90
+ value={
91
+ proteinSequence
92
+ ? `>${getTranscriptDisplayName(selectedTranscript)}\n${proteinSequence}`
93
+ : 'Loading...'
94
+ }
95
+ />
96
+ )}
97
+ </>
98
+ )
99
+ }
@@ -0,0 +1,68 @@
1
+ import {
2
+ dedupe,
3
+ defaultCodonTable,
4
+ generateCodonTable,
5
+ revcom,
6
+ } from '@jbrowse/core/util'
7
+
8
+ import type { Feat } from './types'
9
+ import type { Feature } from '@jbrowse/core/util'
10
+
11
+ export function stitch(subfeats: Feat[], sequence: string) {
12
+ return subfeats.map(sub => sequence.slice(sub.start, sub.end)).join('')
13
+ }
14
+
15
+ export function calculateProteinSequence({
16
+ cds,
17
+ sequence,
18
+ codonTable,
19
+ }: {
20
+ cds: Feat[]
21
+ sequence: string
22
+ codonTable: Record<string, string>
23
+ }) {
24
+ const str = stitch(cds, sequence)
25
+ let protein = ''
26
+ for (let i = 0; i < str.length; i += 3) {
27
+ // use & symbol for undefined codon, or partial slice
28
+ protein += codonTable[str.slice(i, i + 3)] ?? '&'
29
+ }
30
+ return protein
31
+ }
32
+
33
+ export function revlist(list: Feat[], seqlen: number) {
34
+ return list
35
+ .map(sub => ({
36
+ ...sub,
37
+ start: seqlen - sub.end,
38
+ end: seqlen - sub.start,
39
+ }))
40
+ .toSorted((a, b) => a.start - b.start)
41
+ }
42
+
43
+ export function getProteinSequenceFromFeature({
44
+ selectedTranscript,
45
+ seq,
46
+ }: {
47
+ seq: string
48
+ selectedTranscript: Feature
49
+ }) {
50
+ const { subfeatures, start, strand } = selectedTranscript.toJSON()
51
+ const cds = dedupe(
52
+ subfeatures
53
+ ?.toSorted((a, b) => a.start - b.start)
54
+ .map(sub => ({
55
+ ...sub,
56
+ start: sub.start - start,
57
+ end: sub.end - start,
58
+ }))
59
+ .filter(subfeature => subfeature.type === 'CDS') ?? [],
60
+ feat => `${feat.start}-${feat.end}`,
61
+ )
62
+
63
+ return calculateProteinSequence({
64
+ cds: strand === -1 ? revlist(cds, seq.length) : cds,
65
+ sequence: strand === -1 ? revcom(seq) : seq,
66
+ codonTable: generateCodonTable(defaultCodonTable),
67
+ })
68
+ }
@@ -0,0 +1,37 @@
1
+ import { getConf } from '@jbrowse/core/configuration'
2
+
3
+ import type { AbstractSessionModel, Feature } from '@jbrowse/core/util'
4
+
5
+ export async function fetchSeq({
6
+ start,
7
+ end,
8
+ refName,
9
+ session,
10
+ assemblyName,
11
+ }: {
12
+ start: number
13
+ end: number
14
+ refName: string
15
+ assemblyName: string
16
+ session: AbstractSessionModel
17
+ }) {
18
+ const { assemblyManager, rpcManager } = session
19
+ const assembly = await assemblyManager.waitForAssembly(assemblyName)
20
+ if (!assembly) {
21
+ throw new Error('assembly not found')
22
+ }
23
+ const sessionId = 'getSequence'
24
+ const feats = (await rpcManager.call(sessionId, 'CoreGetFeatures', {
25
+ adapterConfig: getConf(assembly, ['sequence', 'adapter']),
26
+ sessionId,
27
+ regions: [
28
+ {
29
+ start,
30
+ end,
31
+ refName: assembly.getCanonicalRefName(refName),
32
+ assemblyName,
33
+ },
34
+ ],
35
+ })) as Feature[]
36
+ return (feats[0]?.get('seq') as string | undefined) ?? ''
37
+ }
@@ -0,0 +1,11 @@
1
+ export interface Feat {
2
+ start: number
3
+ end: number
4
+ type?: string
5
+ }
6
+
7
+ export interface SeqState {
8
+ seq: string
9
+ upstream?: string
10
+ downstream?: string
11
+ }
@@ -1,53 +1,18 @@
1
1
  import { useEffect, useState } from 'react'
2
2
 
3
- import { getConf } from '@jbrowse/core/configuration'
4
- import { AbstractSessionModel, Feature, getSession } from '@jbrowse/core/util'
3
+ import { getSession } from '@jbrowse/core/util'
5
4
 
6
- export interface SeqState {
7
- seq: string
8
- upstream?: string
9
- downstream?: string
10
- }
5
+ import { getProteinSequenceFromFeature } from './calculateProteinSequence'
6
+ import { fetchSeq } from './fetchSeq'
7
+
8
+ import type { SeqState } from './types'
9
+ import type { Feature } from '@jbrowse/core/util'
11
10
 
12
11
  export interface ErrorState {
13
12
  error: string
14
13
  }
15
14
  const BPLIMIT = 500_000
16
15
 
17
- async function fetchSeq({
18
- start,
19
- end,
20
- refName,
21
- session,
22
- assemblyName,
23
- }: {
24
- start: number
25
- end: number
26
- refName: string
27
- assemblyName: string
28
- session: AbstractSessionModel
29
- }) {
30
- const { assemblyManager, rpcManager } = session
31
- const assembly = await assemblyManager.waitForAssembly(assemblyName)
32
- if (!assembly) {
33
- throw new Error('assembly not found')
34
- }
35
- const sessionId = 'getSequence'
36
- const feats = (await rpcManager.call(sessionId, 'CoreGetFeatures', {
37
- adapterConfig: getConf(assembly, ['sequence', 'adapter']),
38
- sessionId,
39
- regions: [
40
- {
41
- start,
42
- end,
43
- refName: assembly.getCanonicalRefName(refName),
44
- assemblyName,
45
- },
46
- ],
47
- })) as Feature[]
48
- return (feats[0]?.get('seq') as string | undefined) ?? ''
49
- }
50
-
51
16
  export function useFeatureSequence({
52
17
  view,
53
18
  feature,
@@ -116,5 +81,18 @@ export function useFeatureSequence({
116
81
  })()
117
82
  }
118
83
  }, [feature, view, upDownBp, assemblyName, forceLoad])
119
- return { sequence, error }
84
+
85
+ const proteinSequence =
86
+ sequence && !('error' in sequence)
87
+ ? getProteinSequenceFromFeature({
88
+ seq: sequence.seq,
89
+ selectedTranscript: feature,
90
+ })
91
+ : ''
92
+
93
+ return {
94
+ proteinSequence,
95
+ sequence,
96
+ error,
97
+ }
120
98
  }
@@ -1,4 +1,6 @@
1
- import { Feature } from '@jbrowse/core/util'
1
+ import { sum } from '@jbrowse/core/util'
2
+
3
+ import type { Feature } from '@jbrowse/core/util'
2
4
 
3
5
  export function getTranscriptFeatures(feature: Feature) {
4
6
  // check if we are looking at a 'two-level' or 'three-level' feature by
@@ -11,6 +13,21 @@ export function getTranscriptFeatures(feature: Feature) {
11
13
  f.get('subfeatures')?.some(f => f.get('type') === 'CDS'),
12
14
  )
13
15
  }
16
+
17
+ export function getTranscriptLength(feature: Feature) {
18
+ const cdsLen = sum(
19
+ feature
20
+ .get('subfeatures')
21
+ ?.filter(
22
+ f => (f.get('type') as string | undefined)?.toLowerCase() === 'cds',
23
+ )
24
+ .map(s => s.get('end') - s.get('start')) ?? [],
25
+ )
26
+ return {
27
+ len: Math.floor(cdsLen / 3),
28
+ mod: cdsLen % 3,
29
+ }
30
+ }
14
31
  export function getId(val?: Feature): string {
15
32
  return val?.get('name') ?? val?.get('id') ?? ''
16
33
  }
@@ -24,7 +41,10 @@ export function getTranscriptDisplayName(val?: Feature) {
24
41
  export function getGeneDisplayName(val?: Feature) {
25
42
  return val === undefined
26
43
  ? ''
27
- : [val.get('gene_name') ?? val.get('name'), val.get('id')]
44
+ : [
45
+ val.get('gene_name') ?? val.get('name'),
46
+ val.get('id') ? `(${val.get('id')})` : '',
47
+ ]
28
48
  .filter(f => !!f)
29
49
  .join(' ')
30
50
  }