@jbrowse/plugin-data-management 2.6.2 → 2.6.3
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/HierarchicalTrackSelectorWidget/components/faceted/FacetedSelector.js +4 -5
- package/dist/HierarchicalTrackSelectorWidget/components/tree/HamburgerMenu.js +35 -19
- package/dist/HierarchicalTrackSelectorWidget/components/tree/HierarchicalHeader.js +10 -6
- package/dist/HierarchicalTrackSelectorWidget/components/tree/HierarchicalTree.d.ts +2 -1
- package/dist/HierarchicalTrackSelectorWidget/components/tree/TrackCategory.js +22 -0
- package/dist/HierarchicalTrackSelectorWidget/components/tree/TrackLabel.js +1 -1
- package/dist/HierarchicalTrackSelectorWidget/components/util.d.ts +2 -1
- package/dist/HierarchicalTrackSelectorWidget/filterTracks.d.ts +12 -0
- package/dist/HierarchicalTrackSelectorWidget/filterTracks.js +32 -0
- package/dist/HierarchicalTrackSelectorWidget/generateHierarchy.d.ts +21 -0
- package/dist/HierarchicalTrackSelectorWidget/generateHierarchy.js +98 -0
- package/dist/HierarchicalTrackSelectorWidget/model.d.ts +68 -28
- package/dist/HierarchicalTrackSelectorWidget/model.js +149 -117
- package/dist/HierarchicalTrackSelectorWidget/util.d.ts +12 -0
- package/dist/HierarchicalTrackSelectorWidget/util.js +53 -0
- package/dist/PluginStoreWidget/components/AddCustomPluginDialog.d.ts +7 -0
- package/dist/PluginStoreWidget/components/{CustomPluginForm.js → AddCustomPluginDialog.js} +12 -21
- package/dist/PluginStoreWidget/components/DeletePluginDialog.d.ts +5 -0
- package/dist/PluginStoreWidget/components/DeletePluginDialog.js +28 -0
- package/dist/PluginStoreWidget/components/InstalledPlugin.d.ts +2 -5
- package/dist/PluginStoreWidget/components/InstalledPlugin.js +19 -50
- package/dist/PluginStoreWidget/components/InstalledPluginsList.d.ts +2 -3
- package/dist/PluginStoreWidget/components/InstalledPluginsList.js +6 -9
- package/dist/PluginStoreWidget/components/PluginCard.js +3 -5
- package/dist/PluginStoreWidget/components/PluginStoreWidget.js +11 -39
- package/dist/PluginStoreWidget/components/util.d.ts +5 -0
- package/dist/PluginStoreWidget/components/util.js +29 -0
- package/dist/PluginStoreWidget/model.d.ts +2 -2
- package/dist/PluginStoreWidget/model.js +2 -2
- package/esm/HierarchicalTrackSelectorWidget/components/faceted/FacetedSelector.js +1 -2
- package/esm/HierarchicalTrackSelectorWidget/components/tree/HamburgerMenu.js +34 -18
- package/esm/HierarchicalTrackSelectorWidget/components/tree/HierarchicalHeader.js +10 -6
- package/esm/HierarchicalTrackSelectorWidget/components/tree/HierarchicalTree.d.ts +2 -1
- package/esm/HierarchicalTrackSelectorWidget/components/tree/TrackCategory.js +22 -0
- package/esm/HierarchicalTrackSelectorWidget/components/tree/TrackLabel.js +1 -1
- package/esm/HierarchicalTrackSelectorWidget/components/util.d.ts +2 -1
- package/esm/HierarchicalTrackSelectorWidget/filterTracks.d.ts +12 -0
- package/esm/HierarchicalTrackSelectorWidget/filterTracks.js +28 -0
- package/esm/HierarchicalTrackSelectorWidget/generateHierarchy.d.ts +21 -0
- package/esm/HierarchicalTrackSelectorWidget/generateHierarchy.js +94 -0
- package/esm/HierarchicalTrackSelectorWidget/model.d.ts +68 -28
- package/esm/HierarchicalTrackSelectorWidget/model.js +151 -116
- package/esm/HierarchicalTrackSelectorWidget/util.d.ts +12 -0
- package/esm/HierarchicalTrackSelectorWidget/util.js +45 -0
- package/esm/PluginStoreWidget/components/AddCustomPluginDialog.d.ts +7 -0
- package/esm/PluginStoreWidget/components/{CustomPluginForm.js → AddCustomPluginDialog.js} +12 -21
- package/esm/PluginStoreWidget/components/DeletePluginDialog.d.ts +5 -0
- package/esm/PluginStoreWidget/components/DeletePluginDialog.js +22 -0
- package/esm/PluginStoreWidget/components/InstalledPlugin.d.ts +2 -5
- package/esm/PluginStoreWidget/components/InstalledPlugin.js +22 -53
- package/esm/PluginStoreWidget/components/InstalledPluginsList.d.ts +2 -3
- package/esm/PluginStoreWidget/components/InstalledPluginsList.js +6 -9
- package/esm/PluginStoreWidget/components/PluginCard.js +3 -5
- package/esm/PluginStoreWidget/components/PluginStoreWidget.js +12 -40
- package/esm/PluginStoreWidget/components/util.d.ts +5 -0
- package/esm/PluginStoreWidget/components/util.js +25 -0
- package/esm/PluginStoreWidget/model.d.ts +2 -2
- package/esm/PluginStoreWidget/model.js +1 -1
- package/package.json +2 -2
- package/dist/PluginStoreWidget/components/CustomPluginForm.d.ts +0 -9
- package/esm/PluginStoreWidget/components/CustomPluginForm.d.ts +0 -9
|
@@ -1,100 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.generateHierarchy = exports.matches = void 0;
|
|
4
3
|
const mobx_state_tree_1 = require("mobx-state-tree");
|
|
5
4
|
const configuration_1 = require("@jbrowse/core/configuration");
|
|
6
5
|
const util_1 = require("@jbrowse/core/util");
|
|
7
|
-
const tracks_1 = require("@jbrowse/core/util/tracks");
|
|
8
6
|
const mst_1 = require("@jbrowse/core/util/types/mst");
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
return true;
|
|
14
|
-
}
|
|
15
|
-
else {
|
|
16
|
-
const s1 = new Set(a1);
|
|
17
|
-
return a2.some(a => s1.has(a));
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
function matches(query, conf, session) {
|
|
21
|
-
const categories = (0, configuration_1.readConfObject)(conf, 'category');
|
|
22
|
-
const queryLower = query.toLowerCase();
|
|
23
|
-
return ((0, tracks_1.getTrackName)(conf, session).toLowerCase().includes(queryLower) ||
|
|
24
|
-
!!(categories === null || categories === void 0 ? void 0 : categories.filter(c => c.toLowerCase().includes(queryLower)).length));
|
|
25
|
-
}
|
|
26
|
-
exports.matches = matches;
|
|
27
|
-
function filterTracks(tracks, self) {
|
|
28
|
-
const { assemblyManager } = (0, util_1.getSession)(self);
|
|
29
|
-
const { pluginManager } = (0, util_1.getEnv)(self);
|
|
30
|
-
const { view } = self;
|
|
31
|
-
const { trackSelectorAnyOverlap } = view;
|
|
32
|
-
const trackListAssemblies = self.assemblyNames
|
|
33
|
-
.map(a => assemblyManager.get(a))
|
|
34
|
-
.filter(util_1.notEmpty);
|
|
35
|
-
return tracks
|
|
36
|
-
.filter(c => {
|
|
37
|
-
const trackAssemblyNames = (0, configuration_1.readConfObject)(c, 'assemblyNames');
|
|
38
|
-
const trackAssemblies = new Set((trackAssemblyNames === null || trackAssemblyNames === void 0 ? void 0 : trackAssemblyNames.map(name => assemblyManager.get(name)).filter(util_1.notEmpty)) || []);
|
|
39
|
-
return trackSelectorAnyOverlap
|
|
40
|
-
? trackListAssemblies.some(a => trackAssemblies.has(a))
|
|
41
|
-
: trackListAssemblies.every(a => trackAssemblies.has(a));
|
|
42
|
-
})
|
|
43
|
-
.filter(c => {
|
|
44
|
-
const { displayTypes } = pluginManager.getViewType(view.type);
|
|
45
|
-
const compatDisplays = displayTypes.map(d => d.name);
|
|
46
|
-
const trackDisplays = c.displays.map((d) => d.type);
|
|
47
|
-
return hasAnyOverlap(compatDisplays, trackDisplays);
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
|
-
function generateHierarchy(model, trackConfigurations, collapsed, extra) {
|
|
51
|
-
const hierarchy = { children: [] };
|
|
52
|
-
const { filterText, view } = model;
|
|
53
|
-
const session = (0, util_1.getSession)(model);
|
|
54
|
-
trackConfigurations
|
|
55
|
-
.filter(conf => matches(filterText, conf, session))
|
|
56
|
-
.forEach(conf => {
|
|
57
|
-
// copy the categories since this array can be mutated downstream
|
|
58
|
-
const categories = [...((0, configuration_1.readConfObject)(conf, 'category') || [])];
|
|
59
|
-
// silly thing where if trackId ends with sessionTrack, then push it to
|
|
60
|
-
// a category that starts with a space to force sort to the top...
|
|
61
|
-
// double whammy hackyness
|
|
62
|
-
if (conf.trackId.endsWith('sessionTrack')) {
|
|
63
|
-
categories.unshift(' Session tracks');
|
|
64
|
-
}
|
|
65
|
-
let currLevel = hierarchy;
|
|
66
|
-
// find existing category to put track into or create it
|
|
67
|
-
for (let i = 0; i < categories.length; i++) {
|
|
68
|
-
const category = categories[i];
|
|
69
|
-
const ret = currLevel.children.find(c => c.name === category);
|
|
70
|
-
const id = extra + '-' + categories.slice(0, i + 1).join(',');
|
|
71
|
-
if (!ret) {
|
|
72
|
-
const n = {
|
|
73
|
-
children: [],
|
|
74
|
-
name: category,
|
|
75
|
-
id,
|
|
76
|
-
isOpenByDefault: !collapsed.get(id),
|
|
77
|
-
};
|
|
78
|
-
currLevel.children.push(n);
|
|
79
|
-
currLevel = n;
|
|
80
|
-
}
|
|
81
|
-
else {
|
|
82
|
-
currLevel = ret;
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
const tracks = view.tracks;
|
|
86
|
-
// using splice here tries to group leaf nodes above hierarchical nodes
|
|
87
|
-
currLevel.children.splice(currLevel.children.findIndex(elt => elt.children.length), 0, {
|
|
88
|
-
id: conf.trackId,
|
|
89
|
-
name: (0, tracks_1.getTrackName)(conf, session),
|
|
90
|
-
conf,
|
|
91
|
-
checked: tracks.some(f => f.configuration === conf),
|
|
92
|
-
children: [],
|
|
93
|
-
});
|
|
94
|
-
});
|
|
95
|
-
return hierarchy.children;
|
|
96
|
-
}
|
|
97
|
-
exports.generateHierarchy = generateHierarchy;
|
|
7
|
+
// locals
|
|
8
|
+
const filterTracks_1 = require("./filterTracks");
|
|
9
|
+
const generateHierarchy_1 = require("./generateHierarchy");
|
|
10
|
+
const util_2 = require("./util");
|
|
98
11
|
/**
|
|
99
12
|
* #stateModel HierarchicalTrackSelectorWidget
|
|
100
13
|
*/
|
|
@@ -109,10 +22,22 @@ function stateTreeFactory(pluginManager) {
|
|
|
109
22
|
* #property
|
|
110
23
|
*/
|
|
111
24
|
type: mobx_state_tree_1.types.literal('HierarchicalTrackSelectorWidget'),
|
|
25
|
+
/**
|
|
26
|
+
* #property
|
|
27
|
+
*/
|
|
28
|
+
initialized: mobx_state_tree_1.types.maybe(mobx_state_tree_1.types.boolean),
|
|
112
29
|
/**
|
|
113
30
|
* #property
|
|
114
31
|
*/
|
|
115
32
|
collapsed: mobx_state_tree_1.types.map(mobx_state_tree_1.types.boolean),
|
|
33
|
+
/**
|
|
34
|
+
* #property
|
|
35
|
+
*/
|
|
36
|
+
sortTrackNames: mobx_state_tree_1.types.maybe(mobx_state_tree_1.types.boolean),
|
|
37
|
+
/**
|
|
38
|
+
* #property
|
|
39
|
+
*/
|
|
40
|
+
sortCategories: mobx_state_tree_1.types.maybe(mobx_state_tree_1.types.boolean),
|
|
116
41
|
/**
|
|
117
42
|
* #property
|
|
118
43
|
*/
|
|
@@ -123,6 +48,18 @@ function stateTreeFactory(pluginManager) {
|
|
|
123
48
|
filterText: '',
|
|
124
49
|
}))
|
|
125
50
|
.actions(self => ({
|
|
51
|
+
/**
|
|
52
|
+
* #action
|
|
53
|
+
*/
|
|
54
|
+
setSortTrackNames(val) {
|
|
55
|
+
self.sortTrackNames = val;
|
|
56
|
+
},
|
|
57
|
+
/**
|
|
58
|
+
* #action
|
|
59
|
+
*/
|
|
60
|
+
setSortCategories(val) {
|
|
61
|
+
self.sortCategories = val;
|
|
62
|
+
},
|
|
126
63
|
/**
|
|
127
64
|
* #action
|
|
128
65
|
*/
|
|
@@ -159,6 +96,18 @@ function stateTreeFactory(pluginManager) {
|
|
|
159
96
|
toggleCategory(pathName) {
|
|
160
97
|
self.collapsed.set(pathName, !self.collapsed.get(pathName));
|
|
161
98
|
},
|
|
99
|
+
/**
|
|
100
|
+
* #action
|
|
101
|
+
*/
|
|
102
|
+
setCategoryCollapsed(pathName, status) {
|
|
103
|
+
self.collapsed.set(pathName, status);
|
|
104
|
+
},
|
|
105
|
+
/**
|
|
106
|
+
* #action
|
|
107
|
+
*/
|
|
108
|
+
expandAllCategories() {
|
|
109
|
+
self.collapsed.clear();
|
|
110
|
+
},
|
|
162
111
|
/**
|
|
163
112
|
* #action
|
|
164
113
|
*/
|
|
@@ -202,24 +151,59 @@ function stateTreeFactory(pluginManager) {
|
|
|
202
151
|
},
|
|
203
152
|
}))
|
|
204
153
|
.views(self => ({
|
|
154
|
+
/**
|
|
155
|
+
* #getter
|
|
156
|
+
*/
|
|
157
|
+
get activeSortTrackNames() {
|
|
158
|
+
var _a;
|
|
159
|
+
return ((_a = self.sortTrackNames) !== null && _a !== void 0 ? _a : (0, configuration_1.getConf)((0, util_1.getSession)(self), ['hierarchical', 'sort', 'trackNames']));
|
|
160
|
+
},
|
|
161
|
+
/**
|
|
162
|
+
* #getter
|
|
163
|
+
*/
|
|
164
|
+
get activeSortCategories() {
|
|
165
|
+
var _a;
|
|
166
|
+
return ((_a = self.sortCategories) !== null && _a !== void 0 ? _a : (0, configuration_1.getConf)((0, util_1.getSession)(self), ['hierarchical', 'sort', 'categories']));
|
|
167
|
+
},
|
|
205
168
|
/**
|
|
206
169
|
* #method
|
|
207
170
|
* filter out tracks that don't match the current display types
|
|
208
171
|
*/
|
|
209
172
|
connectionTrackConfigurations(connection) {
|
|
210
|
-
return
|
|
173
|
+
return (0, filterTracks_1.filterTracks)(connection.tracks, self);
|
|
211
174
|
},
|
|
212
175
|
/**
|
|
213
176
|
* #getter
|
|
214
177
|
* filter out tracks that don't match the current assembly/display types
|
|
215
178
|
*/
|
|
216
179
|
get trackConfigurations() {
|
|
217
|
-
return
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
180
|
+
return [
|
|
181
|
+
...self.assemblyNames.map(a => self.getRefSeqTrackConf(a)),
|
|
182
|
+
...(0, filterTracks_1.filterTracks)((0, util_1.getSession)(self).tracks, self),
|
|
183
|
+
].filter(util_1.notEmpty);
|
|
184
|
+
},
|
|
185
|
+
}))
|
|
186
|
+
.views(self => ({
|
|
187
|
+
/**
|
|
188
|
+
* #method
|
|
189
|
+
*/
|
|
190
|
+
connectionHierarchy(connection) {
|
|
191
|
+
return (0, generateHierarchy_1.generateHierarchy)(self, self.connectionTrackConfigurations(connection), self.collapsed, connection.name);
|
|
192
|
+
},
|
|
193
|
+
}))
|
|
194
|
+
.views(self => ({
|
|
195
|
+
get allTracks() {
|
|
196
|
+
const { connectionInstances = [] } = (0, util_1.getSession)(self);
|
|
197
|
+
return [
|
|
198
|
+
{
|
|
199
|
+
group: 'Tracks',
|
|
200
|
+
tracks: self.trackConfigurations,
|
|
201
|
+
},
|
|
202
|
+
...connectionInstances.flatMap(c => ({
|
|
203
|
+
group: (0, configuration_1.getConf)(c, 'name'),
|
|
204
|
+
tracks: c.tracks,
|
|
205
|
+
})),
|
|
206
|
+
];
|
|
223
207
|
},
|
|
224
208
|
}))
|
|
225
209
|
.views(self => ({
|
|
@@ -227,32 +211,80 @@ function stateTreeFactory(pluginManager) {
|
|
|
227
211
|
* #getter
|
|
228
212
|
*/
|
|
229
213
|
get hierarchy() {
|
|
230
|
-
const hier = generateHierarchy(self, self.trackConfigurations, self.collapsed);
|
|
231
|
-
const session = (0, util_1.getSession)(self);
|
|
232
|
-
const { connectionInstances } = session;
|
|
233
|
-
const conns = (connectionInstances === null || connectionInstances === void 0 ? void 0 : connectionInstances.map(c => ({
|
|
234
|
-
// @ts-expect-error
|
|
235
|
-
id: (0, mobx_state_tree_1.getSnapshot)(c).configuration,
|
|
236
|
-
name: (0, configuration_1.getConf)(c, 'name'),
|
|
237
|
-
children: this.connectionHierarchy(c),
|
|
238
|
-
state: {
|
|
239
|
-
expanded: true,
|
|
240
|
-
},
|
|
241
|
-
})).filter(f => f.children.length)) || [];
|
|
242
214
|
return {
|
|
243
215
|
name: 'Root',
|
|
244
216
|
id: 'Root',
|
|
245
|
-
children:
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
217
|
+
children: self.allTracks
|
|
218
|
+
.map(s => ({
|
|
219
|
+
name: s.group,
|
|
220
|
+
id: s.group,
|
|
221
|
+
children: (0, generateHierarchy_1.generateHierarchy)(self, s.tracks, self.collapsed),
|
|
222
|
+
}))
|
|
223
|
+
// always keep the Tracks entry at idx 0
|
|
224
|
+
.filter((f, idx) => idx === 0 || !!f.children.length),
|
|
249
225
|
};
|
|
250
226
|
},
|
|
227
|
+
}))
|
|
228
|
+
.actions(self => ({
|
|
251
229
|
/**
|
|
252
|
-
* #
|
|
230
|
+
* #action
|
|
253
231
|
*/
|
|
254
|
-
|
|
255
|
-
|
|
232
|
+
collapseSubCategories() {
|
|
233
|
+
const paths = [];
|
|
234
|
+
(0, util_2.findSubCategories)(self.hierarchy.children, paths);
|
|
235
|
+
for (const path of paths) {
|
|
236
|
+
self.setCategoryCollapsed(path, true);
|
|
237
|
+
}
|
|
238
|
+
},
|
|
239
|
+
/**
|
|
240
|
+
* #action
|
|
241
|
+
*/
|
|
242
|
+
collapseTopLevelCategories() {
|
|
243
|
+
const paths = [];
|
|
244
|
+
for (const trackGroups of self.hierarchy.children) {
|
|
245
|
+
if (trackGroups.children.length) {
|
|
246
|
+
(0, util_2.findTopLevelCategories)(trackGroups.children, paths);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
for (const path of paths) {
|
|
250
|
+
self.setCategoryCollapsed(path, true);
|
|
251
|
+
}
|
|
252
|
+
},
|
|
253
|
+
}))
|
|
254
|
+
.actions(self => ({
|
|
255
|
+
afterCreate() {
|
|
256
|
+
if (!self.initialized) {
|
|
257
|
+
const session = (0, util_1.getSession)(self);
|
|
258
|
+
if ((0, configuration_1.getConf)(session, [
|
|
259
|
+
'hierarchical',
|
|
260
|
+
'defaultCollapsed',
|
|
261
|
+
'topLevelCategories',
|
|
262
|
+
])) {
|
|
263
|
+
self.collapseTopLevelCategories();
|
|
264
|
+
}
|
|
265
|
+
else if ((0, configuration_1.getConf)(session, [
|
|
266
|
+
'hierarchical',
|
|
267
|
+
'defaultCollapsed',
|
|
268
|
+
'subCategories',
|
|
269
|
+
])) {
|
|
270
|
+
self.collapseSubCategories();
|
|
271
|
+
}
|
|
272
|
+
else {
|
|
273
|
+
for (const entry of (0, configuration_1.getConf)(session, [
|
|
274
|
+
'hierarchical',
|
|
275
|
+
'defaultCollapsed',
|
|
276
|
+
'categoryNames',
|
|
277
|
+
])) {
|
|
278
|
+
self.collapsed.set(entry, true);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
self.initialized = true;
|
|
282
|
+
}
|
|
283
|
+
},
|
|
284
|
+
}))
|
|
285
|
+
.views(self => ({
|
|
286
|
+
get hasAnySubcategories() {
|
|
287
|
+
return self.allTracks.some(group => group.tracks.some(track => { var _a; return ((_a = (0, configuration_1.readConfObject)(track, 'category')) === null || _a === void 0 ? void 0 : _a.length) > 1; }));
|
|
256
288
|
},
|
|
257
289
|
}));
|
|
258
290
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { AnyConfigurationModel } from '@jbrowse/core/configuration';
|
|
2
|
+
import { AbstractSessionModel } from '@jbrowse/core/util';
|
|
3
|
+
export declare function hasAnyOverlap<T>(a1?: T[], a2?: T[]): boolean;
|
|
4
|
+
export declare function hasAllOverlap<T>(a1?: T[], a2?: T[]): boolean;
|
|
5
|
+
export declare function matches(query: string, conf: AnyConfigurationModel, session: AbstractSessionModel): boolean;
|
|
6
|
+
interface Node {
|
|
7
|
+
children: Node[];
|
|
8
|
+
id: string;
|
|
9
|
+
}
|
|
10
|
+
export declare function findSubCategories(obj: Node[], paths: string[]): boolean;
|
|
11
|
+
export declare function findTopLevelCategories(obj: Node[], paths: string[]): void;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.findTopLevelCategories = exports.findSubCategories = exports.matches = exports.hasAllOverlap = exports.hasAnyOverlap = void 0;
|
|
4
|
+
const configuration_1 = require("@jbrowse/core/configuration");
|
|
5
|
+
const tracks_1 = require("@jbrowse/core/util/tracks");
|
|
6
|
+
function hasAnyOverlap(a1 = [], a2 = []) {
|
|
7
|
+
// shortcut case is that arrays are single entries, and are equal
|
|
8
|
+
// long case is that we use a set
|
|
9
|
+
if (a1[0] === a2[0]) {
|
|
10
|
+
return true;
|
|
11
|
+
}
|
|
12
|
+
else {
|
|
13
|
+
const s1 = new Set(a1);
|
|
14
|
+
return a2.some(a => s1.has(a));
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
exports.hasAnyOverlap = hasAnyOverlap;
|
|
18
|
+
function hasAllOverlap(a1 = [], a2 = []) {
|
|
19
|
+
const s1 = new Set(a1);
|
|
20
|
+
return a2.every(a => s1.has(a));
|
|
21
|
+
}
|
|
22
|
+
exports.hasAllOverlap = hasAllOverlap;
|
|
23
|
+
function matches(query, conf, session) {
|
|
24
|
+
const categories = ((0, configuration_1.readConfObject)(conf, 'category') || []);
|
|
25
|
+
const queryLower = query.toLowerCase();
|
|
26
|
+
return ((0, tracks_1.getTrackName)(conf, session).toLowerCase().includes(queryLower) ||
|
|
27
|
+
!!categories.filter(c => c.toLowerCase().includes(queryLower)).length);
|
|
28
|
+
}
|
|
29
|
+
exports.matches = matches;
|
|
30
|
+
function findSubCategories(obj, paths) {
|
|
31
|
+
let hasSubs = false;
|
|
32
|
+
for (const elt of obj) {
|
|
33
|
+
if (elt.children.length) {
|
|
34
|
+
const hasSubCategories = findSubCategories(elt.children, paths);
|
|
35
|
+
if (hasSubCategories) {
|
|
36
|
+
paths.push(elt.id);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
hasSubs = true;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return hasSubs;
|
|
44
|
+
}
|
|
45
|
+
exports.findSubCategories = findSubCategories;
|
|
46
|
+
function findTopLevelCategories(obj, paths) {
|
|
47
|
+
for (const elt of obj) {
|
|
48
|
+
if (elt.children.length) {
|
|
49
|
+
paths.push(elt.id);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
exports.findTopLevelCategories = findTopLevelCategories;
|
|
@@ -28,10 +28,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
29
|
const react_1 = __importStar(require("react"));
|
|
30
30
|
const mobx_react_1 = require("mobx-react");
|
|
31
|
-
const mobx_state_tree_1 = require("mobx-state-tree");
|
|
32
31
|
const ui_1 = require("@jbrowse/core/ui");
|
|
33
32
|
const material_1 = require("@mui/material");
|
|
34
33
|
const mui_1 = require("tss-react/mui");
|
|
34
|
+
const util_1 = require("@jbrowse/core/util");
|
|
35
35
|
// icons
|
|
36
36
|
const IconButton_1 = __importDefault(require("@mui/material/IconButton"));
|
|
37
37
|
const ExpandMore_1 = __importDefault(require("@mui/icons-material/ExpandMore"));
|
|
@@ -51,40 +51,32 @@ const useStyles = (0, mui_1.makeStyles)()(theme => ({
|
|
|
51
51
|
transform: 'rotate(180deg)',
|
|
52
52
|
},
|
|
53
53
|
}));
|
|
54
|
-
function
|
|
54
|
+
exports.default = (0, mobx_react_1.observer)(function ({ onClose, model, }) {
|
|
55
55
|
const { classes, cx } = useStyles();
|
|
56
56
|
const [umdPluginName, setUMDPluginName] = (0, react_1.useState)('');
|
|
57
57
|
const [umdPluginUrl, setUMDPluginUrl] = (0, react_1.useState)('');
|
|
58
58
|
const [esmPluginUrl, setESMPluginUrl] = (0, react_1.useState)('');
|
|
59
59
|
const [cjsPluginUrl, setCJSPluginUrl] = (0, react_1.useState)('');
|
|
60
60
|
const [advancedOptionsOpen, setAdvancedOptionsOpen] = (0, react_1.useState)(false);
|
|
61
|
-
|
|
62
|
-
const { jbrowse } = (0, mobx_state_tree_1.getRoot)(model);
|
|
61
|
+
const { jbrowse } = (0, util_1.getSession)(model);
|
|
63
62
|
const ready = Boolean((umdPluginName && umdPluginUrl) || esmPluginUrl || cjsPluginUrl);
|
|
64
63
|
function handleSubmit() {
|
|
65
64
|
if (umdPluginName && umdPluginUrl) {
|
|
66
65
|
jbrowse.addPlugin({ name: umdPluginName, umdUrl: umdPluginUrl });
|
|
67
66
|
}
|
|
68
|
-
if (esmPluginUrl) {
|
|
67
|
+
else if (esmPluginUrl) {
|
|
69
68
|
jbrowse.addPlugin({ esmUrl: esmPluginUrl });
|
|
70
69
|
}
|
|
71
|
-
if (cjsPluginUrl) {
|
|
70
|
+
else if (cjsPluginUrl) {
|
|
72
71
|
jbrowse.addPlugin({ cjsUrl: cjsPluginUrl });
|
|
73
72
|
}
|
|
74
73
|
}
|
|
75
|
-
|
|
76
|
-
setUMDPluginName('');
|
|
77
|
-
setUMDPluginUrl('');
|
|
78
|
-
setESMPluginUrl('');
|
|
79
|
-
setCJSPluginUrl('');
|
|
80
|
-
onClose();
|
|
81
|
-
}
|
|
82
|
-
return (react_1.default.createElement(ui_1.Dialog, { open: open, onClose: handleClose, title: "Add custom plugin" },
|
|
74
|
+
return (react_1.default.createElement(ui_1.Dialog, { open: true, onClose: onClose, title: "Add custom plugin" },
|
|
83
75
|
react_1.default.createElement("form", { onSubmit: handleSubmit },
|
|
84
76
|
react_1.default.createElement(material_1.DialogContent, { className: classes.dialogContent },
|
|
85
77
|
react_1.default.createElement(material_1.DialogContentText, null, "Enter the name of the plugin and its URL. The name should match what is defined in the plugin's build."),
|
|
86
|
-
react_1.default.createElement(material_1.TextField, {
|
|
87
|
-
react_1.default.createElement(material_1.TextField, {
|
|
78
|
+
react_1.default.createElement(material_1.TextField, { label: "Plugin name", variant: "outlined", value: umdPluginName, onChange: event => setUMDPluginName(event.target.value) }),
|
|
79
|
+
react_1.default.createElement(material_1.TextField, { label: "Plugin URL", variant: "outlined", value: umdPluginUrl, onChange: event => setUMDPluginUrl(event.target.value) }),
|
|
88
80
|
react_1.default.createElement(material_1.DialogContentText, { onClick: () => setAdvancedOptionsOpen(!advancedOptionsOpen) },
|
|
89
81
|
react_1.default.createElement(IconButton_1.default, { className: cx(classes.expand, {
|
|
90
82
|
[classes.expandOpen]: advancedOptionsOpen,
|
|
@@ -94,10 +86,9 @@ function CustomPluginForm({ open, onClose, model, }) {
|
|
|
94
86
|
react_1.default.createElement(material_1.Collapse, { in: advancedOptionsOpen },
|
|
95
87
|
react_1.default.createElement("div", { className: classes.dialogContent },
|
|
96
88
|
react_1.default.createElement(material_1.DialogContentText, null, "The above fields assume that the plugin is built in UMD format. If your plugin is in another format, or you have additional builds you want to add (such as a CJS build for using NodeJS APIs in desktop), you can enter the URLs for those builds below."),
|
|
97
|
-
react_1.default.createElement(material_1.TextField, {
|
|
98
|
-
react_1.default.createElement(material_1.TextField, {
|
|
89
|
+
react_1.default.createElement(material_1.TextField, { label: "ESM build URL", variant: "outlined", value: esmPluginUrl, onChange: event => setESMPluginUrl(event.target.value) }),
|
|
90
|
+
react_1.default.createElement(material_1.TextField, { label: "CJS build URL", variant: "outlined", value: cjsPluginUrl, onChange: event => setCJSPluginUrl(event.target.value) })))),
|
|
99
91
|
react_1.default.createElement(material_1.DialogActions, null,
|
|
100
|
-
react_1.default.createElement(material_1.Button, { variant: "contained", onClick:
|
|
92
|
+
react_1.default.createElement(material_1.Button, { variant: "contained", onClick: onClose }, "Cancel"),
|
|
101
93
|
react_1.default.createElement(material_1.Button, { variant: "contained", color: "primary", onClick: handleSubmit, disabled: !ready }, "Submit")))));
|
|
102
|
-
}
|
|
103
|
-
exports.default = (0, mobx_react_1.observer)(CustomPluginForm);
|
|
94
|
+
});
|
|
@@ -0,0 +1,28 @@
|
|
|
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
|
+
const react_1 = __importDefault(require("react"));
|
|
7
|
+
const material_1 = require("@mui/material");
|
|
8
|
+
const ui_1 = require("@jbrowse/core/ui");
|
|
9
|
+
function DeletePluginDialog({ onClose, plugin, }) {
|
|
10
|
+
return (react_1.default.createElement(ui_1.Dialog, { open: true, onClose: () => onClose(), title: `Remove ${plugin}` },
|
|
11
|
+
react_1.default.createElement(material_1.DialogContent, null,
|
|
12
|
+
react_1.default.createElement(material_1.Typography, null,
|
|
13
|
+
"Please confirm that you want to remove ",
|
|
14
|
+
plugin,
|
|
15
|
+
"."),
|
|
16
|
+
react_1.default.createElement(material_1.Typography, { color: "error" }, "Note: if any resources in this session still use this plugin, it may cause your session to crash")),
|
|
17
|
+
react_1.default.createElement(material_1.DialogActions, null,
|
|
18
|
+
react_1.default.createElement(material_1.Button, { variant: "contained", color: "primary", onClick: () => {
|
|
19
|
+
// avoid showing runtime plugin warning
|
|
20
|
+
window.setTimeout(() => {
|
|
21
|
+
onClose(plugin);
|
|
22
|
+
}, 500);
|
|
23
|
+
} }, "Confirm"),
|
|
24
|
+
react_1.default.createElement(material_1.Button, { variant: "contained", color: "secondary", onClick: () => {
|
|
25
|
+
onClose();
|
|
26
|
+
} }, "Cancel"))));
|
|
27
|
+
}
|
|
28
|
+
exports.default = DeletePluginDialog;
|
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import PluginManager from '@jbrowse/core/PluginManager';
|
|
3
2
|
import { BasePlugin } from '@jbrowse/core/util/types';
|
|
4
3
|
import { PluginStoreModel } from '../model';
|
|
5
|
-
declare
|
|
4
|
+
declare const _default: ({ plugin, model, }: {
|
|
6
5
|
plugin: BasePlugin;
|
|
7
6
|
model: PluginStoreModel;
|
|
8
|
-
|
|
9
|
-
}): React.JSX.Element;
|
|
10
|
-
declare const _default: typeof InstalledPlugin;
|
|
7
|
+
}) => React.JSX.Element;
|
|
11
8
|
export default _default;
|
|
@@ -28,22 +28,15 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
29
|
const react_1 = __importStar(require("react"));
|
|
30
30
|
const mobx_react_1 = require("mobx-react");
|
|
31
|
-
const mobx_state_tree_1 = require("mobx-state-tree");
|
|
32
31
|
const material_1 = require("@mui/material");
|
|
33
32
|
const mui_1 = require("tss-react/mui");
|
|
34
33
|
const Close_1 = __importDefault(require("@mui/icons-material/Close"));
|
|
35
34
|
const Lock_1 = __importDefault(require("@mui/icons-material/Lock"));
|
|
36
35
|
const util_1 = require("@jbrowse/core/util");
|
|
37
36
|
const types_1 = require("@jbrowse/core/util/types");
|
|
37
|
+
// lazies
|
|
38
|
+
const DeletePluginDialog = (0, react_1.lazy)(() => Promise.resolve().then(() => __importStar(require('./DeletePluginDialog'))));
|
|
38
39
|
const useStyles = (0, mui_1.makeStyles)()(() => ({
|
|
39
|
-
closeDialog: {
|
|
40
|
-
position: 'absolute',
|
|
41
|
-
right: 0,
|
|
42
|
-
top: 0,
|
|
43
|
-
},
|
|
44
|
-
dialogContainer: {
|
|
45
|
-
margin: 15,
|
|
46
|
-
},
|
|
47
40
|
lockedPluginTooltip: {
|
|
48
41
|
marginRight: '0.5rem',
|
|
49
42
|
},
|
|
@@ -53,52 +46,28 @@ function LockedPlugin() {
|
|
|
53
46
|
return (react_1.default.createElement(material_1.Tooltip, { className: classes.lockedPluginTooltip, title: "This plugin was installed by an administrator, you cannot remove it." },
|
|
54
47
|
react_1.default.createElement(Lock_1.default, null)));
|
|
55
48
|
}
|
|
56
|
-
function
|
|
57
|
-
const { classes } = useStyles();
|
|
58
|
-
return (react_1.default.createElement(material_1.Dialog, { open: true, onClose: () => onClose() },
|
|
59
|
-
react_1.default.createElement(material_1.DialogTitle, null,
|
|
60
|
-
react_1.default.createElement(material_1.IconButton, { className: classes.closeDialog, "aria-label": "close-dialog", onClick: () => onClose() },
|
|
61
|
-
react_1.default.createElement(Close_1.default, null))),
|
|
62
|
-
react_1.default.createElement(material_1.DialogContent, null,
|
|
63
|
-
react_1.default.createElement(material_1.Typography, null,
|
|
64
|
-
"Please confirm that you want to remove ",
|
|
65
|
-
plugin,
|
|
66
|
-
". Note: if any resources in this session still use this plugin, it may cause your session to crash"),
|
|
67
|
-
react_1.default.createElement(material_1.DialogActions, null,
|
|
68
|
-
react_1.default.createElement(material_1.Button, { variant: "contained", color: "primary", onClick: () => {
|
|
69
|
-
// avoid showing runtime plugin warning
|
|
70
|
-
window.setTimeout(() => {
|
|
71
|
-
onClose(plugin);
|
|
72
|
-
}, 500);
|
|
73
|
-
} }, "Confirm"),
|
|
74
|
-
react_1.default.createElement(material_1.Button, { variant: "contained", color: "secondary", onClick: () => {
|
|
75
|
-
onClose();
|
|
76
|
-
} }, "Cancel")))));
|
|
77
|
-
}
|
|
78
|
-
function InstalledPlugin({ plugin, model, pluginManager, }) {
|
|
49
|
+
exports.default = (0, mobx_react_1.observer)(function ({ plugin, model, }) {
|
|
79
50
|
const [dialogPlugin, setDialogPlugin] = (0, react_1.useState)();
|
|
51
|
+
const { pluginManager } = (0, util_1.getEnv)(model);
|
|
80
52
|
const session = (0, util_1.getSession)(model);
|
|
81
|
-
const { sessionPlugins } = session;
|
|
82
|
-
const isSessionPlugin = sessionPlugins === null || sessionPlugins === void 0 ? void 0 : sessionPlugins.some(p => pluginManager.pluginMetadata[plugin.name].url === p.url);
|
|
83
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
84
|
-
const rootModel = (0, mobx_state_tree_1.getParent)(model, 3);
|
|
85
|
-
const { jbrowse, adminMode } = rootModel;
|
|
53
|
+
const { jbrowse, adminMode, sessionPlugins } = session;
|
|
54
|
+
const isSessionPlugin = sessionPlugins === null || sessionPlugins === void 0 ? void 0 : sessionPlugins.some((p) => pluginManager.pluginMetadata[plugin.name].url === p.url);
|
|
86
55
|
return (react_1.default.createElement(react_1.default.Fragment, null,
|
|
87
|
-
dialogPlugin ? (react_1.default.createElement(
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
56
|
+
dialogPlugin ? (react_1.default.createElement(react_1.Suspense, { fallback: react_1.default.createElement(react_1.default.Fragment, null) },
|
|
57
|
+
react_1.default.createElement(DeletePluginDialog, { plugin: dialogPlugin, onClose: name => {
|
|
58
|
+
if (name) {
|
|
59
|
+
const pluginMetadata = pluginManager.pluginMetadata[plugin.name];
|
|
60
|
+
if (adminMode) {
|
|
61
|
+
jbrowse.removePlugin(pluginMetadata);
|
|
62
|
+
}
|
|
63
|
+
else if ((0, types_1.isSessionWithSessionPlugins)(session)) {
|
|
64
|
+
session.removeSessionPlugin(pluginMetadata);
|
|
65
|
+
}
|
|
92
66
|
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
setDialogPlugin(undefined);
|
|
98
|
-
} })) : null,
|
|
67
|
+
setDialogPlugin(undefined);
|
|
68
|
+
} }))) : null,
|
|
99
69
|
react_1.default.createElement(material_1.ListItem, { key: plugin.name },
|
|
100
70
|
adminMode || isSessionPlugin ? (react_1.default.createElement(material_1.IconButton, { "aria-label": "removePlugin", "data-testid": `removePlugin-${plugin.name}`, onClick: () => setDialogPlugin(plugin.name) },
|
|
101
71
|
react_1.default.createElement(Close_1.default, null))) : (react_1.default.createElement(LockedPlugin, null)),
|
|
102
72
|
react_1.default.createElement(material_1.Typography, null, plugin.name))));
|
|
103
|
-
}
|
|
104
|
-
exports.default = (0, mobx_react_1.observer)(InstalledPlugin);
|
|
73
|
+
});
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import PluginManager from '@jbrowse/core/PluginManager';
|
|
3
3
|
import { PluginStoreModel } from '../model';
|
|
4
|
-
declare
|
|
4
|
+
declare const _default: ({ pluginManager, model, }: {
|
|
5
5
|
pluginManager: PluginManager;
|
|
6
6
|
model: PluginStoreModel;
|
|
7
|
-
})
|
|
8
|
-
declare const _default: typeof InstalledPluginsList;
|
|
7
|
+
}) => React.JSX.Element;
|
|
9
8
|
export default _default;
|