@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.
Files changed (29) hide show
  1. package/dist/AddTrackWidget/components/DefaultAddTrackWorkflow.js +4 -8
  2. package/dist/HierarchicalTrackSelectorWidget/components/faceted/FacetFilter.d.ts +1 -2
  3. package/dist/HierarchicalTrackSelectorWidget/components/faceted/FacetFilter.js +6 -5
  4. package/dist/HierarchicalTrackSelectorWidget/components/faceted/FacetFilters.d.ts +3 -3
  5. package/dist/HierarchicalTrackSelectorWidget/components/faceted/FacetFilters.js +7 -7
  6. package/dist/HierarchicalTrackSelectorWidget/components/faceted/FacetedSelector.js +3 -9
  7. package/dist/HierarchicalTrackSelectorWidget/components/faceted/util.d.ts +6 -0
  8. package/dist/HierarchicalTrackSelectorWidget/components/faceted/util.js +10 -0
  9. package/dist/HierarchicalTrackSelectorWidget/components/tree/DropdownTrackSelector.js +3 -1
  10. package/dist/HierarchicalTrackSelectorWidget/components/tree/FavoriteTracks.js +5 -2
  11. package/dist/HierarchicalTrackSelectorWidget/facetedModel.d.ts +2 -2
  12. package/dist/HierarchicalTrackSelectorWidget/facetedModel.js +3 -7
  13. package/dist/HierarchicalTrackSelectorWidget/model.d.ts +43 -40
  14. package/dist/HierarchicalTrackSelectorWidget/model.js +71 -32
  15. package/esm/AddTrackWidget/components/DefaultAddTrackWorkflow.js +4 -8
  16. package/esm/HierarchicalTrackSelectorWidget/components/faceted/FacetFilter.d.ts +1 -2
  17. package/esm/HierarchicalTrackSelectorWidget/components/faceted/FacetFilter.js +6 -5
  18. package/esm/HierarchicalTrackSelectorWidget/components/faceted/FacetFilters.d.ts +3 -3
  19. package/esm/HierarchicalTrackSelectorWidget/components/faceted/FacetFilters.js +7 -7
  20. package/esm/HierarchicalTrackSelectorWidget/components/faceted/FacetedSelector.js +3 -9
  21. package/esm/HierarchicalTrackSelectorWidget/components/faceted/util.d.ts +6 -0
  22. package/esm/HierarchicalTrackSelectorWidget/components/faceted/util.js +6 -0
  23. package/esm/HierarchicalTrackSelectorWidget/components/tree/DropdownTrackSelector.js +3 -1
  24. package/esm/HierarchicalTrackSelectorWidget/components/tree/FavoriteTracks.js +5 -2
  25. package/esm/HierarchicalTrackSelectorWidget/facetedModel.d.ts +2 -2
  26. package/esm/HierarchicalTrackSelectorWidget/facetedModel.js +3 -7
  27. package/esm/HierarchicalTrackSelectorWidget/model.d.ts +43 -40
  28. package/esm/HierarchicalTrackSelectorWidget/model.js +71 -32
  29. package/package.json +2 -3
@@ -122,9 +122,6 @@ const DefaultAddTrackWorkflow = (0, mobx_react_1.observer)(function ({ model, })
122
122
  };
123
123
  jobsManager.queueJob(newEntry);
124
124
  }
125
- else {
126
- session.notify('Open a new view, or use the track selector in an existing view, to view this track', 'info');
127
- }
128
125
  model.clearData();
129
126
  if ((0, util_1.isSessionModelWithWidgets)(session)) {
130
127
  session.hideWidget(model);
@@ -134,10 +131,6 @@ const DefaultAddTrackWorkflow = (0, mobx_react_1.observer)(function ({ model, })
134
131
  setTrackErrorMessage('Failed to add track.\nThe configuration of this file is not currently supported.');
135
132
  }
136
133
  }
137
- function handleBack() {
138
- setTrackErrorMessage(undefined);
139
- setActiveStep(activeStep - 1);
140
- }
141
134
  function isNextDisabled() {
142
135
  switch (activeStep) {
143
136
  case 0:
@@ -154,7 +147,10 @@ const DefaultAddTrackWorkflow = (0, mobx_react_1.observer)(function ({ model, })
154
147
  react_1.default.createElement(material_1.StepContent, null,
155
148
  getStepContent(idx),
156
149
  react_1.default.createElement("div", { className: classes.actionsContainer },
157
- react_1.default.createElement(material_1.Button, { disabled: activeStep === 0, onClick: handleBack, className: classes.button }, "Back"),
150
+ react_1.default.createElement(material_1.Button, { disabled: activeStep === 0, onClick: () => {
151
+ setTrackErrorMessage(undefined);
152
+ setActiveStep(activeStep - 1);
153
+ }, className: classes.button }, "Back"),
158
154
  react_1.default.createElement(material_1.Button, { disabled: isNextDisabled(), variant: "contained", color: "primary", onClick: handleNext, className: classes.button, "data-testid": "addTrackNextButton" }, activeStep === steps.length - 1 ? 'Add' : 'Next')),
159
155
  trackErrorMessage ? (react_1.default.createElement("div", { className: classes.alertContainer },
160
156
  react_1.default.createElement(material_1.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, width, model, }: {
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;
@@ -53,15 +53,16 @@ function ExpandButton({ visible, onClick, }) {
53
53
  return (react_1.default.createElement(material_1.Tooltip, { title: "Minimize/expand this facet filter" },
54
54
  react_1.default.createElement(material_1.IconButton, { onClick: () => onClick(), size: "small" }, visible ? react_1.default.createElement(Minimize_1.default, null) : react_1.default.createElement(Add_1.default, null))));
55
55
  }
56
- const FacetFilter = (0, mobx_react_1.observer)(function ({ column, vals, width, model, }) {
56
+ const FacetFilter = (0, mobx_react_1.observer)(function ({ column, vals, model, }) {
57
57
  const { classes } = useStyles();
58
58
  const [visible, setVisible] = (0, react_1.useState)(true);
59
59
  const { faceted } = model;
60
60
  const { filters } = faceted;
61
- return (react_1.default.createElement(material_1.FormControl, { key: column.field, className: classes.facet, style: { width } },
62
- react_1.default.createElement("div", { style: { display: 'flex' } },
63
- react_1.default.createElement(material_1.Typography, null, column.field),
64
- react_1.default.createElement(ClearButton, { onClick: () => model.faceted.setFilter(column.field, []) }),
61
+ const { field } = column;
62
+ return (react_1.default.createElement(material_1.FormControl, { className: classes.facet, fullWidth: true },
63
+ react_1.default.createElement("div", null,
64
+ react_1.default.createElement(material_1.Typography, { component: "span" }, field),
65
+ react_1.default.createElement(ClearButton, { onClick: () => faceted.setFilter(field, []) }),
65
66
  react_1.default.createElement(ExpandButton, { visible: visible, onClick: () => setVisible(!visible) })),
66
67
  visible ? (react_1.default.createElement(material_1.Select, { multiple: true, native: true, className: classes.select, value: filters.get(column.field) || [], onChange: event => {
67
68
  faceted.setFilter(column.field,
@@ -1,11 +1,11 @@
1
1
  import React from 'react';
2
2
  import { HierarchicalTrackSelectorModel } from '../../model';
3
- declare const FacetFilters: ({ rows, columns, width, model, }: {
4
- rows: Record<string, unknown>[];
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;
@@ -4,9 +4,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const react_1 = __importDefault(require("react"));
7
- const FacetFilter_1 = __importDefault(require("./FacetFilter"));
8
7
  const mobx_react_1 = require("mobx-react");
9
- const FacetFilters = (0, mobx_react_1.observer)(function ({ rows, columns, width, model, }) {
8
+ // locals
9
+ const FacetFilter_1 = __importDefault(require("./FacetFilter"));
10
+ const util_1 = require("./util");
11
+ const FacetFilters = (0, mobx_react_1.observer)(function ({ rows, columns, model, }) {
10
12
  var _a, _b;
11
13
  const { faceted } = model;
12
14
  const { filters } = faceted;
@@ -31,7 +33,7 @@ const FacetFilters = (0, mobx_react_1.observer)(function ({ rows, columns, width
31
33
  for (const facet of ret) {
32
34
  const elt = uniqs.get(facet);
33
35
  for (const row of currentRows) {
34
- const key = `${row[facet] || ''}`;
36
+ const key = (0, util_1.getRowStr)(facet, row);
35
37
  const val = elt.get(key);
36
38
  // we don't allow filtering on empty yet
37
39
  if (key) {
@@ -46,10 +48,8 @@ const FacetFilters = (0, mobx_react_1.observer)(function ({ rows, columns, width
46
48
  const filter = ((_b = filters.get(facet)) === null || _b === void 0 ? void 0 : _b.length)
47
49
  ? new Set(filters.get(facet))
48
50
  : undefined;
49
- currentRows = currentRows.filter(row => {
50
- return filter !== undefined ? filter.has(row[facet]) : true;
51
- });
51
+ currentRows = currentRows.filter(row => filter !== undefined ? filter.has((0, util_1.getRowStr)(facet, row)) : true);
52
52
  }
53
- return (react_1.default.createElement("div", null, facets.map(column => (react_1.default.createElement(FacetFilter_1.default, { key: column.field, vals: [...uniqs.get(column.field)], column: column, width: width, model: model })))));
53
+ return (react_1.default.createElement("div", null, facets.map(c => (react_1.default.createElement(FacetFilter_1.default, { key: c.field, vals: [...uniqs.get(c.field)], column: c, model: model })))));
54
54
  });
55
55
  exports.default = FacetFilters;
@@ -34,11 +34,10 @@ const frac = 0.75;
34
34
  const FacetedSelector = (0, mobx_react_1.observer)(function FacetedSelector({ model, }) {
35
35
  var _a;
36
36
  const { classes } = useStyles();
37
- const { view, selection, faceted } = model;
37
+ const { view, selection, shownTrackIds, faceted } = model;
38
38
  const { rows, panelWidth, showFilters, useShoppingCart, showOptions, filteredRows, filteredNonMetadataKeys, filteredMetadataKeys, visible, widths, } = faceted;
39
39
  const { pluginManager } = (0, util_1.getEnv)(model);
40
40
  const { ref, scrollLeft } = (0, useResizeBar_1.useResizeBar)();
41
- const tracks = view.tracks;
42
41
  const widthsDebounced = (0, util_1.useDebounce)(widths, 200);
43
42
  const columns = [
44
43
  {
@@ -80,7 +79,6 @@ const FacetedSelector = (0, mobx_react_1.observer)(function FacetedSelector({ mo
80
79
  });
81
80
  }),
82
81
  ];
83
- const shownTrackIds = new Set(tracks.map(t => t.configuration.trackId));
84
82
  return (react_1.default.createElement(react_1.default.Fragment, null,
85
83
  react_1.default.createElement(FacetedHeader_1.default, { model: model }),
86
84
  react_1.default.createElement("div", { ref: ref, style: {
@@ -130,11 +128,7 @@ const FacetedSelector = (0, mobx_react_1.observer)(function FacetedSelector({ mo
130
128
  }, columns: columns, rowHeight: 25 })),
131
129
  showFilters ? (react_1.default.createElement(react_1.default.Fragment, null,
132
130
  react_1.default.createElement(ui_1.ResizeHandle, { vertical: true, onDrag: dist => faceted.setPanelWidth(panelWidth - dist), className: classes.resizeHandle }),
133
- react_1.default.createElement("div", { style: {
134
- width: panelWidth,
135
- overflowY: 'auto',
136
- overflowX: 'hidden',
137
- } },
138
- react_1.default.createElement(FacetFilters_1.default, { model: model, width: panelWidth - 10, rows: rows, columns: columns })))) : null)));
131
+ react_1.default.createElement("div", { style: { width: panelWidth, overflow: 'auto' } },
132
+ react_1.default.createElement(FacetFilters_1.default, { model: model, rows: rows, columns: columns })))) : null)));
139
133
  });
140
134
  exports.default = FacetedSelector;
@@ -0,0 +1,6 @@
1
+ export interface Row {
2
+ id: string;
3
+ metadata?: Record<string, unknown>;
4
+ [key: string]: unknown;
5
+ }
6
+ export declare function getRowStr(facet: string, row: Row): string;
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getRowStr = void 0;
4
+ function getRowStr(facet, row) {
5
+ var _a;
6
+ return `${(facet.startsWith('metadata.')
7
+ ? (_a = row.metadata) === null || _a === void 0 ? void 0 : _a[facet.replace('metadata.', '')]
8
+ : row[facet]) || ''}`;
9
+ }
10
+ exports.getRowStr = getRowStr;
@@ -47,7 +47,9 @@ const DropdownTrackSelector = (0, mobx_react_1.observer)(function ({ model, trac
47
47
  checked: view.tracks.some((f) => f.configuration === t),
48
48
  onClick: () => {
49
49
  if (!open) {
50
- model.view.toggleTrack(t.trackId);
50
+ if (model.view.toggleTrack(t.trackId)) {
51
+ model.addToRecentlyUsed(t.trackId);
52
+ }
51
53
  }
52
54
  },
53
55
  })),
@@ -6,14 +6,17 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const react_1 = __importDefault(require("react"));
7
7
  const material_1 = require("@mui/material");
8
8
  const mobx_react_1 = require("mobx-react");
9
+ const mui_1 = require("tss-react/mui");
9
10
  // icons
10
11
  const Grade_1 = __importDefault(require("@mui/icons-material/Grade"));
11
12
  const DropdownTrackSelector_1 = __importDefault(require("./DropdownTrackSelector"));
12
- const mui_1 = require("tss-react/mui");
13
13
  const useStyles = (0, mui_1.makeStyles)()({
14
14
  smallBadge: {
15
15
  height: 14,
16
16
  },
17
+ margin: {
18
+ marginRight: 10,
19
+ },
17
20
  });
18
21
  const FavoriteTracks = (0, mobx_react_1.observer)(function ({ model, }) {
19
22
  const { classes } = useStyles();
@@ -36,7 +39,7 @@ const FavoriteTracks = (0, mobx_react_1.observer)(function ({ model, }) {
36
39
  react_1.default.createElement(material_1.Badge, { classes: { badge: classes.smallBadge }, color: "secondary", anchorOrigin: {
37
40
  vertical: 'bottom',
38
41
  horizontal: 'right',
39
- }, style: { marginRight: 10 }, badgeContent: model.favoritesCounter },
42
+ }, className: classes.margin, badgeContent: model.favoritesCounter },
40
43
  react_1.default.createElement(Grade_1.default, null))))) : null;
41
44
  });
42
45
  exports.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: any;
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: any;
114
+ readonly metadata: Record<string, unknown>;
115
115
  }[];
116
116
  } & {
117
117
  /**
@@ -8,6 +8,7 @@ const tracks_1 = require("@jbrowse/core/util/tracks");
8
8
  const util_2 = require("@jbrowse/core/util");
9
9
  const mobx_1 = require("mobx");
10
10
  const facetedUtil_1 = require("./facetedUtil");
11
+ const util_3 = require("./components/faceted/util");
11
12
  const nonMetadataKeys = ['category', 'adapter', 'description'];
12
13
  /**
13
14
  * #stateModel FacetedModel
@@ -101,13 +102,10 @@ function facetedStateTreeF() {
101
102
  get rows() {
102
103
  const session = (0, util_2.getSession)(self);
103
104
  const { allTrackConfigurations, filterText } = self;
104
- // metadata is spread onto the object for easier access and sorting
105
- // by the mui data grid (it's unable to sort by nested objects)
106
105
  return allTrackConfigurations
107
106
  .filter(conf => (0, util_1.matches)(filterText, conf, session))
108
107
  .map(track => {
109
108
  var _a, _b;
110
- const metadata = (0, configuration_1.readConfObject)(track, 'metadata');
111
109
  return {
112
110
  id: track.trackId,
113
111
  conf: track,
@@ -115,7 +113,7 @@ function facetedStateTreeF() {
115
113
  category: (_a = (0, configuration_1.readConfObject)(track, 'category')) === null || _a === void 0 ? void 0 : _a.join(', '),
116
114
  adapter: (_b = (0, configuration_1.readConfObject)(track, 'adapter')) === null || _b === void 0 ? void 0 : _b.type,
117
115
  description: (0, configuration_1.readConfObject)(track, 'description'),
118
- metadata,
116
+ metadata: (0, configuration_1.readConfObject)(track, 'metadata'),
119
117
  };
120
118
  });
121
119
  },
@@ -159,9 +157,7 @@ function facetedStateTreeF() {
159
157
  const arrFilters = [...self.filters.entries()]
160
158
  .filter(f => f[1].length > 0)
161
159
  .map(([key, val]) => [key, new Set(val)]);
162
- return self.rows.filter(row =>
163
- // @ts-expect-error
164
- arrFilters.every(([key, val]) => val.has(row[key])));
160
+ return self.rows.filter(row => arrFilters.every(([key, val]) => val.has((0, util_3.getRowStr)(key, row))));
165
161
  },
166
162
  }))
167
163
  .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: any;
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: any;
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 {};
@@ -25,8 +25,7 @@ function postF() {
25
25
  ].join('-')
26
26
  : 'empty';
27
27
  }
28
- const lsKeyFavoritesF = () => `favoriteTracks-${postF()}}`;
29
- const lsKeyRecentlyUsedF = () => `recentlyUsedTracks-${postF()}}`;
28
+ const MAX_RECENTLY_USED = 10;
30
29
  /**
31
30
  * #stateModel HierarchicalTrackSelectorWidget
32
31
  */
@@ -61,30 +60,27 @@ function stateTreeFactory(pluginManager) {
61
60
  * #property
62
61
  */
63
62
  view: mobx_state_tree_1.types.safeReference(pluginManager.pluggableMstType('view', 'stateModel')),
64
- /**
65
- * #property
66
- * this is removed in postProcessSnapshot, so is generally only loaded
67
- * from localstorage
68
- */
69
- favorites: mobx_state_tree_1.types.optional(mobx_state_tree_1.types.array(mobx_state_tree_1.types.string), () => JSON.parse((0, util_1.localStorageGetItem)(lsKeyFavoritesF()) || '[]')),
70
- /**
71
- * #property
72
- * this is removed in postProcessSnapshot, so is generally only loaded
73
- * from localstorage
74
- */
75
- recentlyUsed: mobx_state_tree_1.types.optional(mobx_state_tree_1.types.array(mobx_state_tree_1.types.string), () => JSON.parse((0, util_1.localStorageGetItem)(lsKeyRecentlyUsedF()) || '[]')),
76
63
  /**
77
64
  * #property
78
65
  */
79
66
  faceted: mobx_state_tree_1.types.optional((0, facetedModel_1.facetedStateTreeF)(), {}),
80
67
  })
81
68
  .volatile(() => ({
69
+ favorites: [],
70
+ recentlyUsed: [],
82
71
  selection: [],
83
72
  filterText: '',
84
73
  recentlyUsedCounter: 0,
85
74
  favoritesCounter: 0,
86
75
  }))
87
76
  .views(self => ({
77
+ /**
78
+ * #getter
79
+ */
80
+ get shownTrackIds() {
81
+ var _a, _b;
82
+ 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));
83
+ },
88
84
  /**
89
85
  * #getter
90
86
  */
@@ -147,19 +143,19 @@ function stateTreeFactory(pluginManager) {
147
143
  */
148
144
  addToFavorites(trackId) {
149
145
  self.favoritesCounter += 1;
150
- self.favorites.push(trackId);
146
+ self.favorites = [...self.favorites, trackId];
151
147
  },
152
148
  /**
153
149
  * #action
154
150
  */
155
151
  removeFromFavorites(trackId) {
156
- self.favorites.remove(trackId);
152
+ self.favorites = self.favorites.filter(f => f !== trackId);
157
153
  },
158
154
  /**
159
155
  * #action
160
156
  */
161
157
  clearFavorites() {
162
- self.favorites.clear();
158
+ self.favorites = [];
163
159
  },
164
160
  /**
165
161
  * #action
@@ -167,6 +163,18 @@ function stateTreeFactory(pluginManager) {
167
163
  setRecentlyUsedCounter(val) {
168
164
  self.recentlyUsedCounter = val;
169
165
  },
166
+ /**
167
+ * #action
168
+ */
169
+ setRecentlyUsed(str) {
170
+ self.recentlyUsed = str;
171
+ },
172
+ /**
173
+ * #action
174
+ */
175
+ setFavorites(str) {
176
+ self.favorites = str;
177
+ },
170
178
  /**
171
179
  * #action
172
180
  */
@@ -177,19 +185,19 @@ function stateTreeFactory(pluginManager) {
177
185
  * #action
178
186
  */
179
187
  addToRecentlyUsed(id) {
180
- self.recentlyUsedCounter += 1;
181
188
  if (!self.recentlyUsed.includes(id)) {
182
- if (self.recentlyUsed.length >= 10) {
183
- self.recentlyUsed.shift();
184
- }
185
- self.recentlyUsed.push(id);
189
+ self.recentlyUsedCounter = Math.min(self.recentlyUsedCounter + 1, MAX_RECENTLY_USED);
190
+ self.recentlyUsed =
191
+ self.recentlyUsed.length >= MAX_RECENTLY_USED
192
+ ? [...self.recentlyUsed.slice(1), id]
193
+ : [...self.recentlyUsed, id];
186
194
  }
187
195
  },
188
196
  /**
189
197
  * #action
190
198
  */
191
199
  clearRecentlyUsed() {
192
- self.recentlyUsed.clear();
200
+ self.recentlyUsed = [];
193
201
  },
194
202
  /**
195
203
  * #action
@@ -276,6 +284,22 @@ function stateTreeFactory(pluginManager) {
276
284
  },
277
285
  }))
278
286
  .views(self => ({
287
+ /**
288
+ * #getter
289
+ */
290
+ get recentlyUsedLocalStorageKey() {
291
+ return `recentlyUsedTracks-${[postF(), self.assemblyNames.join(',')]
292
+ .filter(f => !!f)
293
+ .join('-')}`;
294
+ },
295
+ /**
296
+ * #getter
297
+ */
298
+ get favoritesLocalStorageKey() {
299
+ // this has a extra } at the end because that's how it was initially
300
+ // released
301
+ return `favoriteTracks-${postF()}}`;
302
+ },
279
303
  /**
280
304
  * #getter
281
305
  */
@@ -300,6 +324,9 @@ function stateTreeFactory(pluginManager) {
300
324
  ...(0, filterTracks_1.filterTracks)((0, util_1.getSession)(self).tracks, self),
301
325
  ].filter(util_1.notEmpty);
302
326
  },
327
+ /**
328
+ * #getter
329
+ */
303
330
  get allTrackConfigurations() {
304
331
  const { connectionInstances = [] } = (0, util_1.getSession)(self);
305
332
  return [
@@ -307,6 +334,12 @@ function stateTreeFactory(pluginManager) {
307
334
  ...connectionInstances === null || connectionInstances === void 0 ? void 0 : connectionInstances.flatMap(c => c.tracks),
308
335
  ];
309
336
  },
337
+ /**
338
+ * #getter
339
+ */
340
+ get allTrackConfigurationTrackIdSet() {
341
+ return new Map(this.allTrackConfigurations.map(t => [t.trackId, t]));
342
+ },
310
343
  }))
311
344
  .views(self => ({
312
345
  /**
@@ -314,14 +347,18 @@ function stateTreeFactory(pluginManager) {
314
347
  * filters out tracks that are not in the favorites group
315
348
  */
316
349
  get favoriteTracks() {
317
- return self.allTrackConfigurations.filter(t => self.favoritesSet.has(t.trackId));
350
+ return self.favorites
351
+ .filter(t => self.allTrackConfigurationTrackIdSet.has(t))
352
+ .map(t => self.allTrackConfigurationTrackIdSet.get(t));
318
353
  },
319
354
  /**
320
355
  * #getter
321
356
  * filters out tracks that are not in the recently used group
322
357
  */
323
358
  get recentlyUsedTracks() {
324
- return self.allTrackConfigurations.filter(t => self.recentlyUsedSet.has(t.trackId));
359
+ return self.recentlyUsed
360
+ .filter(t => self.allTrackConfigurationTrackIdSet.has(t))
361
+ .map(t => self.allTrackConfigurationTrackIdSet.get(t));
325
362
  },
326
363
  }))
327
364
  .views(self => ({
@@ -437,15 +474,17 @@ function stateTreeFactory(pluginManager) {
437
474
  }))
438
475
  .actions(self => ({
439
476
  afterAttach() {
477
+ // this should be the first autorun to properly initialize
478
+ (0, mobx_state_tree_1.addDisposer)(self, (0, mobx_1.autorun)(() => {
479
+ self.setRecentlyUsed(JSON.parse((0, util_1.localStorageGetItem)(self.recentlyUsedLocalStorageKey) || '[]'));
480
+ self.setFavorites(JSON.parse((0, util_1.localStorageGetItem)(self.favoritesLocalStorageKey) || '[]'));
481
+ }));
482
+ // this should be the second autorun
440
483
  (0, mobx_state_tree_1.addDisposer)(self, (0, mobx_1.autorun)(() => {
441
- (0, util_1.localStorageSetItem)(lsKeyFavoritesF(), JSON.stringify(self.favorites));
442
- (0, util_1.localStorageSetItem)(lsKeyRecentlyUsedF(), JSON.stringify(self.recentlyUsed));
484
+ (0, util_1.localStorageSetItem)(self.favoritesLocalStorageKey, JSON.stringify(self.favorites));
485
+ (0, util_1.localStorageSetItem)(self.recentlyUsedLocalStorageKey, JSON.stringify(self.recentlyUsed));
443
486
  }));
444
487
  },
445
- }))
446
- .postProcessSnapshot(snap => {
447
- const { favorites: _, recentlyUsed: __, ...rest } = snap;
448
- return rest;
449
- });
488
+ }));
450
489
  }
451
490
  exports.default = stateTreeFactory;