@jbrowse/plugin-linear-genome-view 1.7.8 → 1.7.11

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 (53) hide show
  1. package/dist/BaseLinearDisplay/components/BaseLinearDisplay.d.ts +1 -5
  2. package/dist/BaseLinearDisplay/components/BaseLinearDisplay.js +32 -120
  3. package/dist/BaseLinearDisplay/components/Tooltip.d.ts +8 -0
  4. package/dist/BaseLinearDisplay/components/Tooltip.js +125 -0
  5. package/dist/BaseLinearDisplay/models/BaseLinearDisplayModel.d.ts +4 -4
  6. package/dist/BaseLinearDisplay/models/BaseLinearDisplayModel.js +3 -2
  7. package/dist/LinearBareDisplay/model.d.ts +1 -1
  8. package/dist/LinearBasicDisplay/model.d.ts +1 -2
  9. package/dist/LinearBasicDisplay/model.js +2 -2
  10. package/dist/LinearGenomeView/components/ExportSvgDialog.js +35 -25
  11. package/dist/LinearGenomeView/components/Header.d.ts +0 -1
  12. package/dist/LinearGenomeView/components/Header.js +3 -1
  13. package/dist/LinearGenomeView/components/HelpDialog.js +2 -3
  14. package/dist/LinearGenomeView/components/ImportForm.d.ts +0 -1
  15. package/dist/LinearGenomeView/components/ImportForm.js +40 -70
  16. package/dist/LinearGenomeView/components/LinearGenomeView.js +6 -2
  17. package/dist/LinearGenomeView/components/LinearGenomeView.test.js +2 -2
  18. package/dist/LinearGenomeView/components/OverviewScaleBar.d.ts +21 -5
  19. package/dist/LinearGenomeView/components/OverviewScaleBar.js +25 -18
  20. package/dist/LinearGenomeView/components/ScaleBar.d.ts +6 -2
  21. package/dist/LinearGenomeView/components/ScaleBar.js +8 -3
  22. package/dist/LinearGenomeView/components/SearchBox.js +36 -72
  23. package/dist/LinearGenomeView/components/SearchResultsDialog.d.ts +1 -1
  24. package/dist/LinearGenomeView/components/SearchResultsDialog.js +0 -1
  25. package/dist/LinearGenomeView/components/TrackLabel.js +25 -41
  26. package/dist/LinearGenomeView/components/util.d.ts +12 -0
  27. package/dist/LinearGenomeView/components/util.js +59 -0
  28. package/dist/LinearGenomeView/index.d.ts +7 -11
  29. package/dist/LinearGenomeView/index.js +60 -33
  30. package/dist/LinearGenomeView/index.test.js +22 -5
  31. package/dist/index.d.ts +3 -3
  32. package/dist/index.js +22 -11
  33. package/package.json +3 -2
  34. package/src/BaseLinearDisplay/components/BaseLinearDisplay.tsx +4 -89
  35. package/src/BaseLinearDisplay/components/Tooltip.tsx +97 -0
  36. package/src/BaseLinearDisplay/models/BaseLinearDisplayModel.tsx +11 -4
  37. package/src/LinearBasicDisplay/model.ts +2 -4
  38. package/src/LinearGenomeView/components/ExportSvgDialog.tsx +24 -11
  39. package/src/LinearGenomeView/components/Header.tsx +2 -1
  40. package/src/LinearGenomeView/components/HelpDialog.tsx +5 -4
  41. package/src/LinearGenomeView/components/ImportForm.tsx +18 -25
  42. package/src/LinearGenomeView/components/LinearGenomeView.test.js +2 -2
  43. package/src/LinearGenomeView/components/LinearGenomeView.tsx +16 -10
  44. package/src/LinearGenomeView/components/OverviewScaleBar.tsx +42 -34
  45. package/src/LinearGenomeView/components/ScaleBar.tsx +6 -9
  46. package/src/LinearGenomeView/components/SearchBox.tsx +18 -29
  47. package/src/LinearGenomeView/components/SearchResultsDialog.tsx +0 -1
  48. package/src/LinearGenomeView/components/TrackLabel.tsx +25 -28
  49. package/src/LinearGenomeView/components/__snapshots__/LinearGenomeView.test.js.snap +4 -21
  50. package/src/LinearGenomeView/components/util.ts +43 -0
  51. package/src/LinearGenomeView/index.test.ts +20 -5
  52. package/src/LinearGenomeView/index.tsx +56 -27
  53. package/src/index.ts +35 -30
@@ -82,7 +82,7 @@ function initialize() {
82
82
  }).actions(function (self) {
83
83
  return {
84
84
  isValidRefName: function isValidRefName(str) {
85
- return !str.includes(':');
85
+ return str === 'ctgA' || str === 'ctgB';
86
86
  },
87
87
  get: function get(str) {
88
88
  return self.assemblies.get(str);
@@ -1163,8 +1163,25 @@ test('multi region', function () {
1163
1163
  model.setDisplayedRegions(_volvoxDisplayedRegions.default.slice(0, 1));
1164
1164
  model.navToLocString('ctgA ctgB');
1165
1165
  expect(model.displayedRegions[0].refName).toBe('ctgA');
1166
- expect(model.displayedRegions[1].refName).toBe('ctgB'); // [
1167
- // { refName: 'ctgA', start: 0, end: 50001 },
1168
- // { refName: 'ctgB', start: 0, end: 6079 },
1169
- // ])
1166
+ expect(model.displayedRegions[1].refName).toBe('ctgB');
1167
+ });
1168
+ test('space separated locstring', function () {
1169
+ var _initialize15 = initialize(),
1170
+ Session = _initialize15.Session,
1171
+ LinearGenomeModel = _initialize15.LinearGenomeModel;
1172
+
1173
+ var model = Session.create({
1174
+ configuration: {}
1175
+ }).setView(LinearGenomeModel.create({
1176
+ type: 'LinearGenomeView',
1177
+ tracks: [{
1178
+ name: 'foo track',
1179
+ type: 'BasicTrack'
1180
+ }]
1181
+ }));
1182
+ model.setWidth(800);
1183
+ model.setDisplayedRegions(_volvoxDisplayedRegions.default.slice(0, 1));
1184
+ model.navToLocString('ctgA 0 100');
1185
+ expect(model.offsetPx).toBe(0);
1186
+ expect(model.bpPerPx).toBe(0.125);
1170
1187
  });
package/dist/index.d.ts CHANGED
@@ -124,7 +124,7 @@ export default class LinearGenomeViewPlugin extends Plugin {
124
124
  estimatedRegionStatsP: Promise<import("@jbrowse/core/data_adapters/BaseAdapter").Stats> | undefined;
125
125
  estimatedRegionStats: import("@jbrowse/core/data_adapters/BaseAdapter").Stats | undefined;
126
126
  } & {
127
- readonly blockType: "staticBlocks" | "dynamicBlocks";
127
+ readonly blockType: "dynamicBlocks" | "staticBlocks";
128
128
  readonly blockDefinitions: import("@jbrowse/core/util/blockTypes").BlockSet;
129
129
  } & {
130
130
  readonly renderDelay: number;
@@ -300,7 +300,7 @@ export default class LinearGenomeViewPlugin extends Plugin {
300
300
  estimatedRegionStatsP: Promise<import("@jbrowse/core/data_adapters/BaseAdapter").Stats> | undefined;
301
301
  estimatedRegionStats: import("@jbrowse/core/data_adapters/BaseAdapter").Stats | undefined;
302
302
  } & {
303
- readonly blockType: "staticBlocks" | "dynamicBlocks";
303
+ readonly blockType: "dynamicBlocks" | "staticBlocks";
304
304
  readonly blockDefinitions: import("@jbrowse/core/util/blockTypes").BlockSet;
305
305
  } & {
306
306
  readonly renderDelay: number;
@@ -486,7 +486,7 @@ export default class LinearGenomeViewPlugin extends Plugin {
486
486
  estimatedRegionStatsP: Promise<import("@jbrowse/core/data_adapters/BaseAdapter").Stats> | undefined;
487
487
  estimatedRegionStats: import("@jbrowse/core/data_adapters/BaseAdapter").Stats | undefined;
488
488
  } & {
489
- readonly blockType: "staticBlocks" | "dynamicBlocks";
489
+ readonly blockType: "dynamicBlocks" | "staticBlocks";
490
490
  readonly blockDefinitions: import("@jbrowse/core/util/blockTypes").BlockSet;
491
491
  } & {
492
492
  readonly renderDelay: number;
package/dist/index.js CHANGED
@@ -211,36 +211,37 @@ var LinearGenomeViewPlugin = /*#__PURE__*/function (_Plugin) {
211
211
  switch (_context.prev = _context.next) {
212
212
  case 0:
213
213
  session = _ref.session, assembly = _ref.assembly, loc = _ref.loc, _ref$tracks = _ref.tracks, tracks = _ref$tracks === void 0 ? [] : _ref$tracks;
214
+ _context.prev = 1;
214
215
  assemblyManager = session.assemblyManager;
215
216
  view = session.addView('LinearGenomeView', {});
216
- _context.next = 5;
217
+ _context.next = 6;
217
218
  return (0, _mobx.when)(function () {
218
219
  return !!view.volatileWidth;
219
220
  });
220
221
 
221
- case 5:
222
+ case 6:
222
223
  if (assembly) {
223
- _context.next = 7;
224
+ _context.next = 8;
224
225
  break;
225
226
  }
226
227
 
227
228
  throw new Error('No assembly provided when launching linear genome view');
228
229
 
229
- case 7:
230
- _context.next = 9;
230
+ case 8:
231
+ _context.next = 10;
231
232
  return assemblyManager.waitForAssembly(assembly);
232
233
 
233
- case 9:
234
+ case 10:
234
235
  asm = _context.sent;
235
236
 
236
237
  if (asm) {
237
- _context.next = 12;
238
+ _context.next = 13;
238
239
  break;
239
240
  }
240
241
 
241
242
  throw new Error("Assembly \"".concat(assembly, "\" not found when launching linear genome view"));
242
243
 
243
- case 12:
244
+ case 13:
244
245
  view.navToLocString(loc, assembly);
245
246
  idsNotFound = [];
246
247
  tracks.forEach(function (track) {
@@ -256,18 +257,28 @@ var LinearGenomeViewPlugin = /*#__PURE__*/function (_Plugin) {
256
257
  });
257
258
 
258
259
  if (!idsNotFound.length) {
259
- _context.next = 17;
260
+ _context.next = 18;
260
261
  break;
261
262
  }
262
263
 
263
264
  throw new Error("Could not resolve identifiers: ".concat(idsNotFound.join(',')));
264
265
 
265
- case 17:
266
+ case 18:
267
+ _context.next = 24;
268
+ break;
269
+
270
+ case 20:
271
+ _context.prev = 20;
272
+ _context.t0 = _context["catch"](1);
273
+ session.notify("".concat(_context.t0), 'error');
274
+ throw _context.t0;
275
+
276
+ case 24:
266
277
  case "end":
267
278
  return _context.stop();
268
279
  }
269
280
  }
270
- }, _callee);
281
+ }, _callee, null, [[1, 20]]);
271
282
  }));
272
283
 
273
284
  return function (_x) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jbrowse/plugin-linear-genome-view",
3
- "version": "1.7.8",
3
+ "version": "1.7.11",
4
4
  "description": "JBrowse 2 linear genome view",
5
5
  "keywords": [
6
6
  "jbrowse",
@@ -40,6 +40,7 @@
40
40
  "clsx": "^1.0.4",
41
41
  "copy-to-clipboard": "^3.3.1",
42
42
  "file-saver": "^2.0.0",
43
+ "material-ui-popup-state": "^1.9.3",
43
44
  "normalize-wheel": "^1.0.1",
44
45
  "react-popper": "^2.0.0"
45
46
  },
@@ -57,5 +58,5 @@
57
58
  "publishConfig": {
58
59
  "access": "public"
59
60
  },
60
- "gitHead": "b429fa2bb5734fc8a5380988f6dfdd3f7a41a39f"
61
+ "gitHead": "5c21beb48a21f08b0091d293f09ac99174c48f77"
61
62
  }
@@ -1,19 +1,15 @@
1
- import React, { useState, useRef, useMemo } from 'react'
1
+ import React, { useState, useRef } from 'react'
2
2
  import { observer } from 'mobx-react'
3
- import { Portal, alpha, useTheme, makeStyles } from '@material-ui/core'
3
+ import { useTheme, makeStyles } from '@material-ui/core'
4
4
  import { getConf } from '@jbrowse/core/configuration'
5
5
  import { Menu } from '@jbrowse/core/ui'
6
- import { usePopper } from 'react-popper'
7
6
 
8
7
  // locals
8
+ import Tooltip from './Tooltip'
9
9
  import LinearBlocks from './LinearBlocks'
10
10
  import { BaseLinearDisplayModel } from '../models/BaseLinearDisplayModel'
11
11
 
12
- function round(value: number) {
13
- return Math.round(value * 1e5) / 1e5
14
- }
15
-
16
- const useStyles = makeStyles(theme => ({
12
+ const useStyles = makeStyles({
17
13
  display: {
18
14
  position: 'relative',
19
15
  whiteSpace: 'nowrap',
@@ -21,89 +17,8 @@ const useStyles = makeStyles(theme => ({
21
17
  width: '100%',
22
18
  minHeight: '100%',
23
19
  },
24
-
25
- // these styles come from
26
- // https://github.com/mui-org/material-ui/blob/master/packages/material-ui/src/Tooltip/Tooltip.js
27
- tooltip: {
28
- pointerEvents: 'none',
29
- backgroundColor: alpha(theme.palette.grey[700], 0.9),
30
- borderRadius: theme.shape.borderRadius,
31
- color: theme.palette.common.white,
32
- fontFamily: theme.typography.fontFamily,
33
- padding: '4px 8px',
34
- fontSize: theme.typography.pxToRem(12),
35
- lineHeight: `${round(14 / 10)}em`,
36
- maxWidth: 300,
37
- wordWrap: 'break-word',
38
- },
39
- }))
40
-
41
- const TooltipContents = React.forwardRef<
42
- HTMLDivElement,
43
- { message: React.ReactNode | string }
44
- >(({ message }: { message: React.ReactNode | string }, ref) => {
45
- return <div ref={ref}>{message}</div>
46
20
  })
47
21
 
48
- const Tooltip = observer(
49
- ({
50
- model,
51
- clientMouseCoord,
52
- }: {
53
- model: BaseLinearDisplayModel
54
- clientMouseCoord: Coord
55
- }) => {
56
- const classes = useStyles()
57
- const { featureUnderMouse } = model
58
- const [width, setWidth] = useState(0)
59
- const [popperElt, setPopperElt] = useState<HTMLDivElement | null>(null)
60
-
61
- // must be memoized a la https://github.com/popperjs/react-popper/issues/391
62
- const virtElement = useMemo(
63
- () => ({
64
- getBoundingClientRect: () => {
65
- const x = clientMouseCoord[0] + width / 2 + 20
66
- const y = clientMouseCoord[1]
67
- return {
68
- top: y,
69
- left: x,
70
- bottom: y,
71
- right: x,
72
- width: 0,
73
- height: 0,
74
- x,
75
- y,
76
- toJSON() {},
77
- }
78
- },
79
- }),
80
- [clientMouseCoord, width],
81
- )
82
- const { styles, attributes } = usePopper(virtElement, popperElt)
83
-
84
- const contents = featureUnderMouse
85
- ? getConf(model, 'mouseover', { feature: featureUnderMouse })
86
- : undefined
87
-
88
- return featureUnderMouse && contents ? (
89
- <Portal>
90
- <div
91
- ref={setPopperElt}
92
- className={classes.tooltip}
93
- // zIndex needed to go over widget drawer
94
- style={{ ...styles.popper, zIndex: 100000 }}
95
- {...attributes.popper}
96
- >
97
- <TooltipContents
98
- ref={elt => setWidth(elt?.getBoundingClientRect().width || 0)}
99
- message={contents}
100
- />
101
- </div>
102
- </Portal>
103
- ) : null
104
- },
105
- )
106
-
107
22
  type Coord = [number, number]
108
23
  const BaseLinearDisplay = observer(
109
24
  (props: { model: BaseLinearDisplayModel; children?: React.ReactNode }) => {
@@ -0,0 +1,97 @@
1
+ import React, { useState, useMemo } from 'react'
2
+ import { getConf } from '@jbrowse/core/configuration'
3
+ import { observer } from 'mobx-react'
4
+ import { Portal, alpha, makeStyles } from '@material-ui/core'
5
+ import { usePopper } from 'react-popper'
6
+
7
+ // locals
8
+ import { BaseLinearDisplayModel } from '../models/BaseLinearDisplayModel'
9
+
10
+ function round(value: number) {
11
+ return Math.round(value * 1e5) / 1e5
12
+ }
13
+ const useStyles = makeStyles(theme => ({
14
+ // these styles come from
15
+ // https://github.com/mui-org/material-ui/blob/master/packages/material-ui/src/Tooltip/Tooltip.js
16
+ tooltip: {
17
+ pointerEvents: 'none',
18
+ backgroundColor: alpha(theme.palette.grey[700], 0.9),
19
+ borderRadius: theme.shape.borderRadius,
20
+ color: theme.palette.common.white,
21
+ fontFamily: theme.typography.fontFamily,
22
+ padding: '4px 8px',
23
+ fontSize: theme.typography.pxToRem(12),
24
+ lineHeight: `${round(14 / 10)}em`,
25
+ maxWidth: 300,
26
+ wordWrap: 'break-word',
27
+ },
28
+ }))
29
+
30
+ const TooltipContents = React.forwardRef<
31
+ HTMLDivElement,
32
+ { message: React.ReactNode | string }
33
+ >(({ message }: { message: React.ReactNode | string }, ref) => {
34
+ return <div ref={ref}>{message}</div>
35
+ })
36
+
37
+ type Coord = [number, number]
38
+ const Tooltip = observer(
39
+ ({
40
+ model,
41
+ clientMouseCoord,
42
+ }: {
43
+ model: BaseLinearDisplayModel
44
+ clientMouseCoord: Coord
45
+ }) => {
46
+ const classes = useStyles()
47
+ const { featureUnderMouse } = model
48
+ const [width, setWidth] = useState(0)
49
+ const [popperElt, setPopperElt] = useState<HTMLDivElement | null>(null)
50
+
51
+ // must be memoized a la https://github.com/popperjs/react-popper/issues/391
52
+ const virtElement = useMemo(
53
+ () => ({
54
+ getBoundingClientRect: () => {
55
+ const x = clientMouseCoord[0] + width / 2 + 20
56
+ const y = clientMouseCoord[1]
57
+ return {
58
+ top: y,
59
+ left: x,
60
+ bottom: y,
61
+ right: x,
62
+ width: 0,
63
+ height: 0,
64
+ x,
65
+ y,
66
+ toJSON() {},
67
+ }
68
+ },
69
+ }),
70
+ [clientMouseCoord, width],
71
+ )
72
+ const { styles, attributes } = usePopper(virtElement, popperElt)
73
+
74
+ const contents = featureUnderMouse
75
+ ? getConf(model, 'mouseover', { feature: featureUnderMouse })
76
+ : undefined
77
+
78
+ return featureUnderMouse && contents ? (
79
+ <Portal>
80
+ <div
81
+ ref={setPopperElt}
82
+ className={classes.tooltip}
83
+ // zIndex needed to go over widget drawer
84
+ style={{ ...styles.popper, zIndex: 100000 }}
85
+ {...attributes.popper}
86
+ >
87
+ <TooltipContents
88
+ ref={elt => setWidth(elt?.getBoundingClientRect().width || 0)}
89
+ message={contents}
90
+ />
91
+ </div>
92
+ </Portal>
93
+ ) : null
94
+ },
95
+ )
96
+
97
+ export default Tooltip
@@ -7,6 +7,7 @@ import { MenuItem } from '@jbrowse/core/ui'
7
7
  import {
8
8
  isAbortException,
9
9
  getContainingView,
10
+ getContainingTrack,
10
11
  getSession,
11
12
  getViewParams,
12
13
  isSelectionContainer,
@@ -333,8 +334,13 @@ export const BaseLinearDisplay = types
333
334
  const featureWidget = session.addWidget(
334
335
  'BaseFeatureWidget',
335
336
  'baseFeature',
336
- { featureData: feature.toJSON(), view: getContainingView(self) },
337
+ {
338
+ view: getContainingView(self),
339
+ track: getContainingTrack(self),
340
+ featureData: feature.toJSON(),
341
+ },
337
342
  )
343
+
338
344
  session.showWidget(featureWidget)
339
345
  }
340
346
  if (isSelectionContainer(session)) {
@@ -551,7 +557,7 @@ export const BaseLinearDisplay = types
551
557
  self.currBpPerPx !== view.bpPerPx || !self.estimatedRegionStats,
552
558
  rpcDriverName: self.rpcDriverName,
553
559
  displayModel: self,
554
- onFeatureClick(_: unknown, featureId: string | undefined) {
560
+ onFeatureClick(_: unknown, featureId?: string) {
555
561
  const f = featureId || self.featureIdUnderMouse
556
562
  if (!f) {
557
563
  self.clearFeatureSelection()
@@ -566,7 +572,7 @@ export const BaseLinearDisplay = types
566
572
  self.clearFeatureSelection()
567
573
  },
568
574
  // similar to click but opens a menu with further options
569
- onFeatureContextMenu(_: unknown, featureId: string | undefined) {
575
+ onFeatureContextMenu(_: unknown, featureId?: string) {
570
576
  const f = featureId || self.featureIdUnderMouse
571
577
  if (!f) {
572
578
  self.clearFeatureSelection()
@@ -576,7 +582,7 @@ export const BaseLinearDisplay = types
576
582
  }
577
583
  },
578
584
 
579
- onMouseMove(_: unknown, featureId: string | undefined) {
585
+ onMouseMove(_: unknown, featureId?: string) {
580
586
  self.setFeatureIdUnderMouse(featureId)
581
587
  },
582
588
 
@@ -642,6 +648,7 @@ export const BaseLinearDisplay = types
642
648
  const { offsetPx } = roundedDynamicBlocks[index]
643
649
  const offset = offsetPx - viewOffsetPx
644
650
  const clipid = getId(id, index)
651
+
645
652
  return (
646
653
  <React.Fragment key={`frag-${index}`}>
647
654
  <defs>
@@ -42,7 +42,7 @@ const stateModelFactory = (configSchema: AnyConfigurationSchemaType) =>
42
42
  get showDescriptions() {
43
43
  return (
44
44
  self.trackShowDescriptions ??
45
- getConf(self, ['renderer', 'showLabels'])
45
+ getConf(self, ['renderer', 'showDescriptions'])
46
46
  )
47
47
  },
48
48
 
@@ -116,9 +116,7 @@ const stateModelFactory = (configSchema: AnyConfigurationSchemaType) =>
116
116
  icon: VisibilityIcon,
117
117
  type: 'checkbox',
118
118
  checked: self.showDescriptions,
119
- onClick: () => {
120
- self.toggleShowDescriptions()
121
- },
119
+ onClick: () => self.toggleShowDescriptions(),
122
120
  },
123
121
  {
124
122
  label: 'Display mode',
@@ -1,17 +1,19 @@
1
1
  import React, { useState } from 'react'
2
- import { makeStyles } from '@material-ui/core/styles'
3
2
  import {
4
3
  Button,
4
+ Checkbox,
5
+ CircularProgress,
5
6
  Dialog,
6
7
  DialogActions,
7
8
  DialogContent,
8
9
  DialogTitle,
9
- IconButton,
10
- Checkbox,
11
10
  FormControlLabel,
12
- CircularProgress,
11
+ IconButton,
12
+ TextField,
13
13
  Typography,
14
+ makeStyles,
14
15
  } from '@material-ui/core'
16
+ import { ErrorMessage } from '@jbrowse/core/ui'
15
17
  import CloseIcon from '@material-ui/icons/Close'
16
18
  import { LinearGenomeViewModel as LGV } from '..'
17
19
 
@@ -24,6 +26,15 @@ const useStyles = makeStyles(theme => ({
24
26
  },
25
27
  }))
26
28
 
29
+ function LoadingMessage() {
30
+ return (
31
+ <div>
32
+ <CircularProgress size={20} style={{ marginRight: 20 }} />
33
+ <Typography display="inline">Creating SVG</Typography>
34
+ </div>
35
+ )
36
+ }
37
+
27
38
  export default function ExportSvgDlg({
28
39
  model,
29
40
  handleClose,
@@ -35,6 +46,7 @@ export default function ExportSvgDlg({
35
46
  const offscreenCanvas = typeof OffscreenCanvas !== 'undefined'
36
47
  const [rasterizeLayers, setRasterizeLayers] = useState(offscreenCanvas)
37
48
  const [loading, setLoading] = useState(false)
49
+ const [filename, setFilename] = useState('jbrowse.svg')
38
50
  const [error, setError] = useState<unknown>()
39
51
  const classes = useStyles()
40
52
  return (
@@ -47,13 +59,15 @@ export default function ExportSvgDlg({
47
59
  </DialogTitle>
48
60
  <DialogContent>
49
61
  {error ? (
50
- <div style={{ color: 'red' }}>{`${error}`}</div>
62
+ <ErrorMessage error={error} />
51
63
  ) : loading ? (
52
- <div>
53
- <CircularProgress size={20} style={{ marginRight: 20 }} />
54
- <Typography display="inline">Creating SVG</Typography>
55
- </div>
64
+ <LoadingMessage />
56
65
  ) : null}
66
+ <TextField
67
+ helperText="filename"
68
+ value={filename}
69
+ onChange={event => setFilename(event.target.value)}
70
+ />
57
71
  {offscreenCanvas ? (
58
72
  <FormControlLabel
59
73
  control={
@@ -87,12 +101,11 @@ export default function ExportSvgDlg({
87
101
  setLoading(true)
88
102
  setError(undefined)
89
103
  try {
90
- await model.exportSvg({ rasterizeLayers })
104
+ await model.exportSvg({ rasterizeLayers, filename })
91
105
  handleClose()
92
106
  } catch (e) {
93
107
  console.error(e)
94
108
  setError(e)
95
- } finally {
96
109
  setLoading(false)
97
110
  }
98
111
  }}
@@ -7,6 +7,7 @@ import {
7
7
  makeStyles,
8
8
  alpha,
9
9
  } from '@material-ui/core'
10
+ import { getBpDisplayStr } from '@jbrowse/core/util'
10
11
  import SearchBox from './SearchBox'
11
12
 
12
13
  // icons
@@ -100,7 +101,7 @@ const RegionWidth = observer(({ model }: { model: LGV }) => {
100
101
  const { coarseTotalBp } = model
101
102
  return (
102
103
  <Typography variant="body2" color="textSecondary" className={classes.bp}>
103
- {Math.round(coarseTotalBp).toLocaleString('en-US')} bp
104
+ {getBpDisplayStr(coarseTotalBp)}
104
105
  </Typography>
105
106
  )
106
107
  })
@@ -32,11 +32,8 @@ export default function HelpDialog({
32
32
  Using the search box
33
33
  {handleClose ? (
34
34
  <IconButton
35
- data-testid="close-resultsDialog"
36
35
  className={classes.closeButton}
37
- onClick={() => {
38
- handleClose()
39
- }}
36
+ onClick={() => handleClose()}
40
37
  >
41
38
  <CloseIcon />
42
39
  </IconButton>
@@ -81,6 +78,10 @@ export default function HelpDialog({
81
78
  <code>chr1:1-100[rev] chr2:1-100</code> - open up the first region
82
79
  in the horizontally flipped orientation
83
80
  </li>
81
+ <li>
82
+ <code>chr1 100 200</code> - use whitespace separated refname, start,
83
+ end
84
+ </li>
84
85
  </ul>
85
86
  </DialogContent>
86
87
  <Divider />
@@ -8,7 +8,6 @@ import {
8
8
  Grid,
9
9
  makeStyles,
10
10
  } from '@material-ui/core'
11
- import { SearchType } from '@jbrowse/core/data_adapters/BaseAdapter'
12
11
  import ErrorMessage from '@jbrowse/core/ui/ErrorMessage'
13
12
  import BaseResult from '@jbrowse/core/TextSearch/BaseResults'
14
13
  import AssemblySelector from '@jbrowse/core/ui/AssemblySelector'
@@ -16,6 +15,7 @@ import CloseIcon from '@material-ui/icons/Close'
16
15
 
17
16
  // locals
18
17
  import RefNameAutocomplete from './RefNameAutocomplete'
18
+ import { fetchResults } from './util'
19
19
  import { LinearGenomeViewModel, WIDGET_HEIGHT } from '..'
20
20
  const SearchResultsDialog = lazy(() => import('./SearchResultsDialog'))
21
21
 
@@ -57,28 +57,6 @@ const ImportForm = observer(({ model }: { model: LGV }) => {
57
57
  label: value,
58
58
  })
59
59
 
60
- async function fetchResults(query: string, searchType?: SearchType) {
61
- if (!textSearchManager) {
62
- console.warn('No text search manager')
63
- }
64
-
65
- const textSearchResults = await textSearchManager?.search(
66
- {
67
- queryString: query,
68
- searchType,
69
- },
70
- searchScope,
71
- rankSearchResults,
72
- )
73
-
74
- const refNameResults = assembly?.allRefNames
75
- ?.filter(refName => refName.startsWith(query))
76
- .map(r => new BaseResult({ label: r }))
77
- .slice(0, 10)
78
-
79
- return [...(refNameResults || []), ...(textSearchResults || [])]
80
- }
81
-
82
60
  // gets a string as input, or use stored option results from previous query,
83
61
  // then re-query and
84
62
  // 1) if it has multiple results: pop a dialog
@@ -105,7 +83,14 @@ const ImportForm = observer(({ model }: { model: LGV }) => {
105
83
  ) {
106
84
  model.navToLocString(location, selectedAsm)
107
85
  } else {
108
- const results = await fetchResults(input, 'exact')
86
+ const results = await fetchResults({
87
+ queryString: input,
88
+ searchType: 'exact',
89
+ searchScope,
90
+ rankSearchResults,
91
+ textSearchManager,
92
+ assembly,
93
+ })
109
94
  if (results.length > 1) {
110
95
  model.setSearchResults(results, input.toLowerCase())
111
96
  return
@@ -165,7 +150,15 @@ const ImportForm = observer(({ model }: { model: LGV }) => {
165
150
  <CloseIcon style={{ color: 'red' }} />
166
151
  ) : value ? (
167
152
  <RefNameAutocomplete
168
- fetchResults={fetchResults}
153
+ fetchResults={queryString =>
154
+ fetchResults({
155
+ queryString,
156
+ assembly,
157
+ textSearchManager,
158
+ rankSearchResults,
159
+ searchScope,
160
+ })
161
+ }
169
162
  model={model}
170
163
  assemblyName={assemblyError ? undefined : selectedAsm}
171
164
  value={value}
@@ -79,7 +79,7 @@ describe('<LinearGenomeView />', () => {
79
79
  await findByText('Foo Track')
80
80
  // test needs to wait until it's updated to display 100 bp in the header to
81
81
  // make snapshot pass
82
- await findByText('100 bp')
82
+ await findByText('100bp')
83
83
  expect(container.firstChild).toMatchSnapshot()
84
84
  })
85
85
  it('renders two tracks, two regions', async () => {
@@ -145,7 +145,7 @@ describe('<LinearGenomeView />', () => {
145
145
  <LinearGenomeView model={model} />,
146
146
  )
147
147
  await findByText('Foo Track')
148
- await findByText('798 bp')
148
+ await findByText('798bp')
149
149
  await findAllByTestId('svgfeatures')
150
150
 
151
151
  expect(container.firstChild).toMatchSnapshot()