@jbrowse/plugin-linear-genome-view 1.4.1 → 1.5.2
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.
- package/dist/BaseLinearDisplay/components/Block.d.ts +7 -10
- package/dist/BaseLinearDisplay/models/BaseLinearDisplayModel.d.ts +16 -9
- package/dist/BaseLinearDisplay/models/serverSideRenderedBlock.d.ts +2 -2
- package/dist/LinearBareDisplay/model.d.ts +8 -8
- package/dist/LinearBasicDisplay/model.d.ts +11 -8
- package/dist/LinearGenomeView/components/HelpDialog.d.ts +5 -0
- package/dist/LinearGenomeView/components/LinearGenomeView.d.ts +3 -5
- package/dist/LinearGenomeView/components/LinearGenomeViewSvg.d.ts +4 -0
- package/dist/LinearGenomeView/components/OverviewRubberBand.d.ts +2 -3
- package/dist/LinearGenomeView/components/OverviewScaleBar.d.ts +116 -2
- package/dist/LinearGenomeView/components/RefNameAutocomplete.d.ts +3 -11
- package/dist/LinearGenomeView/components/ScaleBar.d.ts +36 -2
- package/dist/LinearGenomeView/components/util.d.ts +2 -0
- package/dist/LinearGenomeView/index.d.ts +22 -4
- package/dist/index.d.ts +26 -26
- package/dist/plugin-linear-genome-view.cjs.development.js +3178 -2884
- package/dist/plugin-linear-genome-view.cjs.development.js.map +1 -1
- package/dist/plugin-linear-genome-view.cjs.production.min.js +1 -1
- package/dist/plugin-linear-genome-view.cjs.production.min.js.map +1 -1
- package/dist/plugin-linear-genome-view.esm.js +3191 -2898
- package/dist/plugin-linear-genome-view.esm.js.map +1 -1
- package/package.json +2 -2
- package/src/BaseLinearDisplay/components/BaseLinearDisplay.tsx +3 -0
- package/src/BaseLinearDisplay/components/Block.tsx +20 -33
- package/src/BaseLinearDisplay/models/BaseLinearDisplayModel.tsx +3 -7
- package/src/BaseLinearDisplay/models/serverSideRenderedBlock.ts +15 -13
- package/src/LinearBasicDisplay/model.ts +25 -3
- package/src/LinearGenomeView/components/ExportSvgDialog.tsx +6 -6
- package/src/LinearGenomeView/components/Header.tsx +56 -78
- package/src/LinearGenomeView/components/HelpDialog.tsx +81 -0
- package/src/LinearGenomeView/components/ImportForm.tsx +139 -158
- package/src/LinearGenomeView/components/LinearGenomeView.test.js +6 -6
- package/src/LinearGenomeView/components/LinearGenomeView.tsx +30 -245
- package/src/LinearGenomeView/components/LinearGenomeViewSvg.tsx +317 -0
- package/src/LinearGenomeView/components/OverviewRubberBand.tsx +74 -34
- package/src/LinearGenomeView/components/OverviewScaleBar.tsx +326 -177
- package/src/LinearGenomeView/components/RefNameAutocomplete.tsx +152 -157
- package/src/LinearGenomeView/components/SearchResultsDialog.tsx +12 -34
- package/src/LinearGenomeView/components/SequenceDialog.tsx +10 -9
- package/src/LinearGenomeView/components/__snapshots__/LinearGenomeView.test.js.snap +127 -254
- package/src/LinearGenomeView/components/util.ts +10 -0
- package/src/LinearGenomeView/index.tsx +69 -27
- package/src/index.ts +3 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jbrowse/plugin-linear-genome-view",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.2",
|
|
4
4
|
"description": "JBrowse 2 linear genome view",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"jbrowse",
|
|
@@ -61,5 +61,5 @@
|
|
|
61
61
|
"publishConfig": {
|
|
62
62
|
"access": "public"
|
|
63
63
|
},
|
|
64
|
-
"gitHead": "
|
|
64
|
+
"gitHead": "94fdfbc34787ab8f12a87e00038da74b247b42fa"
|
|
65
65
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import React from 'react'
|
|
1
2
|
import { BaseBlock } from '@jbrowse/core/util/blockTypes'
|
|
2
3
|
import { makeStyles } from '@material-ui/core/styles'
|
|
3
4
|
import { observer } from 'mobx-react'
|
|
4
|
-
import React from 'react'
|
|
5
5
|
|
|
6
6
|
const useStyles = makeStyles(theme => ({
|
|
7
7
|
contentBlock: {
|
|
@@ -28,51 +28,38 @@ const useStyles = makeStyles(theme => ({
|
|
|
28
28
|
},
|
|
29
29
|
}))
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
block: BaseBlock
|
|
33
|
-
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
width: number
|
|
43
|
-
style?: React.CSSProperties
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const ContentBlock = observer(({ block, children }: ContentBlockProps) => {
|
|
47
|
-
const classes = useStyles()
|
|
48
|
-
return (
|
|
49
|
-
<div
|
|
50
|
-
style={{
|
|
51
|
-
width: `${block.widthPx}px`,
|
|
52
|
-
}}
|
|
53
|
-
className={classes.contentBlock}
|
|
54
|
-
>
|
|
55
|
-
{children}
|
|
56
|
-
</div>
|
|
57
|
-
)
|
|
58
|
-
})
|
|
31
|
+
const ContentBlock = observer(
|
|
32
|
+
({ block, children }: { block: BaseBlock; children: React.ReactNode }) => {
|
|
33
|
+
const classes = useStyles()
|
|
34
|
+
const { widthPx } = block
|
|
35
|
+
return (
|
|
36
|
+
<div style={{ width: widthPx }} className={classes.contentBlock}>
|
|
37
|
+
{children}
|
|
38
|
+
</div>
|
|
39
|
+
)
|
|
40
|
+
},
|
|
41
|
+
)
|
|
59
42
|
|
|
60
|
-
function ElidedBlock({ width }:
|
|
43
|
+
function ElidedBlock({ width }: { width: number }) {
|
|
61
44
|
const classes = useStyles()
|
|
62
|
-
return <div className={classes.elidedBlock} style={{ width
|
|
45
|
+
return <div className={classes.elidedBlock} style={{ width }} />
|
|
63
46
|
}
|
|
64
47
|
|
|
65
48
|
function InterRegionPaddingBlock({
|
|
66
49
|
boundary,
|
|
67
50
|
width,
|
|
68
51
|
style = {},
|
|
69
|
-
}:
|
|
52
|
+
}: {
|
|
53
|
+
boundary: boolean
|
|
54
|
+
width: number
|
|
55
|
+
style?: React.CSSProperties
|
|
56
|
+
}) {
|
|
70
57
|
const classes = useStyles()
|
|
71
58
|
return (
|
|
72
59
|
<div
|
|
73
60
|
style={{
|
|
74
61
|
...style,
|
|
75
|
-
width
|
|
62
|
+
width,
|
|
76
63
|
}}
|
|
77
64
|
className={
|
|
78
65
|
boundary
|
|
@@ -88,7 +88,7 @@ export const BaseLinearDisplay = types
|
|
|
88
88
|
},
|
|
89
89
|
|
|
90
90
|
get TooltipComponent(): React.FC<any> {
|
|
91
|
-
return
|
|
91
|
+
return Tooltip as unknown as React.FC
|
|
92
92
|
},
|
|
93
93
|
|
|
94
94
|
/**
|
|
@@ -387,12 +387,8 @@ export const BaseLinearDisplay = types
|
|
|
387
387
|
}
|
|
388
388
|
}
|
|
389
389
|
|
|
390
|
-
const {
|
|
391
|
-
|
|
392
|
-
renderArgs,
|
|
393
|
-
renderProps,
|
|
394
|
-
rendererType,
|
|
395
|
-
} = renderBlockData(blockState, self)
|
|
390
|
+
const { rpcManager, renderArgs, renderProps, rendererType } =
|
|
391
|
+
renderBlockData(blockState, self)
|
|
396
392
|
|
|
397
393
|
return rendererType.renderInClient(rpcManager, {
|
|
398
394
|
...renderArgs,
|
|
@@ -3,7 +3,10 @@ import { types, getParent, isAlive, cast, Instance } from 'mobx-state-tree'
|
|
|
3
3
|
import { readConfObject } from '@jbrowse/core/configuration'
|
|
4
4
|
import { Feature } from '@jbrowse/core/util/simpleFeature'
|
|
5
5
|
import { Region } from '@jbrowse/core/util/types/mst'
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
AbstractDisplayModel,
|
|
8
|
+
isRetryException,
|
|
9
|
+
} from '@jbrowse/core/util/types'
|
|
7
10
|
import React from 'react'
|
|
8
11
|
|
|
9
12
|
import {
|
|
@@ -36,7 +39,7 @@ const blockState = types
|
|
|
36
39
|
features: undefined as Map<string, Feature> | undefined,
|
|
37
40
|
layout: undefined as any,
|
|
38
41
|
status: '',
|
|
39
|
-
error: undefined as
|
|
42
|
+
error: undefined as unknown,
|
|
40
43
|
message: undefined as string | undefined,
|
|
41
44
|
maxHeightReached: false,
|
|
42
45
|
ReactComponent: ServerSideRenderedBlockContent,
|
|
@@ -128,7 +131,7 @@ const blockState = types
|
|
|
128
131
|
self.renderProps = renderProps
|
|
129
132
|
renderInProgress = undefined
|
|
130
133
|
},
|
|
131
|
-
setError(error: Error) {
|
|
134
|
+
setError(error: Error | unknown) {
|
|
132
135
|
console.error(error)
|
|
133
136
|
if (renderInProgress && !renderInProgress.signal.aborted) {
|
|
134
137
|
renderInProgress.abort()
|
|
@@ -143,6 +146,9 @@ const blockState = types
|
|
|
143
146
|
self.error = error
|
|
144
147
|
self.renderProps = undefined
|
|
145
148
|
renderInProgress = undefined
|
|
149
|
+
if (isRetryException(error as Error)) {
|
|
150
|
+
this.reload()
|
|
151
|
+
}
|
|
146
152
|
},
|
|
147
153
|
reload() {
|
|
148
154
|
self.renderInProgress = undefined
|
|
@@ -286,16 +292,12 @@ async function renderBlockEffect(
|
|
|
286
292
|
return undefined
|
|
287
293
|
}
|
|
288
294
|
|
|
289
|
-
const {
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
...renderArgs,
|
|
296
|
-
...renderProps,
|
|
297
|
-
signal,
|
|
298
|
-
})
|
|
295
|
+
const { reactElement, features, layout, maxHeightReached } =
|
|
296
|
+
await rendererType.renderInClient(rpcManager, {
|
|
297
|
+
...renderArgs,
|
|
298
|
+
...renderProps,
|
|
299
|
+
signal,
|
|
300
|
+
})
|
|
299
301
|
return {
|
|
300
302
|
reactElement,
|
|
301
303
|
features,
|
|
@@ -17,6 +17,7 @@ const stateModelFactory = (configSchema: AnyConfigurationSchemaType) =>
|
|
|
17
17
|
types.model({
|
|
18
18
|
type: types.literal('LinearBasicDisplay'),
|
|
19
19
|
trackShowLabels: types.maybe(types.boolean),
|
|
20
|
+
trackShowDescriptions: types.maybe(types.boolean),
|
|
20
21
|
trackDisplayMode: types.maybe(types.string),
|
|
21
22
|
trackMaxHeight: types.maybe(types.number),
|
|
22
23
|
configuration: ConfigurationReference(configSchema),
|
|
@@ -34,6 +35,13 @@ const stateModelFactory = (configSchema: AnyConfigurationSchemaType) =>
|
|
|
34
35
|
: showLabels
|
|
35
36
|
},
|
|
36
37
|
|
|
38
|
+
get showDescriptions() {
|
|
39
|
+
const showDescriptions = getConf(self, ['renderer', 'showLabels'])
|
|
40
|
+
return self.trackShowDescriptions !== undefined
|
|
41
|
+
? self.trackShowDescriptions
|
|
42
|
+
: showDescriptions
|
|
43
|
+
},
|
|
44
|
+
|
|
37
45
|
get maxHeight() {
|
|
38
46
|
const maxHeight = getConf(self, ['renderer', 'maxHeight'])
|
|
39
47
|
return self.trackMaxHeight !== undefined
|
|
@@ -54,6 +62,7 @@ const stateModelFactory = (configSchema: AnyConfigurationSchemaType) =>
|
|
|
54
62
|
{
|
|
55
63
|
...configBlob,
|
|
56
64
|
showLabels: this.showLabels,
|
|
65
|
+
showDescriptions: this.showDescriptions,
|
|
57
66
|
displayMode: this.displayMode,
|
|
58
67
|
maxHeight: this.maxHeight,
|
|
59
68
|
},
|
|
@@ -66,6 +75,9 @@ const stateModelFactory = (configSchema: AnyConfigurationSchemaType) =>
|
|
|
66
75
|
toggleShowLabels() {
|
|
67
76
|
self.trackShowLabels = !self.showLabels
|
|
68
77
|
},
|
|
78
|
+
toggleShowDescriptions() {
|
|
79
|
+
self.trackShowDescriptions = !self.showDescriptions
|
|
80
|
+
},
|
|
69
81
|
setDisplayMode(val: string) {
|
|
70
82
|
self.trackDisplayMode = val
|
|
71
83
|
},
|
|
@@ -100,6 +112,15 @@ const stateModelFactory = (configSchema: AnyConfigurationSchemaType) =>
|
|
|
100
112
|
self.toggleShowLabels()
|
|
101
113
|
},
|
|
102
114
|
},
|
|
115
|
+
{
|
|
116
|
+
label: 'Show descriptions',
|
|
117
|
+
icon: VisibilityIcon,
|
|
118
|
+
type: 'checkbox',
|
|
119
|
+
checked: self.showDescriptions,
|
|
120
|
+
onClick: () => {
|
|
121
|
+
self.toggleShowDescriptions()
|
|
122
|
+
},
|
|
123
|
+
},
|
|
103
124
|
{
|
|
104
125
|
label: 'Display mode',
|
|
105
126
|
icon: VisibilityIcon,
|
|
@@ -118,9 +139,10 @@ const stateModelFactory = (configSchema: AnyConfigurationSchemaType) =>
|
|
|
118
139
|
{
|
|
119
140
|
label: 'Set max height',
|
|
120
141
|
onClick: () => {
|
|
121
|
-
getSession(self).
|
|
122
|
-
|
|
123
|
-
|
|
142
|
+
getSession(self).queueDialog((doneCallback: Function) => [
|
|
143
|
+
SetMaxHeightDlg,
|
|
144
|
+
{ model: self, handleClose: doneCallback },
|
|
145
|
+
])
|
|
124
146
|
},
|
|
125
147
|
},
|
|
126
148
|
]
|
|
@@ -31,11 +31,11 @@ export default function ExportSvgDlg({
|
|
|
31
31
|
model: LGV
|
|
32
32
|
handleClose: () => void
|
|
33
33
|
}) {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
)
|
|
34
|
+
// @ts-ignore
|
|
35
|
+
const offscreenCanvas = typeof OffscreenCanvas !== 'undefined'
|
|
36
|
+
const [rasterizeLayers, setRasterizeLayers] = useState(offscreenCanvas)
|
|
37
37
|
const [loading, setLoading] = useState(false)
|
|
38
|
-
const [error, setError] = useState<
|
|
38
|
+
const [error, setError] = useState<unknown>()
|
|
39
39
|
const classes = useStyles()
|
|
40
40
|
return (
|
|
41
41
|
<Dialog open onClose={handleClose}>
|
|
@@ -54,8 +54,7 @@ export default function ExportSvgDlg({
|
|
|
54
54
|
<Typography display="inline">Creating SVG</Typography>
|
|
55
55
|
</div>
|
|
56
56
|
) : null}
|
|
57
|
-
|
|
58
|
-
{typeof OffscreenCanvas !== 'undefined' ? (
|
|
57
|
+
{offscreenCanvas ? (
|
|
59
58
|
<FormControlLabel
|
|
60
59
|
control={
|
|
61
60
|
<Checkbox
|
|
@@ -91,6 +90,7 @@ export default function ExportSvgDlg({
|
|
|
91
90
|
await model.exportSvg({ rasterizeLayers })
|
|
92
91
|
handleClose()
|
|
93
92
|
} catch (e) {
|
|
93
|
+
console.error(e)
|
|
94
94
|
setError(e)
|
|
95
95
|
} finally {
|
|
96
96
|
setLoading(false)
|
|
@@ -1,20 +1,28 @@
|
|
|
1
|
-
import { getSession } from '@jbrowse/core/util'
|
|
2
|
-
import Button from '@material-ui/core/Button'
|
|
3
|
-
import { makeStyles, useTheme } from '@material-ui/core/styles'
|
|
4
|
-
import { alpha } from '@material-ui/core/styles'
|
|
5
|
-
import FormGroup from '@material-ui/core/FormGroup'
|
|
6
|
-
import Typography from '@material-ui/core/Typography'
|
|
7
|
-
import { observer } from 'mobx-react'
|
|
8
1
|
import React from 'react'
|
|
2
|
+
import { observer } from 'mobx-react'
|
|
3
|
+
import { getSession } from '@jbrowse/core/util'
|
|
4
|
+
import {
|
|
5
|
+
Button,
|
|
6
|
+
FormGroup,
|
|
7
|
+
Typography,
|
|
8
|
+
makeStyles,
|
|
9
|
+
useTheme,
|
|
10
|
+
alpha,
|
|
11
|
+
} from '@material-ui/core'
|
|
9
12
|
import BaseResult from '@jbrowse/core/TextSearch/BaseResults'
|
|
13
|
+
import { SearchType } from '@jbrowse/core/data_adapters/BaseAdapter'
|
|
10
14
|
|
|
15
|
+
// icons
|
|
11
16
|
import { TrackSelector as TrackSelectorIcon } from '@jbrowse/core/ui/Icons'
|
|
12
17
|
import ArrowForwardIcon from '@material-ui/icons/ArrowForward'
|
|
13
18
|
import ArrowBackIcon from '@material-ui/icons/ArrowBack'
|
|
19
|
+
|
|
20
|
+
// locals
|
|
14
21
|
import { LinearGenomeViewModel, HEADER_BAR_HEIGHT } from '..'
|
|
15
22
|
import RefNameAutocomplete from './RefNameAutocomplete'
|
|
16
23
|
import OverviewScaleBar from './OverviewScaleBar'
|
|
17
24
|
import ZoomControls from './ZoomControls'
|
|
25
|
+
import { dedupe } from './util'
|
|
18
26
|
|
|
19
27
|
const WIDGET_HEIGHT = 32
|
|
20
28
|
const SPACING = 7
|
|
@@ -107,93 +115,63 @@ const LinearGenomeViewHeader = observer(
|
|
|
107
115
|
const classes = useStyles()
|
|
108
116
|
const theme = useTheme()
|
|
109
117
|
const session = getSession(model)
|
|
110
|
-
|
|
111
|
-
const {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
} = model
|
|
116
|
-
const { assemblyName, refName } = contentBlocks[0] || { refName: '' }
|
|
117
|
-
const assembly = assemblyName
|
|
118
|
-
? assemblyManager.get(assemblyName)
|
|
119
|
-
: undefined
|
|
120
|
-
const regions = assembly?.regions || []
|
|
118
|
+
|
|
119
|
+
const { textSearchManager, assemblyManager } = session
|
|
120
|
+
const { assemblyNames, rankSearchResults } = model
|
|
121
|
+
const assemblyName = assemblyNames[0]
|
|
122
|
+
const assembly = assemblyManager.get(assemblyName)
|
|
121
123
|
const searchScope = model.searchScope(assemblyName)
|
|
122
124
|
|
|
123
|
-
async function fetchResults(
|
|
125
|
+
async function fetchResults(query: string, searchType?: SearchType) {
|
|
124
126
|
if (!textSearchManager) {
|
|
125
127
|
console.warn('No text search manager')
|
|
126
128
|
}
|
|
127
|
-
|
|
129
|
+
|
|
130
|
+
const textSearchResults = await textSearchManager?.search(
|
|
128
131
|
{
|
|
129
|
-
queryString:
|
|
130
|
-
searchType
|
|
132
|
+
queryString: query,
|
|
133
|
+
searchType,
|
|
131
134
|
},
|
|
132
135
|
searchScope,
|
|
133
136
|
rankSearchResults,
|
|
134
137
|
)
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
+
|
|
139
|
+
const refNameResults = assembly?.allRefNames
|
|
140
|
+
?.filter(refName => refName.startsWith(query))
|
|
141
|
+
.map(r => new BaseResult({ label: r }))
|
|
142
|
+
.slice(0, 10)
|
|
143
|
+
|
|
144
|
+
return dedupe(
|
|
145
|
+
[...(refNameResults || []), ...(textSearchResults || [])],
|
|
146
|
+
elt => elt.getId(),
|
|
138
147
|
)
|
|
139
148
|
}
|
|
140
149
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
* 3) if we get any hits by requerying the textSearchManager, then we either
|
|
149
|
-
* navigate to the single hit location or pop open the the dialog with all
|
|
150
|
-
* the results from the search
|
|
151
|
-
* 4) if there were no hits from requerying, then we use (1) the chosen options'
|
|
152
|
-
* trackId and locStr to navigate and show that track
|
|
153
|
-
* 5) error handling
|
|
154
|
-
* @param result - result chosen from dropdown
|
|
155
|
-
*/
|
|
156
|
-
async function setDisplayedRegion(result: BaseResult) {
|
|
157
|
-
if (result) {
|
|
158
|
-
const label = result.getLabel()
|
|
159
|
-
const newRegion = regions.find(region => label === region.refName)
|
|
160
|
-
if (newRegion) {
|
|
161
|
-
model.setDisplayedRegions([newRegion])
|
|
162
|
-
// we use showAllRegions after setDisplayedRegions to make the entire
|
|
163
|
-
// region visible, xref #1703
|
|
164
|
-
model.showAllRegions()
|
|
150
|
+
async function handleSelectedRegion(option: BaseResult) {
|
|
151
|
+
let trackId = option.getTrackId()
|
|
152
|
+
let location = option.getLocation()
|
|
153
|
+
const label = option.getLabel()
|
|
154
|
+
try {
|
|
155
|
+
if (assembly?.allRefNames?.includes(location)) {
|
|
156
|
+
model.navToLocString(location)
|
|
165
157
|
} else {
|
|
166
|
-
|
|
167
|
-
let trackId = result.getTrackId()
|
|
168
|
-
const results = await fetchResults(label)
|
|
158
|
+
const results = await fetchResults(label, 'exact')
|
|
169
159
|
if (results && results.length > 1) {
|
|
170
160
|
model.setSearchResults(results, label.toLowerCase())
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
model.setSearchResults(results, label.toLowerCase())
|
|
181
|
-
} else {
|
|
182
|
-
console.warn(e)
|
|
183
|
-
session.notify(`${e}`, 'warning')
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
try {
|
|
187
|
-
if (trackId) {
|
|
188
|
-
model.showTrack(trackId)
|
|
189
|
-
}
|
|
190
|
-
} catch (e) {
|
|
191
|
-
console.warn(
|
|
192
|
-
`'${e}' occurred while attempting to show track: ${trackId}`,
|
|
193
|
-
)
|
|
194
|
-
}
|
|
161
|
+
return
|
|
162
|
+
} else if (results?.length === 1) {
|
|
163
|
+
location = results[0].getLocation()
|
|
164
|
+
trackId = results[0].getTrackId()
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
model.navToLocString(location, assemblyName)
|
|
168
|
+
if (trackId) {
|
|
169
|
+
model.showTrack(trackId)
|
|
195
170
|
}
|
|
196
171
|
}
|
|
172
|
+
} catch (e) {
|
|
173
|
+
console.error(e)
|
|
174
|
+
session.notify(`${e}`, 'warning')
|
|
197
175
|
}
|
|
198
176
|
}
|
|
199
177
|
|
|
@@ -204,9 +182,9 @@ const LinearGenomeViewHeader = observer(
|
|
|
204
182
|
<FormGroup row className={classes.headerForm}>
|
|
205
183
|
<PanControls model={model} />
|
|
206
184
|
<RefNameAutocomplete
|
|
207
|
-
onSelect={
|
|
185
|
+
onSelect={handleSelectedRegion}
|
|
208
186
|
assemblyName={assemblyName}
|
|
209
|
-
|
|
187
|
+
fetchResults={fetchResults}
|
|
210
188
|
model={model}
|
|
211
189
|
TextFieldProps={{
|
|
212
190
|
variant: 'outlined',
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import {
|
|
3
|
+
Button,
|
|
4
|
+
Dialog,
|
|
5
|
+
DialogActions,
|
|
6
|
+
DialogContent,
|
|
7
|
+
DialogTitle,
|
|
8
|
+
Divider,
|
|
9
|
+
IconButton,
|
|
10
|
+
makeStyles,
|
|
11
|
+
} from '@material-ui/core'
|
|
12
|
+
import CloseIcon from '@material-ui/icons/Close'
|
|
13
|
+
|
|
14
|
+
export const useStyles = makeStyles(theme => ({
|
|
15
|
+
closeButton: {
|
|
16
|
+
position: 'absolute',
|
|
17
|
+
right: theme.spacing(1),
|
|
18
|
+
top: theme.spacing(1),
|
|
19
|
+
color: theme.palette.grey[500],
|
|
20
|
+
},
|
|
21
|
+
}))
|
|
22
|
+
|
|
23
|
+
export default function HelpDialog({
|
|
24
|
+
handleClose,
|
|
25
|
+
}: {
|
|
26
|
+
handleClose: () => void
|
|
27
|
+
}) {
|
|
28
|
+
const classes = useStyles()
|
|
29
|
+
return (
|
|
30
|
+
<Dialog open maxWidth="xl" onClose={handleClose}>
|
|
31
|
+
<DialogTitle>
|
|
32
|
+
Using the search box
|
|
33
|
+
{handleClose ? (
|
|
34
|
+
<IconButton
|
|
35
|
+
data-testid="close-resultsDialog"
|
|
36
|
+
className={classes.closeButton}
|
|
37
|
+
onClick={() => {
|
|
38
|
+
handleClose()
|
|
39
|
+
}}
|
|
40
|
+
>
|
|
41
|
+
<CloseIcon />
|
|
42
|
+
</IconButton>
|
|
43
|
+
) : null}
|
|
44
|
+
</DialogTitle>
|
|
45
|
+
<Divider />
|
|
46
|
+
<DialogContent>
|
|
47
|
+
<h3>Searching</h3>
|
|
48
|
+
<ul>
|
|
49
|
+
<li>
|
|
50
|
+
Jump to a feature or reference sequence by typing its name in the
|
|
51
|
+
location box and pressing Enter.
|
|
52
|
+
</li>
|
|
53
|
+
<li>
|
|
54
|
+
Jump to a specific region by typing the region into the location box
|
|
55
|
+
as: <code>ref:start..end</code> or <code>ref:start-end</code>.
|
|
56
|
+
Commas are allowed in the start and end coordinates.
|
|
57
|
+
</li>
|
|
58
|
+
</ul>
|
|
59
|
+
<h3>Example Searches</h3>
|
|
60
|
+
<ul>
|
|
61
|
+
<li>
|
|
62
|
+
<code>BRCA</code> - searches for the feature named BRCA
|
|
63
|
+
</li>
|
|
64
|
+
<li>
|
|
65
|
+
<code>chr4</code> - jumps to chromosome 4
|
|
66
|
+
</li>
|
|
67
|
+
<li>
|
|
68
|
+
<code>chr4:79,500,000..80,000,000</code> - jumps the region on
|
|
69
|
+
chromosome 4 between 79.5Mb and 80Mb.
|
|
70
|
+
</li>
|
|
71
|
+
</ul>
|
|
72
|
+
</DialogContent>
|
|
73
|
+
<Divider />
|
|
74
|
+
<DialogActions>
|
|
75
|
+
<Button onClick={() => handleClose()} color="primary">
|
|
76
|
+
Close
|
|
77
|
+
</Button>
|
|
78
|
+
</DialogActions>
|
|
79
|
+
</Dialog>
|
|
80
|
+
)
|
|
81
|
+
}
|