@jbrowse/plugin-linear-genome-view 2.8.0 → 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.
- package/dist/BasicTrack/configSchema.d.ts +5 -0
- package/dist/FeatureTrack/configSchema.d.ts +5 -0
- package/dist/LaunchLinearGenomeView/index.js +16 -14
- package/dist/LinearGenomeView/components/CenterLine.js +1 -1
- package/dist/LinearGenomeView/components/ImportForm.js +26 -74
- package/dist/LinearGenomeView/components/ImportFormRefNameAutocomplete.d.ts +12 -0
- package/dist/LinearGenomeView/components/ImportFormRefNameAutocomplete.js +29 -0
- package/dist/LinearGenomeView/components/OverviewScalebar.js +1 -1
- package/dist/LinearGenomeView/components/SearchBox.js +19 -56
- package/dist/LinearGenomeView/model.d.ts +12 -1
- package/dist/LinearGenomeView/model.js +16 -0
- package/dist/index.d.ts +702 -6
- package/dist/index.js +2 -2
- package/dist/searchUtils.d.ts +26 -0
- package/dist/searchUtils.js +90 -0
- package/esm/BasicTrack/configSchema.d.ts +5 -0
- package/esm/FeatureTrack/configSchema.d.ts +5 -0
- package/esm/LaunchLinearGenomeView/index.js +16 -14
- package/esm/LinearGenomeView/components/CenterLine.js +1 -1
- package/esm/LinearGenomeView/components/ImportForm.js +26 -74
- package/esm/LinearGenomeView/components/ImportFormRefNameAutocomplete.d.ts +12 -0
- package/esm/LinearGenomeView/components/ImportFormRefNameAutocomplete.js +24 -0
- package/esm/LinearGenomeView/components/OverviewScalebar.js +1 -1
- package/esm/LinearGenomeView/components/SearchBox.js +20 -57
- package/esm/LinearGenomeView/model.d.ts +12 -1
- package/esm/LinearGenomeView/model.js +16 -0
- package/esm/index.d.ts +702 -6
- package/esm/index.js +2 -2
- package/esm/searchUtils.d.ts +26 -0
- package/esm/searchUtils.js +79 -0
- 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;
|
|
@@ -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
|
|
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
|
+
}
|
|
@@ -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
|
-
|
|
10
|
-
import
|
|
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
|
|
28
|
-
const {
|
|
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
|
-
|
|
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(
|
|
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,18 +5,14 @@ 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
|
|
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,
|
|
13
14
|
},
|
|
14
15
|
}));
|
|
15
|
-
function checkRef(str, allRefs) {
|
|
16
|
-
const [ref, rest] = splitLast(str, ':');
|
|
17
|
-
return (allRefs.includes(str) ||
|
|
18
|
-
(allRefs.includes(ref) && !Number.isNaN(Number.parseInt(rest, 10))));
|
|
19
|
-
}
|
|
20
16
|
const SearchBox = observer(function ({ model, showHelp, }) {
|
|
21
17
|
const { classes } = useStyles();
|
|
22
18
|
const theme = useTheme();
|
|
@@ -26,61 +22,28 @@ const SearchBox = observer(function ({ model, showHelp, }) {
|
|
|
26
22
|
const assemblyName = assemblyNames[0];
|
|
27
23
|
const assembly = assemblyManager.get(assemblyName);
|
|
28
24
|
const searchScope = model.searchScope(assemblyName);
|
|
29
|
-
async
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
if (trackId) {
|
|
35
|
-
model.showTrack(trackId);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
// gets a string as input, or use stored option results from previous query,
|
|
40
|
-
// then re-query and
|
|
41
|
-
// 1) if it has multiple results: pop a dialog
|
|
42
|
-
// 2) if it's a single result navigate to it
|
|
43
|
-
// 3) else assume it's a locstring and navigate to it
|
|
44
|
-
async function handleSelectedRegion(option) {
|
|
45
|
-
var _a;
|
|
46
|
-
try {
|
|
47
|
-
const input = option.getLabel();
|
|
48
|
-
const allRefs = (assembly === null || assembly === void 0 ? void 0 : assembly.allRefNamesWithLowerCase) || [];
|
|
49
|
-
if (option.hasLocation()) {
|
|
50
|
-
await navToOption(option);
|
|
51
|
-
}
|
|
52
|
-
else if ((_a = option.results) === null || _a === void 0 ? void 0 : _a.length) {
|
|
53
|
-
model.setSearchResults(option.results, option.getLabel());
|
|
54
|
-
}
|
|
55
|
-
else if (input.split(' ').every(entry => checkRef(entry, allRefs))) {
|
|
56
|
-
await model.navToLocString(input, assemblyName);
|
|
57
|
-
}
|
|
58
|
-
else {
|
|
59
|
-
const results = await fetchResults({
|
|
60
|
-
queryString: input,
|
|
61
|
-
searchType: 'exact',
|
|
62
|
-
searchScope,
|
|
63
|
-
rankSearchResults,
|
|
64
|
-
textSearchManager,
|
|
65
|
-
assembly,
|
|
66
|
-
});
|
|
67
|
-
if (results.length > 1) {
|
|
68
|
-
model.setSearchResults(results, input.toLowerCase());
|
|
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 });
|
|
69
30
|
}
|
|
70
|
-
else if (results
|
|
71
|
-
|
|
31
|
+
else if ((_a = option.results) === null || _a === void 0 ? void 0 : _a.length) {
|
|
32
|
+
model.setSearchResults(option.results, option.getLabel());
|
|
72
33
|
}
|
|
73
|
-
else {
|
|
74
|
-
await
|
|
34
|
+
else if (assembly) {
|
|
35
|
+
await handleSelectedRegion({
|
|
36
|
+
input: option.getLabel(),
|
|
37
|
+
assembly,
|
|
38
|
+
model,
|
|
39
|
+
});
|
|
75
40
|
}
|
|
76
41
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
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({
|
|
84
47
|
queryString,
|
|
85
48
|
searchScope,
|
|
86
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):
|
|
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
|
|
@@ -24,6 +24,7 @@ import MenuOpenIcon from '@mui/icons-material/MenuOpen';
|
|
|
24
24
|
import MiniControls from './components/MiniControls';
|
|
25
25
|
import Header from './components/Header';
|
|
26
26
|
import { generateLocations, parseLocStrings } from './util';
|
|
27
|
+
import { handleSelectedRegion } from '../searchUtils';
|
|
27
28
|
// lazies
|
|
28
29
|
const ReturnToImportFormDialog = lazy(() => import('@jbrowse/core/ui/ReturnToImportFormDialog'));
|
|
29
30
|
const SequenceSearchDialog = lazy(() => import('./components/SequenceSearchDialog'));
|
|
@@ -595,7 +596,9 @@ export function stateModelFactory(pluginManager) {
|
|
|
595
596
|
// if none had that configuration, turn one on
|
|
596
597
|
if (!hiddenCount) {
|
|
597
598
|
self.showTrack(trackId);
|
|
599
|
+
return true;
|
|
598
600
|
}
|
|
601
|
+
return false;
|
|
599
602
|
},
|
|
600
603
|
/**
|
|
601
604
|
* #action
|
|
@@ -1077,6 +1080,19 @@ export function stateModelFactory(pluginManager) {
|
|
|
1077
1080
|
}
|
|
1078
1081
|
return this.navToLocations(parseLocStrings(input, assemblyName, isValidRefName), assemblyName);
|
|
1079
1082
|
},
|
|
1083
|
+
/**
|
|
1084
|
+
* #action
|
|
1085
|
+
* Performs a text index search, and navigates to it immediately if a
|
|
1086
|
+
* single result is returned. Will pop up a search dialog if multiple
|
|
1087
|
+
* results are returned
|
|
1088
|
+
*/
|
|
1089
|
+
async navToSearchString({ input, assembly, }) {
|
|
1090
|
+
await handleSelectedRegion({
|
|
1091
|
+
input,
|
|
1092
|
+
assembly,
|
|
1093
|
+
model: self,
|
|
1094
|
+
});
|
|
1095
|
+
},
|
|
1080
1096
|
/**
|
|
1081
1097
|
* #action
|
|
1082
1098
|
* Similar to `navToLocString`, but accepts parsed location objects
|