@jbrowse/plugin-linear-genome-view 1.4.4 → 1.5.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.
- 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/RefNameAutocomplete.d.ts +0 -10
- package/dist/LinearGenomeView/components/ScaleBar.d.ts +22 -2
- package/dist/LinearGenomeView/components/util.d.ts +2 -0
- package/dist/LinearGenomeView/index.d.ts +13 -2
- package/dist/index.d.ts +26 -26
- package/dist/plugin-linear-genome-view.cjs.development.js +272 -268
- 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 +272 -269
- 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/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 +40 -74
- package/src/LinearGenomeView/components/ImportForm.tsx +124 -134
- package/src/LinearGenomeView/components/LinearGenomeView.test.js +6 -6
- package/src/LinearGenomeView/components/RefNameAutocomplete.tsx +20 -25
- package/src/LinearGenomeView/components/SequenceDialog.tsx +1 -1
- package/src/LinearGenomeView/components/__snapshots__/LinearGenomeView.test.js.snap +0 -176
- package/src/LinearGenomeView/components/util.ts +8 -0
- package/src/LinearGenomeView/index.tsx +14 -13
- 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.0",
|
|
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": "542025578a39bd170c8a166f2568ee7edbd54072"
|
|
65
65
|
}
|
|
@@ -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,27 @@
|
|
|
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'
|
|
10
13
|
|
|
14
|
+
// icons
|
|
11
15
|
import { TrackSelector as TrackSelectorIcon } from '@jbrowse/core/ui/Icons'
|
|
12
16
|
import ArrowForwardIcon from '@material-ui/icons/ArrowForward'
|
|
13
17
|
import ArrowBackIcon from '@material-ui/icons/ArrowBack'
|
|
18
|
+
|
|
19
|
+
// locals
|
|
14
20
|
import { LinearGenomeViewModel, HEADER_BAR_HEIGHT } from '..'
|
|
15
21
|
import RefNameAutocomplete from './RefNameAutocomplete'
|
|
16
22
|
import OverviewScaleBar from './OverviewScaleBar'
|
|
17
23
|
import ZoomControls from './ZoomControls'
|
|
24
|
+
import { dedupe } from './util'
|
|
18
25
|
|
|
19
26
|
const WIDGET_HEIGHT = 32
|
|
20
27
|
const SPACING = 7
|
|
@@ -107,17 +114,11 @@ const LinearGenomeViewHeader = observer(
|
|
|
107
114
|
const classes = useStyles()
|
|
108
115
|
const theme = useTheme()
|
|
109
116
|
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 || []
|
|
117
|
+
|
|
118
|
+
const { textSearchManager, assemblyManager } = session
|
|
119
|
+
const { assemblyNames, rankSearchResults } = model
|
|
120
|
+
const assemblyName = assemblyNames[0]
|
|
121
|
+
const assembly = assemblyManager.get(assemblyName)
|
|
121
122
|
const searchScope = model.searchScope(assemblyName)
|
|
122
123
|
|
|
123
124
|
async function fetchResults(queryString: string) {
|
|
@@ -132,68 +133,34 @@ const LinearGenomeViewHeader = observer(
|
|
|
132
133
|
searchScope,
|
|
133
134
|
rankSearchResults,
|
|
134
135
|
)
|
|
135
|
-
return results
|
|
136
|
-
(elem, index, self) =>
|
|
137
|
-
index === self.findIndex(t => t.getId() === elem.getId()),
|
|
138
|
-
)
|
|
136
|
+
return dedupe(results)
|
|
139
137
|
}
|
|
140
138
|
|
|
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()
|
|
139
|
+
async function handleSelectedRegion(option: BaseResult) {
|
|
140
|
+
let trackId = option.getTrackId()
|
|
141
|
+
let location = option.getLocation()
|
|
142
|
+
const label = option.getLabel()
|
|
143
|
+
try {
|
|
144
|
+
if (assembly?.refNames?.includes(location)) {
|
|
145
|
+
model.navToLocString(location)
|
|
165
146
|
} else {
|
|
166
|
-
let location = result.getLocation()
|
|
167
|
-
let trackId = result.getTrackId()
|
|
168
147
|
const results = await fetchResults(label)
|
|
169
148
|
if (results && results.length > 1) {
|
|
170
149
|
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
|
-
}
|
|
150
|
+
return
|
|
151
|
+
} else if (results?.length === 1) {
|
|
152
|
+
location = results[0].getLocation()
|
|
153
|
+
trackId = results[0].getTrackId()
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
model.navToLocString(location, assemblyName)
|
|
157
|
+
if (trackId) {
|
|
158
|
+
model.showTrack(trackId)
|
|
195
159
|
}
|
|
196
160
|
}
|
|
161
|
+
} catch (e) {
|
|
162
|
+
console.error(e)
|
|
163
|
+
session.notify(`${e}`, 'warning')
|
|
197
164
|
}
|
|
198
165
|
}
|
|
199
166
|
|
|
@@ -204,9 +171,8 @@ const LinearGenomeViewHeader = observer(
|
|
|
204
171
|
<FormGroup row className={classes.headerForm}>
|
|
205
172
|
<PanControls model={model} />
|
|
206
173
|
<RefNameAutocomplete
|
|
207
|
-
onSelect={
|
|
174
|
+
onSelect={handleSelectedRegion}
|
|
208
175
|
assemblyName={assemblyName}
|
|
209
|
-
value={displayedRegions.length > 1 ? '' : refName}
|
|
210
176
|
model={model}
|
|
211
177
|
TextFieldProps={{
|
|
212
178
|
variant: 'outlined',
|