react-msaview 3.1.12 → 3.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 (186) hide show
  1. package/bundle/index.js +32 -31
  2. package/dist/colorSchemes.d.ts +2 -2
  3. package/dist/colorSchemes.js +3 -4
  4. package/dist/colorSchemes.js.map +1 -1
  5. package/dist/components/Loading.d.ts +1 -1
  6. package/dist/components/Loading.js +4 -4
  7. package/dist/components/Loading.js.map +1 -1
  8. package/dist/components/MSAView.d.ts +1 -1
  9. package/dist/components/MSAView.js +13 -9
  10. package/dist/components/MSAView.js.map +1 -1
  11. package/dist/components/ResizeHandles.d.ts +1 -1
  12. package/dist/components/ResizeHandles.js +2 -2
  13. package/dist/components/TextTrack.d.ts +1 -1
  14. package/dist/components/Track.d.ts +1 -1
  15. package/dist/components/VerticalScrollbar.d.ts +6 -0
  16. package/dist/components/VerticalScrollbar.js +65 -0
  17. package/dist/components/VerticalScrollbar.js.map +1 -0
  18. package/dist/components/dialogs/AddTrackDialog.d.ts +1 -1
  19. package/dist/components/dialogs/DomainDialog.d.ts +1 -1
  20. package/dist/components/dialogs/DomainDialog.js +2 -2
  21. package/dist/components/dialogs/DomainDialog.js.map +1 -1
  22. package/dist/components/dialogs/ExportSVGDialog.d.ts +1 -1
  23. package/dist/components/dialogs/FeatureDialog.d.ts +1 -1
  24. package/dist/components/dialogs/FeatureDialog.js.map +1 -1
  25. package/dist/components/dialogs/{InterProScanPanel.d.ts → InterProScanDialog.d.ts} +1 -1
  26. package/dist/components/dialogs/{InterProScanPanel.js → InterProScanDialog.js} +4 -3
  27. package/dist/components/dialogs/InterProScanDialog.js.map +1 -0
  28. package/dist/components/dialogs/MetadataDialog.d.ts +1 -1
  29. package/dist/components/dialogs/SettingsDialog.d.ts +1 -1
  30. package/dist/components/dialogs/SettingsDialog.js +10 -1
  31. package/dist/components/dialogs/SettingsDialog.js.map +1 -1
  32. package/dist/components/dialogs/TracklistDialog.d.ts +1 -1
  33. package/dist/components/dialogs/UserProvidedDomainsDialog.d.ts +7 -0
  34. package/dist/components/dialogs/UserProvidedDomainsDialog.js +58 -0
  35. package/dist/components/dialogs/UserProvidedDomainsDialog.js.map +1 -0
  36. package/dist/components/header/Header.d.ts +1 -1
  37. package/dist/components/header/Header.js +8 -3
  38. package/dist/components/header/Header.js.map +1 -1
  39. package/dist/components/header/HeaderInfoArea.d.ts +1 -1
  40. package/dist/components/header/HeaderMenu.d.ts +1 -1
  41. package/dist/components/header/HeaderMenuExtra.d.ts +1 -1
  42. package/dist/components/header/HeaderMenuExtra.js +30 -28
  43. package/dist/components/header/HeaderMenuExtra.js.map +1 -1
  44. package/dist/components/header/HeaderStatusArea.d.ts +2 -2
  45. package/dist/components/header/HeaderStatusArea.js +1 -1
  46. package/dist/components/header/HeaderStatusArea.js.map +1 -1
  47. package/dist/components/header/MultiAlignmentSelector.d.ts +1 -1
  48. package/dist/components/header/ZoomControls.js +31 -1
  49. package/dist/components/header/ZoomControls.js.map +1 -1
  50. package/dist/components/import/ImportForm.d.ts +1 -1
  51. package/dist/components/import/ImportForm.js +1 -1
  52. package/dist/components/import/ImportForm.js.map +1 -1
  53. package/dist/components/import/ImportFormExamples.d.ts +1 -1
  54. package/dist/components/import/ImportFormExamples.js +10 -8
  55. package/dist/components/import/ImportFormExamples.js.map +1 -1
  56. package/dist/components/import/util.d.ts +2 -2
  57. package/dist/components/minimap/Minimap.d.ts +1 -1
  58. package/dist/components/minimap/Minimap.js +14 -15
  59. package/dist/components/minimap/Minimap.js.map +1 -1
  60. package/dist/components/minimap/MinimapSVG.d.ts +1 -1
  61. package/dist/components/minimap/MinimapSVG.js +1 -1
  62. package/dist/components/minimap/MinimapSVG.js.map +1 -1
  63. package/dist/components/msa/MSACanvas.d.ts +1 -1
  64. package/dist/components/msa/MSACanvas.js +3 -3
  65. package/dist/components/msa/MSACanvas.js.map +1 -1
  66. package/dist/components/msa/MSACanvasBlock.d.ts +3 -3
  67. package/dist/components/msa/MSACanvasBlock.js +4 -3
  68. package/dist/components/msa/MSACanvasBlock.js.map +1 -1
  69. package/dist/components/msa/MSAMouseoverCanvas.d.ts +2 -2
  70. package/dist/components/msa/MSAMouseoverCanvas.js +1 -1
  71. package/dist/components/msa/MSAMouseoverCanvas.js.map +1 -1
  72. package/dist/components/msa/MSAPanel.d.ts +1 -1
  73. package/dist/components/msa/renderBoxFeatureCanvasBlock.d.ts +1 -1
  74. package/dist/components/msa/renderBoxFeatureCanvasBlock.js +1 -2
  75. package/dist/components/msa/renderBoxFeatureCanvasBlock.js.map +1 -1
  76. package/dist/components/msa/renderMSABlock.d.ts +2 -2
  77. package/dist/components/msa/renderMSABlock.js +12 -12
  78. package/dist/components/msa/renderMSABlock.js.map +1 -1
  79. package/dist/components/msa/renderMSAMouseover.d.ts +1 -1
  80. package/dist/components/tree/TreeBranchMenu.d.ts +1 -1
  81. package/dist/components/tree/TreeCanvas.d.ts +1 -1
  82. package/dist/components/tree/TreeCanvas.js +13 -12
  83. package/dist/components/tree/TreeCanvas.js.map +1 -1
  84. package/dist/components/tree/TreeCanvasBlock.d.ts +1 -1
  85. package/dist/components/tree/TreeCanvasBlock.js +2 -1
  86. package/dist/components/tree/TreeCanvasBlock.js.map +1 -1
  87. package/dist/components/tree/TreeNodeMenu.d.ts +1 -1
  88. package/dist/components/tree/TreeNodeMenu.js +2 -2
  89. package/dist/components/tree/TreeNodeMenu.js.map +1 -1
  90. package/dist/components/tree/TreePanel.d.ts +1 -1
  91. package/dist/components/tree/TreeRuler.d.ts +1 -1
  92. package/dist/components/tree/dialogs/TreeNodeInfoDialog.d.ts +1 -1
  93. package/dist/components/tree/renderTreeCanvas.d.ts +3 -3
  94. package/dist/components/tree/renderTreeCanvas.js +25 -9
  95. package/dist/components/tree/renderTreeCanvas.js.map +1 -1
  96. package/dist/components/util.js +1 -1
  97. package/dist/components/util.js.map +1 -1
  98. package/dist/launchInterProScan.d.ts +1 -1
  99. package/dist/launchInterProScan.js +7 -9
  100. package/dist/launchInterProScan.js.map +1 -1
  101. package/dist/model/DataModel.d.ts +5 -1
  102. package/dist/model/DataModel.js +10 -1
  103. package/dist/model/DataModel.js.map +1 -1
  104. package/dist/model/DialogQueue.d.ts +1 -1
  105. package/dist/model.d.ts +141 -24
  106. package/dist/model.js +236 -50
  107. package/dist/model.js.map +1 -1
  108. package/dist/parseNewick.js +1 -1
  109. package/dist/parseNewick.js.map +1 -1
  110. package/dist/parsers/ClustalMSA.d.ts +1 -1
  111. package/dist/parsers/FastaMSA.d.ts +1 -1
  112. package/dist/parsers/StockholmMSA.d.ts +1 -1
  113. package/dist/parsers/StockholmMSA.js.map +1 -1
  114. package/dist/renderToSvg.d.ts +2 -2
  115. package/dist/renderToSvg.js +3 -5
  116. package/dist/renderToSvg.js.map +1 -1
  117. package/dist/reparseTree.d.ts +1 -1
  118. package/dist/util.d.ts +2 -2
  119. package/dist/util.js +0 -2
  120. package/dist/util.js.map +1 -1
  121. package/dist/version.d.ts +1 -1
  122. package/dist/version.js +1 -1
  123. package/dist/version.js.map +1 -1
  124. package/package.json +5 -2
  125. package/src/colorSchemes.ts +3 -2
  126. package/src/components/Checkbox2.tsx +1 -1
  127. package/src/components/Loading.tsx +11 -5
  128. package/src/components/MSAView.tsx +27 -18
  129. package/src/components/ResizeHandles.tsx +3 -3
  130. package/src/components/TextTrack.tsx +1 -1
  131. package/src/components/Track.tsx +1 -1
  132. package/src/components/VerticalScrollbar.tsx +85 -0
  133. package/src/components/dialogs/AddTrackDialog.tsx +2 -2
  134. package/src/components/dialogs/DomainDialog.tsx +3 -3
  135. package/src/components/dialogs/ExportSVGDialog.tsx +1 -1
  136. package/src/components/dialogs/FeatureDialog.tsx +3 -3
  137. package/src/components/dialogs/{InterProScanPanel.tsx → InterProScanDialog.tsx} +11 -4
  138. package/src/components/dialogs/MetadataDialog.tsx +1 -1
  139. package/src/components/dialogs/SettingsDialog.tsx +38 -3
  140. package/src/components/dialogs/TracklistDialog.tsx +1 -1
  141. package/src/components/dialogs/UserProvidedDomainsDialog.tsx +133 -0
  142. package/src/components/header/Header.tsx +9 -4
  143. package/src/components/header/HeaderInfoArea.tsx +1 -1
  144. package/src/components/header/HeaderMenu.tsx +1 -1
  145. package/src/components/header/HeaderMenuExtra.tsx +36 -32
  146. package/src/components/header/HeaderStatusArea.tsx +2 -6
  147. package/src/components/header/MultiAlignmentSelector.tsx +1 -1
  148. package/src/components/header/ZoomControls.tsx +34 -0
  149. package/src/components/import/ImportForm.tsx +3 -3
  150. package/src/components/import/ImportFormExamples.tsx +19 -17
  151. package/src/components/import/util.ts +2 -2
  152. package/src/components/minimap/Minimap.tsx +15 -22
  153. package/src/components/minimap/MinimapSVG.tsx +2 -2
  154. package/src/components/msa/MSACanvas.tsx +11 -4
  155. package/src/components/msa/MSACanvasBlock.tsx +5 -4
  156. package/src/components/msa/MSAMouseoverCanvas.tsx +2 -6
  157. package/src/components/msa/MSAPanel.tsx +1 -1
  158. package/src/components/msa/renderBoxFeatureCanvasBlock.ts +4 -5
  159. package/src/components/msa/renderMSABlock.ts +37 -17
  160. package/src/components/msa/renderMSAMouseover.ts +1 -1
  161. package/src/components/tree/TreeBranchMenu.tsx +1 -1
  162. package/src/components/tree/TreeCanvas.tsx +15 -16
  163. package/src/components/tree/TreeCanvasBlock.tsx +3 -2
  164. package/src/components/tree/TreeNodeMenu.tsx +3 -3
  165. package/src/components/tree/TreePanel.tsx +1 -1
  166. package/src/components/tree/TreeRuler.tsx +1 -1
  167. package/src/components/tree/dialogs/TreeNodeInfoDialog.tsx +1 -1
  168. package/src/components/tree/renderTreeCanvas.ts +32 -12
  169. package/src/components/util.ts +1 -1
  170. package/src/launchInterProScan.ts +8 -10
  171. package/src/model/DataModel.ts +10 -0
  172. package/src/model/DialogQueue.ts +1 -1
  173. package/src/model.ts +262 -62
  174. package/src/parseNewick.ts +1 -1
  175. package/src/parsers/ClustalMSA.ts +1 -1
  176. package/src/parsers/FastaMSA.ts +1 -1
  177. package/src/parsers/StockholmMSA.ts +1 -1
  178. package/src/renderToSvg.tsx +6 -6
  179. package/src/reparseTree.ts +1 -1
  180. package/src/util.ts +2 -4
  181. package/src/version.ts +1 -1
  182. package/dist/components/dialogs/InterProScanPanel.js.map +0 -1
  183. package/dist/components/dialogs/UserProvidedResultPanel.d.ts +0 -7
  184. package/dist/components/dialogs/UserProvidedResultPanel.js +0 -56
  185. package/dist/components/dialogs/UserProvidedResultPanel.js.map +0 -1
  186. package/src/components/dialogs/UserProvidedResultPanel.tsx +0 -119
@@ -12,7 +12,7 @@ import {
12
12
  Typography,
13
13
  } from '@mui/material'
14
14
 
15
- import { MsaViewModel } from '../../model'
15
+ import type { MsaViewModel } from '../../model'
16
16
  import colorSchemes from '../../colorSchemes'
17
17
  import Checkbox2 from '../Checkbox2'
18
18
 
@@ -115,17 +115,40 @@ const MSASettings = observer(function MSASettings({
115
115
  model: MsaViewModel
116
116
  }) {
117
117
  const { classes } = useStyles()
118
- const { bgColor, colWidth, colorSchemeName, rowHeight } = model
118
+ const {
119
+ bgColor,
120
+ contrastLettering,
121
+ colWidth,
122
+ allowedGappyness,
123
+ drawMsaLetters,
124
+ colorSchemeName,
125
+ hideGaps,
126
+ rowHeight,
127
+ } = model
119
128
 
120
129
  return (
121
130
  <div>
122
131
  <h1>MSA options</h1>
123
-
132
+ <Checkbox2
133
+ checked={drawMsaLetters}
134
+ onChange={() => model.setDrawMsaLetters(!drawMsaLetters)}
135
+ label="Draw letters"
136
+ />
124
137
  <Checkbox2
125
138
  checked={bgColor}
126
139
  onChange={() => model.setBgColor(!bgColor)}
127
140
  label="Color background tiles of MSA?"
128
141
  />
142
+ <Checkbox2
143
+ checked={contrastLettering}
144
+ onChange={() => model.setContrastLettering(!contrastLettering)}
145
+ label="Use contrast lettering"
146
+ />
147
+ <Checkbox2
148
+ checked={hideGaps}
149
+ onChange={() => model.setHideGaps(!hideGaps)}
150
+ label={`Hide columns that are ${100 - allowedGappyness}% gaps`}
151
+ />
129
152
 
130
153
  <div className={classes.flex}>
131
154
  <Typography>Column width ({colWidth}px)</Typography>
@@ -147,6 +170,18 @@ const MSASettings = observer(function MSASettings({
147
170
  onChange={(_, val) => model.setRowHeight(val as number)}
148
171
  />
149
172
  </div>
173
+ {hideGaps ? (
174
+ <div className={classes.flex}>
175
+ <Typography>Allowed gappyness ({100 - allowedGappyness}%)</Typography>
176
+ <Slider
177
+ className={classes.field}
178
+ min={1}
179
+ max={100}
180
+ value={allowedGappyness}
181
+ onChange={(_, val) => model.setAllowedGappyness(val as number)}
182
+ />
183
+ </div>
184
+ ) : null}
150
185
 
151
186
  <TextField
152
187
  select
@@ -12,7 +12,7 @@ import {
12
12
  import { observer } from 'mobx-react'
13
13
 
14
14
  // locals
15
- import { MsaViewModel } from '../../model'
15
+ import type { MsaViewModel } from '../../model'
16
16
 
17
17
  export default observer(function ({
18
18
  model,
@@ -0,0 +1,133 @@
1
+ import React, { useState } from 'react'
2
+ import { observer } from 'mobx-react'
3
+ import {
4
+ Button,
5
+ DialogActions,
6
+ DialogContent,
7
+ FormControlLabel,
8
+ FormControl,
9
+ Radio,
10
+ RadioGroup,
11
+ TextField,
12
+ Typography,
13
+ } from '@mui/material'
14
+ import { getSession } from '@jbrowse/core/util'
15
+ import { Dialog } from '@jbrowse/core/ui'
16
+
17
+ // locals
18
+ import type { MsaViewModel } from '../../model'
19
+ import { jsonfetch } from '../../fetchUtils'
20
+ import type { InterProScanResponse } from '../../launchInterProScan'
21
+
22
+ const UserProvidedDomainsDialog = observer(function ({
23
+ handleClose,
24
+ model,
25
+ }: {
26
+ handleClose: () => void
27
+ model: MsaViewModel
28
+ }) {
29
+ const [file, setFile] = useState<File>()
30
+ const [choice, setChoice] = useState('file')
31
+ const [interProURL, setInterProURL] = useState('')
32
+
33
+ return (
34
+ <Dialog
35
+ maxWidth="xl"
36
+ title="Open protein domains from file"
37
+ onClose={() => handleClose()}
38
+ open
39
+ >
40
+ <DialogContent>
41
+ <div>
42
+ <Typography>
43
+ Open a JSON file of InterProScan results that you run remotely on
44
+ EBI servers or locally
45
+ </Typography>
46
+
47
+ <div style={{ display: 'flex', margin: 30 }}>
48
+ <FormControl component="fieldset">
49
+ <RadioGroup
50
+ value={choice}
51
+ onChange={event => setChoice(event.target.value)}
52
+ >
53
+ <FormControlLabel value="url" control={<Radio />} label="URL" />
54
+ <FormControlLabel
55
+ value="file"
56
+ control={<Radio />}
57
+ label="File"
58
+ />
59
+ </RadioGroup>
60
+ </FormControl>
61
+ {choice === 'url' ? (
62
+ <div>
63
+ <Typography>
64
+ Open a InterProScan JSON file remote URL
65
+ </Typography>
66
+ <TextField
67
+ label="URL"
68
+ value={interProURL}
69
+ onChange={event => setInterProURL(event.target.value)}
70
+ />
71
+ </div>
72
+ ) : null}
73
+ {choice === 'file' ? (
74
+ <div style={{ paddingTop: 20 }}>
75
+ <Typography>
76
+ Open a InterProScan JSON file file from your local drive
77
+ </Typography>
78
+ <Button variant="outlined" component="label">
79
+ Choose File
80
+ <input
81
+ type="file"
82
+ hidden
83
+ onChange={({ target }) => {
84
+ const file = target?.files?.[0]
85
+ if (file) {
86
+ setFile(file)
87
+ }
88
+ }}
89
+ />
90
+ </Button>
91
+ </div>
92
+ ) : null}
93
+ </div>
94
+ </div>
95
+ </DialogContent>
96
+ <DialogActions>
97
+ <Button
98
+ variant="contained"
99
+ color="primary"
100
+ onClick={() => {
101
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
102
+ ;(async () => {
103
+ try {
104
+ const ret: InterProScanResponse = file
105
+ ? JSON.parse(await file.text())
106
+ : await jsonfetch(interProURL)
107
+
108
+ model.setInterProAnnotations(
109
+ Object.fromEntries(ret.results.map(r => [r.xref[0].id, r])),
110
+ )
111
+ model.setShowDomains(true)
112
+ getSession(model).notify(
113
+ 'Loaded interproscan results',
114
+ 'success',
115
+ )
116
+ } catch (e) {
117
+ console.error(e)
118
+ getSession(model).notifyError(`${e}`, e)
119
+ } finally {
120
+ model.setStatus()
121
+ }
122
+ })()
123
+ handleClose()
124
+ }}
125
+ >
126
+ Open results
127
+ </Button>
128
+ </DialogActions>
129
+ </Dialog>
130
+ )
131
+ })
132
+
133
+ export default UserProvidedDomainsDialog
@@ -1,9 +1,10 @@
1
- import React, { lazy } from 'react'
1
+ import React, { lazy, useEffect } from 'react'
2
2
  import { IconButton } from '@mui/material'
3
3
  import { observer } from 'mobx-react'
4
+ import useMeasure from '@jbrowse/core/util/useMeasure'
4
5
 
5
6
  // locals
6
- import { MsaViewModel } from '../../model'
7
+ import type { MsaViewModel } from '../../model'
7
8
 
8
9
  // icons
9
10
  import Help from '@mui/icons-material/Help'
@@ -18,10 +19,14 @@ import HeaderMenuExtra from './HeaderMenuExtra'
18
19
  const AboutDialog = lazy(() => import('../dialogs/AboutDialog'))
19
20
 
20
21
  const Header = observer(function ({ model }: { model: MsaViewModel }) {
22
+ const [ref, { height }] = useMeasure()
23
+ useEffect(() => {
24
+ model.setHeaderHeight(height || 0)
25
+ }, [model, height])
21
26
  return (
22
- <div style={{ display: 'flex' }}>
23
- <ZoomControls model={model} />
27
+ <div ref={ref} style={{ display: 'flex' }}>
24
28
  <HeaderMenuExtra model={model} />
29
+ <ZoomControls model={model} />
25
30
  <MultiAlignmentSelector model={model} />
26
31
  <HeaderInfoArea model={model} />
27
32
  <Spacer />
@@ -4,7 +4,7 @@ import { observer } from 'mobx-react'
4
4
  import { makeStyles } from 'tss-react/mui'
5
5
 
6
6
  // locals
7
- import { MsaViewModel } from '../../model'
7
+ import type { MsaViewModel } from '../../model'
8
8
 
9
9
  const useStyles = makeStyles()({
10
10
  margin: {
@@ -10,7 +10,7 @@ import List from '@mui/icons-material/List'
10
10
  import Menu from '@mui/icons-material/Menu'
11
11
 
12
12
  // locals
13
- import { MsaViewModel } from '../../model'
13
+ import type { MsaViewModel } from '../../model'
14
14
 
15
15
  // lazies
16
16
  const SettingsDialog = lazy(() => import('../dialogs/SettingsDialog'))
@@ -2,23 +2,20 @@ import React, { lazy } from 'react'
2
2
  import { observer } from 'mobx-react'
3
3
  import CascadingMenuButton from '@jbrowse/core/ui/CascadingMenuButton'
4
4
 
5
- // locals
6
-
7
5
  // icons
8
- import MoreVert from '@mui/icons-material/MoreVert'
6
+ import MoreVert from '@mui/icons-material/Menu'
9
7
  import Sort from '@mui/icons-material/Sort'
10
8
  import Visibility from '@mui/icons-material/Visibility'
11
9
  import FilterAlt from '@mui/icons-material/FilterAlt'
12
10
  import Search from '@mui/icons-material/Search'
13
11
  import PhotoCamera from '@mui/icons-material/PhotoCamera'
14
- import RestartAlt from '@mui/icons-material/RestartAlt'
15
- import FolderOpen from '@mui/icons-material/FolderOpen'
16
12
  import Settings from '@mui/icons-material/Settings'
17
13
  import Assignment from '@mui/icons-material/Assignment'
18
14
  import List from '@mui/icons-material/List'
15
+ import FolderOpen from '@mui/icons-material/FolderOpen'
19
16
 
20
17
  // locals
21
- import { MsaViewModel } from '../../model'
18
+ import type { MsaViewModel } from '../../model'
22
19
 
23
20
  // lazies
24
21
  const SettingsDialog = lazy(() => import('../dialogs/SettingsDialog'))
@@ -26,10 +23,13 @@ const MetadataDialog = lazy(() => import('../dialogs/MetadataDialog'))
26
23
  const TracklistDialog = lazy(() => import('../dialogs/TracklistDialog'))
27
24
  const ExportSVGDialog = lazy(() => import('../dialogs/ExportSVGDialog'))
28
25
  const FeatureFilterDialog = lazy(() => import('../dialogs/FeatureDialog'))
29
- const DomainDialog = lazy(() => import('../dialogs/DomainDialog'))
26
+ const UserProvidedDomainsDialog = lazy(
27
+ () => import('../dialogs/UserProvidedDomainsDialog'),
28
+ )
29
+ const InterProScanDialog = lazy(() => import('../dialogs/InterProScanDialog'))
30
30
 
31
- const HeaderMenuExtra = observer(function ({ model }: { model: MsaViewModel }) {
32
- const { showDomains, subFeatureRows, noAnnotations } = model
31
+ const HeaderMenuExtra = observer(({ model }: { model: MsaViewModel }) => {
32
+ const { showDomains, actuallyShowDomains, subFeatureRows, noDomains } = model
33
33
  return (
34
34
  <CascadingMenuButton
35
35
  menuItems={[
@@ -56,14 +56,7 @@ const HeaderMenuExtra = observer(function ({ model }: { model: MsaViewModel }) {
56
56
  model.queueDialog(onClose => [TracklistDialog, { model, onClose }]),
57
57
  icon: List,
58
58
  },
59
- {
60
- label: 'Reset zoom to default',
61
- icon: RestartAlt,
62
- onClick: () => {
63
- model.setColWidth(16)
64
- model.setRowHeight(20)
65
- },
66
- },
59
+
67
60
  {
68
61
  label: 'Export SVG',
69
62
  icon: PhotoCamera,
@@ -75,23 +68,43 @@ const HeaderMenuExtra = observer(function ({ model }: { model: MsaViewModel }) {
75
68
  type: 'subMenu',
76
69
  subMenu: [
77
70
  {
78
- label:
79
- 'Show domains' + (noAnnotations ? ' (no domains loaded)' : ''),
71
+ label: 'Open domains...',
72
+ icon: FolderOpen,
73
+ onClick: () =>
74
+ model.queueDialog(handleClose => [
75
+ UserProvidedDomainsDialog,
76
+ { handleClose, model },
77
+ ]),
78
+ },
79
+ {
80
+ label: 'Query InterProScan for domains...',
81
+ icon: Search,
82
+ onClick: () =>
83
+ model.queueDialog(handleClose => [
84
+ InterProScanDialog,
85
+ { handleClose, model },
86
+ ]),
87
+ },
88
+ {
89
+ label: `Show domains${noDomains ? ' (no domains loaded)' : ''}`,
90
+ disabled: noDomains,
80
91
  icon: Visibility,
81
- checked: showDomains,
92
+ checked: actuallyShowDomains ? showDomains : false,
82
93
  type: 'checkbox',
83
94
  onClick: () => model.setShowDomains(!showDomains),
84
95
  },
85
96
  {
86
- label: 'Use sub-row layout',
87
- checked: subFeatureRows,
97
+ label: `Use sub-row layout${noDomains ? ' (no domains loaded)' : ''}`,
98
+ disabled: noDomains,
99
+ checked: actuallyShowDomains ? subFeatureRows : false,
88
100
  icon: Sort,
89
101
  type: 'checkbox',
90
102
  onClick: () => model.setSubFeatureRows(!subFeatureRows),
91
103
  },
92
104
  {
93
- label: 'Filter domains',
105
+ label: `Filter domains${noDomains ? ' (no domains loaded)' : ''}`,
94
106
  icon: FilterAlt,
107
+ disabled: noDomains,
95
108
  onClick: () => {
96
109
  model.queueDialog(onClose => [
97
110
  FeatureFilterDialog,
@@ -99,15 +112,6 @@ const HeaderMenuExtra = observer(function ({ model }: { model: MsaViewModel }) {
99
112
  ])
100
113
  },
101
114
  },
102
- {
103
- label: 'View domains',
104
- icon: Search,
105
- onClick: () =>
106
- model.queueDialog(handleClose => [
107
- DomainDialog,
108
- { handleClose, model },
109
- ]),
110
- },
111
115
  ],
112
116
  },
113
117
  ...(model.extraViewMenuItems?.() || []),
@@ -5,7 +5,7 @@ import { makeStyles } from 'tss-react/mui'
5
5
  import { LoadingEllipses } from '@jbrowse/core/ui'
6
6
 
7
7
  // locals
8
- import { MsaViewModel } from '../../model'
8
+ import type { MsaViewModel } from '../../model'
9
9
 
10
10
  const useStyles = makeStyles()({
11
11
  margin: {
@@ -14,11 +14,7 @@ const useStyles = makeStyles()({
14
14
  },
15
15
  })
16
16
 
17
- const HeaderStatusArea = observer(function ({
18
- model,
19
- }: {
20
- model: MsaViewModel
21
- }) {
17
+ const HeaderStatusArea = observer(({ model }: { model: MsaViewModel }) => {
22
18
  const { status } = model
23
19
  const { classes } = useStyles()
24
20
  return status ? (
@@ -3,7 +3,7 @@ import { observer } from 'mobx-react'
3
3
  import { Select } from '@mui/material'
4
4
 
5
5
  // locals
6
- import { MsaViewModel } from '../../model'
6
+ import type { MsaViewModel } from '../../model'
7
7
 
8
8
  const MultiAlignmentSelector = observer(function ({
9
9
  model,
@@ -1,6 +1,7 @@
1
1
  import React from 'react'
2
2
  import { IconButton } from '@mui/material'
3
3
  import { observer } from 'mobx-react'
4
+ import CascadingMenuButton from '@jbrowse/core/ui/CascadingMenuButton'
4
5
 
5
6
  // locals
6
7
  import { MsaViewModel } from '../../model'
@@ -8,6 +9,8 @@ import { MsaViewModel } from '../../model'
8
9
  // icons
9
10
  import ZoomIn from '@mui/icons-material/ZoomIn'
10
11
  import ZoomOut from '@mui/icons-material/ZoomOut'
12
+ import MoreVert from '@mui/icons-material/MoreVert'
13
+ import RestartAlt from '@mui/icons-material/RestartAlt'
11
14
 
12
15
  const ZoomControls = observer(function ZoomControls({
13
16
  model,
@@ -22,6 +25,37 @@ const ZoomControls = observer(function ZoomControls({
22
25
  <IconButton onClick={() => model.zoomOut()}>
23
26
  <ZoomOut />
24
27
  </IconButton>
28
+ <CascadingMenuButton
29
+ menuItems={[
30
+ {
31
+ label: 'Zoom in horizontal',
32
+ onClick: () => model.zoomInHorizontal(),
33
+ },
34
+ {
35
+ label: 'Zoom in vertical',
36
+ onClick: () => model.zoomInVertical(),
37
+ },
38
+ {
39
+ label: 'Zoom out horizontal',
40
+ onClick: () => model.zoomOutHorizontal(),
41
+ },
42
+
43
+ {
44
+ label: 'Zoom out vertical',
45
+ onClick: () => model.zoomOutVertical(),
46
+ },
47
+ {
48
+ label: 'Reset zoom to default',
49
+ icon: RestartAlt,
50
+ onClick: () => {
51
+ model.setColWidth(16)
52
+ model.setRowHeight(20)
53
+ },
54
+ },
55
+ ]}
56
+ >
57
+ <MoreVert />
58
+ </CascadingMenuButton>
25
59
  </>
26
60
  )
27
61
  })
@@ -2,14 +2,14 @@ import React, { useState } from 'react'
2
2
  import { observer } from 'mobx-react'
3
3
  import { Button, Container, Grid, Typography } from '@mui/material'
4
4
  import { FileSelector } from '@jbrowse/core/ui'
5
- import { FileLocation } from '@jbrowse/core/util/types'
5
+ import type { FileLocation } from '@jbrowse/core/util/types'
6
6
 
7
7
  // locals
8
- import { MsaViewModel } from '../../model'
8
+ import type { MsaViewModel } from '../../model'
9
9
  import { load } from './util'
10
10
  import ImportFormExamples from './ImportFormExamples'
11
11
 
12
- export default observer(({ model }: { model: MsaViewModel }) => {
12
+ export default observer(function ({ model }: { model: MsaViewModel }) {
13
13
  const [msaFile, setMsaFile] = useState<FileLocation>()
14
14
  const [treeFile, setTreeFile] = useState<FileLocation>()
15
15
  const { error } = model
@@ -3,11 +3,11 @@ import { Typography, Link } from '@mui/material'
3
3
  import { observer } from 'mobx-react'
4
4
 
5
5
  // locals
6
- import { MsaViewModel } from '../../model'
6
+ import type { MsaViewModel } from '../../model'
7
7
  import { smallTree, smallMSA, smallMSAOnly } from './data/seq2'
8
8
  import { load } from './util'
9
9
 
10
- const ListItem = ({
10
+ function ListItem({
11
11
  onClick,
12
12
  model,
13
13
  children,
@@ -15,20 +15,22 @@ const ListItem = ({
15
15
  onClick: () => void
16
16
  model: MsaViewModel
17
17
  children: React.ReactNode
18
- }) => (
19
- <li>
20
- <Link
21
- onClick={event => {
22
- model.setError(undefined)
23
- event.preventDefault()
24
- onClick()
25
- }}
26
- href="#"
27
- >
28
- <Typography display="inline">{children}</Typography>
29
- </Link>
30
- </li>
31
- )
18
+ }) {
19
+ return (
20
+ <li>
21
+ <Link
22
+ onClick={event => {
23
+ model.setError(undefined)
24
+ event.preventDefault()
25
+ onClick()
26
+ }}
27
+ href="#"
28
+ >
29
+ <Typography display="inline">{children}</Typography>
30
+ </Link>
31
+ </li>
32
+ )
33
+ }
32
34
 
33
35
  const ImportFormExamples = observer(function ({
34
36
  model,
@@ -41,7 +43,7 @@ const ImportFormExamples = observer(function ({
41
43
  model={model}
42
44
  onClick={() =>
43
45
  load(model, undefined, {
44
- uri: 'https://jbrowse.org/genomes/newick_trees/sarscov2phylo.pub.ft.nh',
46
+ uri: 'https://jbrowse.org/genomes/newicktrees/sarscov2phylo.pub.ft.nh',
45
47
  locationType: 'UriLocation',
46
48
  })
47
49
  }
@@ -1,5 +1,5 @@
1
- import { FileLocation } from '@jbrowse/core/util'
2
- import { MsaViewModel } from '../../model'
1
+ import type { FileLocation } from '@jbrowse/core/util'
2
+ import type { MsaViewModel } from '../../model'
3
3
 
4
4
  export async function load(
5
5
  model: MsaViewModel,
@@ -1,6 +1,6 @@
1
1
  import React, { useEffect, useRef, useState } from 'react'
2
2
  import { observer } from 'mobx-react'
3
- import { MsaViewModel } from '../../model'
3
+ import type { MsaViewModel } from '../../model'
4
4
 
5
5
  const Minimap = observer(function ({ model }: { model: MsaViewModel }) {
6
6
  const [mouseDown, setMouseDown] = useState<{
@@ -9,19 +9,14 @@ const Minimap = observer(function ({ model }: { model: MsaViewModel }) {
9
9
  }>()
10
10
  const scheduled = useRef(false)
11
11
  const [hovered, setHovered] = useState(false)
12
- const {
13
- scrollX,
14
- msaAreaWidth: W,
15
- minimapHeight: H,
16
- colWidth,
17
- numColumns,
18
- } = model
19
- const unit = W / numColumns / colWidth
12
+ const { scrollX, msaAreaWidth, minimapHeight, colWidth, numColumns } = model
13
+ const unit = msaAreaWidth / numColumns / colWidth
20
14
  const left = -scrollX
21
- const right = left + W
15
+ const right = left + msaAreaWidth
22
16
  const s = left * unit
23
17
  const e = right * unit
24
18
  const fill = 'rgba(66, 119, 127, 0.3)'
19
+ const w = Math.max(e - s, 20)
25
20
 
26
21
  useEffect(() => {
27
22
  function fn(event: MouseEvent) {
@@ -50,14 +45,14 @@ const Minimap = observer(function ({ model }: { model: MsaViewModel }) {
50
45
  }
51
46
  }, [model, unit, mouseDown])
52
47
 
53
- const BAR_HEIGHT = 12
54
- const H2 = H - 12
48
+ const barHeight = 12
49
+ const polygonHeight = minimapHeight - barHeight
55
50
  return (
56
- <div style={{ position: 'relative', height: H, width: '100%' }}>
51
+ <div style={{ position: 'relative', height: minimapHeight, width: '100%' }}>
57
52
  <div
58
53
  style={{
59
54
  boxSizing: 'border-box',
60
- height: BAR_HEIGHT,
55
+ height: barHeight,
61
56
  border: '1px solid #555',
62
57
  }}
63
58
  />
@@ -68,10 +63,8 @@ const Minimap = observer(function ({ model }: { model: MsaViewModel }) {
68
63
  left: Math.max(0, s),
69
64
  background: hovered ? 'rgba(66,119,127,0.6)' : fill,
70
65
  cursor: 'pointer',
71
- border: '1px solid #555',
72
- boxSizing: 'border-box',
73
- height: BAR_HEIGHT,
74
- width: e - s,
66
+ height: barHeight,
67
+ width: w,
75
68
  zIndex: 100,
76
69
  }}
77
70
  onMouseOver={() => setHovered(true)}
@@ -84,14 +77,14 @@ const Minimap = observer(function ({ model }: { model: MsaViewModel }) {
84
77
  }}
85
78
  />
86
79
 
87
- <svg height={H2} style={{ width: '100%' }}>
80
+ <svg height={polygonHeight} style={{ width: '100%' }}>
88
81
  <polygon
89
82
  fill={fill}
90
83
  points={[
91
- [e, 0],
84
+ [s + w, 0],
92
85
  [s, 0],
93
- [0, H2],
94
- [W, H2],
86
+ [0, polygonHeight],
87
+ [msaAreaWidth, polygonHeight],
95
88
  ].toString()}
96
89
  />
97
90
  </svg>
@@ -1,8 +1,8 @@
1
1
  import React from 'react'
2
2
  import { observer } from 'mobx-react'
3
- import { MsaViewModel } from '../../model'
3
+ import type { MsaViewModel } from '../../model'
4
4
 
5
- const MinimapSVG = observer(function ({ model }: { model: MsaViewModel }) {
5
+ const MinimapSVG = observer(({ model }: { model: MsaViewModel }) => {
6
6
  const {
7
7
  scrollX,
8
8
  msaAreaWidth: W,