@jbrowse/plugin-linear-genome-view 1.3.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 (34) hide show
  1. package/dist/BaseLinearDisplay/components/BaseLinearDisplay.d.ts +3 -2
  2. package/dist/BaseLinearDisplay/models/BaseLinearDisplayModel.d.ts +20 -10
  3. package/dist/BaseLinearDisplay/models/serverSideRenderedBlock.d.ts +2 -2
  4. package/dist/LinearBareDisplay/model.d.ts +10 -9
  5. package/dist/LinearBasicDisplay/model.d.ts +13 -9
  6. package/dist/LinearGenomeView/components/Header.d.ts +2 -4
  7. package/dist/LinearGenomeView/components/RefNameAutocomplete.d.ts +1 -11
  8. package/dist/LinearGenomeView/components/ScaleBar.d.ts +46 -14
  9. package/dist/LinearGenomeView/components/util.d.ts +2 -0
  10. package/dist/LinearGenomeView/index.d.ts +13 -2
  11. package/dist/index.d.ts +47 -56
  12. package/dist/plugin-linear-genome-view.cjs.development.js +642 -423
  13. package/dist/plugin-linear-genome-view.cjs.development.js.map +1 -1
  14. package/dist/plugin-linear-genome-view.cjs.production.min.js +1 -1
  15. package/dist/plugin-linear-genome-view.cjs.production.min.js.map +1 -1
  16. package/dist/plugin-linear-genome-view.esm.js +652 -433
  17. package/dist/plugin-linear-genome-view.esm.js.map +1 -1
  18. package/package.json +4 -2
  19. package/src/BaseLinearDisplay/components/BaseLinearDisplay.tsx +100 -21
  20. package/src/BaseLinearDisplay/models/BaseLinearDisplayModel.tsx +10 -10
  21. package/src/BaseLinearDisplay/models/serverSideRenderedBlock.ts +15 -13
  22. package/src/LinearBasicDisplay/model.ts +25 -3
  23. package/src/LinearGenomeView/components/ExportSvgDialog.tsx +17 -8
  24. package/src/LinearGenomeView/components/Header.tsx +101 -104
  25. package/src/LinearGenomeView/components/ImportForm.tsx +146 -113
  26. package/src/LinearGenomeView/components/LinearGenomeView.test.js +6 -6
  27. package/src/LinearGenomeView/components/OverviewScaleBar.tsx +4 -1
  28. package/src/LinearGenomeView/components/RefNameAutocomplete.tsx +196 -169
  29. package/src/LinearGenomeView/components/SearchResultsDialog.tsx +1 -16
  30. package/src/LinearGenomeView/components/SequenceDialog.tsx +59 -58
  31. package/src/LinearGenomeView/components/__snapshots__/LinearGenomeView.test.js.snap +5 -177
  32. package/src/LinearGenomeView/components/util.ts +8 -0
  33. package/src/LinearGenomeView/index.tsx +39 -28
  34. package/src/index.ts +3 -1
@@ -22,12 +22,14 @@ var Typography = _interopDefault(require('@material-ui/core/Typography'));
22
22
  var MenuOpenIcon = _interopDefault(require('@material-ui/icons/MenuOpen'));
23
23
  var mobx = require('mobx');
24
24
  var mobxStateTree = require('mobx-state-tree');
25
+ var core = require('@material-ui/core');
25
26
  var ui = require('@jbrowse/core/ui');
26
- var styles = require('@material-ui/core/styles');
27
27
  var mobxReact = require('mobx-react');
28
- var MUITooltip = _interopDefault(require('@material-ui/core/Tooltip'));
28
+ var reactPopper = require('react-popper');
29
+ var styles = require('@material-ui/core/styles');
29
30
  var blockTypes = require('@jbrowse/core/util/blockTypes');
30
31
  var mst = require('@jbrowse/core/util/types/mst');
32
+ var types = require('@jbrowse/core/util/types');
31
33
  var RefreshIcon = _interopDefault(require('@material-ui/icons/Refresh'));
32
34
  var configurationSchema = require('@jbrowse/core/configuration/configurationSchema');
33
35
  var calculateDynamicBlocks = _interopDefault(require('@jbrowse/core/util/calculateDynamicBlocks'));
@@ -43,17 +45,12 @@ var ZoomIn = _interopDefault(require('@material-ui/icons/ZoomIn'));
43
45
  var clone = _interopDefault(require('clone'));
44
46
  var fileSaver = require('file-saver');
45
47
  var server = require('react-dom/server');
46
- var core = require('@material-ui/core');
47
- var FormGroup = _interopDefault(require('@material-ui/core/FormGroup'));
48
48
  var ArrowForwardIcon = _interopDefault(require('@material-ui/icons/ArrowForward'));
49
49
  var ArrowBackIcon = _interopDefault(require('@material-ui/icons/ArrowBack'));
50
50
  var BaseResult = require('@jbrowse/core/TextSearch/BaseResults');
51
51
  var BaseResult__default = _interopDefault(BaseResult);
52
- var CircularProgress = _interopDefault(require('@material-ui/core/CircularProgress'));
53
- var TextField = _interopDefault(require('@material-ui/core/TextField'));
54
52
  var SearchIcon = _interopDefault(require('@material-ui/icons/Search'));
55
- var Autocomplete = require('@material-ui/lab/Autocomplete');
56
- var Autocomplete__default = _interopDefault(Autocomplete);
53
+ var Autocomplete = _interopDefault(require('@material-ui/lab/Autocomplete'));
57
54
  var LinearProgress = _interopDefault(require('@material-ui/core/LinearProgress'));
58
55
  var clsx = _interopDefault(require('clsx'));
59
56
  var ReactPropTypes = _interopDefault(require('prop-types'));
@@ -67,6 +64,7 @@ var CloseIcon = _interopDefault(require('@material-ui/icons/Close'));
67
64
  var normalizeWheel = _interopDefault(require('normalize-wheel'));
68
65
  var colorManipulator = require('@material-ui/core/styles/colorManipulator');
69
66
  var Popover = _interopDefault(require('@material-ui/core/Popover'));
67
+ var Tooltip$1 = _interopDefault(require('@material-ui/core/Tooltip'));
70
68
  var AssemblySelector = _interopDefault(require('@jbrowse/core/ui/AssemblySelector'));
71
69
  var ArrowDown = _interopDefault(require('@material-ui/icons/KeyboardArrowDown'));
72
70
  var Menu = _interopDefault(require('@jbrowse/core/ui/Menu'));
@@ -292,6 +290,8 @@ function _assertThisInitialized(self) {
292
290
  function _possibleConstructorReturn(self, call) {
293
291
  if (call && (typeof call === "object" || typeof call === "function")) {
294
292
  return call;
293
+ } else if (call !== void 0) {
294
+ throw new TypeError("Derived constructors may only return object or undefined");
295
295
  }
296
296
 
297
297
  return _assertThisInitialized(self);
@@ -555,11 +555,9 @@ var runtime_1 = /*#__PURE__*/createCommonjsModule(function (module) {
555
555
 
556
556
 
557
557
  var IteratorPrototype = {};
558
-
559
- IteratorPrototype[iteratorSymbol] = function () {
558
+ define(IteratorPrototype, iteratorSymbol, function () {
560
559
  return this;
561
- };
562
-
560
+ });
563
561
  var getProto = Object.getPrototypeOf;
564
562
  var NativeIteratorPrototype = getProto && getProto(getProto(values([])));
565
563
 
@@ -570,8 +568,9 @@ var runtime_1 = /*#__PURE__*/createCommonjsModule(function (module) {
570
568
  }
571
569
 
572
570
  var Gp = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(IteratorPrototype);
573
- GeneratorFunction.prototype = Gp.constructor = GeneratorFunctionPrototype;
574
- GeneratorFunctionPrototype.constructor = GeneratorFunction;
571
+ GeneratorFunction.prototype = GeneratorFunctionPrototype;
572
+ define(Gp, "constructor", GeneratorFunctionPrototype);
573
+ define(GeneratorFunctionPrototype, "constructor", GeneratorFunction);
575
574
  GeneratorFunction.displayName = define(GeneratorFunctionPrototype, toStringTagSymbol, "GeneratorFunction"); // Helper for defining the .next, .throw, and .return methods of the
576
575
  // Iterator interface in terms of a single ._invoke method.
577
576
 
@@ -676,11 +675,9 @@ var runtime_1 = /*#__PURE__*/createCommonjsModule(function (module) {
676
675
  }
677
676
 
678
677
  defineIteratorMethods(AsyncIterator.prototype);
679
-
680
- AsyncIterator.prototype[asyncIteratorSymbol] = function () {
678
+ define(AsyncIterator.prototype, asyncIteratorSymbol, function () {
681
679
  return this;
682
- };
683
-
680
+ });
684
681
  exports.AsyncIterator = AsyncIterator; // Note that simple async functions are implemented on top of
685
682
  // AsyncIterator objects; they just return a Promise for the value of
686
683
  // the final result produced by the iterator.
@@ -857,13 +854,12 @@ var runtime_1 = /*#__PURE__*/createCommonjsModule(function (module) {
857
854
  // object to not be returned from this call. This ensures that doesn't happen.
858
855
  // See https://github.com/facebook/regenerator/issues/274 for more details.
859
856
 
860
- Gp[iteratorSymbol] = function () {
857
+ define(Gp, iteratorSymbol, function () {
861
858
  return this;
862
- };
863
-
864
- Gp.toString = function () {
859
+ });
860
+ define(Gp, "toString", function () {
865
861
  return "[object Generator]";
866
- };
862
+ });
867
863
 
868
864
  function pushTryEntry(locs) {
869
865
  var entry = {
@@ -1175,14 +1171,19 @@ var runtime_1 = /*#__PURE__*/createCommonjsModule(function (module) {
1175
1171
  } catch (accidentalStrictMode) {
1176
1172
  // This module should not be running in strict mode, so the above
1177
1173
  // assignment should always work unless something is misconfigured. Just
1178
- // in case runtime.js accidentally runs in strict mode, we can escape
1174
+ // in case runtime.js accidentally runs in strict mode, in modern engines
1175
+ // we can explicitly access globalThis. In older engines we can escape
1179
1176
  // strict mode using a global Function call. This could conceivably fail
1180
1177
  // if a Content Security Policy forbids using Function, but in that case
1181
1178
  // the proper solution is to fix the accidental strict mode problem. If
1182
1179
  // you've misconfigured your bundler to force strict mode and applied a
1183
1180
  // CSP to forbid Function, and you're not willing to fix either of those
1184
1181
  // problems, please detail your unique predicament in a GitHub issue.
1185
- Function("r", "regeneratorRuntime = r")(runtime);
1182
+ if (typeof globalThis === "object") {
1183
+ globalThis.regeneratorRuntime = runtime;
1184
+ } else {
1185
+ Function("r", "regeneratorRuntime = r")(runtime);
1186
+ }
1186
1187
  }
1187
1188
  });
1188
1189
 
@@ -1336,49 +1337,125 @@ LinearBlocks.propTypes = {
1336
1337
  };
1337
1338
  var LinearBlocks$1 = /*#__PURE__*/mobxReact.observer(LinearBlocks);
1338
1339
 
1339
- var useStyles$2 = /*#__PURE__*/styles.makeStyles({
1340
- display: {
1341
- position: 'relative',
1342
- whiteSpace: 'nowrap',
1343
- textAlign: 'left',
1344
- width: '100%',
1345
- minHeight: '100%'
1346
- }
1340
+ function round(value) {
1341
+ return Math.round(value * 1e5) / 1e5;
1342
+ }
1343
+
1344
+ var useStyles$2 = /*#__PURE__*/core.makeStyles(function (theme) {
1345
+ return {
1346
+ display: {
1347
+ position: 'relative',
1348
+ whiteSpace: 'nowrap',
1349
+ textAlign: 'left',
1350
+ width: '100%',
1351
+ minHeight: '100%'
1352
+ },
1353
+ // these styles come from
1354
+ // https://github.com/mui-org/material-ui/blob/master/packages/material-ui/src/Tooltip/Tooltip.js
1355
+ tooltip: {
1356
+ pointerEvents: 'none',
1357
+ backgroundColor: core.alpha(theme.palette.grey[700], 0.9),
1358
+ borderRadius: theme.shape.borderRadius,
1359
+ color: theme.palette.common.white,
1360
+ fontFamily: theme.typography.fontFamily,
1361
+ padding: '4px 8px',
1362
+ fontSize: theme.typography.pxToRem(10),
1363
+ lineHeight: "".concat(round(14 / 10), "em"),
1364
+ maxWidth: 300,
1365
+ wordWrap: 'break-word',
1366
+ fontWeight: theme.typography.fontWeightMedium
1367
+ }
1368
+ };
1347
1369
  });
1348
- var Tooltip = /*#__PURE__*/mobxReact.observer(function (props) {
1349
- var model = props.model,
1350
- mouseCoord = props.mouseCoord;
1370
+ var TooltipContents = /*#__PURE__*/React__default.forwardRef(function (_ref, ref) {
1371
+ var message = _ref.message;
1372
+ return /*#__PURE__*/React__default.createElement("div", {
1373
+ ref: ref
1374
+ }, message);
1375
+ });
1376
+ var Tooltip = /*#__PURE__*/mobxReact.observer(function (_ref2) {
1377
+ var model = _ref2.model,
1378
+ clientMouseCoord = _ref2.clientMouseCoord;
1379
+ var classes = useStyles$2();
1351
1380
  var featureUnderMouse = model.featureUnderMouse;
1352
- var mouseover = featureUnderMouse ? configuration.getConf(model, 'mouseover', {
1381
+
1382
+ var _useState = React.useState(0),
1383
+ _useState2 = _slicedToArray(_useState, 2),
1384
+ width = _useState2[0],
1385
+ setWidth = _useState2[1];
1386
+
1387
+ var _useState3 = React.useState(null),
1388
+ _useState4 = _slicedToArray(_useState3, 2),
1389
+ popperElt = _useState4[0],
1390
+ setPopperElt = _useState4[1]; // must be memoized a la https://github.com/popperjs/react-popper/issues/391
1391
+
1392
+
1393
+ var virtElement = React.useMemo(function () {
1394
+ return {
1395
+ getBoundingClientRect: function getBoundingClientRect() {
1396
+ var x = clientMouseCoord[0] + width / 2 + 20;
1397
+ var y = clientMouseCoord[1];
1398
+ return {
1399
+ top: y,
1400
+ left: x,
1401
+ bottom: y,
1402
+ right: x,
1403
+ width: 0,
1404
+ height: 0,
1405
+ x: x,
1406
+ y: y,
1407
+ toJSON: function toJSON() {}
1408
+ };
1409
+ }
1410
+ };
1411
+ }, [clientMouseCoord, width]);
1412
+
1413
+ var _usePopper = reactPopper.usePopper(virtElement, popperElt),
1414
+ styles = _usePopper.styles,
1415
+ attributes = _usePopper.attributes;
1416
+
1417
+ var contents = featureUnderMouse ? configuration.getConf(model, 'mouseover', {
1353
1418
  feature: featureUnderMouse
1354
1419
  }) : undefined;
1355
- return mouseover ? /*#__PURE__*/React__default.createElement(MUITooltip, {
1356
- title: mouseover,
1357
- open: true,
1358
- placement: "right"
1359
- }, /*#__PURE__*/React__default.createElement("div", {
1360
- style: {
1361
- position: 'absolute',
1362
- left: mouseCoord[0],
1363
- top: mouseCoord[1]
1364
- }
1365
- }, ' ')) : null;
1420
+ return featureUnderMouse && contents ? /*#__PURE__*/React__default.createElement(core.Portal, null, /*#__PURE__*/React__default.createElement("div", Object.assign({
1421
+ ref: setPopperElt,
1422
+ className: classes.tooltip,
1423
+ // zIndex needed to go over widget drawer
1424
+ style: _objectSpread2(_objectSpread2({}, styles.popper), {}, {
1425
+ zIndex: 100000
1426
+ })
1427
+ }, attributes.popper), /*#__PURE__*/React__default.createElement(TooltipContents, {
1428
+ ref: function ref(elt) {
1429
+ return setWidth((elt === null || elt === void 0 ? void 0 : elt.getBoundingClientRect().width) || 0);
1430
+ },
1431
+ message: contents
1432
+ }))) : null;
1366
1433
  });
1367
1434
  var BaseLinearDisplay = /*#__PURE__*/mobxReact.observer(function (props) {
1368
1435
  var classes = useStyles$2();
1369
- var theme = styles.useTheme();
1436
+ var theme = core.useTheme();
1437
+ var ref = React.useRef(null);
1370
1438
 
1371
- var _useState = React.useState([0, 0]),
1372
- _useState2 = _slicedToArray(_useState, 2),
1373
- mouseCoord = _useState2[0],
1374
- setMouseCoord = _useState2[1];
1439
+ var _useState5 = React.useState(),
1440
+ _useState6 = _slicedToArray(_useState5, 2),
1441
+ clientRect = _useState6[0],
1442
+ setClientRect = _useState6[1];
1375
1443
 
1376
- var _useState3 = React.useState(),
1377
- _useState4 = _slicedToArray(_useState3, 2),
1378
- contextCoord = _useState4[0],
1379
- setContextCoord = _useState4[1];
1444
+ var _useState7 = React.useState([0, 0]),
1445
+ _useState8 = _slicedToArray(_useState7, 2),
1446
+ offsetMouseCoord = _useState8[0],
1447
+ setOffsetMouseCoord = _useState8[1];
1448
+
1449
+ var _useState9 = React.useState([0, 0]),
1450
+ _useState10 = _slicedToArray(_useState9, 2),
1451
+ clientMouseCoord = _useState10[0],
1452
+ setClientMouseCoord = _useState10[1];
1453
+
1454
+ var _useState11 = React.useState(),
1455
+ _useState12 = _slicedToArray(_useState11, 2),
1456
+ contextCoord = _useState12[0],
1457
+ setContextCoord = _useState12[1];
1380
1458
 
1381
- var ref = React.useRef(null);
1382
1459
  var model = props.model,
1383
1460
  children = props.children;
1384
1461
  var TooltipComponent = model.TooltipComponent,
@@ -1403,7 +1480,9 @@ var BaseLinearDisplay = /*#__PURE__*/mobxReact.observer(function (props) {
1403
1480
  onMouseMove: function onMouseMove(event) {
1404
1481
  if (ref.current) {
1405
1482
  var rect = ref.current.getBoundingClientRect();
1406
- setMouseCoord([event.clientX - rect.left, event.clientY - rect.top]);
1483
+ setOffsetMouseCoord([event.clientX - rect.left, event.clientY - rect.top]);
1484
+ setClientMouseCoord([event.clientX, event.clientY]);
1485
+ setClientRect(rect);
1407
1486
  }
1408
1487
  },
1409
1488
  role: "presentation"
@@ -1412,7 +1491,10 @@ var BaseLinearDisplay = /*#__PURE__*/mobxReact.observer(function (props) {
1412
1491
  }) : /*#__PURE__*/React__default.createElement(LinearBlocks$1, Object.assign({}, props)), children, /*#__PURE__*/React__default.createElement(TooltipComponent, {
1413
1492
  model: model,
1414
1493
  height: height,
1415
- mouseCoord: mouseCoord
1494
+ offsetMouseCoord: offsetMouseCoord,
1495
+ clientMouseCoord: clientMouseCoord,
1496
+ clientRect: clientRect,
1497
+ mouseCoord: offsetMouseCoord
1416
1498
  }), /*#__PURE__*/React__default.createElement(ui.Menu, {
1417
1499
  open: Boolean(contextCoord) && Boolean(contextMenuItems().length),
1418
1500
  onMenuItemClick: function onMenuItemClick(_, callback) {
@@ -1708,6 +1790,10 @@ var blockState = /*#__PURE__*/mobxStateTree.types.model('BlockState', {
1708
1790
  self.error = error;
1709
1791
  self.renderProps = undefined;
1710
1792
  renderInProgress = undefined;
1793
+
1794
+ if (types.isRetryException(error)) {
1795
+ this.reload();
1796
+ }
1711
1797
  },
1712
1798
  reload: function reload() {
1713
1799
  self.renderInProgress = undefined;
@@ -1945,8 +2031,9 @@ var BaseLinearDisplay$1 = /*#__PURE__*/mobxStateTree.types.compose('BaseLinearDi
1945
2031
  */
1946
2032
  get selectedFeatureId() {
1947
2033
  if (mobxStateTree.isAlive(self)) {
1948
- var session = util.getSession(self);
1949
- var selection = session.selection; // does it quack like a feature?
2034
+ var _getSession = util.getSession(self),
2035
+ selection = _getSession.selection; // does it quack like a feature?
2036
+
1950
2037
 
1951
2038
  if (simpleFeature.isFeature(selection)) {
1952
2039
  return selection.id();
@@ -2003,7 +2090,13 @@ var BaseLinearDisplay$1 = /*#__PURE__*/mobxStateTree.types.compose('BaseLinearDi
2003
2090
 
2004
2091
  return (_self$blockState$get = self.blockState.get(blockKey)) === null || _self$blockState$get === void 0 ? void 0 : (_self$blockState$get$ = _self$blockState$get.layout) === null || _self$blockState$get$ === void 0 ? void 0 : _self$blockState$get$.getByCoord(x, y);
2005
2092
  },
2006
- getFeatureByID: function getFeatureByID(id) {
2093
+ getFeatureByID: function getFeatureByID(blockKey, id) {
2094
+ var _self$blockState$get2, _self$blockState$get3;
2095
+
2096
+ return (_self$blockState$get2 = self.blockState.get(blockKey)) === null || _self$blockState$get2 === void 0 ? void 0 : (_self$blockState$get3 = _self$blockState$get2.layout) === null || _self$blockState$get3 === void 0 ? void 0 : _self$blockState$get3.getByID(id);
2097
+ },
2098
+ // if block key is not supplied, can look at all blocks
2099
+ searchFeatureByID: function searchFeatureByID(id) {
2007
2100
  var ret;
2008
2101
  self.blockState.forEach(function (block) {
2009
2102
  var _block$layout;
@@ -2333,51 +2426,36 @@ function stateModelFactory(configSchema) {
2333
2426
  });
2334
2427
  }
2335
2428
 
2336
- var filter = /*#__PURE__*/Autocomplete.createFilterOptions({
2337
- trim: true,
2338
- ignoreCase: true,
2339
- limit: 100
2340
- });
2341
-
2342
2429
  function fetchResults(_x, _x2, _x3) {
2343
2430
  return _fetchResults.apply(this, arguments);
2344
- }
2431
+ } // the logic of this method is to only apply a filter to RefSequenceResults
2432
+ // because they do not have a matchedObject. the trix search results already
2433
+ // filter so don't need re-filtering
2434
+
2345
2435
 
2346
2436
  function _fetchResults() {
2347
2437
  _fetchResults = _asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee2(self, query, assemblyName) {
2348
- var session, _getEnv, pluginManager, rankSearchResults, textSearchManager, searchScope, args, searchResults;
2438
+ var _getSession, textSearchManager, rankSearchResults, searchScope;
2349
2439
 
2350
2440
  return runtime_1.wrap(function _callee2$(_context2) {
2351
2441
  while (1) {
2352
2442
  switch (_context2.prev = _context2.next) {
2353
2443
  case 0:
2354
- session = util.getSession(self);
2355
- _getEnv = mobxStateTree.getEnv(session), pluginManager = _getEnv.pluginManager;
2444
+ _getSession = util.getSession(self), textSearchManager = _getSession.textSearchManager;
2356
2445
  rankSearchResults = self.rankSearchResults;
2357
- textSearchManager = pluginManager.rootModel.textSearchManager;
2358
2446
  searchScope = self.searchScope(assemblyName);
2359
- args = {
2447
+ return _context2.abrupt("return", textSearchManager === null || textSearchManager === void 0 ? void 0 : textSearchManager.search({
2360
2448
  queryString: query,
2361
2449
  searchType: 'prefix'
2362
- };
2363
- _context2.next = 8;
2364
- return textSearchManager === null || textSearchManager === void 0 ? void 0 : textSearchManager.search(args, searchScope, rankSearchResults);
2365
-
2366
- case 8:
2367
- _context2.t0 = _context2.sent;
2368
-
2369
- if (_context2.t0) {
2370
- _context2.next = 11;
2371
- break;
2372
- }
2373
-
2374
- _context2.t0 = [];
2375
-
2376
- case 11:
2377
- searchResults = _context2.t0;
2378
- return _context2.abrupt("return", searchResults);
2450
+ }, searchScope, rankSearchResults).then(function (results) {
2451
+ return results.filter(function (elem, index, self) {
2452
+ return index === self.findIndex(function (t) {
2453
+ return t.label === elem.label;
2454
+ });
2455
+ });
2456
+ }));
2379
2457
 
2380
- case 13:
2458
+ case 4:
2381
2459
  case "end":
2382
2460
  return _context2.stop();
2383
2461
  }
@@ -2387,6 +2465,27 @@ function _fetchResults() {
2387
2465
  return _fetchResults.apply(this, arguments);
2388
2466
  }
2389
2467
 
2468
+ function _filterOptions(options, searchQuery) {
2469
+ return options.filter(function (option) {
2470
+ var result = option.result;
2471
+ return result.getLabel().toLowerCase().includes(searchQuery) || result.matchedObject;
2472
+ });
2473
+ } // MyPopper used to expand search results box wider if needed
2474
+ // xref https://stackoverflow.com/a/63583835/2129219
2475
+
2476
+
2477
+ var MyPopper = function MyPopper(props) {
2478
+ var style = props.style;
2479
+ return /*#__PURE__*/React__default.createElement(core.Popper, Object.assign({}, props, {
2480
+ style: {
2481
+ width: 'fit-content',
2482
+ minWidth: Math.min(+((style === null || style === void 0 ? void 0 : style.width) || 0), 200),
2483
+ background: 'white'
2484
+ },
2485
+ placement: "bottom-start"
2486
+ }));
2487
+ };
2488
+
2390
2489
  function RefNameAutocomplete(_ref) {
2391
2490
  var model = _ref.model,
2392
2491
  onSelect = _ref.onSelect,
@@ -2396,36 +2495,41 @@ function RefNameAutocomplete(_ref) {
2396
2495
  _ref$TextFieldProps = _ref.TextFieldProps,
2397
2496
  TextFieldProps = _ref$TextFieldProps === void 0 ? {} : _ref$TextFieldProps;
2398
2497
  var session = util.getSession(model);
2498
+ var assemblyManager = session.assemblyManager;
2399
2499
 
2400
2500
  var _useState = React.useState(false),
2401
2501
  _useState2 = _slicedToArray(_useState, 2),
2402
2502
  open = _useState2[0],
2403
2503
  setOpen = _useState2[1];
2404
2504
 
2405
- var _useState3 = React.useState(),
2505
+ var _useState3 = React.useState(true),
2406
2506
  _useState4 = _slicedToArray(_useState3, 2),
2407
- error = _useState4[0],
2408
- setError = _useState4[1];
2507
+ loaded = _useState4[0],
2508
+ setLoaded = _useState4[1];
2409
2509
 
2410
2510
  var _useState5 = React.useState(''),
2411
2511
  _useState6 = _slicedToArray(_useState5, 2),
2412
2512
  currentSearch = _useState6[0],
2413
2513
  setCurrentSearch = _useState6[1];
2414
2514
 
2415
- var debouncedSearch = util.useDebounce(currentSearch, 300);
2416
-
2417
- var _useState7 = React.useState([]),
2515
+ var _useState7 = React.useState(''),
2418
2516
  _useState8 = _slicedToArray(_useState7, 2),
2419
- searchOptions = _useState8[0],
2420
- setSearchOptions = _useState8[1];
2517
+ inputValue = _useState8[0],
2518
+ setInputValue = _useState8[1];
2421
2519
 
2422
- var assemblyManager = session.assemblyManager;
2423
- var coarseVisibleLocStrings = model.coarseVisibleLocStrings;
2520
+ var _useState9 = React.useState([]),
2521
+ _useState10 = _slicedToArray(_useState9, 2),
2522
+ searchOptions = _useState10[0],
2523
+ setSearchOptions = _useState10[1];
2524
+
2525
+ var debouncedSearch = util.useDebounce(currentSearch, 300);
2526
+ var coarseVisibleLocStrings = model.coarseVisibleLocStrings,
2527
+ hasDisplayedRegions = model.hasDisplayedRegions;
2424
2528
  var assembly = assemblyName ? assemblyManager.get(assemblyName) : undefined; // eslint-disable-next-line react-hooks/exhaustive-deps
2425
2529
 
2426
2530
  var regions = (assembly === null || assembly === void 0 ? void 0 : assembly.regions) || [];
2427
2531
  var options = React.useMemo(function () {
2428
- var defaultOptions = regions.map(function (option) {
2532
+ return regions.map(function (option) {
2429
2533
  return {
2430
2534
  result: new BaseResult.RefSequenceResult({
2431
2535
  refName: option.refName,
@@ -2434,40 +2538,43 @@ function RefNameAutocomplete(_ref) {
2434
2538
  })
2435
2539
  };
2436
2540
  });
2437
- return defaultOptions;
2438
2541
  }, [regions]);
2439
2542
  React.useEffect(function () {
2440
2543
  var active = true;
2441
2544
 
2442
2545
  _asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee() {
2443
- var results, searchResults, adapterResults;
2546
+ var results;
2444
2547
  return runtime_1.wrap(function _callee$(_context) {
2445
2548
  while (1) {
2446
2549
  switch (_context.prev = _context.next) {
2447
2550
  case 0:
2448
2551
  _context.prev = 0;
2449
- results = [];
2450
2552
 
2451
- if (!(debouncedSearch && debouncedSearch !== '' && assemblyName)) {
2452
- _context.next = 7;
2553
+ if (!(debouncedSearch === '' || !assemblyName)) {
2554
+ _context.next = 3;
2453
2555
  break;
2454
2556
  }
2455
2557
 
2456
- _context.next = 5;
2558
+ return _context.abrupt("return");
2559
+
2560
+ case 3:
2561
+ setLoaded(false);
2562
+ _context.next = 6;
2457
2563
  return fetchResults(model, debouncedSearch, assemblyName);
2458
2564
 
2459
- case 5:
2460
- searchResults = _context.sent;
2461
- results = results.concat(searchResults);
2565
+ case 6:
2566
+ results = _context.sent;
2462
2567
 
2463
- case 7:
2464
- if (results.length > 0 && active) {
2465
- adapterResults = results.map(function (result) {
2466
- return {
2467
- result: result
2468
- };
2469
- });
2470
- setSearchOptions(adapterResults);
2568
+ if (active) {
2569
+ if (results && results.length >= 0) {
2570
+ setSearchOptions(results.map(function (result) {
2571
+ return {
2572
+ result: result
2573
+ };
2574
+ }));
2575
+ }
2576
+
2577
+ setLoaded(true);
2471
2578
  }
2472
2579
 
2473
2580
  _context.next = 14;
@@ -2479,7 +2586,7 @@ function RefNameAutocomplete(_ref) {
2479
2586
  console.error(_context.t0);
2480
2587
 
2481
2588
  if (active) {
2482
- setError(_context.t0);
2589
+ session.notify("".concat(_context.t0), 'error');
2483
2590
  }
2484
2591
 
2485
2592
  case 14:
@@ -2493,87 +2600,98 @@ function RefNameAutocomplete(_ref) {
2493
2600
  return function () {
2494
2601
  active = false;
2495
2602
  };
2496
- }, [assemblyName, debouncedSearch, model]);
2603
+ }, [assemblyName, debouncedSearch, session, model]);
2604
+ var inputBoxVal = coarseVisibleLocStrings || value || ''; // heuristic, text width + icon width, minimum 200
2497
2605
 
2498
- function _onChange(selectedOption) {
2499
- if (selectedOption && assemblyName) {
2500
- if (typeof selectedOption === 'string') {
2501
- // handles string inputs on keyPress enter
2502
- var newResult = new BaseResult__default({
2503
- label: selectedOption
2504
- });
2505
- onSelect(newResult);
2506
- } else {
2507
- var result = selectedOption.result;
2508
- onSelect(result);
2509
- }
2510
- }
2511
- }
2606
+ var width = Math.min(Math.max(util.measureText(inputBoxVal, 16) + 25, 200), 550); // notes on implementation:
2607
+ // The selectOnFocus setting helps highlight the field when clicked
2512
2608
 
2513
- return /*#__PURE__*/React__default.createElement(React__default.Fragment, null, /*#__PURE__*/React__default.createElement(Autocomplete__default, {
2609
+ return /*#__PURE__*/React__default.createElement(Autocomplete, {
2514
2610
  id: "refNameAutocomplete-".concat(model.id),
2515
2611
  "data-testid": "autocomplete",
2516
- freeSolo: true,
2517
2612
  disableListWrap: true,
2518
2613
  disableClearable: true,
2614
+ PopperComponent: MyPopper,
2615
+ disabled: !assemblyName,
2616
+ freeSolo: true,
2519
2617
  includeInputInList: true,
2520
- clearOnBlur: true,
2521
2618
  selectOnFocus: true,
2522
- disabled: !!error || !assemblyName,
2523
- style: style,
2524
- value: coarseVisibleLocStrings || value || '',
2619
+ style: _objectSpread2(_objectSpread2({}, style), {}, {
2620
+ width: width
2621
+ }),
2622
+ value: inputBoxVal,
2623
+ loading: !loaded,
2624
+ inputValue: inputValue,
2625
+ onInputChange: function onInputChange(event, newInputValue) {
2626
+ return setInputValue(newInputValue);
2627
+ },
2628
+ loadingText: "loading results",
2525
2629
  open: open,
2526
2630
  onOpen: function onOpen() {
2527
2631
  return setOpen(true);
2528
2632
  },
2529
2633
  onClose: function onClose() {
2530
2634
  setOpen(false);
2531
- setCurrentSearch('');
2532
- setSearchOptions([]);
2635
+ setLoaded(true);
2636
+
2637
+ if (hasDisplayedRegions) {
2638
+ setCurrentSearch('');
2639
+ setSearchOptions([]);
2640
+ }
2641
+ },
2642
+ onChange: function onChange(_event, selectedOption) {
2643
+ if (!selectedOption || !assemblyName) {
2644
+ return;
2645
+ }
2646
+
2647
+ if (typeof selectedOption === 'string') {
2648
+ // handles string inputs on keyPress enter
2649
+ onSelect(new BaseResult__default({
2650
+ label: selectedOption
2651
+ }));
2652
+ } else {
2653
+ onSelect(selectedOption.result);
2654
+ }
2655
+
2656
+ setInputValue(inputBoxVal);
2533
2657
  },
2534
2658
  options: searchOptions.length === 0 ? options : searchOptions,
2535
2659
  getOptionDisabled: function getOptionDisabled(option) {
2536
2660
  return (option === null || option === void 0 ? void 0 : option.group) === 'limitOption';
2537
2661
  },
2538
- filterOptions: function filterOptions(possibleOptions, params) {
2539
- var filtered = filter(possibleOptions, params);
2540
- return filtered.length >= 100 ? filtered.concat([{
2662
+ filterOptions: function filterOptions(options, params) {
2663
+ var filtered = _filterOptions(options, params.inputValue.toLocaleLowerCase());
2664
+
2665
+ return [].concat(_toConsumableArray(filtered.slice(0, 100)), _toConsumableArray(filtered.length > 100 ? [{
2541
2666
  group: 'limitOption',
2542
2667
  result: new BaseResult__default({
2543
- label: 'keep typing for more results',
2544
- renderingComponent: /*#__PURE__*/React__default.createElement(Typography, null, 'keep typing for more results')
2668
+ label: 'keep typing for more results'
2545
2669
  })
2546
- }]) : filtered;
2547
- },
2548
- ListboxProps: {
2549
- style: {
2550
- maxHeight: 250
2551
- }
2552
- },
2553
- onChange: function onChange(_, selectedOption) {
2554
- return _onChange(selectedOption);
2670
+ }] : []));
2555
2671
  },
2556
2672
  renderInput: function renderInput(params) {
2557
2673
  var helperText = TextFieldProps.helperText,
2558
2674
  _TextFieldProps$Input = TextFieldProps.InputProps,
2559
2675
  InputProps = _TextFieldProps$Input === void 0 ? {} : _TextFieldProps$Input;
2560
-
2561
- var TextFieldInputProps = _objectSpread2(_objectSpread2(_objectSpread2({}, params.InputProps), InputProps), {}, {
2562
- endAdornment: /*#__PURE__*/React__default.createElement(React__default.Fragment, null, regions.length === 0 && searchOptions.length === 0 ? /*#__PURE__*/React__default.createElement(CircularProgress, {
2563
- color: "inherit",
2564
- size: 20
2565
- }) : /*#__PURE__*/React__default.createElement(core.InputAdornment, {
2566
- position: "end",
2567
- style: {
2568
- marginRight: 7
2569
- }
2570
- }, /*#__PURE__*/React__default.createElement(SearchIcon, null)), params.InputProps.endAdornment)
2571
- });
2572
-
2573
- return /*#__PURE__*/React__default.createElement(TextField, Object.assign({}, params, TextFieldProps, {
2676
+ return /*#__PURE__*/React__default.createElement(core.TextField, Object.assign({
2677
+ onBlur: function onBlur() {
2678
+ // this is used to restore a refName or the non-user-typed input
2679
+ // to the box on blurring
2680
+ setInputValue(inputBoxVal);
2681
+ }
2682
+ }, params, TextFieldProps, {
2574
2683
  helperText: helperText,
2575
- value: coarseVisibleLocStrings || value || '',
2576
- InputProps: TextFieldInputProps,
2684
+ InputProps: _objectSpread2(_objectSpread2(_objectSpread2({}, params.InputProps), InputProps), {}, {
2685
+ endAdornment: /*#__PURE__*/React__default.createElement(React__default.Fragment, null, regions.length === 0 ? /*#__PURE__*/React__default.createElement(core.CircularProgress, {
2686
+ color: "inherit",
2687
+ size: 20
2688
+ }) : /*#__PURE__*/React__default.createElement(core.InputAdornment, {
2689
+ position: "end",
2690
+ style: {
2691
+ marginRight: 7
2692
+ }
2693
+ }, /*#__PURE__*/React__default.createElement(SearchIcon, null)), params.InputProps.endAdornment)
2694
+ }),
2577
2695
  placeholder: "Search for location",
2578
2696
  onChange: function onChange(e) {
2579
2697
  setCurrentSearch(e.target.value);
@@ -2582,28 +2700,20 @@ function RefNameAutocomplete(_ref) {
2582
2700
  },
2583
2701
  renderOption: function renderOption(option) {
2584
2702
  var result = option.result;
2585
- var rendering = result.getLabel(); // if renderingComponent is provided render that
2586
-
2587
2703
  var component = result.getRenderingComponent();
2588
2704
 
2589
- if (component) {
2590
- if ( /*#__PURE__*/React__default.isValidElement(component)) {
2591
- return component;
2592
- }
2705
+ if (component && /*#__PURE__*/React__default.isValidElement(component)) {
2706
+ return component;
2593
2707
  }
2594
2708
 
2595
- return /*#__PURE__*/React__default.createElement(Typography, {
2709
+ return /*#__PURE__*/React__default.createElement(core.Typography, {
2596
2710
  noWrap: true
2597
- }, rendering);
2711
+ }, result.getDisplayString());
2598
2712
  },
2599
2713
  getOptionLabel: function getOptionLabel(option) {
2600
- // needed for filtering options and value
2601
2714
  return (typeof option === 'string' ? option : option.result.getLabel()) || '';
2602
2715
  }
2603
- }), error ? /*#__PURE__*/React__default.createElement(Typography, {
2604
- variant: "h6",
2605
- color: "error"
2606
- }, "".concat(error)) : null);
2716
+ });
2607
2717
  }
2608
2718
 
2609
2719
  var RefNameAutocomplete$1 = /*#__PURE__*/mobxReact.observer(RefNameAutocomplete);
@@ -3132,7 +3242,8 @@ var ScaleBar = /*#__PURE__*/mobxReact.observer(function (_ref2) {
3132
3242
  }
3133
3243
  }, /*#__PURE__*/React__default.createElement(core.Typography, {
3134
3244
  style: {
3135
- color: refNameColor
3245
+ color: refNameColor,
3246
+ zIndex: 100
3136
3247
  },
3137
3248
  className: classes.scaleBarRefName
3138
3249
  }, seq.refName), tickLabels.map(function (tickLabel, labelIdx) {
@@ -3250,9 +3361,17 @@ function ZoomControls(_ref) {
3250
3361
 
3251
3362
  var ZoomControls$1 = /*#__PURE__*/mobxReact.observer(ZoomControls);
3252
3363
 
3364
+ function dedupe(results) {
3365
+ return results === null || results === void 0 ? void 0 : results.filter(function (elem, index, self) {
3366
+ return index === self.findIndex(function (t) {
3367
+ return t.getId() === elem.getId();
3368
+ });
3369
+ });
3370
+ }
3371
+
3253
3372
  var WIDGET_HEIGHT = 32;
3254
3373
  var SPACING = 7;
3255
- var useStyles$7 = /*#__PURE__*/styles.makeStyles(function (theme) {
3374
+ var useStyles$7 = /*#__PURE__*/core.makeStyles(function (theme) {
3256
3375
  return {
3257
3376
  headerBar: {
3258
3377
  height: HEADER_BAR_HEIGHT,
@@ -3270,7 +3389,7 @@ var useStyles$7 = /*#__PURE__*/styles.makeStyles(function (theme) {
3270
3389
  minWidth: 100
3271
3390
  },
3272
3391
  panButton: {
3273
- background: styles.alpha(theme.palette.background.paper, 0.8),
3392
+ background: core.alpha(theme.palette.background.paper, 0.8),
3274
3393
  height: WIDGET_HEIGHT,
3275
3394
  margin: SPACING
3276
3395
  },
@@ -3292,7 +3411,7 @@ var useStyles$7 = /*#__PURE__*/styles.makeStyles(function (theme) {
3292
3411
  var Controls = /*#__PURE__*/mobxReact.observer(function (_ref) {
3293
3412
  var model = _ref.model;
3294
3413
  var classes = useStyles$7();
3295
- return /*#__PURE__*/React__default.createElement(Button, {
3414
+ return /*#__PURE__*/React__default.createElement(core.Button, {
3296
3415
  onClick: model.activateTrackSelector,
3297
3416
  className: classes.toggleButton,
3298
3417
  title: "Open track selector",
@@ -3306,13 +3425,13 @@ var Controls = /*#__PURE__*/mobxReact.observer(function (_ref) {
3306
3425
  function PanControls(_ref2) {
3307
3426
  var model = _ref2.model;
3308
3427
  var classes = useStyles$7();
3309
- return /*#__PURE__*/React__default.createElement(React__default.Fragment, null, /*#__PURE__*/React__default.createElement(Button, {
3428
+ return /*#__PURE__*/React__default.createElement(React__default.Fragment, null, /*#__PURE__*/React__default.createElement(core.Button, {
3310
3429
  variant: "outlined",
3311
3430
  className: classes.panButton,
3312
3431
  onClick: function onClick() {
3313
3432
  return model.slide(-0.9);
3314
3433
  }
3315
- }, /*#__PURE__*/React__default.createElement(ArrowBackIcon, null)), /*#__PURE__*/React__default.createElement(Button, {
3434
+ }, /*#__PURE__*/React__default.createElement(ArrowBackIcon, null)), /*#__PURE__*/React__default.createElement(core.Button, {
3316
3435
  variant: "outlined",
3317
3436
  className: classes.panButton,
3318
3437
  onClick: function onClick() {
@@ -3325,7 +3444,7 @@ var RegionWidth = /*#__PURE__*/mobxReact.observer(function (_ref3) {
3325
3444
  var model = _ref3.model;
3326
3445
  var classes = useStyles$7();
3327
3446
  var coarseTotalBp = model.coarseTotalBp;
3328
- return /*#__PURE__*/React__default.createElement(Typography, {
3447
+ return /*#__PURE__*/React__default.createElement(core.Typography, {
3329
3448
  variant: "body2",
3330
3449
  color: "textSecondary",
3331
3450
  className: classes.bp
@@ -3334,106 +3453,123 @@ var RegionWidth = /*#__PURE__*/mobxReact.observer(function (_ref3) {
3334
3453
  var LinearGenomeViewHeader = /*#__PURE__*/mobxReact.observer(function (_ref4) {
3335
3454
  var model = _ref4.model;
3336
3455
  var classes = useStyles$7();
3337
- var theme = styles.useTheme();
3456
+ var theme = core.useTheme();
3338
3457
  var session = util.getSession(model);
3339
- var assemblyManager = session.assemblyManager;
3340
-
3341
- var _getEnv = mobxStateTree.getEnv(session),
3342
- pluginManager = _getEnv.pluginManager;
3343
-
3344
- var textSearchManager = pluginManager.rootModel.textSearchManager;
3345
- var contentBlocks = model.coarseDynamicBlocks,
3346
- displayedRegions = model.displayedRegions,
3458
+ var textSearchManager = session.textSearchManager,
3459
+ assemblyManager = session.assemblyManager;
3460
+ var assemblyNames = model.assemblyNames,
3347
3461
  rankSearchResults = model.rankSearchResults;
3348
-
3349
- var _ref5 = contentBlocks[0] || {
3350
- refName: ''
3351
- },
3352
- assemblyName = _ref5.assemblyName,
3353
- refName = _ref5.refName;
3354
-
3355
- var assembly = assemblyName && assemblyManager.get(assemblyName);
3356
- var regions = assembly && assembly.regions || [];
3462
+ var assemblyName = assemblyNames[0];
3463
+ var assembly = assemblyManager.get(assemblyName);
3357
3464
  var searchScope = model.searchScope(assemblyName);
3358
3465
 
3359
- function setDisplayedRegion(_x) {
3360
- return _setDisplayedRegion.apply(this, arguments);
3466
+ function fetchResults(_x) {
3467
+ return _fetchResults.apply(this, arguments);
3361
3468
  }
3362
3469
 
3363
- function _setDisplayedRegion() {
3364
- _setDisplayedRegion = _asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee(result) {
3365
- var newRegionValue, newRegion, results;
3470
+ function _fetchResults() {
3471
+ _fetchResults = _asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee(queryString) {
3472
+ var results;
3366
3473
  return runtime_1.wrap(function _callee$(_context) {
3367
3474
  while (1) {
3368
3475
  switch (_context.prev = _context.next) {
3369
3476
  case 0:
3370
- if (!result) {
3371
- _context.next = 15;
3372
- break;
3477
+ if (!textSearchManager) {
3478
+ console.warn('No text search manager');
3373
3479
  }
3374
3480
 
3375
- newRegionValue = result.getLocation(); // need to fix finding region
3481
+ _context.next = 3;
3482
+ return textSearchManager === null || textSearchManager === void 0 ? void 0 : textSearchManager.search({
3483
+ queryString: queryString.toLowerCase(),
3484
+ searchType: 'exact'
3485
+ }, searchScope, rankSearchResults);
3376
3486
 
3377
- newRegion = regions.find(function (region) {
3378
- return newRegionValue === region.refName;
3379
- });
3487
+ case 3:
3488
+ results = _context.sent;
3489
+ return _context.abrupt("return", dedupe(results));
3380
3490
 
3381
- if (!newRegion) {
3382
- _context.next = 8;
3491
+ case 5:
3492
+ case "end":
3493
+ return _context.stop();
3494
+ }
3495
+ }
3496
+ }, _callee);
3497
+ }));
3498
+ return _fetchResults.apply(this, arguments);
3499
+ }
3500
+
3501
+ function handleSelectedRegion(_x2) {
3502
+ return _handleSelectedRegion.apply(this, arguments);
3503
+ }
3504
+
3505
+ function _handleSelectedRegion() {
3506
+ _handleSelectedRegion = _asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee2(option) {
3507
+ var trackId, location, label, _assembly$refNames, results;
3508
+
3509
+ return runtime_1.wrap(function _callee2$(_context2) {
3510
+ while (1) {
3511
+ switch (_context2.prev = _context2.next) {
3512
+ case 0:
3513
+ trackId = option.getTrackId();
3514
+ location = option.getLocation();
3515
+ label = option.getLabel();
3516
+ _context2.prev = 3;
3517
+
3518
+ if (!(assembly !== null && assembly !== void 0 && (_assembly$refNames = assembly.refNames) !== null && _assembly$refNames !== void 0 && _assembly$refNames.includes(location))) {
3519
+ _context2.next = 8;
3383
3520
  break;
3384
3521
  }
3385
3522
 
3386
- model.setDisplayedRegions([newRegion]); // we use showAllRegions after setDisplayedRegions to make the entire
3387
- // region visible, xref #1703
3388
-
3389
- model.showAllRegions();
3390
- _context.next = 15;
3523
+ model.navToLocString(location);
3524
+ _context2.next = 19;
3391
3525
  break;
3392
3526
 
3393
3527
  case 8:
3394
- _context.next = 10;
3395
- return textSearchManager === null || textSearchManager === void 0 ? void 0 : textSearchManager.search({
3396
- queryString: newRegionValue.toLocaleLowerCase(),
3397
- searchType: 'exact'
3398
- }, searchScope, rankSearchResults);
3528
+ _context2.next = 10;
3529
+ return fetchResults(label);
3399
3530
 
3400
3531
  case 10:
3401
- _context.t0 = _context.sent;
3532
+ results = _context2.sent;
3402
3533
 
3403
- if (_context.t0) {
3404
- _context.next = 13;
3534
+ if (!(results && results.length > 1)) {
3535
+ _context2.next = 16;
3405
3536
  break;
3406
3537
  }
3407
3538
 
3408
- _context.t0 = [];
3409
-
3410
- case 13:
3411
- results = _context.t0;
3412
-
3413
- // distinguishes between locstrings and search strings
3414
- if (results.length > 0) {
3415
- model.setSearchResults(results, newRegionValue.toLocaleLowerCase());
3416
- } else {
3417
- try {
3418
- newRegionValue !== '' && model.navToLocString(newRegionValue);
3419
- } catch (e) {
3420
- if ("".concat(e) === "Error: Unknown reference sequence \"".concat(newRegionValue, "\"")) {
3421
- model.setSearchResults(results, newRegionValue.toLocaleLowerCase());
3422
- } else {
3423
- console.warn(e);
3424
- session.notify("".concat(e), 'warning');
3425
- }
3426
- }
3539
+ model.setSearchResults(results, label.toLowerCase());
3540
+ return _context2.abrupt("return");
3541
+
3542
+ case 16:
3543
+ if ((results === null || results === void 0 ? void 0 : results.length) === 1) {
3544
+ location = results[0].getLocation();
3545
+ trackId = results[0].getTrackId();
3427
3546
  }
3428
3547
 
3429
- case 15:
3548
+ case 17:
3549
+ model.navToLocString(location, assemblyName);
3550
+
3551
+ if (trackId) {
3552
+ model.showTrack(trackId);
3553
+ }
3554
+
3555
+ case 19:
3556
+ _context2.next = 25;
3557
+ break;
3558
+
3559
+ case 21:
3560
+ _context2.prev = 21;
3561
+ _context2.t0 = _context2["catch"](3);
3562
+ console.error(_context2.t0);
3563
+ session.notify("".concat(_context2.t0), 'warning');
3564
+
3565
+ case 25:
3430
3566
  case "end":
3431
- return _context.stop();
3567
+ return _context2.stop();
3432
3568
  }
3433
3569
  }
3434
- }, _callee);
3570
+ }, _callee2, null, [[3, 21]]);
3435
3571
  }));
3436
- return _setDisplayedRegion.apply(this, arguments);
3572
+ return _handleSelectedRegion.apply(this, arguments);
3437
3573
  }
3438
3574
 
3439
3575
  var controls = /*#__PURE__*/React__default.createElement("div", {
@@ -3442,15 +3578,14 @@ var LinearGenomeViewHeader = /*#__PURE__*/mobxReact.observer(function (_ref4) {
3442
3578
  model: model
3443
3579
  }), /*#__PURE__*/React__default.createElement("div", {
3444
3580
  className: classes.spacer
3445
- }), /*#__PURE__*/React__default.createElement(FormGroup, {
3581
+ }), /*#__PURE__*/React__default.createElement(core.FormGroup, {
3446
3582
  row: true,
3447
3583
  className: classes.headerForm
3448
3584
  }, /*#__PURE__*/React__default.createElement(PanControls, {
3449
3585
  model: model
3450
3586
  }), /*#__PURE__*/React__default.createElement(RefNameAutocomplete$1, {
3451
- onSelect: setDisplayedRegion,
3587
+ onSelect: handleSelectedRegion,
3452
3588
  assemblyName: assemblyName,
3453
- value: displayedRegions.length > 1 ? '' : refName,
3454
3589
  model: model,
3455
3590
  TextFieldProps: {
3456
3591
  variant: 'outlined',
@@ -3463,7 +3598,7 @@ var LinearGenomeViewHeader = /*#__PURE__*/mobxReact.observer(function (_ref4) {
3463
3598
  style: {
3464
3599
  padding: 0,
3465
3600
  height: WIDGET_HEIGHT,
3466
- background: styles.alpha(theme.palette.background.paper, 0.8)
3601
+ background: core.alpha(theme.palette.background.paper, 0.8)
3467
3602
  }
3468
3603
  }
3469
3604
  }
@@ -3783,7 +3918,7 @@ var VerticalGuide = /*#__PURE__*/mobxReact.observer(function (_ref) {
3783
3918
  var model = _ref.model,
3784
3919
  coordX = _ref.coordX;
3785
3920
  var classes = useStyles$a();
3786
- return /*#__PURE__*/React__default.createElement(MUITooltip, {
3921
+ return /*#__PURE__*/React__default.createElement(Tooltip$1, {
3787
3922
  open: true,
3788
3923
  placement: "top",
3789
3924
  title: util.stringify(model.pxToBp(coordX)),
@@ -4574,19 +4709,6 @@ function SearchResultsDialog(_ref) {
4574
4709
  }
4575
4710
  }
4576
4711
 
4577
- function handleShowTrack(trackId) {
4578
- var trackConfigSchema = pluginManager.pluggableConfigSchemaType('track');
4579
- var configuration = mobxStateTree.resolveIdentifier(trackConfigSchema, mobxStateTree.getRoot(model), trackId); // check if we have any tracks with that configuration
4580
-
4581
- var shownTracks = model.tracks.filter(function (t) {
4582
- return t.configuration === configuration;
4583
- });
4584
-
4585
- if (shownTracks.length === 0) {
4586
- model.showTrack(trackId);
4587
- }
4588
- }
4589
-
4590
4712
  function getTrackName(trackId) {
4591
4713
  if (trackId) {
4592
4714
  var trackConfigSchema = pluginManager.pluggableConfigSchemaType('track');
@@ -4651,7 +4773,7 @@ function SearchResultsDialog(_ref) {
4651
4773
  var resultTrackId = result.getTrackId();
4652
4774
 
4653
4775
  if (resultTrackId) {
4654
- handleShowTrack(resultTrackId);
4776
+ model.showTrack(resultTrackId);
4655
4777
  }
4656
4778
 
4657
4779
  handleClose();
@@ -4673,9 +4795,6 @@ var useStyles$g = /*#__PURE__*/core.makeStyles(function (theme) {
4673
4795
  importFormContainer: {
4674
4796
  padding: theme.spacing(2)
4675
4797
  },
4676
- importFormEntry: {
4677
- minWidth: 180
4678
- },
4679
4798
  button: {
4680
4799
  margin: theme.spacing(2)
4681
4800
  }
@@ -4689,18 +4808,14 @@ var ErrorDisplay = /*#__PURE__*/mobxReact.observer(function (_ref) {
4689
4808
  }, "".concat(error));
4690
4809
  });
4691
4810
  var ImportForm = /*#__PURE__*/mobxReact.observer(function (_ref2) {
4692
- var _regions$;
4811
+ var _regions$, _regions$2;
4693
4812
 
4694
4813
  var model = _ref2.model;
4695
4814
  var classes = useStyles$g();
4696
4815
  var session = util.getSession(model);
4697
4816
  var assemblyNames = session.assemblyNames,
4698
- assemblyManager = session.assemblyManager;
4699
-
4700
- var _getEnv = mobxStateTree.getEnv(session),
4701
- pluginManager = _getEnv.pluginManager;
4702
-
4703
- var textSearchManager = pluginManager.rootModel.textSearchManager;
4817
+ assemblyManager = session.assemblyManager,
4818
+ textSearchManager = session.textSearchManager;
4704
4819
  var rankSearchResults = model.rankSearchResults,
4705
4820
  isSearchDialogDisplayed = model.isSearchDialogDisplayed,
4706
4821
  modelError = model.error;
@@ -4724,69 +4839,139 @@ var ImportForm = /*#__PURE__*/mobxReact.observer(function (_ref2) {
4724
4839
 
4725
4840
  var _useState5 = React.useState(),
4726
4841
  _useState6 = _slicedToArray(_useState5, 2),
4727
- mySelectedRegion = _useState6[0],
4728
- setSelectedRegion = _useState6[1];
4842
+ myOption = _useState6[0],
4843
+ setOption = _useState6[1]; // use this instead of useState initializer because the useState initializer
4844
+ // won't update in response to an observable
4729
4845
 
4730
- var selectedRegion = mySelectedRegion || ((_regions$ = regions[0]) === null || _regions$ === void 0 ? void 0 : _regions$.refName);
4731
4846
 
4732
- function handleSelectedRegion(_x) {
4733
- return _handleSelectedRegion.apply(this, arguments);
4847
+ var option = myOption || new BaseResult.RefSequenceResult({
4848
+ refName: (_regions$ = regions[0]) === null || _regions$ === void 0 ? void 0 : _regions$.refName,
4849
+ label: (_regions$2 = regions[0]) === null || _regions$2 === void 0 ? void 0 : _regions$2.refName
4850
+ });
4851
+ var selectedRegion = option === null || option === void 0 ? void 0 : option.getLocation();
4852
+
4853
+ function fetchResults(_x) {
4854
+ return _fetchResults.apply(this, arguments);
4734
4855
  }
4856
+ /**
4857
+ * gets a string as input, or use stored option results from previous query,
4858
+ * then re-query and
4859
+ * 1) if it has multiple results: pop a dialog
4860
+ * 2) if it's a single result navigate to it
4861
+ * 3) else assume it's a locstring and navigate to it
4862
+ */
4735
4863
 
4736
- function _handleSelectedRegion() {
4737
- _handleSelectedRegion = _asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee(input) {
4738
- var newRegion, results;
4864
+
4865
+ function _fetchResults() {
4866
+ _fetchResults = _asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee(queryString) {
4867
+ var results;
4739
4868
  return runtime_1.wrap(function _callee$(_context) {
4740
4869
  while (1) {
4741
4870
  switch (_context.prev = _context.next) {
4742
4871
  case 0:
4743
- newRegion = regions.find(function (r) {
4744
- return selectedRegion === r.refName;
4745
- });
4872
+ if (!textSearchManager) {
4873
+ console.warn('No text search manager');
4874
+ }
4746
4875
 
4747
- if (!newRegion) {
4748
- _context.next = 6;
4876
+ _context.next = 3;
4877
+ return textSearchManager === null || textSearchManager === void 0 ? void 0 : textSearchManager.search({
4878
+ queryString: queryString.toLowerCase(),
4879
+ searchType: 'exact'
4880
+ }, searchScope, rankSearchResults);
4881
+
4882
+ case 3:
4883
+ results = _context.sent;
4884
+ return _context.abrupt("return", dedupe(results));
4885
+
4886
+ case 5:
4887
+ case "end":
4888
+ return _context.stop();
4889
+ }
4890
+ }
4891
+ }, _callee);
4892
+ }));
4893
+ return _fetchResults.apply(this, arguments);
4894
+ }
4895
+
4896
+ function handleSelectedRegion(_x2) {
4897
+ return _handleSelectedRegion.apply(this, arguments);
4898
+ } // implementation notes:
4899
+ // having this wrapped in a form allows intuitive use of enter key to submit
4900
+
4901
+
4902
+ function _handleSelectedRegion() {
4903
+ _handleSelectedRegion = _asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee2(input) {
4904
+ var trackId, location, _assembly$refNames, results;
4905
+
4906
+ return runtime_1.wrap(function _callee2$(_context2) {
4907
+ while (1) {
4908
+ switch (_context2.prev = _context2.next) {
4909
+ case 0:
4910
+ if (option) {
4911
+ _context2.next = 2;
4749
4912
  break;
4750
4913
  }
4751
4914
 
4752
- model.setDisplayedRegions([newRegion]); // we use showAllRegions after setDisplayedRegions to make the entire
4753
- // region visible, xref #1703
4915
+ return _context2.abrupt("return");
4916
+
4917
+ case 2:
4918
+ trackId = option.getTrackId();
4919
+ location = input || option.getLocation() || '';
4920
+ _context2.prev = 4;
4921
+
4922
+ if (!(assembly !== null && assembly !== void 0 && (_assembly$refNames = assembly.refNames) !== null && _assembly$refNames !== void 0 && _assembly$refNames.includes(location))) {
4923
+ _context2.next = 9;
4924
+ break;
4925
+ }
4754
4926
 
4755
- model.showAllRegions();
4756
- _context.next = 10;
4927
+ model.navToLocString(location, selectedAsm);
4928
+ _context2.next = 20;
4757
4929
  break;
4758
4930
 
4759
- case 6:
4760
- _context.next = 8;
4761
- return textSearchManager === null || textSearchManager === void 0 ? void 0 : textSearchManager.search({
4762
- queryString: input.toLocaleLowerCase(),
4763
- searchType: 'exact'
4764
- }, searchScope, rankSearchResults);
4931
+ case 9:
4932
+ _context2.next = 11;
4933
+ return fetchResults(input);
4765
4934
 
4766
- case 8:
4767
- results = _context.sent;
4935
+ case 11:
4936
+ results = _context2.sent;
4768
4937
 
4769
- if ((results === null || results === void 0 ? void 0 : results.length) > 0) {
4770
- model.setSearchResults(results, input.toLocaleLowerCase());
4771
- } else {
4772
- try {
4773
- input && model.navToLocString(input, selectedAsm);
4774
- } catch (e) {
4775
- if ("".concat(e) === "Error: Unknown reference sequence \"".concat(input, "\"")) {
4776
- model.setSearchResults(results, input.toLocaleLowerCase());
4777
- } else {
4778
- console.warn(e);
4779
- session.notify("".concat(e), 'warning');
4780
- }
4781
- }
4938
+ if (!(results && results.length > 1)) {
4939
+ _context2.next = 17;
4940
+ break;
4782
4941
  }
4783
4942
 
4784
- case 10:
4943
+ model.setSearchResults(results, input.toLowerCase());
4944
+ return _context2.abrupt("return");
4945
+
4946
+ case 17:
4947
+ if ((results === null || results === void 0 ? void 0 : results.length) === 1) {
4948
+ location = results[0].getLocation();
4949
+ trackId = results[0].getTrackId();
4950
+ }
4951
+
4952
+ case 18:
4953
+ model.navToLocString(location, selectedAsm);
4954
+
4955
+ if (trackId) {
4956
+ model.showTrack(trackId);
4957
+ }
4958
+
4959
+ case 20:
4960
+ _context2.next = 26;
4961
+ break;
4962
+
4963
+ case 22:
4964
+ _context2.prev = 22;
4965
+ _context2.t0 = _context2["catch"](4);
4966
+ console.error(_context2.t0);
4967
+ session.notify("".concat(_context2.t0), 'warning');
4968
+
4969
+ case 26:
4785
4970
  case "end":
4786
- return _context.stop();
4971
+ return _context2.stop();
4787
4972
  }
4788
4973
  }
4789
- }, _callee);
4974
+ }, _callee2, null, [[4, 22]]);
4790
4975
  }));
4791
4976
  return _handleSelectedRegion.apply(this, arguments);
4792
4977
  }
@@ -4795,6 +4980,10 @@ var ImportForm = /*#__PURE__*/mobxReact.observer(function (_ref2) {
4795
4980
  error: err
4796
4981
  }) : null, /*#__PURE__*/React__default.createElement(core.Container, {
4797
4982
  className: classes.importFormContainer
4983
+ }, /*#__PURE__*/React__default.createElement("form", {
4984
+ onSubmit: function onSubmit(event) {
4985
+ event.preventDefault();
4986
+ }
4798
4987
  }, /*#__PURE__*/React__default.createElement(core.Grid, {
4799
4988
  container: true,
4800
4989
  spacing: 1,
@@ -4818,27 +5007,12 @@ var ImportForm = /*#__PURE__*/mobxReact.observer(function (_ref2) {
4818
5007
  assemblyName: message ? undefined : selectedAsm,
4819
5008
  value: selectedRegion,
4820
5009
  onSelect: function onSelect(option) {
4821
- return setSelectedRegion(option.getLocation());
5010
+ setOption(option);
4822
5011
  },
4823
5012
  TextFieldProps: {
4824
5013
  margin: 'normal',
4825
5014
  variant: 'outlined',
4826
- helperText: 'Enter a sequence or location',
4827
- className: classes.importFormEntry,
4828
- onBlur: function onBlur(event) {
4829
- if (event.target.value !== '') {
4830
- setSelectedRegion(event.target.value);
4831
- }
4832
- },
4833
- onKeyPress: function onKeyPress(event) {
4834
- var elt = event.target; // maybe check regular expression here to see if it's a
4835
- // locstring try defaulting exact matches to first exact
4836
- // match
4837
-
4838
- if (event.key === 'Enter') {
4839
- handleSelectedRegion(elt.value);
4840
- }
4841
- }
5015
+ helperText: 'Enter a sequence or location'
4842
5016
  }
4843
5017
  }) : /*#__PURE__*/React__default.createElement(core.CircularProgress, {
4844
5018
  role: "progressbar",
@@ -4847,6 +5021,7 @@ var ImportForm = /*#__PURE__*/mobxReact.observer(function (_ref2) {
4847
5021
  }) : null), /*#__PURE__*/React__default.createElement(core.Grid, {
4848
5022
  item: true
4849
5023
  }, /*#__PURE__*/React__default.createElement(core.Button, {
5024
+ type: "submit",
4850
5025
  disabled: !selectedRegion,
4851
5026
  className: classes.button,
4852
5027
  onClick: function onClick() {
@@ -4867,7 +5042,7 @@ var ImportForm = /*#__PURE__*/mobxReact.observer(function (_ref2) {
4867
5042
  },
4868
5043
  variant: "contained",
4869
5044
  color: "secondary"
4870
- }, "Show all regions in assembly")))), isSearchDialogDisplayed ? /*#__PURE__*/React__default.createElement(SearchResultsDialog, {
5045
+ }, "Show all regions in assembly"))))), isSearchDialogDisplayed ? /*#__PURE__*/React__default.createElement(SearchResultsDialog, {
4871
5046
  model: model,
4872
5047
  optAssemblyName: selectedAsm,
4873
5048
  handleClose: function handleClose() {
@@ -4925,7 +5100,7 @@ var MiniControls = /*#__PURE__*/mobxReact.observer(function (props) {
4925
5100
  }));
4926
5101
  });
4927
5102
 
4928
- var useStyles$h = /*#__PURE__*/styles.makeStyles(function (theme) {
5103
+ var useStyles$h = /*#__PURE__*/core.makeStyles(function (theme) {
4929
5104
  return {
4930
5105
  loadingMessage: {
4931
5106
  padding: theme.spacing(5)
@@ -4953,7 +5128,7 @@ function fetchSequence(_x, _x2, _x3) {
4953
5128
  }
4954
5129
 
4955
5130
  function _fetchSequence() {
4956
- _fetchSequence = _asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee2(model, selectedRegions, signal) {
5131
+ _fetchSequence = _asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee2(model, regions, signal) {
4957
5132
  var session, leftOffset, rightOffset, rpcManager, assemblyManager, assemblyName, assembly, adapterConfig, sessionId, chunks;
4958
5133
  return runtime_1.wrap(function _callee2$(_context2) {
4959
5134
  while (1) {
@@ -4993,7 +5168,7 @@ function _fetchSequence() {
4993
5168
  adapterConfig = configuration.readConfObject(assembly.configuration, ['sequence', 'adapter']);
4994
5169
  sessionId = 'getSequence';
4995
5170
  _context2.next = 15;
4996
- return Promise.all(selectedRegions.map(function (region) {
5171
+ return Promise.all(regions.map(function (region) {
4997
5172
  return rpcManager.call(sessionId, 'CoreGetFeatures', {
4998
5173
  adapterConfig: adapterConfig,
4999
5174
  region: region,
@@ -5029,12 +5204,12 @@ function SequenceDialog(_ref) {
5029
5204
  error = _useState2[0],
5030
5205
  setError = _useState2[1];
5031
5206
 
5032
- var _useState3 = React.useState(''),
5207
+ var _useState3 = React.useState(),
5033
5208
  _useState4 = _slicedToArray(_useState3, 2),
5034
5209
  sequence = _useState4[0],
5035
5210
  setSequence = _useState4[1];
5036
5211
 
5037
- var loading = Boolean(!sequence) || Boolean(error);
5212
+ var loading = Boolean(sequence === undefined);
5038
5213
  var leftOffset = model.leftOffset,
5039
5214
  rightOffset = model.rightOffset; // avoid infinite looping of useEffect
5040
5215
  // random note: the current selected region can't be a computed because it
@@ -5047,25 +5222,6 @@ function SequenceDialog(_ref) {
5047
5222
  var active = true;
5048
5223
  var controller = new AbortController();
5049
5224
 
5050
- function formatSequence(seqChunks) {
5051
- return formatFastaStrings.formatSeqFasta(seqChunks.map(function (chunk) {
5052
- var chunkSeq = chunk.get('seq');
5053
- var chunkRefName = chunk.get('refName');
5054
- var chunkStart = chunk.get('start') + 1;
5055
- var chunkEnd = chunk.get('end');
5056
- var chunkLocstring = "".concat(chunkRefName, ":").concat(chunkStart, "-").concat(chunkEnd);
5057
-
5058
- if ((chunkSeq === null || chunkSeq === void 0 ? void 0 : chunkSeq.length) !== chunkEnd - chunkStart + 1) {
5059
- throw new Error("".concat(chunkLocstring, " returned ").concat(chunkSeq.length.toLocaleString(), " bases, but should have returned ").concat((chunkEnd - chunkStart).toLocaleString()));
5060
- }
5061
-
5062
- return {
5063
- header: chunkLocstring,
5064
- seq: chunkSeq
5065
- };
5066
- }));
5067
- }
5068
-
5069
5225
  _asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee() {
5070
5226
  var chunks;
5071
5227
  return runtime_1.wrap(function _callee$(_context) {
@@ -5086,7 +5242,24 @@ function SequenceDialog(_ref) {
5086
5242
  chunks = _context.sent;
5087
5243
 
5088
5244
  if (active) {
5089
- setSequence(formatSequence(chunks));
5245
+ setSequence(formatFastaStrings.formatSeqFasta(chunks.filter(function (f) {
5246
+ return !!f;
5247
+ }).map(function (chunk) {
5248
+ var chunkSeq = chunk.get('seq');
5249
+ var chunkRefName = chunk.get('refName');
5250
+ var chunkStart = chunk.get('start') + 1;
5251
+ var chunkEnd = chunk.get('end');
5252
+ var chunkLocstring = "".concat(chunkRefName, ":").concat(chunkStart, "-").concat(chunkEnd);
5253
+
5254
+ if ((chunkSeq === null || chunkSeq === void 0 ? void 0 : chunkSeq.length) !== chunkEnd - chunkStart + 1) {
5255
+ throw new Error("".concat(chunkLocstring, " returned ").concat(chunkSeq.length.toLocaleString(), " bases, but should have returned ").concat((chunkEnd - chunkStart).toLocaleString()));
5256
+ }
5257
+
5258
+ return {
5259
+ header: chunkLocstring,
5260
+ seq: chunkSeq
5261
+ };
5262
+ })));
5090
5263
  }
5091
5264
 
5092
5265
  _context.next = 9;
@@ -5121,7 +5294,7 @@ function SequenceDialog(_ref) {
5121
5294
  active = false;
5122
5295
  };
5123
5296
  }, [model, session, regionsSelected, setSequence]);
5124
- var sequenceTooLarge = sequence.length > 1000000;
5297
+ var sequenceTooLarge = sequence ? sequence.length > 1000000 : false;
5125
5298
  return /*#__PURE__*/React__default.createElement(core.Dialog, {
5126
5299
  "data-testid": "sequence-dialog",
5127
5300
  maxWidth: "xl",
@@ -5146,7 +5319,7 @@ function SequenceDialog(_ref) {
5146
5319
  },
5147
5320
  size: 20,
5148
5321
  disableShrink: true
5149
- })) : null, sequence !== undefined ? /*#__PURE__*/React__default.createElement(core.TextField, {
5322
+ })) : null, /*#__PURE__*/React__default.createElement(core.TextField, {
5150
5323
  "data-testid": "rubberband-sequence",
5151
5324
  variant: "outlined",
5152
5325
  multiline: true,
@@ -5161,12 +5334,12 @@ function SequenceDialog(_ref) {
5161
5334
  input: classes.textAreaFont
5162
5335
  }
5163
5336
  }
5164
- }) : null), /*#__PURE__*/React__default.createElement(core.DialogActions, null, /*#__PURE__*/React__default.createElement(core.Button, {
5337
+ })), /*#__PURE__*/React__default.createElement(core.DialogActions, null, /*#__PURE__*/React__default.createElement(core.Button, {
5165
5338
  onClick: function onClick() {
5166
5339
  copy(sequence || '');
5167
5340
  session.notify('Copied to clipboard', 'success');
5168
5341
  },
5169
- disabled: loading || sequenceTooLarge,
5342
+ disabled: loading || !!error || sequenceTooLarge,
5170
5343
  color: "primary",
5171
5344
  startIcon: /*#__PURE__*/React__default.createElement(Icons.ContentCopy, null)
5172
5345
  }, "Copy to clipboard"), /*#__PURE__*/React__default.createElement(core.Button, {
@@ -5176,7 +5349,7 @@ function SequenceDialog(_ref) {
5176
5349
  });
5177
5350
  fileSaver.saveAs(seqFastaFile, 'jbrowse_ref_seq.fa');
5178
5351
  },
5179
- disabled: loading,
5352
+ disabled: loading || !!error,
5180
5353
  color: "primary",
5181
5354
  startIcon: /*#__PURE__*/React__default.createElement(GetAppIcon, null)
5182
5355
  }, "Download FASTA"), /*#__PURE__*/React__default.createElement(core.Button, {
@@ -5197,20 +5370,17 @@ function mathPower(num) {
5197
5370
  }
5198
5371
 
5199
5372
  var useStyles$i = /*#__PURE__*/styles.makeStyles(function () {
5200
- return (
5201
- /* theme */
5202
- {
5203
- majorTickLabel: {
5204
- fontSize: '11px'
5205
- },
5206
- majorTick: {
5207
- stroke: '#555'
5208
- },
5209
- minorTick: {
5210
- stroke: '#999'
5211
- }
5373
+ return {
5374
+ majorTickLabel: {
5375
+ fontSize: '11px'
5376
+ },
5377
+ majorTick: {
5378
+ stroke: '#555'
5379
+ },
5380
+ minorTick: {
5381
+ stroke: '#999'
5212
5382
  }
5213
- );
5383
+ };
5214
5384
  });
5215
5385
 
5216
5386
  function Ruler(_ref) {
@@ -5629,8 +5799,10 @@ var useStyles$k = /*#__PURE__*/styles.makeStyles(function (theme) {
5629
5799
  function ExportSvgDlg(_ref) {
5630
5800
  var model = _ref.model,
5631
5801
  handleClose = _ref.handleClose;
5802
+ // @ts-ignore
5803
+ var offscreenCanvas = typeof OffscreenCanvas !== 'undefined';
5632
5804
 
5633
- var _useState = React.useState(typeof OffscreenCanvas !== 'undefined'),
5805
+ var _useState = React.useState(offscreenCanvas),
5634
5806
  _useState2 = _slicedToArray(_useState, 2),
5635
5807
  rasterizeLayers = _useState2[0],
5636
5808
  setRasterizeLayers = _useState2[1];
@@ -5663,7 +5835,7 @@ function ExportSvgDlg(_ref) {
5663
5835
  }
5664
5836
  }), /*#__PURE__*/React__default.createElement(core.Typography, {
5665
5837
  display: "inline"
5666
- }, "Creating SVG")) : null, typeof OffscreenCanvas !== 'undefined' ? /*#__PURE__*/React__default.createElement(core.FormControlLabel, {
5838
+ }, "Creating SVG")) : null, offscreenCanvas ? /*#__PURE__*/React__default.createElement(core.FormControlLabel, {
5667
5839
  control: /*#__PURE__*/React__default.createElement(core.Checkbox, {
5668
5840
  checked: rasterizeLayers,
5669
5841
  onChange: function onChange() {
@@ -5673,7 +5845,13 @@ function ExportSvgDlg(_ref) {
5673
5845
  }
5674
5846
  }),
5675
5847
  label: "Rasterize canvas based tracks? File may be much larger if this is turned off"
5676
- }) : /*#__PURE__*/React__default.createElement(core.Typography, null, "Note: rasterizing layers not yet supported in this browser, so SVG size may be large"), /*#__PURE__*/React__default.createElement(core.Button, {
5848
+ }) : /*#__PURE__*/React__default.createElement(core.Typography, null, "Note: rasterizing layers not yet supported in this browser, so SVG size may be large")), /*#__PURE__*/React__default.createElement(core.DialogActions, null, /*#__PURE__*/React__default.createElement(core.Button, {
5849
+ variant: "contained",
5850
+ color: "secondary",
5851
+ onClick: function onClick() {
5852
+ return handleClose();
5853
+ }
5854
+ }, "Cancel"), /*#__PURE__*/React__default.createElement(core.Button, {
5677
5855
  variant: "contained",
5678
5856
  color: "primary",
5679
5857
  type: "submit",
@@ -5693,25 +5871,26 @@ function ExportSvgDlg(_ref) {
5693
5871
 
5694
5872
  case 5:
5695
5873
  handleClose();
5696
- _context.next = 11;
5874
+ _context.next = 12;
5697
5875
  break;
5698
5876
 
5699
5877
  case 8:
5700
5878
  _context.prev = 8;
5701
5879
  _context.t0 = _context["catch"](2);
5880
+ console.error(_context.t0);
5702
5881
  setError(_context.t0);
5703
5882
 
5704
- case 11:
5705
- _context.prev = 11;
5883
+ case 12:
5884
+ _context.prev = 12;
5706
5885
  setLoading(false);
5707
- return _context.finish(11);
5886
+ return _context.finish(12);
5708
5887
 
5709
- case 14:
5888
+ case 15:
5710
5889
  case "end":
5711
5890
  return _context.stop();
5712
5891
  }
5713
5892
  }
5714
- }, _callee, null, [[2, 8, 11, 14]]);
5893
+ }, _callee, null, [[2, 8, 12, 15]]);
5715
5894
  }));
5716
5895
 
5717
5896
  function onClick() {
@@ -6226,7 +6405,12 @@ function stateModelFactory$1(pluginManager) {
6226
6405
  var displayInitialSnapshot = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
6227
6406
  var trackConfigSchema = pluginManager.pluggableConfigSchemaType('track');
6228
6407
  var configuration = mobxStateTree.resolveIdentifier(trackConfigSchema, mobxStateTree.getRoot(self), trackId);
6229
- var trackType = pluginManager.getTrackType(configuration.type);
6408
+
6409
+ if (!configuration) {
6410
+ throw new Error("Could not resolve identifier");
6411
+ }
6412
+
6413
+ var trackType = pluginManager.getTrackType(configuration === null || configuration === void 0 ? void 0 : configuration.type);
6230
6414
 
6231
6415
  if (!trackType) {
6232
6416
  throw new Error("unknown track type ".concat(configuration.type));
@@ -6244,16 +6428,24 @@ function stateModelFactory$1(pluginManager) {
6244
6428
  throw new Error("could not find a compatible display for view type ".concat(self.type));
6245
6429
  }
6246
6430
 
6247
- var track = trackType.stateModel.create(_objectSpread2(_objectSpread2({}, initialSnapshot), {}, {
6248
- type: configuration.type,
6249
- configuration: configuration,
6250
- displays: [_objectSpread2({
6251
- type: displayConf.type,
6252
- configuration: displayConf
6253
- }, displayInitialSnapshot)]
6254
- }));
6255
- self.tracks.push(track);
6256
- return track;
6431
+ var shownTracks = self.tracks.filter(function (t) {
6432
+ return t.configuration === configuration;
6433
+ });
6434
+
6435
+ if (shownTracks.length === 0) {
6436
+ var track = trackType.stateModel.create(_objectSpread2(_objectSpread2({}, initialSnapshot), {}, {
6437
+ type: configuration.type,
6438
+ configuration: configuration,
6439
+ displays: [_objectSpread2({
6440
+ type: displayConf.type,
6441
+ configuration: displayConf
6442
+ }, displayInitialSnapshot)]
6443
+ }));
6444
+ self.tracks.push(track);
6445
+ return track;
6446
+ }
6447
+
6448
+ return shownTracks[0];
6257
6449
  },
6258
6450
  hideTrack: function hideTrack(trackId) {
6259
6451
  var trackConfigSchema = pluginManager.pluggableConfigSchemaType('track');
@@ -6811,8 +7003,7 @@ function stateModelFactory$1(pluginManager) {
6811
7003
  self.zoomTo(self.bpPerPx);
6812
7004
 
6813
7005
  if ( // already zoomed all the way in
6814
- targetBpPerPx < self.bpPerPx && self.bpPerPx === self.minBpPerPx || // already zoomed all the way out
6815
- targetBpPerPx > self.bpPerPx && self.bpPerPx === self.maxBpPerPx) {
7006
+ targetBpPerPx < self.bpPerPx && self.bpPerPx === self.minBpPerPx || targetBpPerPx > self.bpPerPx && self.bpPerPx === self.maxBpPerPx) {
6816
7007
  return;
6817
7008
  }
6818
7009
 
@@ -6842,8 +7033,11 @@ function stateModelFactory$1(pluginManager) {
6842
7033
  var menuItems = [{
6843
7034
  label: 'Return to import form',
6844
7035
  onClick: function onClick() {
6845
- util.getSession(self).setDialogComponent(ReturnToImportFormDlg, {
6846
- model: self
7036
+ util.getSession(self).queueDialog(function (doneCallback) {
7037
+ return [ReturnToImportFormDlg, {
7038
+ model: self,
7039
+ handleClose: doneCallback
7040
+ }];
6847
7041
  });
6848
7042
  },
6849
7043
  icon: FolderOpenIcon
@@ -6851,8 +7045,11 @@ function stateModelFactory$1(pluginManager) {
6851
7045
  label: 'Export SVG',
6852
7046
  icon: PhotoCameraIcon,
6853
7047
  onClick: function onClick() {
6854
- util.getSession(self).setDialogComponent(ExportSvgDlg, {
6855
- model: self
7048
+ util.getSession(self).queueDialog(function (doneCallback) {
7049
+ return [ExportSvgDlg, {
7050
+ model: self,
7051
+ handleClose: doneCallback
7052
+ }];
6856
7053
  });
6857
7054
  }
6858
7055
  }, {
@@ -7071,6 +7268,7 @@ var stateModelFactory$2 = function stateModelFactory(configSchema) {
7071
7268
  return mobxStateTree.types.compose('LinearBasicDisplay', BaseLinearDisplay$1, mobxStateTree.types.model({
7072
7269
  type: mobxStateTree.types.literal('LinearBasicDisplay'),
7073
7270
  trackShowLabels: mobxStateTree.types.maybe(mobxStateTree.types["boolean"]),
7271
+ trackShowDescriptions: mobxStateTree.types.maybe(mobxStateTree.types["boolean"]),
7074
7272
  trackDisplayMode: mobxStateTree.types.maybe(mobxStateTree.types.string),
7075
7273
  trackMaxHeight: mobxStateTree.types.maybe(mobxStateTree.types.number),
7076
7274
  configuration: configuration.ConfigurationReference(configSchema)
@@ -7085,6 +7283,11 @@ var stateModelFactory$2 = function stateModelFactory(configSchema) {
7085
7283
  return self.trackShowLabels !== undefined ? self.trackShowLabels : showLabels;
7086
7284
  },
7087
7285
 
7286
+ get showDescriptions() {
7287
+ var showDescriptions = configuration.getConf(self, ['renderer', 'showLabels']);
7288
+ return self.trackShowDescriptions !== undefined ? self.trackShowDescriptions : showDescriptions;
7289
+ },
7290
+
7088
7291
  get maxHeight() {
7089
7292
  var maxHeight = configuration.getConf(self, ['renderer', 'maxHeight']);
7090
7293
  return self.trackMaxHeight !== undefined ? self.trackMaxHeight : maxHeight;
@@ -7099,6 +7302,7 @@ var stateModelFactory$2 = function stateModelFactory(configSchema) {
7099
7302
  var configBlob = configuration.getConf(self, ['renderer']) || {};
7100
7303
  return self.rendererType.configSchema.create(_objectSpread2(_objectSpread2({}, configBlob), {}, {
7101
7304
  showLabels: this.showLabels,
7305
+ showDescriptions: this.showDescriptions,
7102
7306
  displayMode: this.displayMode,
7103
7307
  maxHeight: this.maxHeight
7104
7308
  }), mobxStateTree.getEnv(self));
@@ -7110,6 +7314,9 @@ var stateModelFactory$2 = function stateModelFactory(configSchema) {
7110
7314
  toggleShowLabels: function toggleShowLabels() {
7111
7315
  self.trackShowLabels = !self.showLabels;
7112
7316
  },
7317
+ toggleShowDescriptions: function toggleShowDescriptions() {
7318
+ self.trackShowDescriptions = !self.showDescriptions;
7319
+ },
7113
7320
  setDisplayMode: function setDisplayMode(val) {
7114
7321
  self.trackDisplayMode = val;
7115
7322
  },
@@ -7136,6 +7343,14 @@ var stateModelFactory$2 = function stateModelFactory(configSchema) {
7136
7343
  onClick: function onClick() {
7137
7344
  self.toggleShowLabels();
7138
7345
  }
7346
+ }, {
7347
+ label: 'Show descriptions',
7348
+ icon: VisibilityIcon,
7349
+ type: 'checkbox',
7350
+ checked: self.showDescriptions,
7351
+ onClick: function onClick() {
7352
+ self.toggleShowDescriptions();
7353
+ }
7139
7354
  }, {
7140
7355
  label: 'Display mode',
7141
7356
  icon: VisibilityIcon,
@@ -7150,8 +7365,11 @@ var stateModelFactory$2 = function stateModelFactory(configSchema) {
7150
7365
  }, {
7151
7366
  label: 'Set max height',
7152
7367
  onClick: function onClick() {
7153
- util.getSession(self).setDialogComponent(SetMaxHeightDlg, {
7154
- model: self
7368
+ util.getSession(self).queueDialog(function (doneCallback) {
7369
+ return [SetMaxHeightDlg, {
7370
+ model: self,
7371
+ handleClose: doneCallback
7372
+ }];
7155
7373
  });
7156
7374
  }
7157
7375
  }]);
@@ -7262,7 +7480,7 @@ var LinearGenomeViewPlugin = /*#__PURE__*/function (_Plugin) {
7262
7480
  key: "configure",
7263
7481
  value: function configure(pluginManager) {
7264
7482
  if (util.isAbstractMenuManager(pluginManager.rootModel)) {
7265
- pluginManager.rootModel.appendToSubMenu(['File', 'Add'], {
7483
+ pluginManager.rootModel.appendToSubMenu(['Add'], {
7266
7484
  label: 'Linear genome view',
7267
7485
  icon: LineStyleIcon,
7268
7486
  onClick: function onClick(session) {
@@ -7347,6 +7565,7 @@ var SetMaxHeight$1 = {
7347
7565
 
7348
7566
  exports.BaseLinearDisplay = BaseLinearDisplay$1;
7349
7567
  exports.BaseLinearDisplayComponent = BaseLinearDisplay;
7568
+ exports.RefNameAutocomplete = RefNameAutocomplete$1;
7350
7569
  exports.baseLinearDisplayConfigSchema = baseLinearDisplayConfigSchema;
7351
7570
  exports.default = LinearGenomeViewPlugin;
7352
7571
  exports.linearBareDisplayConfigSchemaFactory = configSchemaFactory;