@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.
Files changed (61) hide show
  1. package/dist/HierarchicalTrackSelectorWidget/components/faceted/FacetedSelector.js +4 -5
  2. package/dist/HierarchicalTrackSelectorWidget/components/tree/HamburgerMenu.js +35 -19
  3. package/dist/HierarchicalTrackSelectorWidget/components/tree/HierarchicalHeader.js +10 -6
  4. package/dist/HierarchicalTrackSelectorWidget/components/tree/HierarchicalTree.d.ts +2 -1
  5. package/dist/HierarchicalTrackSelectorWidget/components/tree/TrackCategory.js +22 -0
  6. package/dist/HierarchicalTrackSelectorWidget/components/tree/TrackLabel.js +1 -1
  7. package/dist/HierarchicalTrackSelectorWidget/components/util.d.ts +2 -1
  8. package/dist/HierarchicalTrackSelectorWidget/filterTracks.d.ts +12 -0
  9. package/dist/HierarchicalTrackSelectorWidget/filterTracks.js +32 -0
  10. package/dist/HierarchicalTrackSelectorWidget/generateHierarchy.d.ts +21 -0
  11. package/dist/HierarchicalTrackSelectorWidget/generateHierarchy.js +98 -0
  12. package/dist/HierarchicalTrackSelectorWidget/model.d.ts +68 -28
  13. package/dist/HierarchicalTrackSelectorWidget/model.js +149 -117
  14. package/dist/HierarchicalTrackSelectorWidget/util.d.ts +12 -0
  15. package/dist/HierarchicalTrackSelectorWidget/util.js +53 -0
  16. package/dist/PluginStoreWidget/components/AddCustomPluginDialog.d.ts +7 -0
  17. package/dist/PluginStoreWidget/components/{CustomPluginForm.js → AddCustomPluginDialog.js} +12 -21
  18. package/dist/PluginStoreWidget/components/DeletePluginDialog.d.ts +5 -0
  19. package/dist/PluginStoreWidget/components/DeletePluginDialog.js +28 -0
  20. package/dist/PluginStoreWidget/components/InstalledPlugin.d.ts +2 -5
  21. package/dist/PluginStoreWidget/components/InstalledPlugin.js +19 -50
  22. package/dist/PluginStoreWidget/components/InstalledPluginsList.d.ts +2 -3
  23. package/dist/PluginStoreWidget/components/InstalledPluginsList.js +6 -9
  24. package/dist/PluginStoreWidget/components/PluginCard.js +3 -5
  25. package/dist/PluginStoreWidget/components/PluginStoreWidget.js +11 -39
  26. package/dist/PluginStoreWidget/components/util.d.ts +5 -0
  27. package/dist/PluginStoreWidget/components/util.js +29 -0
  28. package/dist/PluginStoreWidget/model.d.ts +2 -2
  29. package/dist/PluginStoreWidget/model.js +2 -2
  30. package/esm/HierarchicalTrackSelectorWidget/components/faceted/FacetedSelector.js +1 -2
  31. package/esm/HierarchicalTrackSelectorWidget/components/tree/HamburgerMenu.js +34 -18
  32. package/esm/HierarchicalTrackSelectorWidget/components/tree/HierarchicalHeader.js +10 -6
  33. package/esm/HierarchicalTrackSelectorWidget/components/tree/HierarchicalTree.d.ts +2 -1
  34. package/esm/HierarchicalTrackSelectorWidget/components/tree/TrackCategory.js +22 -0
  35. package/esm/HierarchicalTrackSelectorWidget/components/tree/TrackLabel.js +1 -1
  36. package/esm/HierarchicalTrackSelectorWidget/components/util.d.ts +2 -1
  37. package/esm/HierarchicalTrackSelectorWidget/filterTracks.d.ts +12 -0
  38. package/esm/HierarchicalTrackSelectorWidget/filterTracks.js +28 -0
  39. package/esm/HierarchicalTrackSelectorWidget/generateHierarchy.d.ts +21 -0
  40. package/esm/HierarchicalTrackSelectorWidget/generateHierarchy.js +94 -0
  41. package/esm/HierarchicalTrackSelectorWidget/model.d.ts +68 -28
  42. package/esm/HierarchicalTrackSelectorWidget/model.js +151 -116
  43. package/esm/HierarchicalTrackSelectorWidget/util.d.ts +12 -0
  44. package/esm/HierarchicalTrackSelectorWidget/util.js +45 -0
  45. package/esm/PluginStoreWidget/components/AddCustomPluginDialog.d.ts +7 -0
  46. package/esm/PluginStoreWidget/components/{CustomPluginForm.js → AddCustomPluginDialog.js} +12 -21
  47. package/esm/PluginStoreWidget/components/DeletePluginDialog.d.ts +5 -0
  48. package/esm/PluginStoreWidget/components/DeletePluginDialog.js +22 -0
  49. package/esm/PluginStoreWidget/components/InstalledPlugin.d.ts +2 -5
  50. package/esm/PluginStoreWidget/components/InstalledPlugin.js +22 -53
  51. package/esm/PluginStoreWidget/components/InstalledPluginsList.d.ts +2 -3
  52. package/esm/PluginStoreWidget/components/InstalledPluginsList.js +6 -9
  53. package/esm/PluginStoreWidget/components/PluginCard.js +3 -5
  54. package/esm/PluginStoreWidget/components/PluginStoreWidget.js +12 -40
  55. package/esm/PluginStoreWidget/components/util.d.ts +5 -0
  56. package/esm/PluginStoreWidget/components/util.js +25 -0
  57. package/esm/PluginStoreWidget/model.d.ts +2 -2
  58. package/esm/PluginStoreWidget/model.js +1 -1
  59. package/package.json +2 -2
  60. package/dist/PluginStoreWidget/components/CustomPluginForm.d.ts +0 -9
  61. package/esm/PluginStoreWidget/components/CustomPluginForm.d.ts +0 -9
@@ -42,11 +42,10 @@ const util_1 = require("@jbrowse/core/util");
42
42
  const configuration_1 = require("@jbrowse/core/configuration");
43
43
  // icons
44
44
  const MoreHoriz_1 = __importDefault(require("@mui/icons-material/MoreHoriz"));
45
- // locals
46
- const model_1 = require("../../model");
45
+ const util_2 = require("../../util");
47
46
  const FacetedHeader_1 = __importDefault(require("./FacetedHeader"));
48
47
  const FacetFilters_1 = __importDefault(require("./FacetFilters"));
49
- const util_2 = require("./util");
48
+ const util_3 = require("./util");
50
49
  const nonMetadataKeys = ['category', 'adapter', 'description'];
51
50
  const frac = 0.75;
52
51
  exports.default = (0, mobx_react_1.observer)(function FacetedSelector({ model, }) {
@@ -70,7 +69,7 @@ exports.default = (0, mobx_react_1.observer)(function FacetedSelector({ model, }
70
69
  // metadata is spread onto the object for easier access and sorting
71
70
  // by the mui data grid (it's unable to sort by nested objects)
72
71
  return model.trackConfigurations
73
- .filter(conf => (0, model_1.matches)(filterDebounced, conf, session))
72
+ .filter(conf => (0, util_2.matches)(filterDebounced, conf, session))
74
73
  .map(track => {
75
74
  var _a, _b;
76
75
  const metadata = (0, configuration_1.readConfObject)(track, 'metadata');
@@ -87,7 +86,7 @@ exports.default = (0, mobx_react_1.observer)(function FacetedSelector({ model, }
87
86
  });
88
87
  }, [model, filterDebounced, session]);
89
88
  const filteredNonMetadataKeys = (0, react_1.useMemo)(() => nonMetadataKeys.filter(f => !hideSparse ? true : rows.map(r => r[f]).filter(f => !!f).length > 5), [hideSparse, rows]);
90
- const filteredMetadataKeys = (0, react_1.useMemo)(() => [...new Set(rows.flatMap(row => (0, util_2.getRootKeys)(row.metadata)))].filter(f => !hideSparse
89
+ const filteredMetadataKeys = (0, react_1.useMemo)(() => [...new Set(rows.flatMap(row => (0, util_3.getRootKeys)(row.metadata)))].filter(f => !hideSparse
91
90
  ? true
92
91
  : rows.map(r => r.metadata[f]).filter(f => !!f).length > 5), [hideSparse, rows]);
93
92
  const fields = (0, react_1.useMemo)(() => ['name', ...filteredNonMetadataKeys, ...filteredMetadataKeys], [filteredNonMetadataKeys, filteredMetadataKeys]);
@@ -27,33 +27,23 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
27
27
  };
28
28
  Object.defineProperty(exports, "__esModule", { value: true });
29
29
  const react_1 = __importStar(require("react"));
30
- const material_1 = require("@mui/material");
31
- const mui_1 = require("tss-react/mui");
32
30
  const mobx_react_1 = require("mobx-react");
33
- const Menu_1 = __importDefault(require("@jbrowse/core/ui/Menu"));
34
31
  const util_1 = require("@jbrowse/core/util");
35
32
  const configuration_1 = require("@jbrowse/core/configuration");
33
+ const CascadingMenuButton_1 = __importDefault(require("@jbrowse/core/ui/CascadingMenuButton"));
36
34
  // icons
37
- const Menu_2 = __importDefault(require("@mui/icons-material/Menu"));
35
+ const Menu_1 = __importDefault(require("@mui/icons-material/Menu"));
38
36
  // lazy components
39
37
  const CloseConnectionDlg = (0, react_1.lazy)(() => Promise.resolve().then(() => __importStar(require('../dialogs/CloseConnectionDialog'))));
40
38
  const DeleteConnectionDlg = (0, react_1.lazy)(() => Promise.resolve().then(() => __importStar(require('../dialogs/DeleteConnectionDialog'))));
41
39
  const ManageConnectionsDlg = (0, react_1.lazy)(() => Promise.resolve().then(() => __importStar(require('../dialogs/ManageConnectionsDialog'))));
42
40
  const ToggleConnectionsDlg = (0, react_1.lazy)(() => Promise.resolve().then(() => __importStar(require('../dialogs/ToggleConnectionsDialog'))));
43
- const useStyles = (0, mui_1.makeStyles)()(theme => ({
44
- menuIcon: {
45
- marginRight: theme.spacing(1),
46
- marginBottom: 0,
47
- },
48
- }));
49
41
  exports.default = (0, mobx_react_1.observer)(function HamburgerMenu({ model, }) {
50
42
  const session = (0, util_1.getSession)(model);
51
- const [menuEl, setMenuEl] = (0, react_1.useState)();
52
43
  const [modalInfo, setModalInfo] = (0, react_1.useState)();
53
44
  const [deleteDlgDetails, setDeleteDlgDetails] = (0, react_1.useState)();
54
45
  const [connectionToggleOpen, setConnectionToggleOpen] = (0, react_1.useState)(false);
55
46
  const [connectionManagerOpen, setConnectionManagerOpen] = (0, react_1.useState)(false);
56
- const { classes } = useStyles();
57
47
  function breakConnection(connectionConf, deletingConnection) {
58
48
  const name = (0, configuration_1.readConfObject)(connectionConf, 'name');
59
49
  const result = session.prepareToBreakConnection(connectionConf);
@@ -76,12 +66,7 @@ exports.default = (0, mobx_react_1.observer)(function HamburgerMenu({ model, })
76
66
  }
77
67
  }
78
68
  return (react_1.default.createElement(react_1.default.Fragment, null,
79
- react_1.default.createElement(material_1.IconButton, { className: classes.menuIcon, onClick: event => setMenuEl(event.currentTarget) },
80
- react_1.default.createElement(Menu_2.default, null)),
81
- react_1.default.createElement(Menu_1.default, { anchorEl: menuEl, open: Boolean(menuEl), onMenuItemClick: (_, callback) => {
82
- callback();
83
- setMenuEl(undefined);
84
- }, onClose: () => setMenuEl(undefined), menuItems: [
69
+ react_1.default.createElement(CascadingMenuButton_1.default, { menuItems: [
85
70
  ...((0, util_1.isSessionWithAddTracks)(session)
86
71
  ? [
87
72
  {
@@ -120,7 +105,38 @@ exports.default = (0, mobx_react_1.observer)(function HamburgerMenu({ model, })
120
105
  },
121
106
  ]
122
107
  : []),
123
- ] }),
108
+ { type: 'divider' },
109
+ {
110
+ label: 'Sort tracks by name',
111
+ type: 'checkbox',
112
+ checked: model.activeSortTrackNames,
113
+ onClick: () => model.setSortTrackNames(!model.activeSortTrackNames),
114
+ },
115
+ {
116
+ label: 'Sort categories by name',
117
+ type: 'checkbox',
118
+ checked: model.activeSortCategories,
119
+ onClick: () => model.setSortCategories(!model.activeSortCategories),
120
+ },
121
+ { type: 'divider' },
122
+ ...(model.hasAnySubcategories
123
+ ? [
124
+ {
125
+ label: 'Collapse subcategories',
126
+ onClick: () => model.collapseSubCategories(),
127
+ },
128
+ ]
129
+ : []),
130
+ {
131
+ label: 'Collapse top-level categories',
132
+ onClick: () => model.collapseTopLevelCategories(),
133
+ },
134
+ {
135
+ label: 'Expand all categories',
136
+ onClick: () => model.expandAllCategories(),
137
+ },
138
+ ] },
139
+ react_1.default.createElement(Menu_1.default, null)),
124
140
  react_1.default.createElement(react_1.Suspense, { fallback: react_1.default.createElement(react_1.default.Fragment, null) },
125
141
  modalInfo ? (react_1.default.createElement(CloseConnectionDlg, { modalInfo: modalInfo, onClose: () => setModalInfo(undefined) })) : null,
126
142
  deleteDlgDetails ? (react_1.default.createElement(DeleteConnectionDlg, { handleClose: () => setDeleteDlgDetails(undefined), deleteDialogDetails: deleteDlgDetails, session: session })) : null,
@@ -45,19 +45,23 @@ const useStyles = (0, mui_1.makeStyles)()(theme => ({
45
45
  marginBottom: 0,
46
46
  },
47
47
  }));
48
+ const SearchTracksTextField = (0, mobx_react_1.observer)(function ({ model, }) {
49
+ const { filterText } = model;
50
+ const { classes } = useStyles();
51
+ return (react_1.default.createElement(material_1.TextField, { className: classes.searchBox, label: "Filter tracks", value: filterText, onChange: event => model.setFilterText(event.target.value), fullWidth: true, InputProps: {
52
+ endAdornment: (react_1.default.createElement(material_1.InputAdornment, { position: "end" },
53
+ react_1.default.createElement(material_1.IconButton, { onClick: () => model.clearFilterText() },
54
+ react_1.default.createElement(Clear_1.default, null)))),
55
+ } }));
56
+ });
48
57
  function HierarchicalTrackSelectorHeader({ model, setHeaderHeight, }) {
49
58
  const { classes } = useStyles();
50
59
  const [facetedOpen, setFacetedOpen] = (0, react_1.useState)(false);
51
- const { filterText } = model;
52
60
  return (react_1.default.createElement("div", { ref: ref => setHeaderHeight((ref === null || ref === void 0 ? void 0 : ref.getBoundingClientRect().height) || 0), "data-testid": "hierarchical_track_selector" },
53
61
  react_1.default.createElement("div", { style: { display: 'flex' } },
54
62
  react_1.default.createElement(HamburgerMenu_1.default, { model: model }),
55
63
  react_1.default.createElement(ShoppingCart_1.default, { model: model }),
56
- react_1.default.createElement(material_1.TextField, { className: classes.searchBox, label: "Filter tracks", value: filterText, onChange: event => model.setFilterText(event.target.value), fullWidth: true, InputProps: {
57
- endAdornment: (react_1.default.createElement(material_1.InputAdornment, { position: "end" },
58
- react_1.default.createElement(material_1.IconButton, { onClick: () => model.clearFilterText() },
59
- react_1.default.createElement(Clear_1.default, null)))),
60
- } }),
64
+ react_1.default.createElement(SearchTracksTextField, { model: model }),
61
65
  react_1.default.createElement(material_1.Button, { className: classes.menuIcon, onClick: () => setFacetedOpen(true) }, "Open faceted selector")),
62
66
  react_1.default.createElement(react_1.Suspense, { fallback: react_1.default.createElement("div", null) }, facetedOpen ? (react_1.default.createElement(FacetedDialog, { handleClose: () => setFacetedOpen(false), model: model })) : null)));
63
67
  }
@@ -1,5 +1,6 @@
1
1
  import React from 'react';
2
- import { TreeNode, HierarchicalTrackSelectorModel } from '../../model';
2
+ import { TreeNode } from '../../generateHierarchy';
3
+ import { HierarchicalTrackSelectorModel } from '../../model';
3
4
  declare const _default: ({ height, tree, model, }: {
4
5
  height: number;
5
6
  tree: TreeNode;
@@ -80,6 +80,28 @@ function Category({ isOpen, setOpen, data, }) {
80
80
  model.removeFromSelection((0, util_1.getAllChildren)(r));
81
81
  },
82
82
  },
83
+ {
84
+ label: 'Show all tracks',
85
+ onClick: () => {
86
+ var _a;
87
+ for (const entry of ((_a = (0, util_1.treeToMap)(tree).get(id)) === null || _a === void 0 ? void 0 : _a.children) || []) {
88
+ if (!entry.children.length) {
89
+ model.view.showTrack(entry.id);
90
+ }
91
+ }
92
+ },
93
+ },
94
+ {
95
+ label: 'Hide all tracks',
96
+ onClick: () => {
97
+ var _a;
98
+ for (const entry of ((_a = (0, util_1.treeToMap)(tree).get(id)) === null || _a === void 0 ? void 0 : _a.children) || []) {
99
+ if (!entry.children.length) {
100
+ model.view.hideTrack(entry.id);
101
+ }
102
+ }
103
+ },
104
+ },
83
105
  ], onMenuItemClick: (_event, callback) => {
84
106
  callback();
85
107
  setMenuEl(null);
@@ -59,7 +59,7 @@ function TrackLabel({ data }) {
59
59
  react_1.default.createElement(material_1.FormControlLabel, { className: classes.checkboxLabel, control: react_1.default.createElement(material_1.Checkbox, { className: classes.compactCheckbox, checked: checked, onChange: () => onChange(id), disabled: (0, util_2.isUnsupported)(name), inputProps: {
60
60
  // @ts-expect-error
61
61
  'data-testid': `htsTrackEntry-${id}`,
62
- } }), label: react_1.default.createElement("div", { style: { background: selected ? '#cccc' : undefined } },
62
+ } }), label: react_1.default.createElement("div", { "data-testid": `htsTrackLabel-${id}`, style: { background: selected ? '#cccc' : undefined } },
63
63
  react_1.default.createElement(ui_1.SanitizedHTML, { html: name })) })),
64
64
  react_1.default.createElement(material_1.IconButton, { onClick: e => setInfo({ target: e.currentTarget, id, conf }), style: { padding: 0 }, "data-testid": `htsTrackEntryMenu-${id}` },
65
65
  react_1.default.createElement(MoreHoriz_1.default, null)),
@@ -1,5 +1,6 @@
1
1
  import { AnyConfigurationModel } from '@jbrowse/core/configuration';
2
- import { HierarchicalTrackSelectorModel, TreeNode } from '../model';
2
+ import { HierarchicalTrackSelectorModel } from '../model';
3
+ import { TreeNode } from '../generateHierarchy';
3
4
  export interface NodeData {
4
5
  nestingLevel: number;
5
6
  checked: boolean;
@@ -0,0 +1,12 @@
1
+ import { AnyConfigurationModel } from '@jbrowse/core/configuration';
2
+ export declare function filterTracks(tracks: AnyConfigurationModel[], self: {
3
+ view?: {
4
+ type: string;
5
+ trackSelectorAnyOverlap?: boolean;
6
+ };
7
+ assemblyNames: string[];
8
+ }): ({
9
+ [x: string]: any;
10
+ } & import("mobx-state-tree/dist/internal").NonEmptyObject & {
11
+ setSubschema(slotName: string, data: unknown): any;
12
+ } & import("mobx-state-tree").IStateTreeNode<import("@jbrowse/core/configuration").AnyConfigurationSchemaType>)[];
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.filterTracks = void 0;
4
+ const configuration_1 = require("@jbrowse/core/configuration");
5
+ const util_1 = require("@jbrowse/core/util");
6
+ const util_2 = require("./util");
7
+ function filterTracks(tracks, self) {
8
+ const { assemblyManager } = (0, util_1.getSession)(self);
9
+ const { pluginManager } = (0, util_1.getEnv)(self);
10
+ const { view } = self;
11
+ if (!view) {
12
+ return [];
13
+ }
14
+ const trackListAssemblies = self.assemblyNames
15
+ .map(a => assemblyManager.get(a))
16
+ .filter(util_1.notEmpty);
17
+ return tracks
18
+ .filter(c => {
19
+ const trackAssemblyNames = (0, configuration_1.readConfObject)(c, 'assemblyNames');
20
+ const trackAssemblies = trackAssemblyNames === null || trackAssemblyNames === void 0 ? void 0 : trackAssemblyNames.map(name => assemblyManager.get(name)).filter(util_1.notEmpty);
21
+ return view.trackSelectorAnyOverlap
22
+ ? (0, util_2.hasAnyOverlap)(trackAssemblies, trackListAssemblies)
23
+ : (0, util_2.hasAllOverlap)(trackAssemblies, trackListAssemblies);
24
+ })
25
+ .filter(c => {
26
+ const { displayTypes } = pluginManager.getViewType(view.type);
27
+ const compatDisplays = displayTypes.map(d => d.name);
28
+ const trackDisplays = c.displays.map((d) => d.type);
29
+ return (0, util_2.hasAnyOverlap)(compatDisplays, trackDisplays);
30
+ });
31
+ }
32
+ exports.filterTracks = filterTracks;
@@ -0,0 +1,21 @@
1
+ import { AnyConfigurationModel } from '@jbrowse/core/configuration';
2
+ export type TreeNode = {
3
+ name: string;
4
+ id: string;
5
+ conf?: AnyConfigurationModel;
6
+ checked?: boolean;
7
+ isOpenByDefault?: boolean;
8
+ children: TreeNode[];
9
+ };
10
+ export declare function generateHierarchy(model: {
11
+ filterText: string;
12
+ activeSortTrackNames: boolean;
13
+ activeSortCategories: boolean;
14
+ view?: {
15
+ tracks: {
16
+ configuration: AnyConfigurationModel;
17
+ }[];
18
+ };
19
+ }, trackConfs: AnyConfigurationModel[], collapsed: {
20
+ get: (arg: string) => boolean | undefined;
21
+ }, extra?: string): TreeNode[];
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateHierarchy = void 0;
4
+ const configuration_1 = require("@jbrowse/core/configuration");
5
+ const util_1 = require("@jbrowse/core/util");
6
+ const tracks_1 = require("@jbrowse/core/util/tracks");
7
+ // locals
8
+ const util_2 = require("./util");
9
+ function sortConfs(confs, sortNames, sortCategories) {
10
+ // uses readConfObject instead of getTrackName so that the undefined
11
+ // reference sequence track is sorted to the top
12
+ const ret = confs.map(c => {
13
+ var _a, _b, _c;
14
+ return [
15
+ c,
16
+ (0, configuration_1.readConfObject)(c, 'name'),
17
+ ((_a = (0, configuration_1.readConfObject)(c, 'category')) === null || _a === void 0 ? void 0 : _a[0]) || '',
18
+ ((_b = (0, configuration_1.readConfObject)(c, 'category')) === null || _b === void 0 ? void 0 : _b[1]) || '',
19
+ ((_c = (0, configuration_1.readConfObject)(c, 'category')) === null || _c === void 0 ? void 0 : _c[2]) || '',
20
+ ];
21
+ });
22
+ if (sortNames) {
23
+ ret.sort((a, b) => a[1].localeCompare(b[1]));
24
+ }
25
+ if (sortCategories) {
26
+ // sort up to three sub-category levels, harder to code it to go deeper
27
+ // than this and likely rarely used
28
+ ret.sort((a, b) => {
29
+ if (a[2] !== b[2]) {
30
+ return a[2].localeCompare(b[2]);
31
+ }
32
+ else if (a[3] !== b[3]) {
33
+ return a[3].localeCompare(b[3]);
34
+ }
35
+ else if (a[4] !== b[4]) {
36
+ return a[4].localeCompare(b[4]);
37
+ }
38
+ return 0;
39
+ });
40
+ }
41
+ return ret.map(a => a[0]);
42
+ }
43
+ function generateHierarchy(model, trackConfs, collapsed, extra) {
44
+ const hierarchy = { children: [] };
45
+ const { filterText, activeSortTrackNames, activeSortCategories, view } = model;
46
+ if (!view) {
47
+ return [];
48
+ }
49
+ const session = (0, util_1.getSession)(model);
50
+ const viewTracks = view.tracks;
51
+ const confs = trackConfs.filter(conf => (0, util_2.matches)(filterText, conf, session));
52
+ // uses getConf
53
+ for (const conf of sortConfs(confs, activeSortTrackNames, activeSortCategories)) {
54
+ // copy the categories since this array can be mutated downstream
55
+ const categories = [...((0, configuration_1.readConfObject)(conf, 'category') || [])];
56
+ // hack where if trackId ends with sessionTrack, then push it to a
57
+ // category that starts with a space to force sort to the top
58
+ if (conf.trackId.endsWith('sessionTrack')) {
59
+ categories.unshift(' Session tracks');
60
+ }
61
+ let currLevel = hierarchy;
62
+ // find existing category to put track into or create it
63
+ for (let i = 0; i < categories.length; i++) {
64
+ const category = categories[i];
65
+ const ret = currLevel.children.find(c => c.name === category);
66
+ const id = [extra, categories.slice(0, i + 1).join(',')]
67
+ .filter(f => !!f)
68
+ .join('-');
69
+ if (!ret) {
70
+ const n = {
71
+ children: [],
72
+ name: category,
73
+ id,
74
+ isOpenByDefault: !collapsed.get(id),
75
+ };
76
+ currLevel.children.push(n);
77
+ currLevel = n;
78
+ }
79
+ else {
80
+ currLevel = ret;
81
+ }
82
+ }
83
+ // uses splice to try to put all leaf nodes above "category nodes" if you
84
+ // change the splice to a simple push and open
85
+ // test_data/test_order/config.json you will see the weirdness
86
+ const r = currLevel.children.findIndex(elt => elt.children.length);
87
+ const idx = r === -1 ? currLevel.children.length : r;
88
+ currLevel.children.splice(idx, 0, {
89
+ id: conf.trackId,
90
+ name: (0, tracks_1.getTrackName)(conf, session),
91
+ conf,
92
+ checked: viewTracks.some(f => f.configuration === conf),
93
+ children: [],
94
+ });
95
+ }
96
+ return hierarchy.children;
97
+ }
98
+ exports.generateHierarchy = generateHierarchy;
@@ -1,19 +1,7 @@
1
1
  import { Instance } from 'mobx-state-tree';
2
2
  import { AnyConfigurationModel } from '@jbrowse/core/configuration';
3
- import { AbstractSessionModel } from '@jbrowse/core/util';
4
3
  import PluginManager from '@jbrowse/core/PluginManager';
5
- export declare function matches(query: string, conf: AnyConfigurationModel, session: AbstractSessionModel): boolean;
6
- export type TreeNode = {
7
- name: string;
8
- id: string;
9
- conf?: AnyConfigurationModel;
10
- checked?: boolean;
11
- isOpenByDefault?: boolean;
12
- children: TreeNode[];
13
- };
14
- export declare function generateHierarchy(model: HierarchicalTrackSelectorModel, trackConfigurations: AnyConfigurationModel[], collapsed: {
15
- get: (arg: string) => boolean | undefined;
16
- }, extra?: string): TreeNode[];
4
+ import { TreeNode } from './generateHierarchy';
17
5
  /**
18
6
  * #stateModel HierarchicalTrackSelectorWidget
19
7
  */
@@ -26,10 +14,22 @@ export default function stateTreeFactory(pluginManager: PluginManager): import("
26
14
  * #property
27
15
  */
28
16
  type: import("mobx-state-tree").ISimpleType<"HierarchicalTrackSelectorWidget">;
17
+ /**
18
+ * #property
19
+ */
20
+ initialized: import("mobx-state-tree").IMaybe<import("mobx-state-tree").ISimpleType<boolean>>;
29
21
  /**
30
22
  * #property
31
23
  */
32
24
  collapsed: import("mobx-state-tree").IMapType<import("mobx-state-tree").ISimpleType<boolean>>;
25
+ /**
26
+ * #property
27
+ */
28
+ sortTrackNames: import("mobx-state-tree").IMaybe<import("mobx-state-tree").ISimpleType<boolean>>;
29
+ /**
30
+ * #property
31
+ */
32
+ sortCategories: import("mobx-state-tree").IMaybe<import("mobx-state-tree").ISimpleType<boolean>>;
33
33
  /**
34
34
  * #property
35
35
  */
@@ -42,6 +42,14 @@ export default function stateTreeFactory(pluginManager: PluginManager): import("
42
42
  } & import("mobx-state-tree").IStateTreeNode<import("@jbrowse/core/configuration").AnyConfigurationSchemaType>)[];
43
43
  filterText: string;
44
44
  } & {
45
+ /**
46
+ * #action
47
+ */
48
+ setSortTrackNames(val: boolean): void;
49
+ /**
50
+ * #action
51
+ */
52
+ setSortCategories(val: boolean): void;
45
53
  /**
46
54
  * #action
47
55
  */
@@ -66,6 +74,14 @@ export default function stateTreeFactory(pluginManager: PluginManager): import("
66
74
  * #action
67
75
  */
68
76
  toggleCategory(pathName: string): void;
77
+ /**
78
+ * #action
79
+ */
80
+ setCategoryCollapsed(pathName: string, status: boolean): void;
81
+ /**
82
+ * #action
83
+ */
84
+ expandAllCategories(): void;
69
85
  /**
70
86
  * #action
71
87
  */
@@ -85,6 +101,14 @@ export default function stateTreeFactory(pluginManager: PluginManager): import("
85
101
  */
86
102
  readonly assemblyNames: string[];
87
103
  } & {
104
+ /**
105
+ * #getter
106
+ */
107
+ readonly activeSortTrackNames: any;
108
+ /**
109
+ * #getter
110
+ */
111
+ readonly activeSortCategories: any;
88
112
  /**
89
113
  * #method
90
114
  * filter out tracks that don't match the current display types
@@ -105,6 +129,23 @@ export default function stateTreeFactory(pluginManager: PluginManager): import("
105
129
  } & import("mobx-state-tree/dist/internal").NonEmptyObject & {
106
130
  setSubschema(slotName: string, data: unknown): any;
107
131
  } & import("mobx-state-tree").IStateTreeNode<import("@jbrowse/core/configuration").AnyConfigurationSchemaType>)[];
132
+ } & {
133
+ /**
134
+ * #method
135
+ */
136
+ connectionHierarchy(connection: {
137
+ name: string;
138
+ tracks: AnyConfigurationModel[];
139
+ }): TreeNode[];
140
+ } & {
141
+ readonly allTracks: {
142
+ group: any;
143
+ tracks: ({
144
+ [x: string]: any;
145
+ } & import("mobx-state-tree/dist/internal").NonEmptyObject & {
146
+ setSubschema(slotName: string, data: unknown): any;
147
+ } & import("mobx-state-tree").IStateTreeNode<import("@jbrowse/core/configuration").AnyConfigurationSchemaType>)[];
148
+ }[];
108
149
  } & {
109
150
  /**
110
151
  * #getter
@@ -112,26 +153,25 @@ export default function stateTreeFactory(pluginManager: PluginManager): import("
112
153
  readonly hierarchy: {
113
154
  name: string;
114
155
  id: string;
115
- children: ({
116
- id: any;
156
+ children: {
117
157
  name: any;
158
+ id: any;
118
159
  children: TreeNode[];
119
- state: {
120
- expanded: boolean;
121
- };
122
- } | {
123
- name: string;
124
- id: string;
125
- children: TreeNode[];
126
- })[];
160
+ }[];
127
161
  };
162
+ } & {
128
163
  /**
129
- * #method
164
+ * #action
130
165
  */
131
- connectionHierarchy(connection: {
132
- name: string;
133
- tracks: AnyConfigurationModel[];
134
- }): TreeNode[];
166
+ collapseSubCategories(): void;
167
+ /**
168
+ * #action
169
+ */
170
+ collapseTopLevelCategories(): void;
171
+ } & {
172
+ afterCreate(): void;
173
+ } & {
174
+ readonly hasAnySubcategories: boolean;
135
175
  }, import("mobx-state-tree")._NotCustomized, import("mobx-state-tree")._NotCustomized>;
136
176
  export type HierarchicalTrackSelectorStateModel = ReturnType<typeof stateTreeFactory>;
137
177
  export type HierarchicalTrackSelectorModel = Instance<HierarchicalTrackSelectorStateModel>;