@jbrowse/plugin-data-management 2.8.0 → 2.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/dist/AddTrackWidget/components/DefaultAddTrackWorkflow.js +4 -8
  2. package/dist/AddTrackWidget/model.d.ts +81 -0
  3. package/dist/AddTrackWidget/model.js +81 -0
  4. package/dist/HierarchicalTrackSelectorWidget/components/ShoppingCart.d.ts +1 -1
  5. package/dist/HierarchicalTrackSelectorWidget/components/ShoppingCart.js +11 -53
  6. package/dist/HierarchicalTrackSelectorWidget/components/faceted/FacetFilter.d.ts +5 -7
  7. package/dist/HierarchicalTrackSelectorWidget/components/faceted/FacetFilter.js +12 -11
  8. package/dist/HierarchicalTrackSelectorWidget/components/faceted/FacetFilters.d.ts +5 -7
  9. package/dist/HierarchicalTrackSelectorWidget/components/faceted/FacetFilters.js +11 -8
  10. package/dist/HierarchicalTrackSelectorWidget/components/faceted/FacetedHeader.d.ts +1 -11
  11. package/dist/HierarchicalTrackSelectorWidget/components/faceted/FacetedHeader.js +9 -7
  12. package/dist/HierarchicalTrackSelectorWidget/components/faceted/FacetedSelector.js +40 -135
  13. package/dist/HierarchicalTrackSelectorWidget/components/tree/DropdownTrackSelector.d.ts +12 -0
  14. package/dist/HierarchicalTrackSelectorWidget/components/tree/DropdownTrackSelector.js +59 -0
  15. package/dist/HierarchicalTrackSelectorWidget/components/tree/FavoriteTracks.d.ts +6 -0
  16. package/dist/HierarchicalTrackSelectorWidget/components/tree/FavoriteTracks.js +45 -0
  17. package/dist/HierarchicalTrackSelectorWidget/components/tree/HamburgerMenu.js +71 -46
  18. package/dist/HierarchicalTrackSelectorWidget/components/tree/HierarchicalHeader.js +5 -34
  19. package/dist/HierarchicalTrackSelectorWidget/components/tree/HierarchicalTree.js +8 -3
  20. package/dist/HierarchicalTrackSelectorWidget/components/tree/RecentlyUsedTracks.d.ts +6 -0
  21. package/dist/HierarchicalTrackSelectorWidget/components/tree/RecentlyUsedTracks.js +42 -0
  22. package/dist/HierarchicalTrackSelectorWidget/components/tree/TrackCategory.js +7 -6
  23. package/dist/HierarchicalTrackSelectorWidget/components/tree/TrackLabel.js +9 -28
  24. package/dist/HierarchicalTrackSelectorWidget/components/tree/TrackLabelMenu.d.ts +12 -0
  25. package/dist/HierarchicalTrackSelectorWidget/components/tree/TrackLabelMenu.js +50 -0
  26. package/dist/HierarchicalTrackSelectorWidget/components/util.d.ts +3 -0
  27. package/dist/HierarchicalTrackSelectorWidget/components/util.js +5 -1
  28. package/dist/HierarchicalTrackSelectorWidget/facetedModel.d.ts +128 -0
  29. package/dist/HierarchicalTrackSelectorWidget/facetedModel.js +206 -0
  30. package/dist/HierarchicalTrackSelectorWidget/facetedUtil.d.ts +2 -0
  31. package/dist/HierarchicalTrackSelectorWidget/{components/faceted/util.js → facetedUtil.js} +5 -1
  32. package/dist/HierarchicalTrackSelectorWidget/generateHierarchy.d.ts +17 -5
  33. package/dist/HierarchicalTrackSelectorWidget/generateHierarchy.js +27 -21
  34. package/dist/HierarchicalTrackSelectorWidget/model.d.ts +193 -15
  35. package/dist/HierarchicalTrackSelectorWidget/model.js +209 -22
  36. package/dist/ucsc-trackhub/doConnect.d.ts +1 -0
  37. package/dist/ucsc-trackhub/doConnect.js +131 -0
  38. package/dist/ucsc-trackhub/model.d.ts +19 -2
  39. package/dist/ucsc-trackhub/model.js +16 -71
  40. package/dist/ucsc-trackhub/ucscTrackHub.d.ts +161 -4
  41. package/dist/ucsc-trackhub/ucscTrackHub.js +49 -166
  42. package/esm/AddTrackWidget/components/DefaultAddTrackWorkflow.js +4 -8
  43. package/esm/AddTrackWidget/model.d.ts +81 -0
  44. package/esm/AddTrackWidget/model.js +81 -0
  45. package/esm/HierarchicalTrackSelectorWidget/components/ShoppingCart.d.ts +1 -1
  46. package/esm/HierarchicalTrackSelectorWidget/components/ShoppingCart.js +12 -31
  47. package/esm/HierarchicalTrackSelectorWidget/components/faceted/FacetFilter.d.ts +5 -7
  48. package/esm/HierarchicalTrackSelectorWidget/components/faceted/FacetFilter.js +13 -11
  49. package/esm/HierarchicalTrackSelectorWidget/components/faceted/FacetFilters.d.ts +5 -7
  50. package/esm/HierarchicalTrackSelectorWidget/components/faceted/FacetFilters.js +12 -8
  51. package/esm/HierarchicalTrackSelectorWidget/components/faceted/FacetedHeader.d.ts +1 -11
  52. package/esm/HierarchicalTrackSelectorWidget/components/faceted/FacetedHeader.js +9 -7
  53. package/esm/HierarchicalTrackSelectorWidget/components/faceted/FacetedSelector.js +41 -113
  54. package/esm/HierarchicalTrackSelectorWidget/components/tree/DropdownTrackSelector.d.ts +12 -0
  55. package/esm/HierarchicalTrackSelectorWidget/components/tree/DropdownTrackSelector.js +31 -0
  56. package/esm/HierarchicalTrackSelectorWidget/components/tree/FavoriteTracks.d.ts +6 -0
  57. package/esm/HierarchicalTrackSelectorWidget/components/tree/FavoriteTracks.js +40 -0
  58. package/esm/HierarchicalTrackSelectorWidget/components/tree/HamburgerMenu.js +71 -46
  59. package/esm/HierarchicalTrackSelectorWidget/components/tree/HierarchicalHeader.js +6 -12
  60. package/esm/HierarchicalTrackSelectorWidget/components/tree/HierarchicalTree.js +8 -3
  61. package/esm/HierarchicalTrackSelectorWidget/components/tree/RecentlyUsedTracks.d.ts +6 -0
  62. package/esm/HierarchicalTrackSelectorWidget/components/tree/RecentlyUsedTracks.js +37 -0
  63. package/esm/HierarchicalTrackSelectorWidget/components/tree/TrackCategory.js +7 -6
  64. package/esm/HierarchicalTrackSelectorWidget/components/tree/TrackLabel.js +8 -27
  65. package/esm/HierarchicalTrackSelectorWidget/components/tree/TrackLabelMenu.d.ts +12 -0
  66. package/esm/HierarchicalTrackSelectorWidget/components/tree/TrackLabelMenu.js +45 -0
  67. package/esm/HierarchicalTrackSelectorWidget/components/util.d.ts +3 -0
  68. package/esm/HierarchicalTrackSelectorWidget/components/util.js +5 -1
  69. package/esm/HierarchicalTrackSelectorWidget/facetedModel.d.ts +128 -0
  70. package/esm/HierarchicalTrackSelectorWidget/facetedModel.js +202 -0
  71. package/esm/HierarchicalTrackSelectorWidget/facetedUtil.d.ts +2 -0
  72. package/esm/HierarchicalTrackSelectorWidget/{components/faceted/util.js → facetedUtil.js} +3 -0
  73. package/esm/HierarchicalTrackSelectorWidget/generateHierarchy.d.ts +17 -5
  74. package/esm/HierarchicalTrackSelectorWidget/generateHierarchy.js +27 -21
  75. package/esm/HierarchicalTrackSelectorWidget/model.d.ts +193 -15
  76. package/esm/HierarchicalTrackSelectorWidget/model.js +211 -24
  77. package/esm/ucsc-trackhub/doConnect.d.ts +1 -0
  78. package/esm/ucsc-trackhub/doConnect.js +127 -0
  79. package/esm/ucsc-trackhub/model.d.ts +19 -2
  80. package/esm/ucsc-trackhub/model.js +17 -72
  81. package/esm/ucsc-trackhub/ucscTrackHub.d.ts +161 -4
  82. package/esm/ucsc-trackhub/ucscTrackHub.js +48 -141
  83. package/package.json +3 -4
  84. package/dist/HierarchicalTrackSelectorWidget/components/faceted/util.d.ts +0 -1
  85. package/esm/HierarchicalTrackSelectorWidget/components/faceted/util.d.ts +0 -1
@@ -1,14 +1,11 @@
1
1
  import React from 'react';
2
2
  import { Checkbox, FormControlLabel, Tooltip } from '@mui/material';
3
3
  import { makeStyles } from 'tss-react/mui';
4
- import { getSession } from '@jbrowse/core/util';
5
4
  import SanitizedHTML from '@jbrowse/core/ui/SanitizedHTML';
6
5
  import { readConfObject, } from '@jbrowse/core/configuration';
7
- // icons
8
- import MoreHorizIcon from '@mui/icons-material/MoreHoriz';
9
6
  // locals
10
7
  import { isUnsupported } from '../util';
11
- import CascadingMenuButton from '@jbrowse/core/ui/CascadingMenuButton';
8
+ import TrackLabelMenu from './TrackLabelMenu';
12
9
  const useStyles = makeStyles()(theme => ({
13
10
  compactCheckbox: {
14
11
  padding: 0,
@@ -19,36 +16,20 @@ const useStyles = makeStyles()(theme => ({
19
16
  backgroundColor: theme.palette.action.selected,
20
17
  },
21
18
  },
19
+ selected: {
20
+ background: '#cccc',
21
+ },
22
22
  }));
23
23
  export default function TrackLabel({ data }) {
24
24
  const { classes } = useStyles();
25
- const { checked, conf, model, drawerPosition, id, name, onChange, selected } = data;
26
- const description = (conf && readConfObject(conf, ['description'])) || '';
25
+ const { checked, conf, model, drawerPosition, id, trackId, name, onChange, selected, } = data;
26
+ const description = (conf && readConfObject(conf, 'description')) || '';
27
27
  return (React.createElement(React.Fragment, null,
28
28
  React.createElement(Tooltip, { title: description + (selected ? ' (in selection)' : ''), placement: drawerPosition === 'left' ? 'right' : 'left' },
29
- React.createElement(FormControlLabel, { className: classes.checkboxLabel, control: React.createElement(Checkbox, { className: classes.compactCheckbox, checked: checked, onChange: () => onChange(id), disabled: isUnsupported(name), inputProps: {
29
+ React.createElement(FormControlLabel, { className: classes.checkboxLabel, control: React.createElement(Checkbox, { className: classes.compactCheckbox, checked: checked, onChange: () => onChange(trackId), disabled: isUnsupported(name), inputProps: {
30
30
  // @ts-expect-error
31
31
  'data-testid': `htsTrackEntry-${id}`,
32
32
  } }), label: React.createElement("div", { "data-testid": `htsTrackLabel-${id}`, style: { background: selected ? '#cccc' : undefined } },
33
33
  React.createElement(SanitizedHTML, { html: name })) })),
34
- React.createElement(TrackMenuButton, { model: model, selected: selected, id: id, conf: conf })));
35
- }
36
- function TrackMenuButton({ id, model, selected, conf, }) {
37
- var _a, _b;
38
- return (React.createElement(CascadingMenuButton, { style: { padding: 0 }, "data-testid": `htsTrackEntryMenu-${id}`, menuItems: [
39
- ...(((_b = (_a = getSession(model)).getTrackActionMenuItems) === null || _b === void 0 ? void 0 : _b.call(_a, conf)) || []),
40
- {
41
- label: 'Add to selection',
42
- onClick: () => model.addToSelection([conf]),
43
- },
44
- ...(selected
45
- ? [
46
- {
47
- label: 'Remove from selection',
48
- onClick: () => model.removeFromSelection([conf]),
49
- },
50
- ]
51
- : []),
52
- ] },
53
- React.createElement(MoreHorizIcon, null)));
34
+ React.createElement(TrackLabelMenu, { model: model, trackId: trackId, id: id, conf: conf })));
54
35
  }
@@ -0,0 +1,12 @@
1
+ import React from 'react';
2
+ import { AnyConfigurationModel } from '@jbrowse/core/configuration';
3
+ import { HierarchicalTrackSelectorModel } from '../../model';
4
+ declare const TrackLabelMenu: ({ id, trackId, stopPropagation, model, setOpen, conf, }: {
5
+ id: string;
6
+ trackId: string;
7
+ stopPropagation?: boolean | undefined;
8
+ conf: AnyConfigurationModel;
9
+ setOpen?: ((arg: boolean) => void) | undefined;
10
+ model: HierarchicalTrackSelectorModel;
11
+ }) => React.JSX.Element;
12
+ export default TrackLabelMenu;
@@ -0,0 +1,45 @@
1
+ import React from 'react';
2
+ import { makeStyles } from 'tss-react/mui';
3
+ import { getSession } from '@jbrowse/core/util';
4
+ import CascadingMenuButton from '@jbrowse/core/ui/CascadingMenuButton';
5
+ // icons
6
+ import MoreHorizIcon from '@mui/icons-material/MoreHoriz';
7
+ import StarIcon from '@mui/icons-material/StarBorderOutlined';
8
+ import FilledStarIcon from '@mui/icons-material/Star';
9
+ const useStyles = makeStyles()({
10
+ cascadingStyle: {
11
+ padding: 0,
12
+ },
13
+ });
14
+ const TrackLabelMenu = function ({ id, trackId, stopPropagation, model, setOpen, conf, }) {
15
+ var _a, _b;
16
+ const { classes } = useStyles();
17
+ return (React.createElement(CascadingMenuButton, { className: classes.cascadingStyle, stopPropagation: stopPropagation, setOpen: setOpen, "data-testid": `htsTrackEntryMenu-${id}`, menuItems: [
18
+ ...(((_b = (_a = getSession(model)).getTrackActionMenuItems) === null || _b === void 0 ? void 0 : _b.call(_a, conf)) || []),
19
+ model.isFavorite(trackId)
20
+ ? {
21
+ label: 'Remove from favorites',
22
+ onClick: () => model.removeFromFavorites(trackId),
23
+ icon: StarIcon,
24
+ }
25
+ : {
26
+ label: 'Add to favorites',
27
+ onClick: () => model.addToFavorites(trackId),
28
+ icon: FilledStarIcon,
29
+ },
30
+ {
31
+ label: 'Add to selection',
32
+ onClick: () => model.addToSelection([conf]),
33
+ },
34
+ ...(model.isSelected(conf)
35
+ ? [
36
+ {
37
+ label: 'Remove from selection',
38
+ onClick: () => model.removeFromSelection([conf]),
39
+ },
40
+ ]
41
+ : []),
42
+ ] },
43
+ React.createElement(MoreHorizIcon, null)));
44
+ };
45
+ export default TrackLabelMenu;
@@ -1,18 +1,21 @@
1
1
  import { AnyConfigurationModel } from '@jbrowse/core/configuration';
2
2
  import { HierarchicalTrackSelectorModel } from '../model';
3
3
  import { TreeNode } from '../generateHierarchy';
4
+ import { MenuItem } from '@jbrowse/core/ui';
4
5
  export interface NodeData {
5
6
  nestingLevel: number;
6
7
  checked: boolean;
7
8
  conf: AnyConfigurationModel;
8
9
  drawerPosition: unknown;
9
10
  id: string;
11
+ trackId: string;
10
12
  isLeaf: boolean;
11
13
  name: string;
12
14
  onChange: Function;
13
15
  toggleCollapse: (arg: string) => void;
14
16
  tree: TreeNode;
15
17
  selected: boolean;
18
+ menuItems?: MenuItem[];
16
19
  model: HierarchicalTrackSelectorModel;
17
20
  }
18
21
  export declare function getAllChildren(subtree?: TreeNode): AnyConfigurationModel[];
@@ -1,6 +1,10 @@
1
1
  export function getAllChildren(subtree) {
2
2
  // @ts-expect-error
3
- return ((subtree === null || subtree === void 0 ? void 0 : subtree.children.map(t => t.children.length ? getAllChildren(t) : t.conf)) || []).flat(Infinity);
3
+ return (subtree === null || subtree === void 0 ? void 0 : subtree.type) === 'category'
4
+ ? subtree.children
5
+ .map(t => (t.type === 'category' ? getAllChildren(t) : t.conf))
6
+ .flat(Infinity)
7
+ : [];
4
8
  }
5
9
  export function treeToMap(tree, map = new Map()) {
6
10
  if (tree.id && tree.children.length) {
@@ -0,0 +1,128 @@
1
+ import { Instance } from 'mobx-state-tree';
2
+ /**
3
+ * #stateModel FacetedModel
4
+ */
5
+ export declare function facetedStateTreeF(): import("mobx-state-tree").IModelType<{
6
+ /**
7
+ * #property
8
+ */
9
+ filterText: import("mobx-state-tree").IOptionalIType<import("mobx-state-tree").ISimpleType<string>, [undefined]>;
10
+ /**
11
+ * #property
12
+ */
13
+ showSparse: import("mobx-state-tree").IOptionalIType<import("mobx-state-tree").ISimpleType<boolean>, [undefined]>;
14
+ /**
15
+ * #property
16
+ */
17
+ showFilters: import("mobx-state-tree").IOptionalIType<import("mobx-state-tree").ISimpleType<boolean>, [undefined]>;
18
+ /**
19
+ * #property
20
+ */
21
+ showOptions: import("mobx-state-tree").IOptionalIType<import("mobx-state-tree").ISimpleType<boolean>, [undefined]>;
22
+ /**
23
+ * #property
24
+ */
25
+ panelWidth: import("mobx-state-tree").IOptionalIType<import("mobx-state-tree").ISimpleType<number>, [undefined]>;
26
+ }, {
27
+ visible: Record<string, boolean>;
28
+ widths: Record<string, number | undefined>;
29
+ useShoppingCart: boolean;
30
+ filters: import("mobx").ObservableMap<string, string[]>;
31
+ } & {
32
+ /**
33
+ * #action
34
+ */
35
+ setFilter(key: string, value: string[]): void;
36
+ /**
37
+ * #action
38
+ */
39
+ setPanelWidth(width: number): void;
40
+ /**
41
+ * #action
42
+ */
43
+ setUseShoppingCart(f: boolean): void;
44
+ /**
45
+ * #action
46
+ */
47
+ setFilterText(str: string): void;
48
+ /**
49
+ * #action
50
+ */
51
+ setShowSparse(f: boolean): void;
52
+ /**
53
+ * #action
54
+ */
55
+ setShowOptions(f: boolean): void;
56
+ /**
57
+ * #action
58
+ */
59
+ setShowFilters(f: boolean): void;
60
+ } & {
61
+ /**
62
+ * #getter
63
+ */
64
+ readonly allTrackConfigurations: ({
65
+ [x: string]: any;
66
+ } & import("mobx-state-tree/dist/internal").NonEmptyObject & {
67
+ setSubschema(slotName: string, data: unknown): any;
68
+ } & import("mobx-state-tree").IStateTreeNode<import("@jbrowse/core/configuration").AnyConfigurationSchemaType>)[];
69
+ } & {
70
+ /**
71
+ * #getter
72
+ */
73
+ readonly rows: {
74
+ readonly id: string;
75
+ readonly conf: {
76
+ [x: string]: any;
77
+ } & import("mobx-state-tree/dist/internal").NonEmptyObject & {
78
+ setSubschema(slotName: string, data: unknown): any;
79
+ } & import("mobx-state-tree").IStateTreeNode<import("@jbrowse/core/configuration").AnyConfigurationSchemaType>;
80
+ readonly name: string;
81
+ readonly category: string;
82
+ readonly adapter: string;
83
+ readonly description: string;
84
+ readonly metadata: any;
85
+ }[];
86
+ } & {
87
+ /**
88
+ * #getter
89
+ */
90
+ readonly filteredNonMetadataKeys: string[] | readonly ["category", "adapter", "description"];
91
+ /**
92
+ * #getter
93
+ */
94
+ readonly metadataKeys: string[];
95
+ readonly filteredMetadataKeys: string[];
96
+ /**
97
+ * #getter
98
+ */
99
+ readonly fields: string[];
100
+ /**
101
+ * #getter
102
+ */
103
+ readonly filteredRows: {
104
+ readonly id: string;
105
+ readonly conf: {
106
+ [x: string]: any;
107
+ } & import("mobx-state-tree/dist/internal").NonEmptyObject & {
108
+ setSubschema(slotName: string, data: unknown): any;
109
+ } & import("mobx-state-tree").IStateTreeNode<import("@jbrowse/core/configuration").AnyConfigurationSchemaType>;
110
+ readonly name: string;
111
+ readonly category: string;
112
+ readonly adapter: string;
113
+ readonly description: string;
114
+ readonly metadata: any;
115
+ }[];
116
+ } & {
117
+ /**
118
+ * #action
119
+ */
120
+ setVisible(args: Record<string, boolean>): void;
121
+ /**
122
+ * #action
123
+ */
124
+ setWidths(args: Record<string, number | undefined>): void;
125
+ afterAttach(): void;
126
+ }, import("mobx-state-tree")._NotCustomized, import("mobx-state-tree")._NotCustomized>;
127
+ export type FacetedStateModel = ReturnType<typeof facetedStateTreeF>;
128
+ export type FacetedModel = Instance<FacetedStateModel>;
@@ -0,0 +1,202 @@
1
+ import { addDisposer, getParent, types } from 'mobx-state-tree';
2
+ import { matches } from './util';
3
+ import { readConfObject, } from '@jbrowse/core/configuration';
4
+ import { getTrackName } from '@jbrowse/core/util/tracks';
5
+ import { getSession, localStorageGetItem, measureGridWidth, } from '@jbrowse/core/util';
6
+ import { autorun, observable } from 'mobx';
7
+ import { getRootKeys, findNonSparseKeys } from './facetedUtil';
8
+ const nonMetadataKeys = ['category', 'adapter', 'description'];
9
+ /**
10
+ * #stateModel FacetedModel
11
+ */
12
+ export function facetedStateTreeF() {
13
+ return types
14
+ .model('FacetedModel', {
15
+ /**
16
+ * #property
17
+ */
18
+ filterText: types.optional(types.string, ''),
19
+ /**
20
+ * #property
21
+ */
22
+ showSparse: types.optional(types.boolean, () => JSON.parse(localStorageGetItem('facet-showSparse') || 'false')),
23
+ /**
24
+ * #property
25
+ */
26
+ showFilters: types.optional(types.boolean, () => JSON.parse(localStorageGetItem('facet-showFilters') || 'true')),
27
+ /**
28
+ * #property
29
+ */
30
+ showOptions: types.optional(types.boolean, () => JSON.parse(localStorageGetItem('facet-showTableOptions') || 'false')),
31
+ /**
32
+ * #property
33
+ */
34
+ panelWidth: types.optional(types.number, () => JSON.parse(localStorageGetItem('facet-panelWidth') || '400')),
35
+ })
36
+ .volatile(() => ({
37
+ visible: {},
38
+ widths: {},
39
+ useShoppingCart: false,
40
+ filters: observable.map(),
41
+ }))
42
+ .actions(self => ({
43
+ /**
44
+ * #action
45
+ */
46
+ setFilter(key, value) {
47
+ self.filters.set(key, value);
48
+ },
49
+ /**
50
+ * #action
51
+ */
52
+ setPanelWidth(width) {
53
+ self.panelWidth = width;
54
+ },
55
+ /**
56
+ * #action
57
+ */
58
+ setUseShoppingCart(f) {
59
+ self.useShoppingCart = f;
60
+ },
61
+ /**
62
+ * #action
63
+ */
64
+ setFilterText(str) {
65
+ self.filterText = str;
66
+ },
67
+ /**
68
+ * #action
69
+ */
70
+ setShowSparse(f) {
71
+ self.showSparse = f;
72
+ },
73
+ /**
74
+ * #action
75
+ */
76
+ setShowOptions(f) {
77
+ self.showOptions = f;
78
+ },
79
+ /**
80
+ * #action
81
+ */
82
+ setShowFilters(f) {
83
+ self.showFilters = f;
84
+ },
85
+ }))
86
+ .views(self => ({
87
+ /**
88
+ * #getter
89
+ */
90
+ get allTrackConfigurations() {
91
+ return getParent(self).allTrackConfigurations;
92
+ },
93
+ }))
94
+ .views(self => ({
95
+ /**
96
+ * #getter
97
+ */
98
+ get rows() {
99
+ const session = getSession(self);
100
+ 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
+ return allTrackConfigurations
104
+ .filter(conf => matches(filterText, conf, session))
105
+ .map(track => {
106
+ var _a, _b;
107
+ const metadata = readConfObject(track, 'metadata');
108
+ return {
109
+ id: track.trackId,
110
+ conf: track,
111
+ name: getTrackName(track, session),
112
+ category: (_a = readConfObject(track, 'category')) === null || _a === void 0 ? void 0 : _a.join(', '),
113
+ adapter: (_b = readConfObject(track, 'adapter')) === null || _b === void 0 ? void 0 : _b.type,
114
+ description: readConfObject(track, 'description'),
115
+ metadata,
116
+ };
117
+ });
118
+ },
119
+ }))
120
+ .views(self => ({
121
+ /**
122
+ * #getter
123
+ */
124
+ get filteredNonMetadataKeys() {
125
+ return self.showSparse
126
+ ? nonMetadataKeys
127
+ : findNonSparseKeys(nonMetadataKeys, self.rows, (r, f) => r[f]);
128
+ },
129
+ /**
130
+ * #getter
131
+ */
132
+ get metadataKeys() {
133
+ return [...new Set(self.rows.flatMap(row => getRootKeys(row.metadata)))];
134
+ },
135
+ get filteredMetadataKeys() {
136
+ return self.showSparse
137
+ ? this.metadataKeys
138
+ : findNonSparseKeys(this.metadataKeys, self.rows,
139
+ // @ts-expect-error
140
+ (r, f) => r.metadata[f]);
141
+ },
142
+ /**
143
+ * #getter
144
+ */
145
+ get fields() {
146
+ return [
147
+ 'name',
148
+ ...this.filteredNonMetadataKeys,
149
+ ...this.filteredMetadataKeys.map(m => `metadata.${m}`),
150
+ ];
151
+ },
152
+ /**
153
+ * #getter
154
+ */
155
+ get filteredRows() {
156
+ const arrFilters = [...self.filters.entries()]
157
+ .filter(f => f[1].length > 0)
158
+ .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])));
162
+ },
163
+ }))
164
+ .actions(self => ({
165
+ /**
166
+ * #action
167
+ */
168
+ setVisible(args) {
169
+ self.visible = args;
170
+ },
171
+ /**
172
+ * #action
173
+ */
174
+ setWidths(args) {
175
+ self.widths = args;
176
+ },
177
+ afterAttach() {
178
+ addDisposer(self, autorun(() => {
179
+ this.setVisible(Object.fromEntries(self.fields.map(c => [c, true])));
180
+ }));
181
+ addDisposer(self, autorun(() => {
182
+ this.setWidths({
183
+ name: measureGridWidth(self.rows.map(r => r.name), { maxWidth: 500, stripHTML: true }) + 15,
184
+ ...Object.fromEntries(self.filteredNonMetadataKeys
185
+ .filter(f => self.visible[f])
186
+ .map(e => [
187
+ e,
188
+ measureGridWidth(self.rows.map(r => r[e]), { maxWidth: 400, stripHTML: true }),
189
+ ])),
190
+ ...Object.fromEntries(self.filteredMetadataKeys
191
+ .filter(f => self.visible['metadata.' + f])
192
+ .map(e => {
193
+ return [
194
+ 'metadata.' + e,
195
+ measureGridWidth(self.rows.map(r => r.metadata[e]), { maxWidth: 400, stripHTML: true }),
196
+ ];
197
+ })),
198
+ });
199
+ }));
200
+ },
201
+ }));
202
+ }
@@ -0,0 +1,2 @@
1
+ export declare function findNonSparseKeys(keys: readonly string[], rows: Record<string, unknown>[], cb: (row: Record<string, unknown>, f: string) => unknown): string[];
2
+ export declare function getRootKeys(obj: Record<string, unknown>): string[];
@@ -1,3 +1,6 @@
1
+ export function findNonSparseKeys(keys, rows, cb) {
2
+ return keys.filter(f => rows.map(r => cb(r, f)).filter(f => !!f).length > 5);
3
+ }
1
4
  export function getRootKeys(obj) {
2
5
  return Object.entries(obj)
3
6
  .map(([key, val]) => (typeof val === 'string' ? key : ''))
@@ -1,13 +1,23 @@
1
1
  import { AnyConfigurationModel } from '@jbrowse/core/configuration';
2
- export interface TreeNode {
2
+ import { MenuItem } from '@jbrowse/core/ui';
3
+ export interface TreeTrackNode {
3
4
  name: string;
4
5
  id: string;
5
- conf?: AnyConfigurationModel;
6
- checked?: boolean;
7
- isOpenByDefault?: boolean;
6
+ trackId: string;
7
+ conf: AnyConfigurationModel;
8
+ checked: boolean;
8
9
  children: TreeNode[];
10
+ type: 'track';
9
11
  }
10
- export declare function generateHierarchy({ model, trackConfs, extra, }: {
12
+ export interface TreeCategoryNode {
13
+ name: string;
14
+ id: string;
15
+ isOpenByDefault: boolean;
16
+ children: TreeNode[];
17
+ type: 'category';
18
+ }
19
+ export type TreeNode = TreeTrackNode | TreeCategoryNode;
20
+ export declare function generateHierarchy({ model, trackConfs, extra, noCategories, menuItems, }: {
11
21
  model: {
12
22
  filterText: string;
13
23
  activeSortTrackNames: boolean;
@@ -19,6 +29,8 @@ export declare function generateHierarchy({ model, trackConfs, extra, }: {
19
29
  }[];
20
30
  };
21
31
  };
32
+ noCategories?: boolean;
33
+ menuItems?: MenuItem[];
22
34
  trackConfs: AnyConfigurationModel[];
23
35
  extra?: string;
24
36
  }): TreeNode[];
@@ -37,7 +37,7 @@ function sortConfs(confs, sortNames, sortCategories) {
37
37
  }
38
38
  return ret.map(a => a[0]);
39
39
  }
40
- export function generateHierarchy({ model, trackConfs, extra, }) {
40
+ export function generateHierarchy({ model, trackConfs, extra, noCategories, menuItems, }) {
41
41
  const hierarchy = { children: [] };
42
42
  const { collapsed, filterText, activeSortTrackNames, activeSortCategories, view, } = model;
43
43
  if (!view) {
@@ -56,25 +56,29 @@ export function generateHierarchy({ model, trackConfs, extra, }) {
56
56
  categories.unshift(' Session tracks');
57
57
  }
58
58
  let currLevel = hierarchy;
59
- // find existing category to put track into or create it
60
- for (let i = 0; i < categories.length; i++) {
61
- const category = categories[i];
62
- const ret = currLevel.children.find(c => c.name === category);
63
- const id = [extra, categories.slice(0, i + 1).join(',')]
64
- .filter(f => !!f)
65
- .join('-');
66
- if (!ret) {
67
- const n = {
68
- children: [],
69
- name: category,
70
- id,
71
- isOpenByDefault: !collapsed.get(id),
72
- };
73
- currLevel.children.push(n);
74
- currLevel = n;
75
- }
76
- else {
77
- currLevel = ret;
59
+ if (!noCategories) {
60
+ // find existing category to put track into or create it
61
+ for (let i = 0; i < categories.length; i++) {
62
+ const category = categories[i];
63
+ const ret = currLevel.children.find(c => c.name === category);
64
+ const id = [extra, categories.slice(0, i + 1).join(',')]
65
+ .filter(f => !!f)
66
+ .join('-');
67
+ if (!ret) {
68
+ const n = {
69
+ children: [],
70
+ name: category,
71
+ id,
72
+ isOpenByDefault: !collapsed.get(id),
73
+ menuItems,
74
+ type: 'category',
75
+ };
76
+ currLevel.children.push(n);
77
+ currLevel = n;
78
+ }
79
+ else {
80
+ currLevel = ret;
81
+ }
78
82
  }
79
83
  }
80
84
  // uses splice to try to put all leaf nodes above "category nodes" if you
@@ -83,11 +87,13 @@ export function generateHierarchy({ model, trackConfs, extra, }) {
83
87
  const r = currLevel.children.findIndex(elt => elt.children.length);
84
88
  const idx = r === -1 ? currLevel.children.length : r;
85
89
  currLevel.children.splice(idx, 0, {
86
- id: conf.trackId,
90
+ id: [extra, conf.trackId].filter(f => !!f).join(','),
91
+ trackId: conf.trackId,
87
92
  name: getTrackName(conf, session),
88
93
  conf,
89
94
  checked: viewTracks.some(f => f.configuration === conf),
90
95
  children: [],
96
+ type: 'track',
91
97
  });
92
98
  }
93
99
  return hierarchy.children;