@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.
Files changed (30) hide show
  1. package/dist/BaseLinearDisplay/models/BaseLinearDisplayModel.d.ts +16 -9
  2. package/dist/BaseLinearDisplay/models/serverSideRenderedBlock.d.ts +2 -2
  3. package/dist/LinearBareDisplay/model.d.ts +8 -8
  4. package/dist/LinearBasicDisplay/model.d.ts +11 -8
  5. package/dist/LinearGenomeView/components/RefNameAutocomplete.d.ts +0 -10
  6. package/dist/LinearGenomeView/components/ScaleBar.d.ts +22 -2
  7. package/dist/LinearGenomeView/components/util.d.ts +2 -0
  8. package/dist/LinearGenomeView/index.d.ts +13 -2
  9. package/dist/index.d.ts +26 -26
  10. package/dist/plugin-linear-genome-view.cjs.development.js +272 -268
  11. package/dist/plugin-linear-genome-view.cjs.development.js.map +1 -1
  12. package/dist/plugin-linear-genome-view.cjs.production.min.js +1 -1
  13. package/dist/plugin-linear-genome-view.cjs.production.min.js.map +1 -1
  14. package/dist/plugin-linear-genome-view.esm.js +272 -269
  15. package/dist/plugin-linear-genome-view.esm.js.map +1 -1
  16. package/package.json +2 -2
  17. package/src/BaseLinearDisplay/components/BaseLinearDisplay.tsx +3 -0
  18. package/src/BaseLinearDisplay/models/BaseLinearDisplayModel.tsx +3 -7
  19. package/src/BaseLinearDisplay/models/serverSideRenderedBlock.ts +15 -13
  20. package/src/LinearBasicDisplay/model.ts +25 -3
  21. package/src/LinearGenomeView/components/ExportSvgDialog.tsx +6 -6
  22. package/src/LinearGenomeView/components/Header.tsx +40 -74
  23. package/src/LinearGenomeView/components/ImportForm.tsx +124 -134
  24. package/src/LinearGenomeView/components/LinearGenomeView.test.js +6 -6
  25. package/src/LinearGenomeView/components/RefNameAutocomplete.tsx +20 -25
  26. package/src/LinearGenomeView/components/SequenceDialog.tsx +1 -1
  27. package/src/LinearGenomeView/components/__snapshots__/LinearGenomeView.test.js.snap +0 -176
  28. package/src/LinearGenomeView/components/util.ts +8 -0
  29. package/src/LinearGenomeView/index.tsx +14 -13
  30. 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.4.4",
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": "c12a2b1cef07dbc5ea40be5c76e03b655b7f3636"
64
+ "gitHead": "542025578a39bd170c8a166f2568ee7edbd54072"
65
65
  }
@@ -73,6 +73,9 @@ const Tooltip = observer(
73
73
  right: x,
74
74
  width: 0,
75
75
  height: 0,
76
+ x,
77
+ y,
78
+ toJSON() {},
76
79
  }
77
80
  },
78
81
  }),
@@ -88,7 +88,7 @@ export const BaseLinearDisplay = types
88
88
  },
89
89
 
90
90
  get TooltipComponent(): React.FC<any> {
91
- return (Tooltip as unknown) as React.FC
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
- rpcManager,
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 { AbstractDisplayModel } from '@jbrowse/core/util/types'
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 Error | undefined,
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
- reactElement,
291
- features,
292
- layout,
293
- maxHeightReached,
294
- } = await rendererType.renderInClient(rpcManager, {
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).setDialogComponent(SetMaxHeightDlg, {
122
- model: self,
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
- const [rasterizeLayers, setRasterizeLayers] = useState(
35
- typeof OffscreenCanvas !== 'undefined',
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<Error>()
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
- const { assemblyManager, textSearchManager } = session
111
- const {
112
- coarseDynamicBlocks: contentBlocks,
113
- displayedRegions,
114
- rankSearchResults,
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?.filter(
136
- (elem, index, self) =>
137
- index === self.findIndex(t => t.getId() === elem.getId()),
138
- )
136
+ return dedupe(results)
139
137
  }
140
138
 
141
- /**
142
- * We first check to see if the identifier/label is an appropriate region,
143
- * if it is then we set that as our displayed region
144
- * if the label was not a valid region, then
145
- * 1) we get the trackId and the location/locStr of the option we chose
146
- * 2) we then use the label to try and fetch for exact matches through our
147
- * textSearchManager
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
- } else {
172
- if (results?.length === 1) {
173
- location = results[0].getLocation()
174
- trackId = results[0].getTrackId()
175
- }
176
- try {
177
- label !== '' && model.navToLocString(location)
178
- } catch (e) {
179
- if (`${e}` === `Error: Unknown reference sequence "${label}"`) {
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={setDisplayedRegion}
174
+ onSelect={handleSelectedRegion}
208
175
  assemblyName={assemblyName}
209
- value={displayedRegions.length > 1 ? '' : refName}
210
176
  model={model}
211
177
  TextFieldProps={{
212
178
  variant: 'outlined',