@jbrowse/product-core 5.0.0-beta.10 → 5.0.0-beta.13

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 (49) hide show
  1. package/esm/RootModel/PreferencesConfig.d.ts +0 -5
  2. package/esm/RootModel/PreferencesConfig.js +0 -11
  3. package/esm/RootModel/createConfigModel.d.ts +0 -10
  4. package/esm/RootModel/index.d.ts +1 -1
  5. package/esm/RootModel/index.js +1 -1
  6. package/esm/RootModel/menuItems.d.ts +0 -2
  7. package/esm/RootModel/menuItems.js +0 -18
  8. package/esm/Session/BaseSession.d.ts +1 -4
  9. package/esm/Session/BaseSession.js +1 -4
  10. package/esm/Session/DrawerWidgets.d.ts +2 -0
  11. package/esm/Session/DrawerWidgets.js +34 -16
  12. package/esm/Session/MultipleViews.d.ts +5 -54
  13. package/esm/Session/MultipleViews.js +8 -66
  14. package/esm/Session/Preferences.js +4 -2
  15. package/esm/Session/SessionTracks.d.ts +14 -14
  16. package/esm/Session/SessionTracks.js +4 -10
  17. package/esm/Session/Themes.d.ts +13 -2
  18. package/esm/Session/Themes.js +23 -5
  19. package/esm/Session/TrackMenu.d.ts +4 -4
  20. package/esm/Session/TrackMenuSessionMixin.d.ts +2 -2
  21. package/esm/Session/Tracks.d.ts +11 -11
  22. package/esm/Session/Tracks.js +2 -2
  23. package/esm/Session/copyTrackSnapshot.d.ts +2 -2
  24. package/esm/Session/index.d.ts +1 -1
  25. package/esm/Session/index.js +1 -1
  26. package/esm/Session/pluginExtraTrackItems.d.ts +2 -2
  27. package/esm/Session/shareableSnapshot.d.ts +3 -19
  28. package/esm/Session/shareableSnapshot.js +4 -61
  29. package/esm/controllerTracks.js +2 -2
  30. package/esm/index.d.ts +2 -2
  31. package/esm/index.js +2 -2
  32. package/esm/sessionUrl.d.ts +0 -4
  33. package/esm/sessionUrl.js +0 -4
  34. package/esm/sessionUtils.js +1 -1
  35. package/esm/ui/AboutDialogContents.js +5 -4
  36. package/esm/ui/DescriptionPanel.js +43 -6
  37. package/esm/ui/GeneralPreferencesTab.d.ts +1 -0
  38. package/esm/ui/GeneralPreferencesTab.js +3 -1
  39. package/esm/ui/ViewPreferencesTab.d.ts +0 -2
  40. package/esm/ui/ViewPreferencesTab.js +0 -2
  41. package/esm/ui/aboutTestUtils.d.ts +105 -0
  42. package/esm/ui/aboutTestUtils.js +15 -1
  43. package/esm/ui/descriptionHtml.d.ts +31 -9
  44. package/esm/ui/descriptionHtml.js +74 -21
  45. package/esm/ui/preferencesReset.d.ts +0 -3
  46. package/esm/ui/preferencesReset.js +0 -13
  47. package/esm/ui/util.d.ts +5 -6
  48. package/esm/ui/util.js +8 -11
  49. package/package.json +5 -5
@@ -24,11 +24,6 @@ export declare function PreferencesConfigSchemaFactory(): import("@jbrowse/core/
24
24
  } & {
25
25
  defaultValue: boolean;
26
26
  };
27
- readonly useWorkspaces: {
28
- type: "boolean";
29
- } & {
30
- defaultValue: boolean;
31
- };
32
27
  readonly developerMode: {
33
28
  type: "boolean";
34
29
  } & {
@@ -45,17 +45,6 @@ export function PreferencesConfigSchemaFactory() {
45
45
  type: 'boolean',
46
46
  defaultValue: true,
47
47
  },
48
- /**
49
- * #slot configuration.preferences.useWorkspaces
50
- * when true, views open in the tabbed/tiled workspace layout rather than
51
- * stacked vertically. Only the default: a session that names
52
- * `useWorkspaces` itself (a shared snapshot, or a session spec carrying a
53
- * `layout`) still wins, and a user's own toggle overrides it.
54
- */
55
- useWorkspaces: {
56
- type: 'boolean',
57
- defaultValue: false,
58
- },
59
48
  /**
60
49
  * #slot configuration.preferences.developerMode
61
50
  * when true, the ordering-contract checks a display or plugin can break
@@ -69,11 +69,6 @@ declare function rootConfigurationSchema(): import("@jbrowse/core/configuration/
69
69
  } & {
70
70
  defaultValue: boolean;
71
71
  };
72
- readonly useWorkspaces: {
73
- type: "boolean";
74
- } & {
75
- defaultValue: boolean;
76
- };
77
72
  readonly developerMode: {
78
73
  type: "boolean";
79
74
  } & {
@@ -191,11 +186,6 @@ export declare function createConfigModel(pluginManager: PluginManager, assembly
191
186
  } & {
192
187
  defaultValue: boolean;
193
188
  };
194
- readonly useWorkspaces: {
195
- type: "boolean";
196
- } & {
197
- defaultValue: boolean;
198
- };
199
189
  readonly developerMode: {
200
190
  type: "boolean";
201
191
  } & {
@@ -7,4 +7,4 @@ export { HierarchicalConfigSchemaFactory } from './HierarchicalConfig.ts';
7
7
  export { PreferencesConfigSchemaFactory } from './PreferencesConfig.ts';
8
8
  export { createConfigModel } from './createConfigModel.ts';
9
9
  export type { RootConfigurationSnapshot } from './createConfigModel.ts';
10
- export { exportSessionMenuItem, importSessionMenuItem, newSessionMenuItem, openConnectionMenuItem, openTrackMenuItem, pluginStoreMenuItem, preferencesMenuItem, redoMenuItem, undoMenuItem, workspacesMenuItem, } from './menuItems.ts';
10
+ export { exportSessionMenuItem, importSessionMenuItem, newSessionMenuItem, openConnectionMenuItem, openTrackMenuItem, pluginStoreMenuItem, preferencesMenuItem, redoMenuItem, undoMenuItem, } from './menuItems.ts';
@@ -7,4 +7,4 @@ export { FormatAboutConfigSchemaFactory, FormatDetailsConfigSchemaFactory, } fro
7
7
  export { HierarchicalConfigSchemaFactory } from './HierarchicalConfig.js';
8
8
  export { PreferencesConfigSchemaFactory } from './PreferencesConfig.js';
9
9
  export { createConfigModel } from './createConfigModel.js';
10
- export { exportSessionMenuItem, importSessionMenuItem, newSessionMenuItem, openConnectionMenuItem, openTrackMenuItem, pluginStoreMenuItem, preferencesMenuItem, redoMenuItem, undoMenuItem, workspacesMenuItem, } from './menuItems.js';
10
+ export { exportSessionMenuItem, importSessionMenuItem, newSessionMenuItem, openConnectionMenuItem, openTrackMenuItem, pluginStoreMenuItem, preferencesMenuItem, redoMenuItem, undoMenuItem, } from './menuItems.js';
@@ -1,4 +1,3 @@
1
- import type { SessionWithMultipleViews } from '../Session/index.ts';
2
1
  import type PluginManager from '@jbrowse/core/PluginManager';
3
2
  import type { MenuItem } from '@jbrowse/core/ui';
4
3
  import type { DialogComponentType } from '@jbrowse/core/util';
@@ -20,5 +19,4 @@ interface HistoryManager {
20
19
  }
21
20
  export declare function undoMenuItem(history: HistoryManager): MenuItem;
22
21
  export declare function redoMenuItem(history: HistoryManager): MenuItem;
23
- export declare function workspacesMenuItem(session: SessionWithMultipleViews | undefined): MenuItem;
24
22
  export {};
@@ -5,14 +5,12 @@ import GetAppIcon from '@mui/icons-material/GetApp';
5
5
  import PublishIcon from '@mui/icons-material/Publish';
6
6
  import RedoIcon from '@mui/icons-material/Redo';
7
7
  import SettingsIcon from '@mui/icons-material/Settings';
8
- import SpaceDashboardIcon from '@mui/icons-material/SpaceDashboard';
9
8
  import StorageIcon from '@mui/icons-material/Storage';
10
9
  import UndoIcon from '@mui/icons-material/Undo';
11
10
  import { getShareableSessionSnapshot } from '../Session/index.js';
12
11
  // the renderer binds the active session into each onClick (see AppToolbar's
13
12
  // wrapMenuItems), so these handlers receive it as their argument
14
13
  const MULTI_VIEW_WARNING = 'This will add a track to the first view. Note: if you want to open a track in a specific view open the track selector for that view and use the add track (plus icon) in the bottom right';
15
- const WORKSPACES_HELP_TEXT = 'Workspaces allow you to organize views into tabs and tiles. There are a variety of unique features, for instance, you can drag views between tabs or split them side-by-side. Try clicking and dragging the tab header to create a new split';
16
14
  export function newSessionMenuItem(root) {
17
15
  return {
18
16
  label: 'New session',
@@ -123,19 +121,3 @@ export function redoMenuItem(history) {
123
121
  },
124
122
  };
125
123
  }
126
- export function workspacesMenuItem(session) {
127
- return {
128
- label: 'Use workspaces',
129
- icon: SpaceDashboardIcon,
130
- type: 'checkbox',
131
- checked: session?.effectiveUseWorkspaces ?? false,
132
- helpText: WORKSPACES_HELP_TEXT,
133
- // opts out of the checkbox "stay open" default: this re-lays out the whole
134
- // app (classic stack <-> tiled workspace), so it's a one-shot mode switch
135
- // rather than a setting to flip repeatedly with the menu up
136
- keepMenuOpen: false,
137
- onClick: () => {
138
- session?.setUseWorkspacesPreference(!session.effectiveUseWorkspaces);
139
- },
140
- };
141
- }
@@ -139,10 +139,7 @@ export declare function BaseSessionModel<ROOT_MODEL_TYPE extends BaseRootModelTy
139
139
  /**
140
140
  * #method
141
141
  * the admin/embedder `configuration.preferences` value for a key, ignoring
142
- * any runtime override — i.e. what a reset falls back to. Exposed rather
143
- * than inlined because "differs from the default" is a question the
144
- * Preferences reset diff asks about settings this map doesn't hold (see
145
- * `defaultUseWorkspaces`).
142
+ * any runtime override — i.e. what a reset falls back to
146
143
  */
147
144
  getPreferenceDefault(key: string): unknown;
148
145
  /**
@@ -172,10 +172,7 @@ export function BaseSessionModel(_pluginManager) {
172
172
  /**
173
173
  * #method
174
174
  * the admin/embedder `configuration.preferences` value for a key, ignoring
175
- * any runtime override — i.e. what a reset falls back to. Exposed rather
176
- * than inlined because "differs from the default" is a question the
177
- * Preferences reset diff asks about settings this map doesn't hold (see
178
- * `defaultUseWorkspaces`).
175
+ * any runtime override — i.e. what a reset falls back to
179
176
  */
180
177
  getPreferenceDefault(key) {
181
178
  const { preferences } = self.configuration;
@@ -86,6 +86,8 @@ export declare function DrawerWidgetSessionMixin(pluginManager: PluginManager):
86
86
  showWidget(widget: any): void;
87
87
  /**
88
88
  * #action
89
+ * closes the widget, and removes it from the session when its type sets
90
+ * `discardOnClose`. Minimizing the drawer is not closing.
89
91
  */
90
92
  hideWidget(widget: any): void;
91
93
  /**
@@ -1,6 +1,7 @@
1
1
  import { isConfigurationModel } from '@jbrowse/core/configuration';
2
- import { localStorageGetItem, localStorageSetItem } from '@jbrowse/core/util';
3
- import { addDisposer, getEnv, isAlive, isStateTreeNode, types, } from '@jbrowse/mobx-state-tree';
2
+ import { localStorageGetItem, localStorageSetItem, scheduleDetachedDestroy, } from '@jbrowse/core/util';
3
+ import { getEditableTrackConfigById } from '@jbrowse/core/util/types';
4
+ import { addDisposer, detach, getEnv, isAlive, types, } from '@jbrowse/mobx-state-tree';
4
5
  import { autorun } from 'mobx';
5
6
  import { isBaseSession } from './BaseSession.js';
6
7
  const minDrawerWidth = 128;
@@ -171,12 +172,19 @@ export function DrawerWidgetSessionMixin(pluginManager) {
171
172
  },
172
173
  /**
173
174
  * #action
175
+ * closes the widget, and removes it from the session when its type sets
176
+ * `discardOnClose`. Minimizing the drawer is not closing.
174
177
  */
175
178
  hideWidget(widget) {
176
179
  self.activeWidgets.delete(widget.id);
177
180
  if (self.activeWidgets.size === 0) {
178
181
  self.poppedOut = false;
179
182
  }
183
+ if (self.widgets.get(widget.id) === widget &&
184
+ pluginManager.getWidgetType(widget.type).discardOnClose) {
185
+ detach(widget);
186
+ scheduleDetachedDestroy(widget);
187
+ }
180
188
  },
181
189
  /**
182
190
  * #action
@@ -213,7 +221,9 @@ export function DrawerWidgetSessionMixin(pluginManager) {
213
221
  * #action
214
222
  */
215
223
  hideAllWidgets() {
216
- self.activeWidgets.clear();
224
+ for (const widget of [...self.activeWidgets.values()]) {
225
+ this.hideWidget(widget);
226
+ }
217
227
  self.poppedOut = false;
218
228
  },
219
229
  afterAttach() {
@@ -255,23 +265,31 @@ export function DrawerWidgetSessionMixin(pluginManager) {
255
265
  * @param configuration - can be an MST model or a frozen/plain object with trackId
256
266
  */
257
267
  editConfiguration(configuration, opts) {
258
- let targetConfig;
259
- if (isStateTreeNode(configuration) &&
260
- isConfigurationModel(configuration)) {
261
- // Already an MST model (e.g., from track.configuration), use directly
262
- targetConfig = configuration;
268
+ const isNode = isConfigurationModel(configuration);
269
+ if (!isNode && !('trackId' in configuration)) {
270
+ throw new Error('must pass a configuration model or frozen config with trackId to editConfiguration');
263
271
  }
264
- else if ('trackId' in configuration) {
265
- // Frozen/plain object - create a temporary MST model for editing
266
- const trackSchema = pluginManager.pluggableConfigSchemaType('track');
267
- targetConfig = trackSchema.create(configuration, getEnv(self));
272
+ const trackId = configuration.trackId;
273
+ const workingCopy = typeof trackId === 'string'
274
+ ? getEditableTrackConfigById(self, trackId)
275
+ : undefined;
276
+ const editor = self.openWidget('ConfigurationEditorWidget', 'configEditor');
277
+ // A shown track edits its working copy, so the editor edits that same
278
+ // node, and follows it when an undo replaces it (ADR-032). A node the
279
+ // session does not resolve by id, such as a track a view holds
280
+ // inline, is edited as it stands.
281
+ if (typeof trackId === 'string' &&
282
+ workingCopy &&
283
+ (!isNode || workingCopy === configuration)) {
284
+ editor.setTrackId(trackId);
268
285
  }
269
286
  else {
270
- throw new Error('must pass a configuration model or frozen config with trackId to editConfiguration');
287
+ editor.setTarget(isNode
288
+ ? configuration
289
+ : pluginManager
290
+ .pluggableConfigSchemaType('track')
291
+ .create(configuration, getEnv(self)));
271
292
  }
272
- const editor = self.openWidget('ConfigurationEditorWidget', 'configEditor');
273
- // Set target via action since it's now volatile
274
- editor.setTarget(targetConfig);
275
293
  editor.setExpandedDisplayId(opts?.expandedDisplayId);
276
294
  },
277
295
  }))
@@ -19,7 +19,7 @@ export declare function MultipleViewsSessionMixin(pluginManager: PluginManager):
19
19
  widgets: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").IMapType<import("@jbrowse/mobx-state-tree").IAnyType>, [undefined]>;
20
20
  activeWidgets: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").IMapType<import("@jbrowse/mobx-state-tree").IMaybe<import("@jbrowse/mobx-state-tree").IReferenceType<import("@jbrowse/mobx-state-tree").IAnyType>>>, [undefined]>;
21
21
  minimized: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").ISimpleType<boolean>, [undefined]>;
22
- }, "stickyViewHeaders" | "useWorkspaces" | "views"> & {
22
+ }, "stickyViewHeaders" | "views"> & {
23
23
  /**
24
24
  * #property
25
25
  */
@@ -28,12 +28,6 @@ export declare function MultipleViewsSessionMixin(pluginManager: PluginManager):
28
28
  * #property
29
29
  */
30
30
  stickyViewHeaders: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").ISimpleType<boolean>, [undefined]>;
31
- /**
32
- * #property
33
- * enables the tabbed/tiled workspace layout for this session. Undefined
34
- * means unspecified — read `effectiveUseWorkspaces`.
35
- */
36
- useWorkspaces: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").IMaybe<import("@jbrowse/mobx-state-tree").ISimpleType<boolean>>, [undefined]>;
37
31
  }, {
38
32
  selection: unknown;
39
33
  hovered: unknown;
@@ -1434,25 +1428,6 @@ export declare function MultipleViewsSessionMixin(pluginManager: PluginManager):
1434
1428
  }, opts?: {
1435
1429
  expandedDisplayId?: string;
1436
1430
  }): void;
1437
- } & {
1438
- /**
1439
- * #getter
1440
- * resolved workspaces flag (never undefined): this session's value, else
1441
- * the user preference over the `configuration.preferences.useWorkspaces`
1442
- * admin default. Every consumer reads this, not the raw property — only
1443
- * sessions built from a snapshot or a spec `layout` set that, so the
1444
- * admin default is what reaches the arrivals that bypass defaultSession.
1445
- */
1446
- readonly effectiveUseWorkspaces: boolean;
1447
- /**
1448
- * #getter
1449
- * what `effectiveUseWorkspaces` becomes after `resetUseWorkspaces` — the
1450
- * admin default, with both this session's own value and the user's
1451
- * override out of the way. The Preferences reset diff needs this rather
1452
- * than the override map, which can't see a session-scoped value (a spec
1453
- * `layout`, a "move view to a tab") and so reported nothing to reset.
1454
- */
1455
- readonly defaultUseWorkspaces: boolean;
1456
1431
  } & {
1457
1432
  /**
1458
1433
  * #action
@@ -1556,28 +1531,10 @@ export declare function MultipleViewsSessionMixin(pluginManager: PluginManager):
1556
1531
  setStickyViewHeaders(sticky: boolean): void;
1557
1532
  /**
1558
1533
  * #action
1559
- * set the workspaces layout for this session only, leaving the user's
1560
- * personal default untouched. For session-scoped intent — a spec
1561
- * carrying a `layout`, or an ad-hoc "move view to a tab/split" — where
1562
- * rewriting the visitor's global preference would be a surprise. The
1563
- * user-facing default toggle is `setUseWorkspacesPreference`.
1534
+ * Does nothing: the workspace is always on. Kept because published
1535
+ * protein3d and msaview bundles call it after placing a view.
1564
1536
  */
1565
- setUseWorkspaces(useWorkspaces: boolean): void;
1566
- /**
1567
- * #action
1568
- * the user-facing workspaces toggle: applies to this session and
1569
- * becomes their default for sessions that don't specify one. Persisted
1570
- * only here, on an explicit toggle — an autorun mirroring the resolved
1571
- * value would bake the admin default into every visitor's localStorage
1572
- * on first load, so a later admin change could never reach them.
1573
- */
1574
- setUseWorkspacesPreference(useWorkspaces: boolean): void;
1575
- /**
1576
- * #action
1577
- * drop both this session's explicit value and the user's override so
1578
- * workspaces falls back to the admin default
1579
- */
1580
- resetUseWorkspaces(): void;
1537
+ setUseWorkspaces(_useWorkspaces?: boolean): void;
1581
1538
  afterAttach(): void;
1582
1539
  } & {
1583
1540
  /**
@@ -1603,7 +1560,7 @@ export declare function MultipleViewsSessionMixin(pluginManager: PluginManager):
1603
1560
  widgets: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").IMapType<import("@jbrowse/mobx-state-tree").IAnyType>, [undefined]>;
1604
1561
  activeWidgets: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").IMapType<import("@jbrowse/mobx-state-tree").IMaybe<import("@jbrowse/mobx-state-tree").IReferenceType<import("@jbrowse/mobx-state-tree").IAnyType>>>, [undefined]>;
1605
1562
  minimized: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").ISimpleType<boolean>, [undefined]>;
1606
- }, "stickyViewHeaders" | "useWorkspaces" | "views"> & {
1563
+ }, "stickyViewHeaders" | "views"> & {
1607
1564
  /**
1608
1565
  * #property
1609
1566
  */
@@ -1612,12 +1569,6 @@ export declare function MultipleViewsSessionMixin(pluginManager: PluginManager):
1612
1569
  * #property
1613
1570
  */
1614
1571
  stickyViewHeaders: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").ISimpleType<boolean>, [undefined]>;
1615
- /**
1616
- * #property
1617
- * enables the tabbed/tiled workspace layout for this session. Undefined
1618
- * means unspecified — read `effectiveUseWorkspaces`.
1619
- */
1620
- useWorkspaces: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").IMaybe<import("@jbrowse/mobx-state-tree").ISimpleType<boolean>>, [undefined]>;
1621
1572
  }>, "activeWidgets" | "drawerPosition" | "drawerWidth" | "minimized" | "widgets"> & import("@jbrowse/mobx-state-tree").ModelSnapshotType<{
1622
1573
  drawerPosition: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").ISimpleType<import("@jbrowse/core/util").DrawerPosition>, [undefined]>;
1623
1574
  drawerWidth: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").ISimpleType<number>, [undefined]>;
@@ -81,36 +81,6 @@ export function MultipleViewsSessionMixin(pluginManager) {
81
81
  * #property
82
82
  */
83
83
  stickyViewHeaders: types.optional(types.boolean, () => localStorageGetBoolean('stickyViewHeaders', true)),
84
- /**
85
- * #property
86
- * enables the tabbed/tiled workspace layout for this session. Undefined
87
- * means unspecified — read `effectiveUseWorkspaces`.
88
- */
89
- useWorkspaces: types.stripDefault(types.maybe(types.boolean), undefined),
90
- }))
91
- .views(self => ({
92
- /**
93
- * #getter
94
- * resolved workspaces flag (never undefined): this session's value, else
95
- * the user preference over the `configuration.preferences.useWorkspaces`
96
- * admin default. Every consumer reads this, not the raw property — only
97
- * sessions built from a snapshot or a spec `layout` set that, so the
98
- * admin default is what reaches the arrivals that bypass defaultSession.
99
- */
100
- get effectiveUseWorkspaces() {
101
- return (self.useWorkspaces ?? self.getPreference('useWorkspaces') === true);
102
- },
103
- /**
104
- * #getter
105
- * what `effectiveUseWorkspaces` becomes after `resetUseWorkspaces` — the
106
- * admin default, with both this session's own value and the user's
107
- * override out of the way. The Preferences reset diff needs this rather
108
- * than the override map, which can't see a session-scoped value (a spec
109
- * `layout`, a "move view to a tab") and so reported nothing to reset.
110
- */
111
- get defaultUseWorkspaces() {
112
- return self.getPreferenceDefault('useWorkspaces') === true;
113
- },
114
84
  }))
115
85
  .actions(self => {
116
86
  // `scopeIds` narrows the move to a subset of the stack: in a tabbed
@@ -162,11 +132,11 @@ export function MultipleViewsSessionMixin(pluginManager) {
162
132
  viewIdsWithin(view).includes(focusedViewId)) {
163
133
  self.setFocusedViewId(undefined);
164
134
  }
165
- // Every widget, not the active ones: a widget the user closed keeps
166
- // its references and its autoruns. One that pointed into the view is
167
- // now empty, so hide it rather than leave the panel showing what it no
168
- // longer has.
169
- for (const [, widget] of self.widgets) {
135
+ // Every widget, not the active ones: a closed widget that stays in the
136
+ // session keeps its references and its autoruns. One that pointed into
137
+ // the view is now empty, so close it rather than leave the panel
138
+ // showing what it no longer has.
139
+ for (const widget of [...self.widgets.values()]) {
170
140
  if (dropRefsInto(widget, view)) {
171
141
  self.hideWidget(widget);
172
142
  }
@@ -345,36 +315,10 @@ export function MultipleViewsSessionMixin(pluginManager) {
345
315
  },
346
316
  /**
347
317
  * #action
348
- * set the workspaces layout for this session only, leaving the user's
349
- * personal default untouched. For session-scoped intent — a spec
350
- * carrying a `layout`, or an ad-hoc "move view to a tab/split" — where
351
- * rewriting the visitor's global preference would be a surprise. The
352
- * user-facing default toggle is `setUseWorkspacesPreference`.
318
+ * Does nothing: the workspace is always on. Kept because published
319
+ * protein3d and msaview bundles call it after placing a view.
353
320
  */
354
- setUseWorkspaces(useWorkspaces) {
355
- self.useWorkspaces = useWorkspaces;
356
- },
357
- /**
358
- * #action
359
- * the user-facing workspaces toggle: applies to this session and
360
- * becomes their default for sessions that don't specify one. Persisted
361
- * only here, on an explicit toggle — an autorun mirroring the resolved
362
- * value would bake the admin default into every visitor's localStorage
363
- * on first load, so a later admin change could never reach them.
364
- */
365
- setUseWorkspacesPreference(useWorkspaces) {
366
- self.useWorkspaces = useWorkspaces;
367
- self.setPreferenceOverride('useWorkspaces', useWorkspaces);
368
- },
369
- /**
370
- * #action
371
- * drop both this session's explicit value and the user's override so
372
- * workspaces falls back to the admin default
373
- */
374
- resetUseWorkspaces() {
375
- self.useWorkspaces = undefined;
376
- self.clearPreferenceOverride('useWorkspaces');
377
- },
321
+ setUseWorkspaces(_useWorkspaces) { },
378
322
  afterAttach() {
379
323
  addDisposer(self, autorun(function stickyViewHeadersAutorun() {
380
324
  localStorageSetBoolean('stickyViewHeaders', self.stickyViewHeaders);
@@ -407,8 +351,6 @@ export function MultipleViewsSessionMixin(pluginManager) {
407
351
  // stickyViewHeaders is a personal per-browser UI preference, not shared
408
352
  // view state: destructure it out so it never lands in the snapshot. It
409
353
  // stays localStorage-backed, so each browser keeps its own value.
410
- // useWorkspaces stays: it changes layout intent (and pairs with the
411
- // `layout` tree the snapshot carries), which is meaningful to share.
412
354
  const { stickyViewHeaders, ...rest } = snap;
413
355
  return rest;
414
356
  });
@@ -35,8 +35,10 @@ export function PreferencesSessionMixin(pluginManager) {
35
35
  .actions(self => ({
36
36
  afterAttach() {
37
37
  // the restore path bypasses `setPreferenceOverride`, so it freezes here
38
- // too
39
- self.preferencesOverrides.replace(freezeDeep(loadStoredPreferences()));
38
+ // too; a key the config no longer declares is a retired preference
39
+ const { preferences } = self.configuration;
40
+ const stored = Object.entries(loadStoredPreferences()).filter(([key]) => !preferences || key in preferences);
41
+ self.preferencesOverrides.replace(freezeDeep(Object.fromEntries(stored)));
40
42
  // Applied once, here, rather than reactively: the same setting has to
41
43
  // hold in the RPC workers (which format tooltip strings from jexl
42
44
  // `mouseover` slots) and they only learn it at boot, so a live
@@ -1,5 +1,5 @@
1
1
  import type PluginManager from '@jbrowse/core/PluginManager';
2
- import type { AnyConfiguration, AnyConfigurationModel } from '@jbrowse/core/configuration';
2
+ import type { AnyConfiguration, AnyConfigurationModel, AnyTrackConfig, TrackConfigEntry } from '@jbrowse/core/configuration';
3
3
  import type { IAnyStateTreeNode, IAnyType, Instance } from '@jbrowse/mobx-state-tree';
4
4
  export interface PlainTrackConfig {
5
5
  trackId: string;
@@ -1423,14 +1423,14 @@ export declare function SessionTracksManagerSessionMixin(pluginManager: PluginMa
1423
1423
  } & {
1424
1424
  dereferenceTrack(trackId: string, referring: import("./ReferenceManagement.ts").ReferringNode[]): void;
1425
1425
  } & {
1426
- readonly trackBasesById: Map<string, AnyConfigurationModel>;
1427
- withTrackEdits(base: AnyConfigurationModel): AnyConfigurationModel;
1428
- readonly tracks: AnyConfigurationModel[];
1426
+ readonly trackBasesById: Map<string, TrackConfigEntry>;
1427
+ withTrackEdits(base: TrackConfigEntry): TrackConfigEntry;
1428
+ readonly tracks: TrackConfigEntry[];
1429
1429
  } & {
1430
1430
  afterAttach(): void;
1431
1431
  } & {
1432
- getTrackById(id: string): AnyConfigurationModel | undefined;
1433
- getTracksById(): Record<string, AnyConfigurationModel>;
1432
+ getTrackById(id: string): AnyTrackConfig | undefined;
1433
+ getTracksById(): Record<string, AnyTrackConfig>;
1434
1434
  } & {
1435
1435
  addSessionTrackConf(trackConf: AnyConfiguration): any;
1436
1436
  publishTrackConf(trackConf: AnyConfiguration): any;
@@ -1439,7 +1439,7 @@ export declare function SessionTracksManagerSessionMixin(pluginManager: PluginMa
1439
1439
  trackId: string;
1440
1440
  [key: string]: unknown;
1441
1441
  }): void;
1442
- deleteTrackConf(trackConf: AnyConfigurationModel): any;
1442
+ deleteTrackConf(trackConf: AnyTrackConfig): any;
1443
1443
  } & {
1444
1444
  /**
1445
1445
  * Per-track private working copies, keyed by trackId. A plain
@@ -1468,21 +1468,21 @@ export declare function SessionTracksManagerSessionMixin(pluginManager: PluginMa
1468
1468
  * config.json entry. Rebuilt when either list changes, never on an
1469
1469
  * edit.
1470
1470
  */
1471
- readonly trackBasesById: Map<string, AnyConfigurationModel>;
1471
+ readonly trackBasesById: Map<string, TrackConfigEntry>;
1472
1472
  /**
1473
1473
  * #method
1474
1474
  * `base` with its delta (trackConfigDeltas) merged over it, or `base`
1475
1475
  * itself by identity when it has none, which keeps the hydration cache
1476
1476
  * warm.
1477
1477
  */
1478
- withTrackEdits(base: AnyConfigurationModel): AnyConfigurationModel;
1478
+ withTrackEdits(base: TrackConfigEntry): TrackConfigEntry;
1479
1479
  /**
1480
1480
  * #getter
1481
1481
  * Session tracks first, then the config tracks, each with its edits.
1482
1482
  * An edit copies the list of bases and lays each delta at its track's
1483
1483
  * position, so past that copy it costs the count of edited tracks.
1484
1484
  */
1485
- readonly tracks: AnyConfigurationModel[];
1485
+ readonly tracks: TrackConfigEntry[];
1486
1486
  /**
1487
1487
  * #method
1488
1488
  * The entry `trackId` edits over, hydrated: the one the session added
@@ -1490,7 +1490,7 @@ export declare function SessionTracksManagerSessionMixin(pluginManager: PluginMa
1490
1490
  * arranged" and "reset" compare its live config against. Per-id
1491
1491
  * reactive, like `getTrackById`.
1492
1492
  */
1493
- baseTrackConfig(trackId: string): PlainTrackConfig | undefined;
1493
+ baseTrackConfig(trackId: string): TrackConfigEntry | undefined;
1494
1494
  /**
1495
1495
  * #method
1496
1496
  * The config node `trackId` resolves to: a live node as it stands,
@@ -1553,7 +1553,7 @@ export declare function SessionTracksManagerSessionMixin(pluginManager: PluginMa
1553
1553
  * Returns the entry, which is the track's base: edit the track through
1554
1554
  * `updateTrackConfiguration` or a display's `setConf`, not the entry.
1555
1555
  */
1556
- addSessionTrackConf(trackConf: AnyConfiguration): AnyConfigurationModel | undefined;
1556
+ addSessionTrackConf(trackConf: AnyConfiguration): AnyTrackConfig | undefined;
1557
1557
  /**
1558
1558
  * #action
1559
1559
  * Publish a track config to the shared catalog if this user can, and
@@ -1599,7 +1599,7 @@ export declare function SessionTracksManagerSessionMixin(pluginManager: PluginMa
1599
1599
  * for why it survives and why it now means the session; nothing in tree
1600
1600
  * may call it.
1601
1601
  */
1602
- addTrackConf(trackConf: AnyConfiguration): AnyConfigurationModel | undefined;
1602
+ addTrackConf(trackConf: AnyConfiguration): AnyTrackConfig | undefined;
1603
1603
  /**
1604
1604
  * #action
1605
1605
  * Persist an edited track config as a delta (trackConfigDeltas) against
@@ -1633,7 +1633,7 @@ export declare function SessionTracksManagerSessionMixin(pluginManager: PluginMa
1633
1633
  /**
1634
1634
  * #action
1635
1635
  */
1636
- deleteTrackConf(trackConf: AnyConfigurationModel): (import("@jbrowse/core/configuration").PluggableConfigNode & import("@jbrowse/mobx-state-tree").IStateTreeNode<import("@jbrowse/core/PluginManager").PluggableConfigSchemaType>)[] | undefined;
1636
+ deleteTrackConf(trackConf: AnyTrackConfig): (import("@jbrowse/core/configuration").PluggableConfigNode & import("@jbrowse/mobx-state-tree").IStateTreeNode<import("@jbrowse/core/PluginManager").PluggableConfigSchemaType>)[] | undefined;
1637
1637
  }, import("@jbrowse/mobx-state-tree")._NotCustomized, import("@jbrowse/mobx-state-tree")._NotCustomized>;
1638
1638
  /** Session mixin MST type for a session that has `sessionTracks` */
1639
1639
  export type SessionWithSessionTracksType = ReturnType<typeof SessionTracksManagerSessionMixin>;
@@ -1,14 +1,12 @@
1
1
  import { readConfObject } from '@jbrowse/core/configuration';
2
2
  import { diffTrackConfig, flattenTrackConfigDelta, mergeTrackConfig, } from '@jbrowse/core/util';
3
- import { expandLooseTrackConfig } from '@jbrowse/core/util/tracks';
3
+ import { expandLooseTrackConfig, getConfAssemblyNamesOrNone, } from '@jbrowse/core/util/tracks';
4
4
  import { applySnapshot, getSnapshot, isStateTreeNode, types, } from '@jbrowse/mobx-state-tree';
5
5
  import { compareStructural, computed } from 'mobx';
6
6
  import { TracksManagerSessionMixin } from './Tracks.js';
7
7
  import { hydratedTrackForm } from './hydratedForms.js';
8
8
  import { assertNotReaddedDifferently } from './readdedTrackConf.js';
9
9
  import { assertTrackConfOutlivesItsAssemblies } from './temporaryAssemblyTracks.js';
10
- // jbrowse.tracks holds frozen plain objects in every product; single site for
11
- // the cast from its loose frozen type.
12
10
  function baseTracks(self) {
13
11
  return self.jbrowse.tracks;
14
12
  }
@@ -38,8 +36,7 @@ function assembliesNotInTheCatalog(self, trackConf) {
38
36
  readConfObject(a, 'name'),
39
37
  ...(readConfObject(a, 'aliases') ?? []),
40
38
  ]));
41
- const names = readConfObject(trackConf, 'assemblyNames');
42
- return names?.filter(name => !catalog.has(name)) ?? [];
39
+ return getConfAssemblyNamesOrNone(trackConf).filter(name => !catalog.has(name));
43
40
  }
44
41
  function withoutDelta(deltas, trackId) {
45
42
  const { [trackId]: _dropped, ...rest } = deltas;
@@ -177,9 +174,7 @@ export function SessionTracksManagerSessionMixin(pluginManager) {
177
174
  const deltaFor = perIdComputed(trackId => self.trackConfigDeltas[trackId]);
178
175
  const baseFor = perIdComputed(trackId => {
179
176
  const base = self.trackBasesById.get(trackId);
180
- return base
181
- ? toPlainConfig(base)
182
- : undefined;
177
+ return base ? toPlainConfig(base) : undefined;
183
178
  });
184
179
  const editableBySchema = new Map();
185
180
  return {
@@ -199,8 +194,7 @@ export function SessionTracksManagerSessionMixin(pluginManager) {
199
194
  * warm.
200
195
  */
201
196
  withTrackEdits(base) {
202
- const plain = base;
203
- return withDelta(plain, deltaFor(plain.trackId));
197
+ return withDelta(base, deltaFor(base.trackId));
204
198
  },
205
199
  /**
206
200
  * #getter
@@ -18,6 +18,7 @@ export declare function ThemeManagerSessionMixin(_pluginManager: PluginManager):
18
18
  sessionThemeMode: ThemeModeSelection;
19
19
  systemThemeOverride: PaletteMode | undefined;
20
20
  systemPrefersDark: boolean;
21
+ darkReaderDark: boolean;
21
22
  } & {
22
23
  /**
23
24
  * #method
@@ -39,8 +40,14 @@ export declare function ThemeManagerSessionMixin(_pluginManager: PluginManager):
39
40
  readonly themeMode: ThemeModeSelection;
40
41
  /**
41
42
  * #getter
42
- * Light or dark, with `system` resolved against the OS preference or
43
- * the toolbar's hold on the other mode.
43
+ * Light or dark as the reader chose it, `system` resolved against the
44
+ * OS or the toolbar's hold. What a file leaves the session in, since
45
+ * Dark Reader never touches the file.
46
+ */
47
+ readonly selectedThemeMode: PaletteMode;
48
+ /**
49
+ * #getter
50
+ * `selectedThemeMode`, but dark while Dark Reader darkens the page.
44
51
  */
45
52
  readonly effectiveThemeMode: PaletteMode;
46
53
  /**
@@ -115,6 +122,10 @@ export declare function ThemeManagerSessionMixin(_pluginManager: PluginManager):
115
122
  * which would otherwise resurface on the next palette change.
116
123
  */
117
124
  setThemeName(name: string): void;
125
+ /**
126
+ * #action
127
+ */
128
+ noteDarkReader(): void;
118
129
  /**
119
130
  * #action
120
131
  */