@jbrowse/plugin-linear-genome-view 5.0.0-beta.17 → 5.0.0-beta.19
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/esm/LinearGenomeView/afterAttach.js +6 -4
- package/esm/LinearGenomeView/components/ImportForm.js +2 -4
- package/esm/LinearGenomeView/components/LinearGenomeViewContainer.js +4 -2
- package/esm/LinearGenomeView/components/SearchBox.js +1 -9
- package/esm/LinearGenomeView/components/SearchResultsDialog.js +1 -1
- package/esm/LinearGenomeView/components/SearchResultsTable.d.ts +2 -1
- package/esm/LinearGenomeView/components/SearchResultsTable.js +23 -5
- package/esm/LinearGenomeView/components/SequenceFeatureHoverHighlight.js +2 -3
- package/esm/LinearGenomeView/components/TrackContainer.d.ts +2 -3
- package/esm/LinearGenomeView/components/TrackContainer.js +3 -4
- package/esm/LinearGenomeView/components/TrackLabelRefNameWarning.d.ts +3 -4
- package/esm/LinearGenomeView/components/TrackLabelRefNameWarning.js +23 -10
- package/esm/LinearGenomeView/components/TrackRenderingContainer.d.ts +2 -3
- package/esm/LinearGenomeView/components/TrackRenderingContainer.js +1 -1
- package/esm/LinearGenomeView/components/useSearchBoxPrefs.d.ts +1 -1
- package/esm/LinearGenomeView/components/useSearchBoxPrefs.js +1 -1
- package/esm/LinearGenomeView/index.d.ts +1 -1
- package/esm/LinearGenomeView/index.js +2 -0
- package/esm/LinearGenomeView/keyboardHandler.d.ts +8 -9
- package/esm/LinearGenomeView/keyboardHandler.js +58 -34
- package/esm/LinearGenomeView/menuItems.js +3 -2
- package/esm/LinearGenomeView/model.d.ts +489 -52
- package/esm/LinearGenomeView/model.js +125 -45
- package/esm/LinearGenomeView/rExport/exportLinearView.js +4 -5
- package/esm/LinearGenomeView/rExport/rScript.d.ts +26 -1
- package/esm/LinearGenomeView/rExport/rScript.js +27 -6
- package/esm/LinearGenomeView/sharedScaleContainer.js +2 -12
- package/esm/LinearGenomeView/showFiles.d.ts +2 -0
- package/esm/LinearGenomeView/showFiles.js +19 -0
- package/esm/LinearGenomeView/showRegionsWithUndo.d.ts +1 -1
- package/esm/LinearGenomeView/showRegionsWithUndo.js +1 -1
- package/esm/LinearGenomeView/svgcomponents/SVGLinearGenomeView.js +3 -1
- package/esm/LinearGenomeView/util.d.ts +1 -1
- package/esm/LinearGenomeView/util.js +1 -1
- package/esm/TrackModifiers/index.d.ts +80 -0
- package/esm/TrackModifiers/index.js +212 -0
- package/esm/displayKitTests/perRegionTestEnv.d.ts +10 -4
- package/esm/index.d.ts +3 -1
- package/esm/index.js +1 -2
- package/esm/searchUtils.d.ts +14 -2
- package/esm/searchUtils.js +56 -36
- package/package.json +10 -9
- package/esm/FeatureTrack/configSchema.d.ts +0 -217
- package/esm/FeatureTrack/configSchema.js +0 -55
- package/esm/FeatureTrack/index.d.ts +0 -2
- package/esm/FeatureTrack/index.js +0 -13
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import { mergeConfSettings } from '@jbrowse/core/configuration';
|
|
2
|
+
import { getEnv, getSession } from '@jbrowse/core/util';
|
|
3
|
+
import { basePaintedAt } from '@jbrowse/core/util/Base1DUtils';
|
|
4
|
+
import { predicatesOf, testsSomething, withFields, } from '@jbrowse/core/util/fieldPredicate';
|
|
5
|
+
import { normalizeTrackInit, trackDisplayType } from '@jbrowse/core/util/tracks';
|
|
6
|
+
import { buildDisplaySnapshot, displayCategory, memberPatch, memberWrites, mergeSettings, requestedDisplayType, } from '@jbrowse/launch-args/displaySettings';
|
|
7
|
+
import { getSnapshot, getType, isArrayType, isStateTreeNode, } from '@jbrowse/mobx-state-tree';
|
|
8
|
+
/**
|
|
9
|
+
* The display a linear view opens `conf` as, read off the display picker so it
|
|
10
|
+
* follows `display:` and the adapter rather than a list of track types.
|
|
11
|
+
*/
|
|
12
|
+
function displayTypeOf(pluginManager, conf, modifiers, displayType) {
|
|
13
|
+
return trackDisplayType(pluginManager, conf, 'LinearGenomeView', requestedDisplayType(modifiers) ?? displayType);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* `displayTypeOf` for a track the session holds, undefined for one it does
|
|
17
|
+
* not; `displayType` is the display the caller opens it as when no
|
|
18
|
+
* `display:` modifier names one.
|
|
19
|
+
*/
|
|
20
|
+
export function openedDisplayType(session, trackId, modifiers, displayType) {
|
|
21
|
+
const conf = session.getTrackById(trackId);
|
|
22
|
+
return conf
|
|
23
|
+
? displayTypeOf(getEnv(session).pluginManager, (isStateTreeNode(conf) ? getSnapshot(conf) : conf), modifiers, displayType)
|
|
24
|
+
: undefined;
|
|
25
|
+
}
|
|
26
|
+
const consoleWarn = (message) => {
|
|
27
|
+
console.warn(`Warning: ${message}`);
|
|
28
|
+
};
|
|
29
|
+
function modifierLaunch(displayType, modifiers, warn = consoleWarn) {
|
|
30
|
+
return {
|
|
31
|
+
displayType,
|
|
32
|
+
settings: buildDisplaySnapshot(displayType, modifiers, warn),
|
|
33
|
+
members: memberWrites(displayType, modifiers),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
// the entries grouped by field, as `setFilterFields` takes them: a field whose
|
|
37
|
+
// entries are all bare is `[]`, which clears it, defaults included
|
|
38
|
+
function filterPatch(entries) {
|
|
39
|
+
const patch = {};
|
|
40
|
+
for (const p of entries) {
|
|
41
|
+
patch[p.field] = [
|
|
42
|
+
...(patch[p.field] ?? []),
|
|
43
|
+
...(testsSomething(p) ? [p] : []),
|
|
44
|
+
];
|
|
45
|
+
}
|
|
46
|
+
return patch;
|
|
47
|
+
}
|
|
48
|
+
// the display snapshot a track opens with. `filter` stays out of it:
|
|
49
|
+
// `writeFilter` writes it once the track is open, since the list in a
|
|
50
|
+
// snapshot would replace the configured one
|
|
51
|
+
function launchSnapshot({ settings }) {
|
|
52
|
+
const { snap, displayType } = settings;
|
|
53
|
+
const { filter: _filter, ...unfiltered } = snap;
|
|
54
|
+
return {
|
|
55
|
+
...unfiltered,
|
|
56
|
+
...(displayType ? { type: displayType } : {}),
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Write the `filter` of `trackId`'s `settings` onto its display open in
|
|
61
|
+
* `view`, by field over the configured filter, as the track menu would.
|
|
62
|
+
* Returns the display's filter as written, which reopens the track as drawn,
|
|
63
|
+
* or undefined when the settings write no filter.
|
|
64
|
+
*/
|
|
65
|
+
export function writeFilter(view, trackId, settings) {
|
|
66
|
+
const { filter } = settings.snap;
|
|
67
|
+
const track = view.tracks.find(t => t.configuration.trackId === trackId);
|
|
68
|
+
if (!filter || !track) {
|
|
69
|
+
return undefined;
|
|
70
|
+
}
|
|
71
|
+
const patch = filterPatch(filter);
|
|
72
|
+
const display = track.displays[0];
|
|
73
|
+
if (display?.setFilterFields) {
|
|
74
|
+
display.setFilterFields(patch);
|
|
75
|
+
return display.writtenFilter;
|
|
76
|
+
}
|
|
77
|
+
const written = withFields(predicatesOf(track.activeDisplay.configuration.filter), patch);
|
|
78
|
+
view.showTrack(trackId, {}, { filter: written });
|
|
79
|
+
return written;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* @deprecated `writeFilter`, which every display category takes. This one
|
|
83
|
+
* writes an alignments `display`'s filter only.
|
|
84
|
+
*/
|
|
85
|
+
export function writeReadFilter(display, displayType, settings) {
|
|
86
|
+
const { filter } = settings.snap;
|
|
87
|
+
if (displayCategory(displayType) !== 'alignments' || !filter) {
|
|
88
|
+
return undefined;
|
|
89
|
+
}
|
|
90
|
+
const filterDisplay = display;
|
|
91
|
+
filterDisplay?.setFilterFields?.(filterPatch(filter));
|
|
92
|
+
return filterDisplay?.writtenFilter;
|
|
93
|
+
}
|
|
94
|
+
// the pivot is the base under the view's center, which a view has only once
|
|
95
|
+
// it shows a region
|
|
96
|
+
function centerSort(view, trackId, field, warn) {
|
|
97
|
+
const center = view.centerLineInfo;
|
|
98
|
+
if (center && !center.oob) {
|
|
99
|
+
return {
|
|
100
|
+
field,
|
|
101
|
+
pos: basePaintedAt(center, center.offset),
|
|
102
|
+
refName: center.refName ?? '',
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
warn(`sort:${field} on "${trackId}" ignored — the view has no center position to sort at (pass --loc)`);
|
|
107
|
+
return undefined;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
// The modifiers' settings written over the entry's own as a settings bag
|
|
111
|
+
// writes them (`mergeConfSettings`): a namespace such as `pileup` member by
|
|
112
|
+
// member, a bare value lifted first, and a channel such as `encoding.color`
|
|
113
|
+
// whole, so a `color:` modifier is not mixed into the entry's color by field.
|
|
114
|
+
// Plain JSON where no registered display type says which is which.
|
|
115
|
+
function overEntry(view, displayType, entry, over) {
|
|
116
|
+
const pluginManager = isStateTreeNode(view)
|
|
117
|
+
? getEnv(view).pluginManager
|
|
118
|
+
: undefined;
|
|
119
|
+
return displayType && pluginManager?.displayTypes.has(displayType)
|
|
120
|
+
? mergeConfSettings(pluginManager.getDisplayType(displayType).configSchema, entry, over)
|
|
121
|
+
: mergeSettings(structuredClone(entry), over);
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Open `trackId` in `view` with its command-line modifiers applied, and return
|
|
125
|
+
* the session-spec track entry that reopens it as drawn, or undefined when the
|
|
126
|
+
* open fails, which `launchTrack` reports to the session.
|
|
127
|
+
*/
|
|
128
|
+
export async function launchTrackWithModifiers(view, trackId, displayType, modifiers, { displaySnapshot = {}, trackSnapshot = {}, adjust, warn = consoleWarn, } = {}) {
|
|
129
|
+
const launch = modifierLaunch(displayType, modifiers, warn);
|
|
130
|
+
const { snap, sort } = launch.settings;
|
|
131
|
+
const at = sort && centerSort(view, trackId, sort.field, warn);
|
|
132
|
+
if (at) {
|
|
133
|
+
snap.sort = at;
|
|
134
|
+
}
|
|
135
|
+
adjust?.(launch.settings);
|
|
136
|
+
const launched = overEntry(view, displayType, displaySnapshot, launchSnapshot(launch));
|
|
137
|
+
const opened = await view.launchTrack(trackId, trackSnapshot, launched);
|
|
138
|
+
if (!opened) {
|
|
139
|
+
return undefined;
|
|
140
|
+
}
|
|
141
|
+
const drawnFilter = writeFilter(view, trackId, launch.settings);
|
|
142
|
+
const members = writeMembers(view, trackId, launch.members);
|
|
143
|
+
return {
|
|
144
|
+
trackId,
|
|
145
|
+
...launched,
|
|
146
|
+
...(drawnFilter ? { filter: drawnFilter } : {}),
|
|
147
|
+
...members,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Open a session spec's track entry in a navigated `view`, its `modifiers`
|
|
152
|
+
* written over its display settings. When a modifier or the open fails, the
|
|
153
|
+
* session's snackbar says why and the track opens with its own settings.
|
|
154
|
+
*/
|
|
155
|
+
export async function launchTrackInit(view, t) {
|
|
156
|
+
const { trackId, trackSnapshot, displaySnapshot, modifiers } = normalizeTrackInit(t);
|
|
157
|
+
if (modifiers.length === 0) {
|
|
158
|
+
await view.launchTrack(trackId, trackSnapshot, displaySnapshot);
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
const session = getSession(view);
|
|
162
|
+
const { type } = displaySnapshot;
|
|
163
|
+
const notes = [];
|
|
164
|
+
try {
|
|
165
|
+
await launchTrackWithModifiers(view, trackId, openedDisplayType(session, trackId, modifiers, typeof type === 'string' ? type : undefined), modifiers, {
|
|
166
|
+
trackSnapshot,
|
|
167
|
+
displaySnapshot,
|
|
168
|
+
warn: message => notes.push(message),
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
catch (e) {
|
|
172
|
+
console.error(e);
|
|
173
|
+
session.notifyError(`"${trackId}" ${modifiers.join(' ')}: ${e}`, e);
|
|
174
|
+
}
|
|
175
|
+
// launchTrack reports its own failure, such as a display:
|
|
176
|
+
// the track cannot open as
|
|
177
|
+
if (!view.tracks.some(t => t.configuration.trackId === trackId)) {
|
|
178
|
+
await view.launchTrack(trackId, trackSnapshot, displaySnapshot);
|
|
179
|
+
}
|
|
180
|
+
if (notes.length) {
|
|
181
|
+
session.notify(notes.join('; '), 'warning');
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Write a track's `memberWrites` onto what its display in `view` already has,
|
|
186
|
+
* after every other modifier, so a member write keeps the rest of the setting
|
|
187
|
+
* whatever order the command line gives them in. A display replaces a color
|
|
188
|
+
* or facet object whole, which is why these cannot ride in on the launch
|
|
189
|
+
* snapshot.
|
|
190
|
+
*/
|
|
191
|
+
export function writeMembers(view, trackId, members) {
|
|
192
|
+
if (members.length === 0) {
|
|
193
|
+
return {};
|
|
194
|
+
}
|
|
195
|
+
const track = view.tracks.find(t => t.configuration.trackId === trackId);
|
|
196
|
+
if (!track) {
|
|
197
|
+
throw new Error(`"${trackId}" is not open, so ${members.join(' ')} has nothing to write to`);
|
|
198
|
+
}
|
|
199
|
+
const { configuration } = track.activeDisplay;
|
|
200
|
+
const configured = getSnapshot(configuration);
|
|
201
|
+
const patch = memberPatch(members, root => {
|
|
202
|
+
// a list at a default the snapshot strips, Manhattan's marks, still seeds
|
|
203
|
+
// the write, so `marks.0.mark=bar` edits the mark drawn
|
|
204
|
+
const member = configuration[root];
|
|
205
|
+
return (configured[root] ??
|
|
206
|
+
(isStateTreeNode(member) && isArrayType(getType(member))
|
|
207
|
+
? getSnapshot(member)
|
|
208
|
+
: undefined));
|
|
209
|
+
});
|
|
210
|
+
view.showTrack(trackId, {}, patch);
|
|
211
|
+
return patch;
|
|
212
|
+
}
|
|
@@ -31,7 +31,7 @@ export interface PerRegionTestControl {
|
|
|
31
31
|
*/
|
|
32
32
|
estimateBytes: number;
|
|
33
33
|
estimateCalls: number;
|
|
34
|
-
/** the display's own density verdict,
|
|
34
|
+
/** the display's own density verdict, the feature display's second too-large axis */
|
|
35
35
|
densityTooLarge: boolean;
|
|
36
36
|
/**
|
|
37
37
|
* What the next fetch stores, so a test can tell the payload a refetch
|
|
@@ -45,7 +45,7 @@ export interface PerRegionTestControl {
|
|
|
45
45
|
* displays compose this foundation, and every one of them adds a plugin's worth
|
|
46
46
|
* of behavior on top — so a test that boots one is testing that plugin as much
|
|
47
47
|
* as the foundation, which is how the foundation's own autoruns came to be
|
|
48
|
-
* pinned only by
|
|
48
|
+
* pinned only by the feature display's suite.
|
|
49
49
|
*/
|
|
50
50
|
/** Which of the gate's opt-in hooks this display overrides. */
|
|
51
51
|
export interface GateOptIns {
|
|
@@ -266,7 +266,9 @@ declare function makeStateModel(control: PerRegionTestControl, gate: GateOptIns,
|
|
|
266
266
|
readonly plotKeys: string[];
|
|
267
267
|
readonly plot: import("@jbrowse/core/configuration").Plot;
|
|
268
268
|
readonly configNotices: string[];
|
|
269
|
+
} & {
|
|
269
270
|
readonly notices: string[];
|
|
271
|
+
} & {
|
|
270
272
|
readonly cornerNotices: string[];
|
|
271
273
|
readonly plotExamples: readonly import("@jbrowse/core/configuration").PlotExample[];
|
|
272
274
|
readonly configDocsUrl: string;
|
|
@@ -498,12 +500,12 @@ export declare function createPerRegionTestEnvironment({ measuresBytes, gate, es
|
|
|
498
500
|
*/
|
|
499
501
|
estimateBytes?: number;
|
|
500
502
|
}): {
|
|
501
|
-
createDisplay: (
|
|
503
|
+
createDisplay: (args_0?: {
|
|
502
504
|
displayedRegions?: import("@jbrowse/core/util").Region[];
|
|
503
505
|
displaySnapshot?: Record<string, unknown>;
|
|
504
506
|
skipWidth?: boolean;
|
|
505
507
|
regionsInSnapshot?: boolean;
|
|
506
|
-
}) => {
|
|
508
|
+
} | undefined) => {
|
|
507
509
|
session: import("@jbrowse/mobx-state-tree").ModelInstanceTypeProps<{
|
|
508
510
|
name: import("@jbrowse/mobx-state-tree").IType<string | undefined, string, string>;
|
|
509
511
|
view: import("@jbrowse/mobx-state-tree").IMaybe<import("@jbrowse/mobx-state-tree").IAnyModelType>;
|
|
@@ -804,7 +806,9 @@ export declare function createPerRegionTestEnvironment({ measuresBytes, gate, es
|
|
|
804
806
|
readonly plotKeys: string[];
|
|
805
807
|
readonly plot: import("@jbrowse/core/configuration").Plot;
|
|
806
808
|
readonly configNotices: string[];
|
|
809
|
+
} & {
|
|
807
810
|
readonly notices: string[];
|
|
811
|
+
} & {
|
|
808
812
|
readonly cornerNotices: string[];
|
|
809
813
|
readonly plotExamples: readonly import("@jbrowse/core/configuration").PlotExample[];
|
|
810
814
|
readonly configDocsUrl: string;
|
|
@@ -1231,7 +1235,9 @@ export declare function createPerRegionTestEnvironment({ measuresBytes, gate, es
|
|
|
1231
1235
|
readonly plotKeys: string[];
|
|
1232
1236
|
readonly plot: import("@jbrowse/core/configuration").Plot;
|
|
1233
1237
|
readonly configNotices: string[];
|
|
1238
|
+
} & {
|
|
1234
1239
|
readonly notices: string[];
|
|
1240
|
+
} & {
|
|
1235
1241
|
readonly cornerNotices: string[];
|
|
1236
1242
|
readonly plotExamples: readonly import("@jbrowse/core/configuration").PlotExample[];
|
|
1237
1243
|
readonly configDocsUrl: string;
|
package/esm/index.d.ts
CHANGED
|
@@ -29,12 +29,14 @@ export { searchBoxMenuItems, useSearchBoxPrefs, } from './LinearGenomeView/compo
|
|
|
29
29
|
export type { SearchBoxPrefs } from './LinearGenomeView/components/useSearchBoxPrefs.ts';
|
|
30
30
|
export { normalizeTrackInit } from '@jbrowse/core/util/tracks';
|
|
31
31
|
export { applyInitHighlights } from './LinearGenomeView/afterAttach.ts';
|
|
32
|
+
export { launchTrackInit, launchTrackWithModifiers, openedDisplayType, writeFilter, writeMembers, writeReadFilter, } from './TrackModifiers/index.ts';
|
|
33
|
+
export type { ModifierView } from './TrackModifiers/index.ts';
|
|
32
34
|
export { MultiLevelRubberband, multiLevelRowClickMenuItems, multiLevelRowMenuItems, rowLabels, } from './MultiLevelRubberband/index.ts';
|
|
33
35
|
export { fetchResults, SearchResultsNotFoundError } from './searchUtils.ts';
|
|
34
36
|
export type { LaunchLinearGenomeViewArgs } from './LaunchLinearGenomeView/index.ts';
|
|
35
37
|
export type { BpOffset, ExportSvgOptions, HighlightInput, HighlightType, InitState, LinearGenomeViewLaunchProps, NavLocation, TrackLabelMode, ViewTrackLabelMode, VolatileGuide, } from './LinearGenomeView/types.ts';
|
|
36
38
|
export type { ScalebarRefNameLabel } from './LinearGenomeView/util.ts';
|
|
37
|
-
export type { HighlightRegion, SearchPickerRow, SearchPickerState, } from './LinearGenomeView/model.ts';
|
|
39
|
+
export type { HighlightRegion, SearchHits, SearchPickerRow, SearchPickerState, } from './LinearGenomeView/model.ts';
|
|
38
40
|
export type { RegionsOrientation } from './LinearGenomeView/util.ts';
|
|
39
41
|
export type { RegionEdit } from './LinearGenomeView/util.ts';
|
|
40
42
|
export { makeTicks } from './LinearGenomeView/util.ts';
|
package/esm/index.js
CHANGED
|
@@ -4,7 +4,6 @@ import { isAbstractMenuManager } from '@jbrowse/core/util';
|
|
|
4
4
|
import { VIEW_TRACK_LABEL_MODES } from '@jbrowse/display-kit/types';
|
|
5
5
|
import { types } from '@jbrowse/mobx-state-tree';
|
|
6
6
|
import LineStyleIcon from '@mui/icons-material/LineStyle';
|
|
7
|
-
import FeatureTrackF from './FeatureTrack/index.js';
|
|
8
7
|
import LaunchLinearGenomeViewF from './LaunchLinearGenomeView/index.js';
|
|
9
8
|
import SequenceFeatureHoverHighlightExtensionF from './LinearGenomeView/components/SequenceFeatureHoverHighlightExtension.js';
|
|
10
9
|
import LinearGenomeViewF from './LinearGenomeView/index.js';
|
|
@@ -33,7 +32,6 @@ export default class LinearGenomeViewPlugin extends Plugin {
|
|
|
33
32
|
},
|
|
34
33
|
});
|
|
35
34
|
install(pluginManager) {
|
|
36
|
-
FeatureTrackF(pluginManager);
|
|
37
35
|
LinearGenomeViewF(pluginManager);
|
|
38
36
|
LaunchLinearGenomeViewF(pluginManager);
|
|
39
37
|
SequenceFeatureHoverHighlightExtensionF(pluginManager);
|
|
@@ -71,6 +69,7 @@ export { default as HeaderSearchBoxRow } from './LinearGenomeView/components/Hea
|
|
|
71
69
|
export { searchBoxMenuItems, useSearchBoxPrefs, } from './LinearGenomeView/components/useSearchBoxPrefs.js';
|
|
72
70
|
export { normalizeTrackInit } from '@jbrowse/core/util/tracks';
|
|
73
71
|
export { applyInitHighlights } from './LinearGenomeView/afterAttach.js';
|
|
72
|
+
export { launchTrackInit, launchTrackWithModifiers, openedDisplayType, writeFilter, writeMembers, writeReadFilter, } from './TrackModifiers/index.js';
|
|
74
73
|
export { MultiLevelRubberband, multiLevelRowClickMenuItems, multiLevelRowMenuItems, rowLabels, } from './MultiLevelRubberband/index.js';
|
|
75
74
|
export { fetchResults, SearchResultsNotFoundError } from './searchUtils.js';
|
|
76
75
|
// The scalebar's grid, published because it is a contract other views draw
|
package/esm/searchUtils.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import type BaseResult from '@jbrowse/core/TextSearch/BaseResults';
|
|
|
3
3
|
import type TextSearchManager from '@jbrowse/core/TextSearch/TextSearchManager';
|
|
4
4
|
import type { Assembly } from '@jbrowse/core/assemblyManager/assembly';
|
|
5
5
|
import type { SearchType } from '@jbrowse/core/data_adapters/BaseAdapter';
|
|
6
|
-
import type { AssemblyHost, NotificationSink, TrackCatalog } from '@jbrowse/core/util';
|
|
6
|
+
import type { AbstractSessionModel, AssemblyHost, NotificationSink, TrackCatalog } from '@jbrowse/core/util';
|
|
7
7
|
declare module '@jbrowse/core/PluginManager' {
|
|
8
8
|
interface ExtensionPointRegistry {
|
|
9
9
|
'LinearGenomeView-searchResultSelected': {
|
|
@@ -67,7 +67,19 @@ interface SearchArgs {
|
|
|
67
67
|
assembly?: Assembly;
|
|
68
68
|
signal?: AbortSignal;
|
|
69
69
|
}
|
|
70
|
-
|
|
70
|
+
interface SessionSearchArgs {
|
|
71
|
+
session: Pick<AbstractSessionModel, 'assemblyManager' | 'textSearchManager'>;
|
|
72
|
+
queryString: string;
|
|
73
|
+
assemblyName: string;
|
|
74
|
+
searchType?: SearchType;
|
|
75
|
+
signal?: AbortSignal;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* The search box's hits for a query: refNames and text-index results, merged.
|
|
79
|
+
* Pass the session and the function finds the index manager and the assembly
|
|
80
|
+
* itself; passing `textSearchManager` and `assembly` is the older form.
|
|
81
|
+
*/
|
|
82
|
+
export declare function fetchResults(args: SessionSearchArgs | SearchArgs): Promise<BaseResult[]>;
|
|
71
83
|
export declare function nameNotFound(input: string, assemblyName: string, { indexCount, failures }: {
|
|
72
84
|
indexCount: number;
|
|
73
85
|
failures: unknown[];
|
package/esm/searchUtils.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { RefSequenceResult } from '@jbrowse/core/TextSearch/BaseResults';
|
|
2
|
-
import { groupByPlace } from '@jbrowse/core/TextSearch/places';
|
|
3
|
-
import { dedupe, getEnv, getNotificationSink, getSession, matchRefNames, MAX_GLOB_REGIONS, UnknownRefNameError, } from '@jbrowse/core/util';
|
|
2
|
+
import { groupByPlace, landsInAssembly } from '@jbrowse/core/TextSearch/places';
|
|
3
|
+
import { dedupe, getEnv, getNotificationSink, getSession, matchRefNames, MAX_GLOB_REGIONS, rankRefNames, UnknownRefNameError, } from '@jbrowse/core/util';
|
|
4
4
|
import { isAlive } from '@jbrowse/mobx-state-tree';
|
|
5
5
|
import { parseLocStrings } from './LinearGenomeView/util.js';
|
|
6
6
|
// Budget for refName suggestions from a query. Deliberately far below the
|
|
7
|
-
// autocomplete's ~100-row display cap:
|
|
8
|
-
// search hits, so a scaffold-heavy assembly would otherwise fill every row with
|
|
7
|
+
// autocomplete's ~100-row display cap: exact and prefix refName hits are
|
|
8
|
+
// returned ahead of the text search hits, so a scaffold-heavy assembly would otherwise fill every row with
|
|
9
9
|
// scaffolds and push the gene hits out of the list entirely. Raising this to
|
|
10
10
|
// match the display cap looks like a consistency fix and is not one.
|
|
11
11
|
const MAX_REFNAME_HITS = 10;
|
|
@@ -274,16 +274,20 @@ export async function handleSelectedRegion({ input, model, assemblyName, grow, s
|
|
|
274
274
|
}
|
|
275
275
|
else {
|
|
276
276
|
// no search hits: still try to resolve the input as a locstring (bare
|
|
277
|
-
// refname, "ref start end" triplet, etc).
|
|
278
|
-
// refname
|
|
279
|
-
//
|
|
280
|
-
// error for coordinate
|
|
277
|
+
// refname, "ref start end" triplet, etc). If that also can't find a
|
|
278
|
+
// refname and the input names no sequence and no coordinate — a gene
|
|
279
|
+
// name, or a phrase like "breast cancer" — reframe the unknown-ref error
|
|
280
|
+
// as a name miss; keep the specific ref error for coordinate-shaped input
|
|
281
281
|
try {
|
|
282
282
|
await navToLocstrings();
|
|
283
283
|
return true;
|
|
284
284
|
}
|
|
285
285
|
catch (e) {
|
|
286
|
-
const isPlainName = !input.includes(':') &&
|
|
286
|
+
const isPlainName = !input.includes(':') &&
|
|
287
|
+
input
|
|
288
|
+
.trim()
|
|
289
|
+
.split(/\s+/)
|
|
290
|
+
.every(token => !isRef(token) && !/^\d[\d,]*$/.test(token));
|
|
287
291
|
if (e instanceof UnknownRefNameError && isPlainName) {
|
|
288
292
|
throw nameNotFound(input, assemblyName, found);
|
|
289
293
|
}
|
|
@@ -308,17 +312,39 @@ async function searchNames({ queryString, searchType, assemblyName, textSearchMa
|
|
|
308
312
|
// not itself kick off the lazy load. A load failure just leaves allRefNames
|
|
309
313
|
// undefined, so this still returns whatever the text search turned up
|
|
310
314
|
await assembly?.load().catch(() => { });
|
|
311
|
-
const
|
|
315
|
+
const { strong, weak } = assembly
|
|
312
316
|
? searchRefNames(assembly, queryString, searchType)
|
|
313
|
-
: [];
|
|
317
|
+
: { strong: [], weak: [] };
|
|
314
318
|
return {
|
|
315
|
-
results: dedupe([
|
|
319
|
+
results: dedupe([
|
|
320
|
+
...strong,
|
|
321
|
+
...(report?.results ?? []).filter(r => landsInAssembly(r, assembly)),
|
|
322
|
+
...weak,
|
|
323
|
+
], elt => elt.getId()),
|
|
316
324
|
indexCount: report?.indexCount ?? 0,
|
|
317
325
|
failures: report?.failures ?? [],
|
|
318
326
|
};
|
|
319
327
|
}
|
|
328
|
+
/**
|
|
329
|
+
* The search box's hits for a query: refNames and text-index results, merged.
|
|
330
|
+
* Pass the session and the function finds the index manager and the assembly
|
|
331
|
+
* itself; passing `textSearchManager` and `assembly` is the older form.
|
|
332
|
+
*/
|
|
320
333
|
export async function fetchResults(args) {
|
|
321
|
-
|
|
334
|
+
if ('session' in args) {
|
|
335
|
+
const { session, ...rest } = args;
|
|
336
|
+
const assembly = await session.assemblyManager
|
|
337
|
+
.waitForAssembly(args.assemblyName)
|
|
338
|
+
.catch(() => undefined);
|
|
339
|
+
return (await searchNames({
|
|
340
|
+
...rest,
|
|
341
|
+
textSearchManager: session.textSearchManager,
|
|
342
|
+
assembly,
|
|
343
|
+
})).results;
|
|
344
|
+
}
|
|
345
|
+
else {
|
|
346
|
+
return (await searchNames(args)).results;
|
|
347
|
+
}
|
|
322
348
|
}
|
|
323
349
|
// A miss says when an index could not answer: with none answering it is a
|
|
324
350
|
// failure, and with some answering it is still a miss, naming what failed
|
|
@@ -333,30 +359,24 @@ export function nameNotFound(input, assemblyName, { indexCount, failures }) {
|
|
|
333
359
|
})
|
|
334
360
|
: new SearchResultsNotFoundError(`${miss} (a search index failed: ${failure})`, { cause: failure });
|
|
335
361
|
}
|
|
336
|
-
//
|
|
337
|
-
//
|
|
338
|
-
//
|
|
339
|
-
// once enough unique canonical hits accumulate rather than lowercasing and
|
|
340
|
-
// scanning the entire list on every keystroke.
|
|
362
|
+
// The refNames a query names, through the same ranking the dropdown's fallback
|
|
363
|
+
// list uses. A refName the query is only a substring of is the weakest kind of
|
|
364
|
+
// hit, so it goes behind the text-search results rather than ahead of them
|
|
341
365
|
function searchRefNames(assembly, queryString, searchType) {
|
|
342
|
-
const
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
return [...canonicalHits].map(([r, exact]) => new RefSequenceResult({ label: r, refName: r, exact }));
|
|
366
|
+
const hits = rankRefNames(assembly, queryString, MAX_REFNAME_HITS)
|
|
367
|
+
.filter(({ tier }) => searchType !== 'exact' || tier === 'exact')
|
|
368
|
+
.map(({ refName, tier }) => ({
|
|
369
|
+
tier,
|
|
370
|
+
result: new RefSequenceResult({
|
|
371
|
+
label: refName,
|
|
372
|
+
refName,
|
|
373
|
+
exact: tier === 'exact',
|
|
374
|
+
}),
|
|
375
|
+
}));
|
|
376
|
+
return {
|
|
377
|
+
strong: hits.filter(h => h.tier !== 'substring').map(h => h.result),
|
|
378
|
+
weak: hits.filter(h => h.tier === 'substring').map(h => h.result),
|
|
379
|
+
};
|
|
360
380
|
}
|
|
361
381
|
// splits on the last instance of a character
|
|
362
382
|
export function splitLast(str, split) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jbrowse/plugin-linear-genome-view",
|
|
3
|
-
"version": "5.0.0-beta.
|
|
3
|
+
"version": "5.0.0-beta.19",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "JBrowse 2 linear genome view",
|
|
6
6
|
"keywords": [
|
|
@@ -21,15 +21,16 @@
|
|
|
21
21
|
"esm"
|
|
22
22
|
],
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@jbrowse/mobx-state-tree": "^6.
|
|
24
|
+
"@jbrowse/mobx-state-tree": "^6.10.0",
|
|
25
25
|
"@mui/icons-material": "^9.5.0",
|
|
26
26
|
"@mui/material": "^9.5.0",
|
|
27
|
-
"mobx": "^7.
|
|
28
|
-
"mobx-react": "^10.0.
|
|
29
|
-
"@jbrowse/core": "^5.0.0-beta.
|
|
30
|
-
"@jbrowse/display-
|
|
31
|
-
"@jbrowse/
|
|
32
|
-
"@jbrowse/display-
|
|
27
|
+
"mobx": "^7.1.3",
|
|
28
|
+
"mobx-react": "^10.0.3",
|
|
29
|
+
"@jbrowse/core": "^5.0.0-beta.19",
|
|
30
|
+
"@jbrowse/display-kit": "^5.0.0-beta.19",
|
|
31
|
+
"@jbrowse/launch-args": "^5.0.0-beta.19",
|
|
32
|
+
"@jbrowse/display-ui": "^5.0.0-beta.19",
|
|
33
|
+
"@jbrowse/render-core": "^5.0.0-beta.19"
|
|
33
34
|
},
|
|
34
35
|
"peerDependencies": {
|
|
35
36
|
"react": ">=19.0.0",
|
|
@@ -40,7 +41,7 @@
|
|
|
40
41
|
},
|
|
41
42
|
"sideEffects": false,
|
|
42
43
|
"devDependencies": {
|
|
43
|
-
"@jbrowse/display-test-utils": "^5.0.0-beta.
|
|
44
|
+
"@jbrowse/display-test-utils": "^5.0.0-beta.19"
|
|
44
45
|
},
|
|
45
46
|
"scripts": {
|
|
46
47
|
"prebuild": "pnpm clean",
|