@jbrowse/plugin-linear-genome-view 2.7.2 → 2.9.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 (41) hide show
  1. package/dist/BaseLinearDisplay/models/BaseLinearDisplayModel.d.ts +18 -11
  2. package/dist/BaseLinearDisplay/models/BaseLinearDisplayModel.js +25 -2
  3. package/dist/BaseLinearDisplay/models/renderSvg.d.ts +1 -1
  4. package/dist/BaseLinearDisplay/models/renderSvg.js +2 -1
  5. package/dist/BasicTrack/configSchema.d.ts +5 -0
  6. package/dist/FeatureTrack/configSchema.d.ts +5 -0
  7. package/dist/LaunchLinearGenomeView/index.js +16 -14
  8. package/dist/LinearBasicDisplay/model.d.ts +3 -1
  9. package/dist/LinearGenomeView/components/CenterLine.js +1 -1
  10. package/dist/LinearGenomeView/components/ImportForm.js +26 -74
  11. package/dist/LinearGenomeView/components/ImportFormRefNameAutocomplete.d.ts +12 -0
  12. package/dist/LinearGenomeView/components/ImportFormRefNameAutocomplete.js +29 -0
  13. package/dist/LinearGenomeView/components/OverviewScalebar.js +1 -1
  14. package/dist/LinearGenomeView/components/SearchBox.js +18 -54
  15. package/dist/LinearGenomeView/model.d.ts +12 -1
  16. package/dist/LinearGenomeView/model.js +16 -0
  17. package/dist/index.d.ts +702 -6
  18. package/dist/index.js +2 -2
  19. package/dist/searchUtils.d.ts +26 -0
  20. package/dist/searchUtils.js +90 -0
  21. package/esm/BaseLinearDisplay/models/BaseLinearDisplayModel.d.ts +18 -11
  22. package/esm/BaseLinearDisplay/models/BaseLinearDisplayModel.js +1 -1
  23. package/esm/BaseLinearDisplay/models/renderSvg.d.ts +1 -1
  24. package/esm/BaseLinearDisplay/models/renderSvg.js +1 -1
  25. package/esm/BasicTrack/configSchema.d.ts +5 -0
  26. package/esm/FeatureTrack/configSchema.d.ts +5 -0
  27. package/esm/LaunchLinearGenomeView/index.js +16 -14
  28. package/esm/LinearBasicDisplay/model.d.ts +3 -1
  29. package/esm/LinearGenomeView/components/CenterLine.js +1 -1
  30. package/esm/LinearGenomeView/components/ImportForm.js +26 -74
  31. package/esm/LinearGenomeView/components/ImportFormRefNameAutocomplete.d.ts +12 -0
  32. package/esm/LinearGenomeView/components/ImportFormRefNameAutocomplete.js +24 -0
  33. package/esm/LinearGenomeView/components/OverviewScalebar.js +1 -1
  34. package/esm/LinearGenomeView/components/SearchBox.js +19 -55
  35. package/esm/LinearGenomeView/model.d.ts +12 -1
  36. package/esm/LinearGenomeView/model.js +16 -0
  37. package/esm/index.d.ts +702 -6
  38. package/esm/index.js +2 -2
  39. package/esm/searchUtils.d.ts +26 -0
  40. package/esm/searchUtils.js +79 -0
  41. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -29,6 +29,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
29
29
  exports.linearBasicDisplayModelFactory = exports.linearBasicDisplayConfigSchemaFactory = exports.SVGRuler = exports.totalHeight = exports.SVGTracks = exports.renderToSvg = exports.SearchBox = exports.RefNameAutocomplete = exports.TooLargeMessage = exports.FeatureDensityMixin = exports.TrackHeightMixin = exports.BaseLinearDisplayComponent = exports.BlockMsg = exports.BaseLinearDisplay = exports.baseLinearDisplayConfigSchema = exports.linearBareDisplayConfigSchemaFactory = void 0;
30
30
  const Plugin_1 = __importDefault(require("@jbrowse/core/Plugin"));
31
31
  const util_1 = require("@jbrowse/core/util");
32
+ const configuration_1 = require("@jbrowse/core/configuration");
33
+ const mobx_state_tree_1 = require("mobx-state-tree");
32
34
  // icons
33
35
  const LineStyle_1 = __importDefault(require("@mui/icons-material/LineStyle"));
34
36
  // locals
@@ -39,8 +41,6 @@ const LinearBasicDisplay_1 = __importDefault(require("./LinearBasicDisplay"));
39
41
  const FeatureTrack_1 = __importDefault(require("./FeatureTrack"));
40
42
  const BasicTrack_1 = __importDefault(require("./BasicTrack"));
41
43
  const LaunchLinearGenomeView_1 = __importDefault(require("./LaunchLinearGenomeView"));
42
- const configuration_1 = require("@jbrowse/core/configuration");
43
- const mobx_state_tree_1 = require("mobx-state-tree");
44
44
  class LinearGenomeViewPlugin extends Plugin_1.default {
45
45
  constructor() {
46
46
  super(...arguments);
@@ -0,0 +1,26 @@
1
+ import BaseResult from '@jbrowse/core/TextSearch/BaseResults';
2
+ import { Assembly } from '@jbrowse/core/assemblyManager/assembly';
3
+ import { SearchType } from '@jbrowse/core/data_adapters/BaseAdapter';
4
+ import { SearchScope } from '@jbrowse/core/TextSearch/TextSearchManager';
5
+ import { TextSearchManager } from '@jbrowse/core/util';
6
+ import { LinearGenomeViewModel } from './LinearGenomeView';
7
+ export declare function navToOption({ option, model, assemblyName, }: {
8
+ model: LinearGenomeViewModel;
9
+ option: BaseResult;
10
+ assemblyName: string;
11
+ }): Promise<void>;
12
+ export declare function handleSelectedRegion({ input, model, assembly, }: {
13
+ input: string;
14
+ model: LinearGenomeViewModel;
15
+ assembly: Assembly;
16
+ }): Promise<void>;
17
+ export declare function checkRef(str: string, allRefs: string[]): boolean;
18
+ export declare function fetchResults({ queryString, searchType, searchScope, rankSearchResults, textSearchManager, assembly, }: {
19
+ queryString: string;
20
+ searchScope: SearchScope;
21
+ rankSearchResults: (results: BaseResult[]) => BaseResult[];
22
+ searchType?: SearchType;
23
+ textSearchManager?: TextSearchManager;
24
+ assembly?: Assembly;
25
+ }): Promise<BaseResult[]>;
26
+ export declare function splitLast(str: string, split: string): [string, string];
@@ -0,0 +1,90 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.splitLast = exports.fetchResults = exports.checkRef = exports.handleSelectedRegion = exports.navToOption = void 0;
7
+ const util_1 = require("@jbrowse/core/util");
8
+ const BaseResults_1 = __importDefault(require("@jbrowse/core/TextSearch/BaseResults"));
9
+ const util_2 = require("@jbrowse/core/util");
10
+ async function navToOption({ option, model, assemblyName, }) {
11
+ const location = option.getLocation();
12
+ const trackId = option.getTrackId();
13
+ if (location) {
14
+ await model.navToLocString(location, assemblyName);
15
+ if (trackId) {
16
+ model.showTrack(trackId);
17
+ }
18
+ }
19
+ }
20
+ exports.navToOption = navToOption;
21
+ // gets a string as input, or use stored option results from previous query,
22
+ // then re-query and
23
+ // 1) if it has multiple results: pop a dialog
24
+ // 2) if it's a single result navigate to it
25
+ // 3) else assume it's a locstring and navigate to it
26
+ async function handleSelectedRegion({ input, model, assembly, }) {
27
+ const allRefs = (assembly === null || assembly === void 0 ? void 0 : assembly.allRefNamesWithLowerCase) || [];
28
+ const assemblyName = assembly.name;
29
+ if (input.split(' ').every(entry => checkRef(entry, allRefs))) {
30
+ await model.navToLocString(input, assembly.name);
31
+ }
32
+ else {
33
+ const searchScope = model.searchScope(assemblyName);
34
+ const { textSearchManager } = (0, util_1.getSession)(model);
35
+ const results = await fetchResults({
36
+ queryString: input,
37
+ searchType: 'exact',
38
+ searchScope,
39
+ rankSearchResults: model.rankSearchResults,
40
+ textSearchManager,
41
+ assembly,
42
+ });
43
+ if (results.length > 1) {
44
+ model.setSearchResults(results, input.toLowerCase(), assemblyName);
45
+ }
46
+ else if (results.length === 1) {
47
+ await navToOption({
48
+ option: results[0],
49
+ model,
50
+ assemblyName,
51
+ });
52
+ }
53
+ else {
54
+ await model.navToLocString(input, assemblyName);
55
+ }
56
+ }
57
+ }
58
+ exports.handleSelectedRegion = handleSelectedRegion;
59
+ function checkRef(str, allRefs) {
60
+ const [ref, rest] = splitLast(str, ':');
61
+ return (allRefs.includes(str) ||
62
+ (allRefs.includes(ref) && !Number.isNaN(Number.parseInt(rest, 10))));
63
+ }
64
+ exports.checkRef = checkRef;
65
+ async function fetchResults({ queryString, searchType, searchScope, rankSearchResults, textSearchManager, assembly, }) {
66
+ var _a;
67
+ if (!textSearchManager) {
68
+ console.warn('No text search manager');
69
+ }
70
+ const textSearchResults = await (textSearchManager === null || textSearchManager === void 0 ? void 0 : textSearchManager.search({
71
+ queryString,
72
+ searchType,
73
+ }, searchScope, rankSearchResults));
74
+ const refNameResults = (_a = assembly === null || assembly === void 0 ? void 0 : assembly.allRefNames) === null || _a === void 0 ? void 0 : _a.filter(ref => ref.toLowerCase().startsWith(queryString.toLowerCase())).slice(0, 10).map(r => new BaseResults_1.default({ label: r }));
75
+ return (0, util_2.dedupe)([...(refNameResults || []), ...(textSearchResults || [])], elt => elt.getId());
76
+ }
77
+ exports.fetchResults = fetchResults;
78
+ // splits on the last instance of a character
79
+ function splitLast(str, split) {
80
+ const lastIndex = str.lastIndexOf(split);
81
+ if (lastIndex === -1) {
82
+ return [str, ''];
83
+ }
84
+ else {
85
+ const before = str.slice(0, lastIndex);
86
+ const after = str.slice(lastIndex + 1);
87
+ return [before, after];
88
+ }
89
+ }
90
+ exports.splitLast = splitLast;
@@ -69,7 +69,11 @@ export declare const BaseLinearDisplay: import("mobx-state-tree").IModelType<{
69
69
  setMessage(messageText: string): void;
70
70
  setRendered(props: {
71
71
  reactElement: React.ReactElement<any, string | React.JSXElementConstructor<any>>;
72
- features: Map<string, Feature>;
72
+ features: Map<string, Feature>; /**
73
+ * #getter
74
+ * a CompositeMap of `featureId -> feature obj` that
75
+ * just looks in all the block data for that feature
76
+ */
73
77
  layout: any;
74
78
  maxHeightReached: boolean;
75
79
  renderProps: any;
@@ -128,7 +132,9 @@ export declare const BaseLinearDisplay: import("mobx-state-tree").IModelType<{
128
132
  message: string | undefined;
129
133
  }, import("mobx-state-tree")._NotCustomized, import("mobx-state-tree")._NotCustomized>>;
130
134
  onHorizontalScroll?: Function | undefined;
131
- blockState?: Record<string, any> | undefined;
135
+ blockState?: Record<string, any> | undefined; /**
136
+ * #property
137
+ */
132
138
  }>;
133
139
  readonly DisplayBlurb: React.FC<{
134
140
  model: {
@@ -136,7 +142,9 @@ export declare const BaseLinearDisplay: import("mobx-state-tree").IModelType<{
136
142
  type: string;
137
143
  rpcDriverName: string | undefined;
138
144
  } & import("mobx-state-tree/dist/internal").NonEmptyObject & {
139
- rendererTypeName: string;
145
+ rendererTypeName: string; /**
146
+ * #getter
147
+ */
140
148
  error: unknown;
141
149
  message: string | undefined;
142
150
  } & import("mobx-state-tree").IStateTreeNode<import("mobx-state-tree").IModelType<{
@@ -144,9 +152,7 @@ export declare const BaseLinearDisplay: import("mobx-state-tree").IModelType<{
144
152
  type: import("mobx-state-tree").ISimpleType<string>;
145
153
  rpcDriverName: import("mobx-state-tree").IMaybe<import("mobx-state-tree").ISimpleType<string>>;
146
154
  }, {
147
- rendererTypeName: string; /**
148
- * #getter
149
- */
155
+ rendererTypeName: string;
150
156
  error: unknown;
151
157
  message: string | undefined;
152
158
  }, import("mobx-state-tree")._NotCustomized, import("mobx-state-tree")._NotCustomized>>;
@@ -179,10 +185,7 @@ export declare const BaseLinearDisplay: import("mobx-state-tree").IModelType<{
179
185
  } & {
180
186
  readonly currentBytesRequested: number;
181
187
  readonly currentFeatureScreenDensity: number;
182
- readonly maxFeatureScreenDensity: any; /**
183
- * #property
184
- * updated via autorun
185
- */
188
+ readonly maxFeatureScreenDensity: any;
186
189
  readonly featureDensityStatsReady: boolean;
187
190
  readonly maxAllowableBytes: number;
188
191
  } & {
@@ -358,7 +361,11 @@ export declare const BaseLinearDisplay: import("mobx-state-tree").IModelType<{
358
361
  setMessage(messageText: string): void;
359
362
  setRendered(props: {
360
363
  reactElement: React.ReactElement<any, string | React.JSXElementConstructor<any>>;
361
- features: Map<string, Feature>;
364
+ features: Map<string, Feature>; /**
365
+ * #getter
366
+ * a CompositeMap of `featureId -> feature obj` that
367
+ * just looks in all the block data for that feature
368
+ */
362
369
  layout: any;
363
370
  maxHeightReached: boolean;
364
371
  renderProps: any;
@@ -10,7 +10,6 @@ import MenuOpenIcon from '@mui/icons-material/MenuOpen';
10
10
  import { Tooltip } from '../components/BaseLinearDisplay';
11
11
  import BlockState from './serverSideRenderedBlock';
12
12
  import configSchema from './configSchema';
13
- import renderBaseLinearDisplaySvg from './renderSvg';
14
13
  import TrackHeightMixin from './TrackHeightMixin';
15
14
  import FeatureDensityMixin from './FeatureDensityMixin';
16
15
  /**
@@ -290,6 +289,7 @@ function stateModelFactory() {
290
289
  * #method
291
290
  */
292
291
  async renderSvg(opts) {
292
+ const { renderBaseLinearDisplaySvg } = await import('./renderSvg');
293
293
  return renderBaseLinearDisplaySvg(self, opts);
294
294
  },
295
295
  afterAttach() {
@@ -2,7 +2,7 @@ import React from 'react';
2
2
  import { ThemeOptions } from '@mui/material';
3
3
  import { ExportSvgOptions } from '../../LinearGenomeView';
4
4
  import { BaseLinearDisplayModel } from './BaseLinearDisplayModel';
5
- export default function renderBaseLinearDisplaySvg(self: BaseLinearDisplayModel, opts: ExportSvgOptions & {
5
+ export declare function renderBaseLinearDisplaySvg(self: BaseLinearDisplayModel, opts: ExportSvgOptions & {
6
6
  overrideHeight: number;
7
7
  theme: ThemeOptions;
8
8
  }): Promise<React.JSX.Element>;
@@ -2,7 +2,7 @@ import React from 'react';
2
2
  import { getContainingView, getViewParams, ReactRendering, } from '@jbrowse/core/util';
3
3
  import BlockState, { renderBlockData } from './serverSideRenderedBlock';
4
4
  import { getId } from './util';
5
- export default async function renderBaseLinearDisplaySvg(self, opts) {
5
+ export async function renderBaseLinearDisplaySvg(self, opts) {
6
6
  const { height, id } = self;
7
7
  const { overrideHeight } = opts;
8
8
  const view = getContainingView(self);
@@ -58,6 +58,11 @@ declare const configSchema: (pluginManager: PluginManager) => import("@jbrowse/c
58
58
  defaultValue: number;
59
59
  description: string;
60
60
  };
61
+ maxDepth: {
62
+ type: string;
63
+ defaultValue: number;
64
+ description: string;
65
+ };
61
66
  }, import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaOptions<undefined, undefined>>;
62
67
  formatAbout: import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaType<{
63
68
  config: {
@@ -58,6 +58,11 @@ declare const configSchema: (pluginManager: PluginManager) => import("@jbrowse/c
58
58
  defaultValue: number;
59
59
  description: string;
60
60
  };
61
+ maxDepth: {
62
+ type: string;
63
+ defaultValue: number;
64
+ description: string;
65
+ };
61
66
  }, import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaOptions<undefined, undefined>>;
62
67
  formatAbout: import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaType<{
63
68
  config: {
@@ -1,4 +1,5 @@
1
1
  import { when } from '@jbrowse/core/util';
2
+ import { handleSelectedRegion } from '..//searchUtils';
2
3
  export default (pluginManager) => {
3
4
  pluginManager.addToExtensionPoint('LaunchView-LinearGenomeView',
4
5
  // @ts-expect-error
@@ -14,21 +15,9 @@ export default (pluginManager) => {
14
15
  if (!asm) {
15
16
  throw new Error(`Assembly "${assembly}" not found when launching linear genome view`);
16
17
  }
17
- await view.navToLocString(loc, assembly);
18
+ await handleSelectedRegion({ input: loc, model: view, assembly: asm });
18
19
  const idsNotFound = [];
19
- tracks.forEach(track => {
20
- try {
21
- view.showTrack(track);
22
- }
23
- catch (e) {
24
- if (`${e}`.match('Could not resolve identifier')) {
25
- idsNotFound.push(track);
26
- }
27
- else {
28
- throw e;
29
- }
30
- }
31
- });
20
+ tracks.forEach(track => tryTrack(view, track, idsNotFound));
32
21
  if (idsNotFound.length) {
33
22
  throw new Error(`Could not resolve identifiers: ${idsNotFound.join(',')}`);
34
23
  }
@@ -39,3 +28,16 @@ export default (pluginManager) => {
39
28
  }
40
29
  });
41
30
  };
31
+ function tryTrack(model, trackId, idsNotFound) {
32
+ try {
33
+ model.showTrack(trackId);
34
+ }
35
+ catch (e) {
36
+ if (`${e}`.match('Could not resolve identifier')) {
37
+ idsNotFound.push(trackId);
38
+ }
39
+ else {
40
+ throw e;
41
+ }
42
+ }
43
+ }
@@ -219,7 +219,9 @@ declare function stateModelFactory(configSchema: AnyConfigurationSchemaType): im
219
219
  featureIdUnderMouse: string | undefined;
220
220
  contextMenuFeature: import("@jbrowse/core/util").Feature | undefined;
221
221
  } & {
222
- readonly blockType: "dynamicBlocks" | "staticBlocks";
222
+ readonly blockType: "dynamicBlocks" | "staticBlocks"; /**
223
+ * #getter
224
+ */
223
225
  readonly blockDefinitions: import("@jbrowse/core/util/blockTypes").BlockSet;
224
226
  } & {
225
227
  readonly renderDelay: number;
@@ -5,7 +5,7 @@ const useStyles = makeStyles()(theme => ({
5
5
  centerLineContainer: {
6
6
  background: 'transparent',
7
7
  height: '100%',
8
- zIndex: 5,
8
+ zIndex: 5, // above the track but under menu
9
9
  position: 'absolute',
10
10
  border: `1px ${theme.palette.action.active} dashed`,
11
11
  borderTop: 'none',
@@ -6,9 +6,8 @@ import { Button, FormControl, Container, Grid, CircularProgress, } from '@mui/ma
6
6
  import { ErrorMessage, AssemblySelector } from '@jbrowse/core/ui';
7
7
  // icons
8
8
  import CloseIcon from '@mui/icons-material/Close';
9
- // locals
10
- import RefNameAutocomplete from './RefNameAutocomplete';
11
- import { fetchResults, splitLast } from './util';
9
+ import { handleSelectedRegion, navToOption } from '../../searchUtils';
10
+ import ImportFormRefNameAutocomplete from './ImportFormRefNameAutocomplete';
12
11
  const useStyles = makeStyles()(theme => ({
13
12
  importFormContainer: {
14
13
  padding: theme.spacing(2),
@@ -24,11 +23,10 @@ const LinearGenomeViewImportForm = observer(function ({ model, }) {
24
23
  var _a;
25
24
  const { classes } = useStyles();
26
25
  const session = getSession(model);
27
- const { assemblyNames, assemblyManager, textSearchManager } = session;
28
- const { rankSearchResults, error } = model;
26
+ const { assemblyNames, assemblyManager } = session;
27
+ const { error } = model;
29
28
  const [selectedAsm, setSelectedAsm] = useState(assemblyNames[0]);
30
29
  const [option, setOption] = useState();
31
- const searchScope = model.searchScope(selectedAsm);
32
30
  const assembly = assemblyManager.get(selectedAsm);
33
31
  const assemblyError = assemblyNames.length
34
32
  ? assembly === null || assembly === void 0 ? void 0 : assembly.error
@@ -46,74 +44,37 @@ const LinearGenomeViewImportForm = observer(function ({ model, }) {
46
44
  useEffect(() => {
47
45
  setValue(r0);
48
46
  }, [r0, selectedAsm]);
49
- async function navToOption(option) {
50
- const location = option.getLocation();
51
- const trackId = option.getTrackId();
52
- if (location) {
53
- await model.navToLocString(location, selectedAsm);
54
- if (trackId) {
55
- model.showTrack(trackId);
56
- }
57
- }
58
- }
59
- // gets a string as input, or use stored option results from previous query,
60
- // then re-query and
61
- // 1) if it has multiple results: pop a dialog
62
- // 2) if it's a single result navigate to it
63
- // 3) else assume it's a locstring and navigate to it
64
- async function handleSelectedRegion(input) {
65
- var _a;
66
- try {
67
- if ((option === null || option === void 0 ? void 0 : option.getDisplayString()) === input && option.hasLocation()) {
68
- await navToOption(option);
69
- }
70
- else if ((_a = option === null || option === void 0 ? void 0 : option.results) === null || _a === void 0 ? void 0 : _a.length) {
71
- model.setSearchResults(option.results, option.getLabel(), selectedAsm);
72
- }
73
- else {
74
- const [ref, rest] = splitLast(input, ':');
75
- const allRefs = (assembly === null || assembly === void 0 ? void 0 : assembly.allRefNamesWithLowerCase) || [];
76
- if (allRefs.includes(input) ||
77
- (allRefs.includes(ref) && !Number.isNaN(Number.parseInt(rest, 10)))) {
78
- await model.navToLocString(input, selectedAsm);
79
- }
80
- else {
81
- const results = await fetchResults({
82
- queryString: input,
83
- searchType: 'exact',
84
- searchScope,
85
- rankSearchResults,
86
- textSearchManager,
87
- assembly,
88
- });
89
- if (results.length > 1) {
90
- model.setSearchResults(results, input.toLowerCase(), selectedAsm);
91
- }
92
- else if (results.length === 1) {
93
- await navToOption(results[0]);
94
- }
95
- else {
96
- await model.navToLocString(input, selectedAsm);
97
- }
98
- }
99
- }
100
- }
101
- catch (e) {
102
- console.error(e);
103
- session.notify(`${e}`, 'warning');
104
- }
105
- }
106
47
  // implementation notes:
107
48
  // having this wrapped in a form allows intuitive use of enter key to submit
108
49
  return (React.createElement("div", { className: classes.container },
109
50
  displayError ? React.createElement(ErrorMessage, { error: displayError }) : null,
110
51
  React.createElement(Container, { className: classes.importFormContainer },
111
52
  React.createElement("form", { onSubmit: async (event) => {
53
+ var _a;
112
54
  event.preventDefault();
113
55
  model.setError(undefined);
114
56
  if (value) {
115
57
  // has it's own error handling
116
- await handleSelectedRegion(value);
58
+ try {
59
+ if ((option === null || option === void 0 ? void 0 : option.getDisplayString()) === value &&
60
+ option.hasLocation()) {
61
+ await navToOption({
62
+ option,
63
+ model,
64
+ assemblyName: selectedAsm,
65
+ });
66
+ }
67
+ else if ((_a = option === null || option === void 0 ? void 0 : option.results) === null || _a === void 0 ? void 0 : _a.length) {
68
+ model.setSearchResults(option.results, option.getLabel(), selectedAsm);
69
+ }
70
+ else if (assembly) {
71
+ await handleSelectedRegion({ input: value, assembly, model });
72
+ }
73
+ }
74
+ catch (e) {
75
+ console.error(e);
76
+ session.notify(`${e}`, 'warning');
77
+ }
117
78
  }
118
79
  } },
119
80
  React.createElement(Grid, { container: true, spacing: 1, justifyContent: "center", alignItems: "center" },
@@ -121,16 +82,7 @@ const LinearGenomeViewImportForm = observer(function ({ model, }) {
121
82
  React.createElement(FormControl, null,
122
83
  React.createElement(AssemblySelector, { onChange: val => setSelectedAsm(val), localStorageKey: "lgv", session: session, selected: selectedAsm }))),
123
84
  React.createElement(Grid, { item: true }, selectedAsm ? (assemblyError ? (React.createElement(CloseIcon, { style: { color: 'red' } })) : assemblyLoaded ? (React.createElement(FormControl, null,
124
- React.createElement(RefNameAutocomplete, { fetchResults: queryString => fetchResults({
125
- queryString,
126
- assembly,
127
- textSearchManager,
128
- rankSearchResults,
129
- searchScope,
130
- }), model: model, assemblyName: selectedAsm, value: value, minWidth: 270, onChange: str => setValue(str), onSelect: val => setOption(val), TextFieldProps: {
131
- variant: 'outlined',
132
- helperText: 'Enter sequence name, feature name, or location',
133
- } }))) : (React.createElement(CircularProgress, { size: 20, disableShrink: true }))) : null),
85
+ React.createElement(ImportFormRefNameAutocomplete, { value: value, setValue: setValue, selectedAsm: selectedAsm, setOption: setOption, model: model }))) : (React.createElement(CircularProgress, { size: 20, disableShrink: true }))) : null),
134
86
  React.createElement(Grid, { item: true },
135
87
  React.createElement(FormControl, null,
136
88
  React.createElement(Button, { type: "submit", disabled: !value, className: classes.button, variant: "contained", color: "primary" }, "Open")),
@@ -0,0 +1,12 @@
1
+ import React from 'react';
2
+ import BaseResult from '@jbrowse/core/TextSearch/BaseResults';
3
+ import { LinearGenomeViewModel } from '..';
4
+ type LGV = LinearGenomeViewModel;
5
+ declare const ImportFormRefNameAutocomplete: ({ model, selectedAsm, value, setValue, setOption, }: {
6
+ value: string;
7
+ setValue: (arg: string) => void;
8
+ model: LGV;
9
+ selectedAsm: string;
10
+ setOption: (arg: BaseResult) => void;
11
+ }) => React.JSX.Element;
12
+ export default ImportFormRefNameAutocomplete;
@@ -0,0 +1,24 @@
1
+ import React from 'react';
2
+ import { observer } from 'mobx-react';
3
+ import { getSession } from '@jbrowse/core/util';
4
+ // locals
5
+ import RefNameAutocomplete from './RefNameAutocomplete';
6
+ import { fetchResults } from './util';
7
+ const ImportFormRefNameAutocomplete = observer(function ({ model, selectedAsm, value, setValue, setOption, }) {
8
+ const session = getSession(model);
9
+ const { assemblyManager, textSearchManager } = session;
10
+ const { rankSearchResults } = model;
11
+ const searchScope = model.searchScope(selectedAsm);
12
+ const assembly = assemblyManager.get(selectedAsm);
13
+ return (React.createElement(RefNameAutocomplete, { fetchResults: queryString => fetchResults({
14
+ queryString,
15
+ assembly,
16
+ textSearchManager,
17
+ rankSearchResults,
18
+ searchScope,
19
+ }), model: model, assemblyName: selectedAsm, value: value, minWidth: 270, onChange: str => setValue(str), onSelect: val => setOption(val), TextFieldProps: {
20
+ variant: 'outlined',
21
+ helperText: 'Enter sequence name, feature name, or location',
22
+ } }));
23
+ });
24
+ export default ImportFormRefNameAutocomplete;
@@ -195,7 +195,7 @@ const OverviewScalebar = observer(function ({ model, children, }) {
195
195
  overview.showAllRegions();
196
196
  return overview;
197
197
  }, [
198
- JSON.stringify(displayedRegions),
198
+ JSON.stringify(displayedRegions), // eslint-disable-line react-hooks/exhaustive-deps
199
199
  model.minimumBlockWidth,
200
200
  modWidth,
201
201
  displayedRegions,
@@ -5,8 +5,9 @@ import { makeStyles } from 'tss-react/mui';
5
5
  import { getSession } from '@jbrowse/core/util';
6
6
  // locals
7
7
  import RefNameAutocomplete from './RefNameAutocomplete';
8
- import { fetchResults, splitLast } from './util';
8
+ import { fetchResults } from './util';
9
9
  import { SPACING, WIDGET_HEIGHT } from '..';
10
+ import { handleSelectedRegion, navToOption } from '../../searchUtils';
10
11
  const useStyles = makeStyles()(() => ({
11
12
  headerRefName: {
12
13
  minWidth: 100,
@@ -21,65 +22,28 @@ const SearchBox = observer(function ({ model, showHelp, }) {
21
22
  const assemblyName = assemblyNames[0];
22
23
  const assembly = assemblyManager.get(assemblyName);
23
24
  const searchScope = model.searchScope(assemblyName);
24
- async function navToOption(option) {
25
- const location = option.getLocation();
26
- const trackId = option.getTrackId();
27
- if (location) {
28
- await model.navToLocString(location, assemblyName);
29
- if (trackId) {
30
- model.showTrack(trackId);
31
- }
32
- }
33
- }
34
- // gets a string as input, or use stored option results from previous query,
35
- // then re-query and
36
- // 1) if it has multiple results: pop a dialog
37
- // 2) if it's a single result navigate to it
38
- // 3) else assume it's a locstring and navigate to it
39
- async function handleSelectedRegion(option) {
40
- var _a;
41
- try {
42
- if (option.hasLocation()) {
43
- await navToOption(option);
44
- }
45
- else if ((_a = option.results) === null || _a === void 0 ? void 0 : _a.length) {
46
- model.setSearchResults(option.results, option.getLabel());
47
- }
48
- else {
49
- const input = option.getLabel();
50
- const [ref, rest] = splitLast(input, ':');
51
- const allRefs = (assembly === null || assembly === void 0 ? void 0 : assembly.allRefNamesWithLowerCase) || [];
52
- if (allRefs.includes(input) ||
53
- (allRefs.includes(ref) && !Number.isNaN(Number.parseInt(rest, 10)))) {
54
- await model.navToLocString(input, assemblyName);
25
+ return (React.createElement(RefNameAutocomplete, { showHelp: showHelp, onSelect: async (option) => {
26
+ var _a;
27
+ try {
28
+ if (option.hasLocation()) {
29
+ await navToOption({ option, model, assemblyName });
55
30
  }
56
- else {
57
- const results = await fetchResults({
58
- queryString: input,
59
- searchType: 'exact',
60
- searchScope,
61
- rankSearchResults,
62
- textSearchManager,
31
+ else if ((_a = option.results) === null || _a === void 0 ? void 0 : _a.length) {
32
+ model.setSearchResults(option.results, option.getLabel());
33
+ }
34
+ else if (assembly) {
35
+ await handleSelectedRegion({
36
+ input: option.getLabel(),
63
37
  assembly,
38
+ model,
64
39
  });
65
- if (results.length > 1) {
66
- model.setSearchResults(results, input.toLowerCase());
67
- }
68
- else if (results.length === 1) {
69
- await navToOption(results[0]);
70
- }
71
- else {
72
- await model.navToLocString(input, assemblyName);
73
- }
74
40
  }
75
41
  }
76
- }
77
- catch (e) {
78
- console.error(e);
79
- session.notify(`${e}`, 'warning');
80
- }
81
- }
82
- return (React.createElement(RefNameAutocomplete, { showHelp: showHelp, onSelect: handleSelectedRegion, assemblyName: assemblyName, fetchResults: queryString => fetchResults({
42
+ catch (e) {
43
+ console.error(e);
44
+ getSession(model).notify(`${e}`, 'warning');
45
+ }
46
+ }, assemblyName: assemblyName, fetchResults: queryString => fetchResults({
83
47
  queryString,
84
48
  searchScope,
85
49
  rankSearchResults,
@@ -6,6 +6,7 @@ import BaseResult from '@jbrowse/core/TextSearch/BaseResults';
6
6
  import { BlockSet, BaseBlock } from '@jbrowse/core/util/blockTypes';
7
7
  import { Instance } from 'mobx-state-tree';
8
8
  import PluginManager from '@jbrowse/core/PluginManager';
9
+ import { Assembly } from '@jbrowse/core/assemblyManager/assembly';
9
10
  export interface BpOffset {
10
11
  refName?: string;
11
12
  index: number;
@@ -292,7 +293,7 @@ export declare function stateModelFactory(pluginManager: PluginManager): import(
292
293
  /**
293
294
  * #action
294
295
  */
295
- toggleTrack(trackId: string): void;
296
+ toggleTrack(trackId: string): boolean;
296
297
  /**
297
298
  * #action
298
299
  */
@@ -463,6 +464,16 @@ export declare function stateModelFactory(pluginManager: PluginManager): import(
463
464
  * navigating to the locstring
464
465
  */
465
466
  navToLocString(input: string, optAssemblyName?: string): Promise<void>;
467
+ /**
468
+ * #action
469
+ * Performs a text index search, and navigates to it immediately if a
470
+ * single result is returned. Will pop up a search dialog if multiple
471
+ * results are returned
472
+ */
473
+ navToSearchString({ input, assembly, }: {
474
+ input: string;
475
+ assembly: Assembly;
476
+ }): Promise<void>;
466
477
  /**
467
478
  * #action
468
479
  * Similar to `navToLocString`, but accepts parsed location objects