jbrowse-plugin-msaview 1.0.17 → 2.0.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 (147) hide show
  1. package/CHANGELOG.md +10 -4
  2. package/README.md +6 -4
  3. package/dist/AddHighlightModel/GenomeMouseoverHighlight.d.ts +6 -0
  4. package/dist/AddHighlightModel/GenomeMouseoverHighlight.js +30 -0
  5. package/dist/AddHighlightModel/GenomeMouseoverHighlight.js.map +1 -0
  6. package/dist/AddHighlightModel/HighlightComponents.d.ts +7 -0
  7. package/dist/AddHighlightModel/HighlightComponents.js +12 -0
  8. package/dist/AddHighlightModel/HighlightComponents.js.map +1 -0
  9. package/dist/AddHighlightModel/MsaToGenomeHighlight.d.ts +7 -0
  10. package/dist/AddHighlightModel/MsaToGenomeHighlight.js +26 -0
  11. package/dist/AddHighlightModel/MsaToGenomeHighlight.js.map +1 -0
  12. package/dist/AddHighlightModel/index.d.ts +2 -0
  13. package/dist/AddHighlightModel/index.js +14 -0
  14. package/dist/AddHighlightModel/index.js.map +1 -0
  15. package/dist/AddHighlightModel/util.d.ts +9 -0
  16. package/dist/AddHighlightModel/util.js +14 -0
  17. package/dist/AddHighlightModel/util.js.map +1 -0
  18. package/dist/LaunchMsaView/components/LaunchMsaViewDialog.d.ts +7 -0
  19. package/dist/LaunchMsaView/components/LaunchMsaViewDialog.js +20 -0
  20. package/dist/LaunchMsaView/components/LaunchMsaViewDialog.js.map +1 -0
  21. package/dist/LaunchMsaView/components/NewNCBIBlastQuery/NcbiBlastPanel.d.ts +8 -0
  22. package/dist/LaunchMsaView/components/NewNCBIBlastQuery/NcbiBlastPanel.js +76 -0
  23. package/dist/LaunchMsaView/components/NewNCBIBlastQuery/NcbiBlastPanel.js.map +1 -0
  24. package/dist/LaunchMsaView/components/NewNCBIBlastQuery/calculateProteinSequence.d.ts +26 -0
  25. package/dist/LaunchMsaView/components/NewNCBIBlastQuery/calculateProteinSequence.js +48 -0
  26. package/dist/LaunchMsaView/components/NewNCBIBlastQuery/calculateProteinSequence.js.map +1 -0
  27. package/dist/LaunchMsaView/components/NewNCBIBlastQuery/index.d.ts +2 -0
  28. package/dist/LaunchMsaView/components/NewNCBIBlastQuery/index.js +3 -0
  29. package/dist/LaunchMsaView/components/NewNCBIBlastQuery/index.js.map +1 -0
  30. package/dist/LaunchMsaView/components/NewNCBIBlastQuery/ncbiBlastLaunchView.d.ts +8 -0
  31. package/dist/LaunchMsaView/components/NewNCBIBlastQuery/ncbiBlastLaunchView.js +17 -0
  32. package/dist/LaunchMsaView/components/NewNCBIBlastQuery/ncbiBlastLaunchView.js.map +1 -0
  33. package/dist/LaunchMsaView/components/NewNCBIBlastQuery/useFeatureSequence.d.ts +20 -0
  34. package/dist/LaunchMsaView/components/NewNCBIBlastQuery/useFeatureSequence.js +64 -0
  35. package/dist/LaunchMsaView/components/NewNCBIBlastQuery/useFeatureSequence.js.map +1 -0
  36. package/dist/LaunchMsaView/components/NewNCBIBlastQuery/util.d.ts +5 -0
  37. package/dist/LaunchMsaView/components/NewNCBIBlastQuery/util.js +7 -0
  38. package/dist/LaunchMsaView/components/NewNCBIBlastQuery/util.js.map +1 -0
  39. package/dist/LaunchMsaView/components/PreLoadedMSA/PreLoadedMSADataPanel.d.ts +8 -0
  40. package/dist/LaunchMsaView/components/PreLoadedMSA/PreLoadedMSADataPanel.js +90 -0
  41. package/dist/LaunchMsaView/components/PreLoadedMSA/PreLoadedMSADataPanel.js.map +1 -0
  42. package/dist/LaunchMsaView/components/PreLoadedMSA/fetchGeneList.d.ts +1 -0
  43. package/dist/LaunchMsaView/components/PreLoadedMSA/fetchGeneList.js +12 -0
  44. package/dist/LaunchMsaView/components/PreLoadedMSA/fetchGeneList.js.map +1 -0
  45. package/dist/LaunchMsaView/components/PreLoadedMSA/preCalculatedLaunchView.d.ts +9 -0
  46. package/dist/LaunchMsaView/components/PreLoadedMSA/preCalculatedLaunchView.js +36 -0
  47. package/dist/LaunchMsaView/components/PreLoadedMSA/preCalculatedLaunchView.js.map +1 -0
  48. package/dist/LaunchMsaView/components/TabUtils.d.ts +12 -0
  49. package/dist/LaunchMsaView/components/TabUtils.js +13 -0
  50. package/dist/LaunchMsaView/components/TabUtils.js.map +1 -0
  51. package/dist/LaunchMsaView/index.d.ts +2 -0
  52. package/dist/LaunchMsaView/index.js +50 -0
  53. package/dist/LaunchMsaView/index.js.map +1 -0
  54. package/dist/LaunchMsaView/util.d.ts +5 -0
  55. package/dist/LaunchMsaView/util.js +25 -0
  56. package/dist/LaunchMsaView/util.js.map +1 -0
  57. package/dist/MsaViewPanel/components/LoadingBLAST.d.ts +6 -0
  58. package/dist/MsaViewPanel/components/LoadingBLAST.js +36 -0
  59. package/dist/MsaViewPanel/components/LoadingBLAST.js.map +1 -0
  60. package/dist/MsaViewPanel/components/MsaViewPanel.d.ts +6 -0
  61. package/dist/MsaViewPanel/components/MsaViewPanel.js +10 -0
  62. package/dist/MsaViewPanel/components/MsaViewPanel.js.map +1 -0
  63. package/dist/MsaViewPanel/components/RIDLink.d.ts +5 -0
  64. package/dist/MsaViewPanel/components/RIDLink.js +17 -0
  65. package/dist/MsaViewPanel/components/RIDLink.js.map +1 -0
  66. package/dist/MsaViewPanel/doLaunchBlast.d.ts +7 -0
  67. package/dist/MsaViewPanel/doLaunchBlast.js +27 -0
  68. package/dist/MsaViewPanel/doLaunchBlast.js.map +1 -0
  69. package/dist/MsaViewPanel/genomeToMSA.d.ts +4 -0
  70. package/dist/MsaViewPanel/genomeToMSA.js +18 -0
  71. package/dist/MsaViewPanel/genomeToMSA.js.map +1 -0
  72. package/dist/MsaViewPanel/index.d.ts +2 -0
  73. package/dist/MsaViewPanel/index.js +16 -0
  74. package/dist/MsaViewPanel/index.js.map +1 -0
  75. package/dist/MsaViewPanel/model.d.ts +596 -0
  76. package/dist/MsaViewPanel/model.js +235 -0
  77. package/dist/MsaViewPanel/model.js.map +1 -0
  78. package/dist/MsaViewPanel/msaCoordToGenomeCoord.d.ts +9 -0
  79. package/dist/MsaViewPanel/msaCoordToGenomeCoord.js +20 -0
  80. package/dist/MsaViewPanel/msaCoordToGenomeCoord.js.map +1 -0
  81. package/dist/MsaViewPanel/util.d.ts +8 -0
  82. package/dist/MsaViewPanel/util.js +7 -0
  83. package/dist/MsaViewPanel/util.js.map +1 -0
  84. package/dist/OpenInNewIcon.d.ts +3 -0
  85. package/dist/OpenInNewIcon.js +8 -0
  86. package/dist/OpenInNewIcon.js.map +1 -0
  87. package/dist/TextField2.d.ts +4 -0
  88. package/dist/TextField2.js +8 -0
  89. package/dist/TextField2.js.map +1 -0
  90. package/dist/index.d.ts +8 -8
  91. package/dist/index.js +32 -7
  92. package/dist/index.js.map +1 -0
  93. package/dist/jbrowse-plugin-msaview.umd.production.min.js +109 -1
  94. package/dist/jbrowse-plugin-msaview.umd.production.min.js.map +7 -1
  95. package/dist/utils/fetch.d.ts +4 -0
  96. package/dist/utils/fetch.js +19 -0
  97. package/dist/utils/fetch.js.map +1 -0
  98. package/dist/utils/msa.d.ts +8 -0
  99. package/dist/utils/msa.js +75 -0
  100. package/dist/utils/msa.js.map +1 -0
  101. package/dist/utils/ncbiBlast.d.ts +20 -0
  102. package/dist/utils/ncbiBlast.js +66 -0
  103. package/dist/utils/ncbiBlast.js.map +1 -0
  104. package/package.json +51 -40
  105. package/src/AddHighlightModel/GenomeMouseoverHighlight.tsx +44 -0
  106. package/src/AddHighlightModel/HighlightComponents.tsx +24 -0
  107. package/src/AddHighlightModel/MsaToGenomeHighlight.tsx +50 -0
  108. package/src/AddHighlightModel/index.tsx +27 -0
  109. package/src/AddHighlightModel/util.ts +14 -0
  110. package/src/LaunchMsaView/components/LaunchMsaViewDialog.tsx +52 -0
  111. package/src/LaunchMsaView/components/NewNCBIBlastQuery/NcbiBlastPanel.tsx +160 -0
  112. package/src/LaunchMsaView/components/NewNCBIBlastQuery/calculateProteinSequence.ts +92 -0
  113. package/src/LaunchMsaView/components/NewNCBIBlastQuery/index.tsx +2 -0
  114. package/src/LaunchMsaView/components/NewNCBIBlastQuery/ncbiBlastLaunchView.ts +28 -0
  115. package/src/LaunchMsaView/components/NewNCBIBlastQuery/useFeatureSequence.ts +85 -0
  116. package/src/LaunchMsaView/components/NewNCBIBlastQuery/util.ts +7 -0
  117. package/src/LaunchMsaView/components/PreLoadedMSA/PreLoadedMSADataPanel.tsx +149 -0
  118. package/src/LaunchMsaView/components/PreLoadedMSA/fetchGeneList.ts +13 -0
  119. package/src/LaunchMsaView/components/PreLoadedMSA/preCalculatedLaunchView.ts +54 -0
  120. package/src/LaunchMsaView/components/TabUtils.tsx +30 -0
  121. package/src/LaunchMsaView/index.ts +61 -0
  122. package/src/LaunchMsaView/util.ts +30 -0
  123. package/src/MsaViewPanel/components/LoadingBLAST.tsx +59 -0
  124. package/src/MsaViewPanel/components/MsaViewPanel.tsx +22 -0
  125. package/src/MsaViewPanel/components/RIDLink.tsx +18 -0
  126. package/src/MsaViewPanel/doLaunchBlast.ts +38 -0
  127. package/src/MsaViewPanel/genomeToMSA.ts +21 -0
  128. package/src/MsaViewPanel/index.ts +19 -0
  129. package/src/MsaViewPanel/model.ts +290 -0
  130. package/src/MsaViewPanel/msaCoordToGenomeCoord.ts +29 -0
  131. package/src/MsaViewPanel/util.ts +13 -0
  132. package/src/OpenInNewIcon.tsx +11 -0
  133. package/src/TextField2.tsx +12 -0
  134. package/src/index.ts +12 -14
  135. package/src/utils/fetch.ts +25 -0
  136. package/src/utils/msa.ts +111 -0
  137. package/src/utils/ncbiBlast.ts +105 -0
  138. package/dist/config.json +0 -8
  139. package/dist/jbrowse-plugin-msaview.cjs.development.js +0 -168
  140. package/dist/jbrowse-plugin-msaview.cjs.development.js.map +0 -1
  141. package/dist/jbrowse-plugin-msaview.cjs.production.min.js +0 -2
  142. package/dist/jbrowse-plugin-msaview.cjs.production.min.js.map +0 -1
  143. package/dist/jbrowse-plugin-msaview.esm.js +0 -163
  144. package/dist/jbrowse-plugin-msaview.esm.js.map +0 -1
  145. package/dist/jbrowse-plugin-msaview.umd.development.js +0 -8641
  146. package/dist/jbrowse-plugin-msaview.umd.development.js.map +0 -1
  147. package/src/index.test.ts +0 -3
@@ -0,0 +1,30 @@
1
+ import { Feature } from '@jbrowse/core/util'
2
+
3
+ export function getTranscriptFeatures(feature: Feature) {
4
+ // check if we are looking at a 'two-level' or 'three-level' feature by
5
+ // finding exon/CDS subfeatures. we want to select from transcript names
6
+ const subfeatures = feature.get('subfeatures') ?? []
7
+ return subfeatures.some(f => f.get('type') === 'CDS')
8
+ ? [feature]
9
+ : // filter out non-coding by finding subfeatures with CDS subfeatures
10
+ subfeatures.filter(f =>
11
+ f.get('subfeatures')?.some(f => f.get('type') === 'CDS'),
12
+ )
13
+ }
14
+ export function getId(val?: Feature) {
15
+ return val === undefined ? '' : val.get('name') || val.get('id')
16
+ }
17
+
18
+ export function getTranscriptDisplayName(val?: Feature) {
19
+ return val === undefined
20
+ ? ''
21
+ : [val.get('name'), val.get('id')].filter(f => !!f).join(' ')
22
+ }
23
+
24
+ export function getGeneDisplayName(val?: Feature) {
25
+ return val === undefined
26
+ ? ''
27
+ : [val.get('gene_name') || val.get('name'), val.get('id')]
28
+ .filter(f => !!f)
29
+ .join(' ')
30
+ }
@@ -0,0 +1,59 @@
1
+ import React from 'react'
2
+ import { JBrowsePluginMsaViewModel } from '../model'
3
+ import { Typography } from '@mui/material'
4
+ import { observer } from 'mobx-react'
5
+ import { makeStyles } from 'tss-react/mui'
6
+ import { ErrorMessage, LoadingEllipses } from '@jbrowse/core/ui'
7
+
8
+ // locals
9
+ import RIDLink from './RIDLink'
10
+
11
+ const useStyles = makeStyles()(theme => ({
12
+ margin: {
13
+ padding: 20,
14
+ },
15
+ loading: {
16
+ background: theme.palette.background.paper,
17
+ },
18
+ }))
19
+
20
+ function RIDError({ rid, error }: { rid?: string; error: unknown }) {
21
+ return (
22
+ <div>
23
+ {rid ? <RIDLink rid={rid} /> : null}
24
+ <ErrorMessage error={error} />
25
+ </div>
26
+ )
27
+ }
28
+
29
+ function RIDProgress({ rid, progress }: { rid: string; progress: string }) {
30
+ const { classes } = useStyles()
31
+ return (
32
+ <div className={classes.loading}>
33
+ {rid ? <RIDLink rid={rid} /> : null}
34
+ <Typography>{progress}</Typography>
35
+ </div>
36
+ )
37
+ }
38
+
39
+ const LoadingBLAST = observer(function LoadingBLAST2({
40
+ model,
41
+ }: {
42
+ model: JBrowsePluginMsaViewModel
43
+ }) {
44
+ const { progress, rid, error, processing } = model
45
+ const { classes } = useStyles()
46
+ return (
47
+ <div className={classes.margin}>
48
+ <LoadingEllipses message="Running NCBI BLAST" variant="h5" />
49
+ {error ? (
50
+ <RIDError rid={rid} error={error} />
51
+ ) : rid ? (
52
+ <RIDProgress rid={rid} progress={progress} />
53
+ ) : null}
54
+ <Typography>{processing || 'Initializing BLAST query'}</Typography>
55
+ </div>
56
+ )
57
+ })
58
+
59
+ export default LoadingBLAST
@@ -0,0 +1,22 @@
1
+ import React from 'react'
2
+ import { observer } from 'mobx-react'
3
+ import { MSAView } from 'react-msaview'
4
+
5
+ // locals
6
+ import { JBrowsePluginMsaViewModel } from '../model'
7
+ import LoadingBLAST from './LoadingBLAST'
8
+
9
+ const MsaViewPanel = observer(function MsaViewPanel2({
10
+ model,
11
+ }: {
12
+ model: JBrowsePluginMsaViewModel
13
+ }) {
14
+ const { blastParams } = model
15
+ return (
16
+ <div>
17
+ {blastParams ? <LoadingBLAST model={model} /> : <MSAView model={model} />}
18
+ </div>
19
+ )
20
+ })
21
+
22
+ export default MsaViewPanel
@@ -0,0 +1,18 @@
1
+ import React from 'react'
2
+ import { Link, Typography } from '@mui/material'
3
+ // locals
4
+ import OpenInNewIcon from '../../OpenInNewIcon'
5
+ import { BLAST_URL } from '../../utils/ncbiBlast'
6
+
7
+ function RIDLink({ rid }: { rid: string }) {
8
+ return (
9
+ <Typography>
10
+ RID {rid}{' '}
11
+ <Link target="_black" href={`${BLAST_URL}?CMD=Get&RID=${rid}`}>
12
+ (see status at NCBI <OpenInNewIcon />)
13
+ </Link>
14
+ </Typography>
15
+ )
16
+ }
17
+
18
+ export default RIDLink
@@ -0,0 +1,38 @@
1
+ import { launchMSA } from '../utils/msa'
2
+ import { queryBlast } from '../utils/ncbiBlast'
3
+ import {
4
+ makeId,
5
+ strip,
6
+ } from '../LaunchMsaView/components/NewNCBIBlastQuery/util'
7
+ import { JBrowsePluginMsaViewModel } from './model'
8
+
9
+ export async function doLaunchBlast({
10
+ self,
11
+ }: {
12
+ self: JBrowsePluginMsaViewModel
13
+ }) {
14
+ const { blastDatabase, blastProgram, msaAlgorithm, proteinSequence } =
15
+ self.blastParams!
16
+ const query = proteinSequence.replaceAll('*', '').replaceAll('&', '')
17
+ const { hits } = await queryBlast({
18
+ query,
19
+ blastDatabase,
20
+ blastProgram,
21
+ onProgress: arg => self.setProgress(arg),
22
+ onRid: rid => self.setRid(rid),
23
+ })
24
+
25
+ const sequence = [
26
+ `>QUERY\n${query}`,
27
+ ...hits
28
+ .map(h => [makeId(h.description[0]), strip(h.hsps[0].hseq)] as const)
29
+ .map(([id, seq]) => `>${id}\n${seq}`),
30
+ ].join('\n')
31
+
32
+ const data = await launchMSA({
33
+ algorithm: msaAlgorithm,
34
+ sequence,
35
+ onProgress: arg => self.setProgress(arg),
36
+ })
37
+ return data
38
+ }
@@ -0,0 +1,21 @@
1
+ import { getSession } from '@jbrowse/core/util'
2
+ import { checkHovered } from './util'
3
+ import { JBrowsePluginMsaViewModel } from './model'
4
+
5
+ export function genomeToMSA({ model }: { model: JBrowsePluginMsaViewModel }) {
6
+ const { hovered } = getSession(model)
7
+ const { transcriptToMsaMap, connectedView } = model
8
+ if (
9
+ connectedView?.initialized &&
10
+ transcriptToMsaMap &&
11
+ checkHovered(hovered)
12
+ ) {
13
+ const { coord: hoverCoord } = hovered.hoverPosition
14
+ const { g2p } = transcriptToMsaMap
15
+ const ret = g2p[hoverCoord]
16
+ if (ret !== undefined) {
17
+ return model.seqCoordToRowSpecificGlobalCoord('QUERY', ret + 1)
18
+ }
19
+ }
20
+ return undefined
21
+ }
@@ -0,0 +1,19 @@
1
+ import { lazy } from 'react'
2
+ import PluginManager from '@jbrowse/core/PluginManager'
3
+ import ViewType from '@jbrowse/core/pluggableElementTypes/ViewType'
4
+
5
+ // locals
6
+ import stateModelFactory from './model'
7
+
8
+ // lazies
9
+ const MsaViewPanel = lazy(() => import('./components/MsaViewPanel'))
10
+
11
+ export default function MsaViewF(pluginManager: PluginManager) {
12
+ pluginManager.addViewType(() => {
13
+ return new ViewType({
14
+ name: 'MsaView',
15
+ stateModel: stateModelFactory(),
16
+ ReactComponent: MsaViewPanel,
17
+ })
18
+ })
19
+ }
@@ -0,0 +1,290 @@
1
+ import { Instance, addDisposer, cast, types } from 'mobx-state-tree'
2
+ import { autorun } from 'mobx'
3
+ import { MSAModelF } from 'react-msaview'
4
+ import { Feature, getSession, notEmpty } from '@jbrowse/core/util'
5
+ import { LinearGenomeViewModel } from '@jbrowse/plugin-linear-genome-view'
6
+ import { BaseViewModel } from '@jbrowse/core/pluggableElementTypes'
7
+
8
+ // locals
9
+ import { doLaunchBlast } from './doLaunchBlast'
10
+ import { genomeToMSA } from './genomeToMSA'
11
+ import { msaCoordToGenomeCoord } from './msaCoordToGenomeCoord'
12
+ import { genomeToTranscriptSeqMapping } from 'g2p_mapper'
13
+
14
+ type LGV = LinearGenomeViewModel
15
+
16
+ type MaybeLGV = LGV | undefined
17
+
18
+ export interface IRegion {
19
+ refName: string
20
+ start: number
21
+ end: number
22
+ }
23
+
24
+ export interface BlastParams {
25
+ blastDatabase: string
26
+ msaAlgorithm: string
27
+ blastProgram: string
28
+ selectedTranscript: Feature
29
+ proteinSequence: string
30
+ }
31
+
32
+ /**
33
+ * #stateModel MsaViewPlugin
34
+ * extends
35
+ * - MSAModel from https://github.com/GMOD/react-msaview
36
+ */
37
+ export default function stateModelFactory() {
38
+ return types
39
+ .compose(
40
+ BaseViewModel,
41
+ MSAModelF(),
42
+ types.model('MsaView', {
43
+ /**
44
+ * #property
45
+ */
46
+ connectedViewId: types.maybe(types.string),
47
+ /**
48
+ * #property
49
+ */
50
+ connectedFeature: types.frozen(),
51
+ /**
52
+ * #property
53
+ */
54
+ connectedHighlights: types.array(
55
+ types.model({
56
+ refName: types.string,
57
+ start: types.number,
58
+ end: types.number,
59
+ }),
60
+ ),
61
+ /**
62
+ * #property
63
+ */
64
+ blastParams: types.frozen<BlastParams | undefined>(),
65
+
66
+ /**
67
+ * #property
68
+ */
69
+ zoomToBaseLevel: false,
70
+ }),
71
+ )
72
+
73
+ .volatile(() => ({
74
+ rid: undefined as string | undefined,
75
+ progress: '',
76
+ error: undefined as unknown,
77
+ }))
78
+
79
+ .views(self => ({
80
+ /**
81
+ * #method
82
+ */
83
+ ungappedCoordMap(rowName: string, position: number) {
84
+ const row = self.rows.find(f => f[0] === rowName)
85
+ const seq = row?.[1]
86
+ if (seq && position < seq.length) {
87
+ let i = 0
88
+ let j = 0
89
+ for (; j < position; j++, i++) {
90
+ while (seq[i] === '-') {
91
+ i++
92
+ }
93
+ }
94
+ return i
95
+ }
96
+ return undefined
97
+ },
98
+ }))
99
+ .views(self => ({
100
+ /**
101
+ * #getter
102
+ */
103
+ get transcriptToMsaMap() {
104
+ console.log(self.connectedFeature)
105
+ return self.connectedFeature
106
+ ? genomeToTranscriptSeqMapping(self.connectedFeature)
107
+ : undefined
108
+ },
109
+ }))
110
+ .views(self => ({
111
+ /**
112
+ * #getter
113
+ */
114
+ get mouseCol2(): number | undefined {
115
+ return genomeToMSA({ model: self as JBrowsePluginMsaViewModel })
116
+ },
117
+ /**
118
+ * #getter
119
+ */
120
+ get clickCol2() {
121
+ return undefined
122
+ },
123
+ }))
124
+
125
+ .views(self => ({
126
+ /**
127
+ * #getter
128
+ */
129
+ get processing() {
130
+ return !!self.progress
131
+ },
132
+
133
+ /**
134
+ * #getter
135
+ */
136
+ get connectedView() {
137
+ const { views } = getSession(self)
138
+ return views.find(f => f.id === self.connectedViewId) as MaybeLGV
139
+ },
140
+ }))
141
+ .actions(self => ({
142
+ /**
143
+ * #action
144
+ */
145
+ setZoomToBaseLevel(arg: boolean) {
146
+ self.zoomToBaseLevel = arg
147
+ },
148
+ /**
149
+ * #action
150
+ */
151
+ setError(e: unknown) {
152
+ self.error = e
153
+ },
154
+ /**
155
+ * #action
156
+ */
157
+ setProgress(arg: string) {
158
+ self.progress = arg
159
+ },
160
+ /**
161
+ * #action
162
+ */
163
+ setRid(arg: string) {
164
+ self.rid = arg
165
+ },
166
+ /**
167
+ * #action
168
+ */
169
+ setConnectedHighlights(r: IRegion[]) {
170
+ self.connectedHighlights = cast(r)
171
+ },
172
+ /**
173
+ * #action
174
+ */
175
+ addToConnectedHighlights(r: IRegion) {
176
+ self.connectedHighlights.push(r)
177
+ },
178
+ /**
179
+ * #action
180
+ */
181
+ clearConnectedHighlights() {
182
+ self.connectedHighlights = cast([])
183
+ },
184
+ /**
185
+ * #action
186
+ */
187
+ setBlastParams(args?: BlastParams) {
188
+ self.blastParams = args
189
+ },
190
+ }))
191
+
192
+ .views(self => ({
193
+ /**
194
+ * #method
195
+ * overrides base
196
+ */
197
+ extraViewMenuItems() {
198
+ return [
199
+ {
200
+ label: 'Zoom to base level on click?',
201
+ checked: self.zoomToBaseLevel,
202
+ type: 'checkbox',
203
+ onClick: () => self.setZoomToBaseLevel(!self.zoomToBaseLevel),
204
+ },
205
+ ]
206
+ },
207
+ /**
208
+ * #getter
209
+ */
210
+ get processing() {
211
+ return !!self.progress
212
+ },
213
+
214
+ /**
215
+ * #getter
216
+ */
217
+ get connectedView() {
218
+ const { views } = getSession(self)
219
+ return views.find(f => f.id === self.connectedViewId) as MaybeLGV
220
+ },
221
+ }))
222
+
223
+ .actions(self => ({
224
+ afterCreate() {
225
+ addDisposer(
226
+ self,
227
+ autorun(async () => {
228
+ if (self.blastParams) {
229
+ self.setProgress('Submitting query')
230
+ const data = await doLaunchBlast({
231
+ self: self as JBrowsePluginMsaViewModel,
232
+ })
233
+ self.setData(data)
234
+ self.setBlastParams(undefined)
235
+ self.setProgress('')
236
+ }
237
+ }),
238
+ )
239
+
240
+ // this adds highlights to the genome view when mouse-ing over the MSA
241
+ addDisposer(
242
+ self,
243
+ autorun(() => {
244
+ const { mouseCol, mouseClickCol } = self
245
+ const r1 =
246
+ mouseCol !== undefined
247
+ ? msaCoordToGenomeCoord({ model: self, coord: mouseCol })
248
+ : undefined
249
+ const r2 =
250
+ mouseClickCol !== undefined
251
+ ? msaCoordToGenomeCoord({ model: self, coord: mouseClickCol })
252
+ : undefined
253
+ self.setConnectedHighlights([r1, r2].filter(notEmpty))
254
+ }),
255
+ )
256
+
257
+ // nav to genome position after click
258
+ addDisposer(
259
+ self,
260
+ autorun(() => {
261
+ const { connectedView, zoomToBaseLevel, mouseClickCol } = self
262
+ const { assemblyManager } = getSession(self)
263
+ const r2 =
264
+ mouseClickCol !== undefined
265
+ ? msaCoordToGenomeCoord({ model: self, coord: mouseClickCol })
266
+ : undefined
267
+
268
+ if (!r2 || !connectedView) {
269
+ return
270
+ }
271
+
272
+ if (zoomToBaseLevel) {
273
+ connectedView.navTo(r2)
274
+ } else {
275
+ const r =
276
+ assemblyManager
277
+ .get(connectedView.assemblyNames[0])
278
+ ?.getCanonicalRefName(r2.refName) ?? r2.refName
279
+ connectedView.centerAt(r2.start, r)
280
+ }
281
+ }),
282
+ )
283
+ },
284
+ }))
285
+ }
286
+
287
+ export type JBrowsePluginMsaViewStateModel = ReturnType<
288
+ typeof stateModelFactory
289
+ >
290
+ export type JBrowsePluginMsaViewModel = Instance<JBrowsePluginMsaViewStateModel>
@@ -0,0 +1,29 @@
1
+ // locals
2
+ import { JBrowsePluginMsaViewModel } from './model'
3
+
4
+ export function msaCoordToGenomeCoord({
5
+ model,
6
+ coord: mouseCol,
7
+ }: {
8
+ model: JBrowsePluginMsaViewModel
9
+ coord: number
10
+ }) {
11
+ const { transcriptToMsaMap } = model
12
+ if (mouseCol === undefined || transcriptToMsaMap === undefined) {
13
+ return
14
+ }
15
+
16
+ const c = mouseCol - 1
17
+ const k1 = model.globalCoordToRowSpecificSeqCoord('QUERY', c) || 0
18
+ const k2 = model.globalCoordToRowSpecificSeqCoord('QUERY', c + 1) || 0
19
+ const { refName, p2g } = transcriptToMsaMap
20
+ const s = p2g[k1]
21
+ const e = p2g[k2]
22
+ return s !== undefined && e !== undefined
23
+ ? {
24
+ refName,
25
+ start: Math.min(s, e),
26
+ end: Math.max(s, e),
27
+ }
28
+ : undefined
29
+ }
@@ -0,0 +1,13 @@
1
+ import { Feature } from '@jbrowse/core/util'
2
+
3
+ export function checkHovered(hovered: unknown): hovered is {
4
+ hoverFeature: Feature
5
+ hoverPosition: { coord: number; refName: string }
6
+ } {
7
+ return (
8
+ !!hovered &&
9
+ typeof hovered == 'object' &&
10
+ 'hoverFeature' in hovered &&
11
+ 'hoverPosition' in hovered
12
+ )
13
+ }
@@ -0,0 +1,11 @@
1
+ import React from 'react'
2
+ import { SvgIcon, SvgIconProps } from '@mui/material'
3
+
4
+ export default function OpenInNewIcon(props: SvgIconProps) {
5
+ return (
6
+ <SvgIcon {...props}>
7
+ <path d="M0 0h24v24H0z" fill="none" />
8
+ <path d="M19 19H5V5h7V3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2v-7h-2v7zM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7z" />
9
+ </SvgIcon>
10
+ )
11
+ }
@@ -0,0 +1,12 @@
1
+ import React from 'react'
2
+ import { TextField, TextFieldProps } from '@mui/material'
3
+
4
+ function TextField2({ children, ...rest }: TextFieldProps) {
5
+ return (
6
+ <div>
7
+ <TextField {...rest}>{children}</TextField>
8
+ </div>
9
+ )
10
+ }
11
+
12
+ export default TextField2
package/src/index.ts CHANGED
@@ -1,26 +1,24 @@
1
1
  import Plugin from '@jbrowse/core/Plugin'
2
2
  import PluginManager from '@jbrowse/core/PluginManager'
3
- import { version } from '../package.json'
4
3
  import { AbstractSessionModel, isAbstractMenuManager } from '@jbrowse/core/util'
5
- import * as MSA from 'react-msaview'
6
- import ViewType from '@jbrowse/core/pluggableElementTypes/ViewType'
7
- import GridOn from '@material-ui/icons/GridOn'
4
+
5
+ // icons
6
+ import GridOn from '@mui/icons-material/GridOn'
7
+
8
+ // locals
9
+ import { version } from '../package.json'
10
+ import MsaViewF from './MsaViewPanel'
11
+ import LaunchMsaViewF from './LaunchMsaView'
12
+ import AddHighlightModelF from './AddHighlightModel'
8
13
 
9
14
  export default class MsaViewPlugin extends Plugin {
10
15
  name = 'MsaViewPlugin'
11
16
  version = version
12
17
 
13
18
  install(pluginManager: PluginManager) {
14
- console.log({ MSA })
15
- pluginManager.addViewType(
16
- () =>
17
- new ViewType({
18
- name: 'MsaView',
19
- //@ts-ignore
20
- stateModel: MSA.MSAModel,
21
- ReactComponent: MSA.MSAView,
22
- }),
23
- )
19
+ MsaViewF(pluginManager)
20
+ LaunchMsaViewF(pluginManager)
21
+ AddHighlightModelF(pluginManager)
24
22
  }
25
23
 
26
24
  configure(pluginManager: PluginManager) {
@@ -0,0 +1,25 @@
1
+ export async function myfetch(url: string, args?: RequestInit) {
2
+ const response = await fetch(url, args)
3
+
4
+ if (!response.ok) {
5
+ throw new Error(
6
+ `HTTP ${response.status} fetching ${url} ${await response.text()}`,
7
+ )
8
+ }
9
+
10
+ return response
11
+ }
12
+
13
+ export async function textfetch(url: string, args?: RequestInit) {
14
+ const response = await myfetch(url, args)
15
+ return response.text()
16
+ }
17
+
18
+ export async function jsonfetch(url: string, args?: RequestInit) {
19
+ const response = await myfetch(url, args)
20
+ return response.json()
21
+ }
22
+
23
+ export function timeout(time: number) {
24
+ return new Promise(res => setTimeout(res, time))
25
+ }