@jbrowse/plugin-data-management 2.9.0 → 2.10.1
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/AddTrackWidget/components/DefaultAddTrackWorkflow.js +4 -8
- package/dist/HierarchicalTrackSelectorWidget/components/faceted/FacetFilter.d.ts +1 -2
- package/dist/HierarchicalTrackSelectorWidget/components/faceted/FacetFilter.js +6 -5
- package/dist/HierarchicalTrackSelectorWidget/components/faceted/FacetFilters.d.ts +3 -3
- package/dist/HierarchicalTrackSelectorWidget/components/faceted/FacetFilters.js +7 -7
- package/dist/HierarchicalTrackSelectorWidget/components/faceted/FacetedSelector.js +3 -9
- package/dist/HierarchicalTrackSelectorWidget/components/faceted/util.d.ts +6 -0
- package/dist/HierarchicalTrackSelectorWidget/components/faceted/util.js +10 -0
- package/dist/HierarchicalTrackSelectorWidget/components/tree/DropdownTrackSelector.js +3 -1
- package/dist/HierarchicalTrackSelectorWidget/components/tree/FavoriteTracks.js +5 -2
- package/dist/HierarchicalTrackSelectorWidget/facetedModel.d.ts +2 -2
- package/dist/HierarchicalTrackSelectorWidget/facetedModel.js +3 -7
- package/dist/HierarchicalTrackSelectorWidget/model.d.ts +43 -40
- package/dist/HierarchicalTrackSelectorWidget/model.js +71 -32
- package/esm/AddTrackWidget/components/DefaultAddTrackWorkflow.js +4 -8
- package/esm/HierarchicalTrackSelectorWidget/components/faceted/FacetFilter.d.ts +1 -2
- package/esm/HierarchicalTrackSelectorWidget/components/faceted/FacetFilter.js +6 -5
- package/esm/HierarchicalTrackSelectorWidget/components/faceted/FacetFilters.d.ts +3 -3
- package/esm/HierarchicalTrackSelectorWidget/components/faceted/FacetFilters.js +7 -7
- package/esm/HierarchicalTrackSelectorWidget/components/faceted/FacetedSelector.js +3 -9
- package/esm/HierarchicalTrackSelectorWidget/components/faceted/util.d.ts +6 -0
- package/esm/HierarchicalTrackSelectorWidget/components/faceted/util.js +6 -0
- package/esm/HierarchicalTrackSelectorWidget/components/tree/DropdownTrackSelector.js +3 -1
- package/esm/HierarchicalTrackSelectorWidget/components/tree/FavoriteTracks.js +5 -2
- package/esm/HierarchicalTrackSelectorWidget/facetedModel.d.ts +2 -2
- package/esm/HierarchicalTrackSelectorWidget/facetedModel.js +3 -7
- package/esm/HierarchicalTrackSelectorWidget/model.d.ts +43 -40
- package/esm/HierarchicalTrackSelectorWidget/model.js +71 -32
- package/package.json +2 -3
|
@@ -94,9 +94,6 @@ const DefaultAddTrackWorkflow = observer(function ({ model, }) {
|
|
|
94
94
|
};
|
|
95
95
|
jobsManager.queueJob(newEntry);
|
|
96
96
|
}
|
|
97
|
-
else {
|
|
98
|
-
session.notify('Open a new view, or use the track selector in an existing view, to view this track', 'info');
|
|
99
|
-
}
|
|
100
97
|
model.clearData();
|
|
101
98
|
if (isSessionModelWithWidgets(session)) {
|
|
102
99
|
session.hideWidget(model);
|
|
@@ -106,10 +103,6 @@ const DefaultAddTrackWorkflow = observer(function ({ model, }) {
|
|
|
106
103
|
setTrackErrorMessage('Failed to add track.\nThe configuration of this file is not currently supported.');
|
|
107
104
|
}
|
|
108
105
|
}
|
|
109
|
-
function handleBack() {
|
|
110
|
-
setTrackErrorMessage(undefined);
|
|
111
|
-
setActiveStep(activeStep - 1);
|
|
112
|
-
}
|
|
113
106
|
function isNextDisabled() {
|
|
114
107
|
switch (activeStep) {
|
|
115
108
|
case 0:
|
|
@@ -126,7 +119,10 @@ const DefaultAddTrackWorkflow = observer(function ({ model, }) {
|
|
|
126
119
|
React.createElement(StepContent, null,
|
|
127
120
|
getStepContent(idx),
|
|
128
121
|
React.createElement("div", { className: classes.actionsContainer },
|
|
129
|
-
React.createElement(Button, { disabled: activeStep === 0, onClick:
|
|
122
|
+
React.createElement(Button, { disabled: activeStep === 0, onClick: () => {
|
|
123
|
+
setTrackErrorMessage(undefined);
|
|
124
|
+
setActiveStep(activeStep - 1);
|
|
125
|
+
}, className: classes.button }, "Back"),
|
|
130
126
|
React.createElement(Button, { disabled: isNextDisabled(), variant: "contained", color: "primary", onClick: handleNext, className: classes.button, "data-testid": "addTrackNextButton" }, activeStep === steps.length - 1 ? 'Add' : 'Next')),
|
|
131
127
|
trackErrorMessage ? (React.createElement("div", { className: classes.alertContainer },
|
|
132
128
|
React.createElement(Alert, { severity: "error" }, trackErrorMessage))) : null)))))));
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { HierarchicalTrackSelectorModel } from '../../model';
|
|
3
|
-
declare const FacetFilter: ({ column, vals,
|
|
3
|
+
declare const FacetFilter: ({ column, vals, model, }: {
|
|
4
4
|
column: {
|
|
5
5
|
field: string;
|
|
6
6
|
};
|
|
7
7
|
vals: [string, number][];
|
|
8
|
-
width: number;
|
|
9
8
|
model: HierarchicalTrackSelectorModel;
|
|
10
9
|
}) => React.JSX.Element;
|
|
11
10
|
export default FacetFilter;
|
|
@@ -25,15 +25,16 @@ function ExpandButton({ visible, onClick, }) {
|
|
|
25
25
|
return (React.createElement(Tooltip, { title: "Minimize/expand this facet filter" },
|
|
26
26
|
React.createElement(IconButton, { onClick: () => onClick(), size: "small" }, visible ? React.createElement(MinimizeIcon, null) : React.createElement(AddIcon, null))));
|
|
27
27
|
}
|
|
28
|
-
const FacetFilter = observer(function ({ column, vals,
|
|
28
|
+
const FacetFilter = observer(function ({ column, vals, model, }) {
|
|
29
29
|
const { classes } = useStyles();
|
|
30
30
|
const [visible, setVisible] = useState(true);
|
|
31
31
|
const { faceted } = model;
|
|
32
32
|
const { filters } = faceted;
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
React.createElement(
|
|
33
|
+
const { field } = column;
|
|
34
|
+
return (React.createElement(FormControl, { className: classes.facet, fullWidth: true },
|
|
35
|
+
React.createElement("div", null,
|
|
36
|
+
React.createElement(Typography, { component: "span" }, field),
|
|
37
|
+
React.createElement(ClearButton, { onClick: () => faceted.setFilter(field, []) }),
|
|
37
38
|
React.createElement(ExpandButton, { visible: visible, onClick: () => setVisible(!visible) })),
|
|
38
39
|
visible ? (React.createElement(Select, { multiple: true, native: true, className: classes.select, value: filters.get(column.field) || [], onChange: event => {
|
|
39
40
|
faceted.setFilter(column.field,
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { HierarchicalTrackSelectorModel } from '../../model';
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
import { Row } from './util';
|
|
4
|
+
declare const FacetFilters: ({ rows, columns, model, }: {
|
|
5
|
+
rows: Row[];
|
|
5
6
|
columns: {
|
|
6
7
|
field: string;
|
|
7
8
|
}[];
|
|
8
|
-
width: number;
|
|
9
9
|
model: HierarchicalTrackSelectorModel;
|
|
10
10
|
}) => React.JSX.Element;
|
|
11
11
|
export default FacetFilters;
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import FacetFilter from './FacetFilter';
|
|
3
2
|
import { observer } from 'mobx-react';
|
|
4
|
-
|
|
3
|
+
// locals
|
|
4
|
+
import FacetFilter from './FacetFilter';
|
|
5
|
+
import { getRowStr } from './util';
|
|
6
|
+
const FacetFilters = observer(function ({ rows, columns, model, }) {
|
|
5
7
|
var _a, _b;
|
|
6
8
|
const { faceted } = model;
|
|
7
9
|
const { filters } = faceted;
|
|
@@ -26,7 +28,7 @@ const FacetFilters = observer(function ({ rows, columns, width, model, }) {
|
|
|
26
28
|
for (const facet of ret) {
|
|
27
29
|
const elt = uniqs.get(facet);
|
|
28
30
|
for (const row of currentRows) {
|
|
29
|
-
const key =
|
|
31
|
+
const key = getRowStr(facet, row);
|
|
30
32
|
const val = elt.get(key);
|
|
31
33
|
// we don't allow filtering on empty yet
|
|
32
34
|
if (key) {
|
|
@@ -41,10 +43,8 @@ const FacetFilters = observer(function ({ rows, columns, width, model, }) {
|
|
|
41
43
|
const filter = ((_b = filters.get(facet)) === null || _b === void 0 ? void 0 : _b.length)
|
|
42
44
|
? new Set(filters.get(facet))
|
|
43
45
|
: undefined;
|
|
44
|
-
currentRows = currentRows.filter(row =>
|
|
45
|
-
return filter !== undefined ? filter.has(row[facet]) : true;
|
|
46
|
-
});
|
|
46
|
+
currentRows = currentRows.filter(row => filter !== undefined ? filter.has(getRowStr(facet, row)) : true);
|
|
47
47
|
}
|
|
48
|
-
return (React.createElement("div", null, facets.map(
|
|
48
|
+
return (React.createElement("div", null, facets.map(c => (React.createElement(FacetFilter, { key: c.field, vals: [...uniqs.get(c.field)], column: c, model: model })))));
|
|
49
49
|
});
|
|
50
50
|
export default FacetFilters;
|
|
@@ -29,11 +29,10 @@ const frac = 0.75;
|
|
|
29
29
|
const FacetedSelector = observer(function FacetedSelector({ model, }) {
|
|
30
30
|
var _a;
|
|
31
31
|
const { classes } = useStyles();
|
|
32
|
-
const { view, selection, faceted } = model;
|
|
32
|
+
const { view, selection, shownTrackIds, faceted } = model;
|
|
33
33
|
const { rows, panelWidth, showFilters, useShoppingCart, showOptions, filteredRows, filteredNonMetadataKeys, filteredMetadataKeys, visible, widths, } = faceted;
|
|
34
34
|
const { pluginManager } = getEnv(model);
|
|
35
35
|
const { ref, scrollLeft } = useResizeBar();
|
|
36
|
-
const tracks = view.tracks;
|
|
37
36
|
const widthsDebounced = useDebounce(widths, 200);
|
|
38
37
|
const columns = [
|
|
39
38
|
{
|
|
@@ -75,7 +74,6 @@ const FacetedSelector = observer(function FacetedSelector({ model, }) {
|
|
|
75
74
|
});
|
|
76
75
|
}),
|
|
77
76
|
];
|
|
78
|
-
const shownTrackIds = new Set(tracks.map(t => t.configuration.trackId));
|
|
79
77
|
return (React.createElement(React.Fragment, null,
|
|
80
78
|
React.createElement(FacetedHeader, { model: model }),
|
|
81
79
|
React.createElement("div", { ref: ref, style: {
|
|
@@ -125,11 +123,7 @@ const FacetedSelector = observer(function FacetedSelector({ model, }) {
|
|
|
125
123
|
}, columns: columns, rowHeight: 25 })),
|
|
126
124
|
showFilters ? (React.createElement(React.Fragment, null,
|
|
127
125
|
React.createElement(ResizeHandle, { vertical: true, onDrag: dist => faceted.setPanelWidth(panelWidth - dist), className: classes.resizeHandle }),
|
|
128
|
-
React.createElement("div", { style: {
|
|
129
|
-
|
|
130
|
-
overflowY: 'auto',
|
|
131
|
-
overflowX: 'hidden',
|
|
132
|
-
} },
|
|
133
|
-
React.createElement(FacetFilters, { model: model, width: panelWidth - 10, rows: rows, columns: columns })))) : null)));
|
|
126
|
+
React.createElement("div", { style: { width: panelWidth, overflow: 'auto' } },
|
|
127
|
+
React.createElement(FacetFilters, { model: model, rows: rows, columns: columns })))) : null)));
|
|
134
128
|
});
|
|
135
129
|
export default FacetedSelector;
|
|
@@ -19,7 +19,9 @@ const DropdownTrackSelector = observer(function ({ model, tracks, extraMenuItems
|
|
|
19
19
|
checked: view.tracks.some((f) => f.configuration === t),
|
|
20
20
|
onClick: () => {
|
|
21
21
|
if (!open) {
|
|
22
|
-
model.view.toggleTrack(t.trackId)
|
|
22
|
+
if (model.view.toggleTrack(t.trackId)) {
|
|
23
|
+
model.addToRecentlyUsed(t.trackId);
|
|
24
|
+
}
|
|
23
25
|
}
|
|
24
26
|
},
|
|
25
27
|
})),
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { Badge, Tooltip } from '@mui/material';
|
|
3
3
|
import { observer } from 'mobx-react';
|
|
4
|
+
import { makeStyles } from 'tss-react/mui';
|
|
4
5
|
// icons
|
|
5
6
|
import GradeIcon from '@mui/icons-material/Grade';
|
|
6
7
|
import DropdownTrackSelector from './DropdownTrackSelector';
|
|
7
|
-
import { makeStyles } from 'tss-react/mui';
|
|
8
8
|
const useStyles = makeStyles()({
|
|
9
9
|
smallBadge: {
|
|
10
10
|
height: 14,
|
|
11
11
|
},
|
|
12
|
+
margin: {
|
|
13
|
+
marginRight: 10,
|
|
14
|
+
},
|
|
12
15
|
});
|
|
13
16
|
const FavoriteTracks = observer(function ({ model, }) {
|
|
14
17
|
const { classes } = useStyles();
|
|
@@ -31,7 +34,7 @@ const FavoriteTracks = observer(function ({ model, }) {
|
|
|
31
34
|
React.createElement(Badge, { classes: { badge: classes.smallBadge }, color: "secondary", anchorOrigin: {
|
|
32
35
|
vertical: 'bottom',
|
|
33
36
|
horizontal: 'right',
|
|
34
|
-
},
|
|
37
|
+
}, className: classes.margin, badgeContent: model.favoritesCounter },
|
|
35
38
|
React.createElement(GradeIcon, null))))) : null;
|
|
36
39
|
});
|
|
37
40
|
export default FavoriteTracks;
|
|
@@ -81,7 +81,7 @@ export declare function facetedStateTreeF(): import("mobx-state-tree").IModelTyp
|
|
|
81
81
|
readonly category: string;
|
|
82
82
|
readonly adapter: string;
|
|
83
83
|
readonly description: string;
|
|
84
|
-
readonly metadata:
|
|
84
|
+
readonly metadata: Record<string, unknown>;
|
|
85
85
|
}[];
|
|
86
86
|
} & {
|
|
87
87
|
/**
|
|
@@ -111,7 +111,7 @@ export declare function facetedStateTreeF(): import("mobx-state-tree").IModelTyp
|
|
|
111
111
|
readonly category: string;
|
|
112
112
|
readonly adapter: string;
|
|
113
113
|
readonly description: string;
|
|
114
|
-
readonly metadata:
|
|
114
|
+
readonly metadata: Record<string, unknown>;
|
|
115
115
|
}[];
|
|
116
116
|
} & {
|
|
117
117
|
/**
|
|
@@ -5,6 +5,7 @@ import { getTrackName } from '@jbrowse/core/util/tracks';
|
|
|
5
5
|
import { getSession, localStorageGetItem, measureGridWidth, } from '@jbrowse/core/util';
|
|
6
6
|
import { autorun, observable } from 'mobx';
|
|
7
7
|
import { getRootKeys, findNonSparseKeys } from './facetedUtil';
|
|
8
|
+
import { getRowStr } from './components/faceted/util';
|
|
8
9
|
const nonMetadataKeys = ['category', 'adapter', 'description'];
|
|
9
10
|
/**
|
|
10
11
|
* #stateModel FacetedModel
|
|
@@ -98,13 +99,10 @@ export function facetedStateTreeF() {
|
|
|
98
99
|
get rows() {
|
|
99
100
|
const session = getSession(self);
|
|
100
101
|
const { allTrackConfigurations, filterText } = self;
|
|
101
|
-
// metadata is spread onto the object for easier access and sorting
|
|
102
|
-
// by the mui data grid (it's unable to sort by nested objects)
|
|
103
102
|
return allTrackConfigurations
|
|
104
103
|
.filter(conf => matches(filterText, conf, session))
|
|
105
104
|
.map(track => {
|
|
106
105
|
var _a, _b;
|
|
107
|
-
const metadata = readConfObject(track, 'metadata');
|
|
108
106
|
return {
|
|
109
107
|
id: track.trackId,
|
|
110
108
|
conf: track,
|
|
@@ -112,7 +110,7 @@ export function facetedStateTreeF() {
|
|
|
112
110
|
category: (_a = readConfObject(track, 'category')) === null || _a === void 0 ? void 0 : _a.join(', '),
|
|
113
111
|
adapter: (_b = readConfObject(track, 'adapter')) === null || _b === void 0 ? void 0 : _b.type,
|
|
114
112
|
description: readConfObject(track, 'description'),
|
|
115
|
-
metadata,
|
|
113
|
+
metadata: readConfObject(track, 'metadata'),
|
|
116
114
|
};
|
|
117
115
|
});
|
|
118
116
|
},
|
|
@@ -156,9 +154,7 @@ export function facetedStateTreeF() {
|
|
|
156
154
|
const arrFilters = [...self.filters.entries()]
|
|
157
155
|
.filter(f => f[1].length > 0)
|
|
158
156
|
.map(([key, val]) => [key, new Set(val)]);
|
|
159
|
-
return self.rows.filter(row =>
|
|
160
|
-
// @ts-expect-error
|
|
161
|
-
arrFilters.every(([key, val]) => val.has(row[key])));
|
|
157
|
+
return self.rows.filter(row => arrFilters.every(([key, val]) => val.has(getRowStr(key, row))));
|
|
162
158
|
},
|
|
163
159
|
}))
|
|
164
160
|
.actions(self => ({
|
|
@@ -34,18 +34,6 @@ export default function stateTreeFactory(pluginManager: PluginManager): import("
|
|
|
34
34
|
* #property
|
|
35
35
|
*/
|
|
36
36
|
view: import("mobx-state-tree").IMaybe<import("mobx-state-tree").IReferenceType<import("mobx-state-tree").IAnyType>>;
|
|
37
|
-
/**
|
|
38
|
-
* #property
|
|
39
|
-
* this is removed in postProcessSnapshot, so is generally only loaded
|
|
40
|
-
* from localstorage
|
|
41
|
-
*/
|
|
42
|
-
favorites: import("mobx-state-tree").IOptionalIType<import("mobx-state-tree").IArrayType<import("mobx-state-tree").ISimpleType<string>>, [undefined]>;
|
|
43
|
-
/**
|
|
44
|
-
* #property
|
|
45
|
-
* this is removed in postProcessSnapshot, so is generally only loaded
|
|
46
|
-
* from localstorage
|
|
47
|
-
*/
|
|
48
|
-
recentlyUsed: import("mobx-state-tree").IOptionalIType<import("mobx-state-tree").IArrayType<import("mobx-state-tree").ISimpleType<string>>, [undefined]>;
|
|
49
37
|
/**
|
|
50
38
|
* #property
|
|
51
39
|
*/
|
|
@@ -56,13 +44,14 @@ export default function stateTreeFactory(pluginManager: PluginManager): import("
|
|
|
56
44
|
showOptions: import("mobx-state-tree").IOptionalIType<import("mobx-state-tree").ISimpleType<boolean>, [undefined]>;
|
|
57
45
|
panelWidth: import("mobx-state-tree").IOptionalIType<import("mobx-state-tree").ISimpleType<number>, [undefined]>;
|
|
58
46
|
}, {
|
|
59
|
-
|
|
47
|
+
visible: Record<string, boolean>;
|
|
48
|
+
widths: Record<string, number | undefined>; /**
|
|
60
49
|
* #property
|
|
61
50
|
*/
|
|
62
|
-
visible: Record<string, boolean>;
|
|
63
|
-
widths: Record<string, number | undefined>;
|
|
64
51
|
useShoppingCart: boolean;
|
|
65
|
-
filters: import("mobx").ObservableMap<string, string[]>;
|
|
52
|
+
filters: import("mobx").ObservableMap<string, string[]>; /**
|
|
53
|
+
* #property
|
|
54
|
+
*/
|
|
66
55
|
} & {
|
|
67
56
|
setFilter(key: string, value: string[]): void;
|
|
68
57
|
setPanelWidth(width: number): void;
|
|
@@ -86,12 +75,10 @@ export default function stateTreeFactory(pluginManager: PluginManager): import("
|
|
|
86
75
|
setSubschema(slotName: string, data: unknown): any;
|
|
87
76
|
} & import("mobx-state-tree").IStateTreeNode<import("@jbrowse/core/configuration").AnyConfigurationSchemaType>;
|
|
88
77
|
readonly name: string;
|
|
89
|
-
readonly category: string;
|
|
90
|
-
* #action
|
|
91
|
-
*/
|
|
78
|
+
readonly category: string;
|
|
92
79
|
readonly adapter: string;
|
|
93
80
|
readonly description: string;
|
|
94
|
-
readonly metadata:
|
|
81
|
+
readonly metadata: Record<string, unknown>;
|
|
95
82
|
}[];
|
|
96
83
|
} & {
|
|
97
84
|
readonly filteredNonMetadataKeys: string[] | readonly ["category", "adapter", "description"];
|
|
@@ -106,12 +93,10 @@ export default function stateTreeFactory(pluginManager: PluginManager): import("
|
|
|
106
93
|
setSubschema(slotName: string, data: unknown): any;
|
|
107
94
|
} & import("mobx-state-tree").IStateTreeNode<import("@jbrowse/core/configuration").AnyConfigurationSchemaType>;
|
|
108
95
|
readonly name: string;
|
|
109
|
-
readonly category: string;
|
|
110
|
-
* #action
|
|
111
|
-
*/
|
|
96
|
+
readonly category: string;
|
|
112
97
|
readonly adapter: string;
|
|
113
98
|
readonly description: string;
|
|
114
|
-
readonly metadata:
|
|
99
|
+
readonly metadata: Record<string, unknown>;
|
|
115
100
|
}[];
|
|
116
101
|
} & {
|
|
117
102
|
setVisible(args: Record<string, boolean>): void;
|
|
@@ -119,6 +104,8 @@ export default function stateTreeFactory(pluginManager: PluginManager): import("
|
|
|
119
104
|
afterAttach(): void;
|
|
120
105
|
}, import("mobx-state-tree")._NotCustomized, import("mobx-state-tree")._NotCustomized>, [undefined]>;
|
|
121
106
|
}, {
|
|
107
|
+
favorites: string[];
|
|
108
|
+
recentlyUsed: string[];
|
|
122
109
|
selection: ({
|
|
123
110
|
[x: string]: any;
|
|
124
111
|
} & import("mobx-state-tree/dist/internal").NonEmptyObject & {
|
|
@@ -128,6 +115,10 @@ export default function stateTreeFactory(pluginManager: PluginManager): import("
|
|
|
128
115
|
recentlyUsedCounter: number;
|
|
129
116
|
favoritesCounter: number;
|
|
130
117
|
} & {
|
|
118
|
+
/**
|
|
119
|
+
* #getter
|
|
120
|
+
*/
|
|
121
|
+
readonly shownTrackIds: Set<string>;
|
|
131
122
|
/**
|
|
132
123
|
* #getter
|
|
133
124
|
*/
|
|
@@ -185,6 +176,14 @@ export default function stateTreeFactory(pluginManager: PluginManager): import("
|
|
|
185
176
|
* #action
|
|
186
177
|
*/
|
|
187
178
|
setRecentlyUsedCounter(val: number): void;
|
|
179
|
+
/**
|
|
180
|
+
* #action
|
|
181
|
+
*/
|
|
182
|
+
setRecentlyUsed(str: string[]): void;
|
|
183
|
+
/**
|
|
184
|
+
* #action
|
|
185
|
+
*/
|
|
186
|
+
setFavorites(str: string[]): void;
|
|
188
187
|
/**
|
|
189
188
|
* #action
|
|
190
189
|
*/
|
|
@@ -244,6 +243,14 @@ export default function stateTreeFactory(pluginManager: PluginManager): import("
|
|
|
244
243
|
*/
|
|
245
244
|
readonly assemblyNames: string[];
|
|
246
245
|
} & {
|
|
246
|
+
/**
|
|
247
|
+
* #getter
|
|
248
|
+
*/
|
|
249
|
+
readonly recentlyUsedLocalStorageKey: string;
|
|
250
|
+
/**
|
|
251
|
+
* #getter
|
|
252
|
+
*/
|
|
253
|
+
readonly favoritesLocalStorageKey: string;
|
|
247
254
|
/**
|
|
248
255
|
* #getter
|
|
249
256
|
*/
|
|
@@ -261,11 +268,22 @@ export default function stateTreeFactory(pluginManager: PluginManager): import("
|
|
|
261
268
|
} & import("mobx-state-tree/dist/internal").NonEmptyObject & {
|
|
262
269
|
setSubschema(slotName: string, data: unknown): any;
|
|
263
270
|
} & import("mobx-state-tree").IStateTreeNode<import("@jbrowse/core/configuration").AnyConfigurationSchemaType>)[];
|
|
271
|
+
/**
|
|
272
|
+
* #getter
|
|
273
|
+
*/
|
|
264
274
|
readonly allTrackConfigurations: ({
|
|
265
275
|
[x: string]: any;
|
|
266
276
|
} & import("mobx-state-tree/dist/internal").NonEmptyObject & {
|
|
267
277
|
setSubschema(slotName: string, data: unknown): any;
|
|
268
278
|
} & import("mobx-state-tree").IStateTreeNode<import("@jbrowse/core/configuration").AnyConfigurationSchemaType>)[];
|
|
279
|
+
/**
|
|
280
|
+
* #getter
|
|
281
|
+
*/
|
|
282
|
+
readonly allTrackConfigurationTrackIdSet: Map<any, {
|
|
283
|
+
[x: string]: any;
|
|
284
|
+
} & import("mobx-state-tree/dist/internal").NonEmptyObject & {
|
|
285
|
+
setSubschema(slotName: string, data: unknown): any;
|
|
286
|
+
} & import("mobx-state-tree").IStateTreeNode<import("@jbrowse/core/configuration").AnyConfigurationSchemaType>>;
|
|
269
287
|
} & {
|
|
270
288
|
/**
|
|
271
289
|
* #getter
|
|
@@ -335,22 +353,7 @@ export default function stateTreeFactory(pluginManager: PluginManager): import("
|
|
|
335
353
|
readonly hasAnySubcategories: boolean;
|
|
336
354
|
} & {
|
|
337
355
|
afterAttach(): void;
|
|
338
|
-
}, import("mobx-state-tree")._NotCustomized,
|
|
339
|
-
type: "HierarchicalTrackSelectorWidget";
|
|
340
|
-
view: import("mobx-state-tree").ReferenceIdentifier | undefined;
|
|
341
|
-
id: string;
|
|
342
|
-
collapsed: import("mobx").IKeyValueMap<boolean>;
|
|
343
|
-
initialized: boolean | undefined;
|
|
344
|
-
sortTrackNames: boolean | undefined;
|
|
345
|
-
sortCategories: boolean | undefined;
|
|
346
|
-
faceted: import("mobx-state-tree").ModelSnapshotType<{
|
|
347
|
-
filterText: import("mobx-state-tree").IOptionalIType<import("mobx-state-tree").ISimpleType<string>, [undefined]>;
|
|
348
|
-
showSparse: import("mobx-state-tree").IOptionalIType<import("mobx-state-tree").ISimpleType<boolean>, [undefined]>;
|
|
349
|
-
showFilters: import("mobx-state-tree").IOptionalIType<import("mobx-state-tree").ISimpleType<boolean>, [undefined]>;
|
|
350
|
-
showOptions: import("mobx-state-tree").IOptionalIType<import("mobx-state-tree").ISimpleType<boolean>, [undefined]>;
|
|
351
|
-
panelWidth: import("mobx-state-tree").IOptionalIType<import("mobx-state-tree").ISimpleType<number>, [undefined]>;
|
|
352
|
-
}>;
|
|
353
|
-
}>;
|
|
356
|
+
}, import("mobx-state-tree")._NotCustomized, import("mobx-state-tree")._NotCustomized>;
|
|
354
357
|
export type HierarchicalTrackSelectorStateModel = ReturnType<typeof stateTreeFactory>;
|
|
355
358
|
export type HierarchicalTrackSelectorModel = Instance<HierarchicalTrackSelectorStateModel>;
|
|
356
359
|
export {};
|
|
@@ -23,8 +23,7 @@ function postF() {
|
|
|
23
23
|
].join('-')
|
|
24
24
|
: 'empty';
|
|
25
25
|
}
|
|
26
|
-
const
|
|
27
|
-
const lsKeyRecentlyUsedF = () => `recentlyUsedTracks-${postF()}}`;
|
|
26
|
+
const MAX_RECENTLY_USED = 10;
|
|
28
27
|
/**
|
|
29
28
|
* #stateModel HierarchicalTrackSelectorWidget
|
|
30
29
|
*/
|
|
@@ -59,30 +58,27 @@ export default function stateTreeFactory(pluginManager) {
|
|
|
59
58
|
* #property
|
|
60
59
|
*/
|
|
61
60
|
view: types.safeReference(pluginManager.pluggableMstType('view', 'stateModel')),
|
|
62
|
-
/**
|
|
63
|
-
* #property
|
|
64
|
-
* this is removed in postProcessSnapshot, so is generally only loaded
|
|
65
|
-
* from localstorage
|
|
66
|
-
*/
|
|
67
|
-
favorites: types.optional(types.array(types.string), () => JSON.parse(localStorageGetItem(lsKeyFavoritesF()) || '[]')),
|
|
68
|
-
/**
|
|
69
|
-
* #property
|
|
70
|
-
* this is removed in postProcessSnapshot, so is generally only loaded
|
|
71
|
-
* from localstorage
|
|
72
|
-
*/
|
|
73
|
-
recentlyUsed: types.optional(types.array(types.string), () => JSON.parse(localStorageGetItem(lsKeyRecentlyUsedF()) || '[]')),
|
|
74
61
|
/**
|
|
75
62
|
* #property
|
|
76
63
|
*/
|
|
77
64
|
faceted: types.optional(facetedStateTreeF(), {}),
|
|
78
65
|
})
|
|
79
66
|
.volatile(() => ({
|
|
67
|
+
favorites: [],
|
|
68
|
+
recentlyUsed: [],
|
|
80
69
|
selection: [],
|
|
81
70
|
filterText: '',
|
|
82
71
|
recentlyUsedCounter: 0,
|
|
83
72
|
favoritesCounter: 0,
|
|
84
73
|
}))
|
|
85
74
|
.views(self => ({
|
|
75
|
+
/**
|
|
76
|
+
* #getter
|
|
77
|
+
*/
|
|
78
|
+
get shownTrackIds() {
|
|
79
|
+
var _a, _b;
|
|
80
|
+
return new Set((_b = (_a = self.view) === null || _a === void 0 ? void 0 : _a.tracks) === null || _b === void 0 ? void 0 : _b.map((t) => t.configuration.trackId));
|
|
81
|
+
},
|
|
86
82
|
/**
|
|
87
83
|
* #getter
|
|
88
84
|
*/
|
|
@@ -145,19 +141,19 @@ export default function stateTreeFactory(pluginManager) {
|
|
|
145
141
|
*/
|
|
146
142
|
addToFavorites(trackId) {
|
|
147
143
|
self.favoritesCounter += 1;
|
|
148
|
-
self.favorites.
|
|
144
|
+
self.favorites = [...self.favorites, trackId];
|
|
149
145
|
},
|
|
150
146
|
/**
|
|
151
147
|
* #action
|
|
152
148
|
*/
|
|
153
149
|
removeFromFavorites(trackId) {
|
|
154
|
-
self.favorites.
|
|
150
|
+
self.favorites = self.favorites.filter(f => f !== trackId);
|
|
155
151
|
},
|
|
156
152
|
/**
|
|
157
153
|
* #action
|
|
158
154
|
*/
|
|
159
155
|
clearFavorites() {
|
|
160
|
-
self.favorites
|
|
156
|
+
self.favorites = [];
|
|
161
157
|
},
|
|
162
158
|
/**
|
|
163
159
|
* #action
|
|
@@ -165,6 +161,18 @@ export default function stateTreeFactory(pluginManager) {
|
|
|
165
161
|
setRecentlyUsedCounter(val) {
|
|
166
162
|
self.recentlyUsedCounter = val;
|
|
167
163
|
},
|
|
164
|
+
/**
|
|
165
|
+
* #action
|
|
166
|
+
*/
|
|
167
|
+
setRecentlyUsed(str) {
|
|
168
|
+
self.recentlyUsed = str;
|
|
169
|
+
},
|
|
170
|
+
/**
|
|
171
|
+
* #action
|
|
172
|
+
*/
|
|
173
|
+
setFavorites(str) {
|
|
174
|
+
self.favorites = str;
|
|
175
|
+
},
|
|
168
176
|
/**
|
|
169
177
|
* #action
|
|
170
178
|
*/
|
|
@@ -175,19 +183,19 @@ export default function stateTreeFactory(pluginManager) {
|
|
|
175
183
|
* #action
|
|
176
184
|
*/
|
|
177
185
|
addToRecentlyUsed(id) {
|
|
178
|
-
self.recentlyUsedCounter += 1;
|
|
179
186
|
if (!self.recentlyUsed.includes(id)) {
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
187
|
+
self.recentlyUsedCounter = Math.min(self.recentlyUsedCounter + 1, MAX_RECENTLY_USED);
|
|
188
|
+
self.recentlyUsed =
|
|
189
|
+
self.recentlyUsed.length >= MAX_RECENTLY_USED
|
|
190
|
+
? [...self.recentlyUsed.slice(1), id]
|
|
191
|
+
: [...self.recentlyUsed, id];
|
|
184
192
|
}
|
|
185
193
|
},
|
|
186
194
|
/**
|
|
187
195
|
* #action
|
|
188
196
|
*/
|
|
189
197
|
clearRecentlyUsed() {
|
|
190
|
-
self.recentlyUsed
|
|
198
|
+
self.recentlyUsed = [];
|
|
191
199
|
},
|
|
192
200
|
/**
|
|
193
201
|
* #action
|
|
@@ -274,6 +282,22 @@ export default function stateTreeFactory(pluginManager) {
|
|
|
274
282
|
},
|
|
275
283
|
}))
|
|
276
284
|
.views(self => ({
|
|
285
|
+
/**
|
|
286
|
+
* #getter
|
|
287
|
+
*/
|
|
288
|
+
get recentlyUsedLocalStorageKey() {
|
|
289
|
+
return `recentlyUsedTracks-${[postF(), self.assemblyNames.join(',')]
|
|
290
|
+
.filter(f => !!f)
|
|
291
|
+
.join('-')}`;
|
|
292
|
+
},
|
|
293
|
+
/**
|
|
294
|
+
* #getter
|
|
295
|
+
*/
|
|
296
|
+
get favoritesLocalStorageKey() {
|
|
297
|
+
// this has a extra } at the end because that's how it was initially
|
|
298
|
+
// released
|
|
299
|
+
return `favoriteTracks-${postF()}}`;
|
|
300
|
+
},
|
|
277
301
|
/**
|
|
278
302
|
* #getter
|
|
279
303
|
*/
|
|
@@ -298,6 +322,9 @@ export default function stateTreeFactory(pluginManager) {
|
|
|
298
322
|
...filterTracks(getSession(self).tracks, self),
|
|
299
323
|
].filter(notEmpty);
|
|
300
324
|
},
|
|
325
|
+
/**
|
|
326
|
+
* #getter
|
|
327
|
+
*/
|
|
301
328
|
get allTrackConfigurations() {
|
|
302
329
|
const { connectionInstances = [] } = getSession(self);
|
|
303
330
|
return [
|
|
@@ -305,6 +332,12 @@ export default function stateTreeFactory(pluginManager) {
|
|
|
305
332
|
...connectionInstances === null || connectionInstances === void 0 ? void 0 : connectionInstances.flatMap(c => c.tracks),
|
|
306
333
|
];
|
|
307
334
|
},
|
|
335
|
+
/**
|
|
336
|
+
* #getter
|
|
337
|
+
*/
|
|
338
|
+
get allTrackConfigurationTrackIdSet() {
|
|
339
|
+
return new Map(this.allTrackConfigurations.map(t => [t.trackId, t]));
|
|
340
|
+
},
|
|
308
341
|
}))
|
|
309
342
|
.views(self => ({
|
|
310
343
|
/**
|
|
@@ -312,14 +345,18 @@ export default function stateTreeFactory(pluginManager) {
|
|
|
312
345
|
* filters out tracks that are not in the favorites group
|
|
313
346
|
*/
|
|
314
347
|
get favoriteTracks() {
|
|
315
|
-
return self.
|
|
348
|
+
return self.favorites
|
|
349
|
+
.filter(t => self.allTrackConfigurationTrackIdSet.has(t))
|
|
350
|
+
.map(t => self.allTrackConfigurationTrackIdSet.get(t));
|
|
316
351
|
},
|
|
317
352
|
/**
|
|
318
353
|
* #getter
|
|
319
354
|
* filters out tracks that are not in the recently used group
|
|
320
355
|
*/
|
|
321
356
|
get recentlyUsedTracks() {
|
|
322
|
-
return self.
|
|
357
|
+
return self.recentlyUsed
|
|
358
|
+
.filter(t => self.allTrackConfigurationTrackIdSet.has(t))
|
|
359
|
+
.map(t => self.allTrackConfigurationTrackIdSet.get(t));
|
|
323
360
|
},
|
|
324
361
|
}))
|
|
325
362
|
.views(self => ({
|
|
@@ -435,14 +472,16 @@ export default function stateTreeFactory(pluginManager) {
|
|
|
435
472
|
}))
|
|
436
473
|
.actions(self => ({
|
|
437
474
|
afterAttach() {
|
|
475
|
+
// this should be the first autorun to properly initialize
|
|
476
|
+
addDisposer(self, autorun(() => {
|
|
477
|
+
self.setRecentlyUsed(JSON.parse(localStorageGetItem(self.recentlyUsedLocalStorageKey) || '[]'));
|
|
478
|
+
self.setFavorites(JSON.parse(localStorageGetItem(self.favoritesLocalStorageKey) || '[]'));
|
|
479
|
+
}));
|
|
480
|
+
// this should be the second autorun
|
|
438
481
|
addDisposer(self, autorun(() => {
|
|
439
|
-
localStorageSetItem(
|
|
440
|
-
localStorageSetItem(
|
|
482
|
+
localStorageSetItem(self.favoritesLocalStorageKey, JSON.stringify(self.favorites));
|
|
483
|
+
localStorageSetItem(self.recentlyUsedLocalStorageKey, JSON.stringify(self.recentlyUsed));
|
|
441
484
|
}));
|
|
442
485
|
},
|
|
443
|
-
}))
|
|
444
|
-
.postProcessSnapshot(snap => {
|
|
445
|
-
const { favorites: _, recentlyUsed: __, ...rest } = snap;
|
|
446
|
-
return rest;
|
|
447
|
-
});
|
|
486
|
+
}));
|
|
448
487
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jbrowse/plugin-data-management",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.10.1",
|
|
4
4
|
"description": "JBrowse 2 linear genome view",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"jbrowse",
|
|
@@ -39,7 +39,6 @@
|
|
|
39
39
|
"@gmod/ucsc-hub": "^0.3.0",
|
|
40
40
|
"@mui/icons-material": "^5.0.1",
|
|
41
41
|
"@mui/x-data-grid": "^6.0.1",
|
|
42
|
-
"clsx": "^2.0.0",
|
|
43
42
|
"react-virtualized-auto-sizer": "^1.0.2",
|
|
44
43
|
"react-vtree": "^3.0.0-beta.1",
|
|
45
44
|
"react-window": "^1.8.6"
|
|
@@ -61,5 +60,5 @@
|
|
|
61
60
|
"distModule": "esm/index.js",
|
|
62
61
|
"srcModule": "src/index.ts",
|
|
63
62
|
"module": "esm/index.js",
|
|
64
|
-
"gitHead": "
|
|
63
|
+
"gitHead": "442b5f87efddfdf4ccf520b4d9dd01ddd370cb07"
|
|
65
64
|
}
|