@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
@@ -3,7 +3,7 @@ import { resolvePalette, resolveThemeSelection } from '@jbrowse/core/ui/palette'
3
3
  import { resolveStyleTheme } from '@jbrowse/core/ui/styleTheme';
4
4
  import { createJBrowseThemeFromArgs, defaultThemes, } from '@jbrowse/core/ui/theme';
5
5
  import { localStorageGetItem, localStorageSetItem } from '@jbrowse/core/util';
6
- import { onColorSchemeChange, prefersDarkColorScheme, } from '@jbrowse/core/util/systemColorScheme';
6
+ import { darkReaderIsDark, onColorSchemeChange, onDarkReaderChange, prefersDarkColorScheme, } from '@jbrowse/core/util/systemColorScheme';
7
7
  import { addDisposer, types } from '@jbrowse/mobx-state-tree';
8
8
  import { autorun } from 'mobx';
9
9
  import { asSession } from '../siblingCast.js';
@@ -70,6 +70,7 @@ export function ThemeManagerSessionMixin(_pluginManager) {
70
70
  .volatile(() => ({
71
71
  ...storedSelection(),
72
72
  systemPrefersDark: prefersDarkColorScheme(),
73
+ darkReaderDark: darkReaderIsDark(),
73
74
  }))
74
75
  .views(s => {
75
76
  const self = asSession(s);
@@ -101,15 +102,23 @@ export function ThemeManagerSessionMixin(_pluginManager) {
101
102
  },
102
103
  /**
103
104
  * #getter
104
- * Light or dark, with `system` resolved against the OS preference or
105
- * the toolbar's hold on the other mode.
105
+ * Light or dark as the reader chose it, `system` resolved against the
106
+ * OS or the toolbar's hold. What a file leaves the session in, since
107
+ * Dark Reader never touches the file.
106
108
  */
107
- get effectiveThemeMode() {
109
+ get selectedThemeMode() {
108
110
  return this.themeMode === 'system'
109
111
  ? (self.systemThemeOverride ??
110
112
  (self.systemPrefersDark ? 'dark' : 'light'))
111
113
  : this.themeMode;
112
114
  },
115
+ /**
116
+ * #getter
117
+ * `selectedThemeMode`, but dark while Dark Reader darkens the page.
118
+ */
119
+ get effectiveThemeMode() {
120
+ return self.darkReaderDark ? 'dark' : this.selectedThemeMode;
121
+ },
113
122
  /**
114
123
  * #getter
115
124
  * Whether what is drawn right now is dark. Read off the resolved
@@ -195,7 +204,7 @@ export function ThemeManagerSessionMixin(_pluginManager) {
195
204
  const selection = resolveThemeSelection(name ?? this.themeName, undefined, all);
196
205
  const themeName = resolveThemeName(all, selection.themeName);
197
206
  const theme = all[themeName];
198
- const mode = theme?.palette?.mode ?? selection.mode ?? this.effectiveThemeMode;
207
+ const mode = theme?.palette?.mode ?? selection.mode ?? this.selectedThemeMode;
199
208
  if (themeName !== 'default') {
200
209
  return { ...theme, palette: { ...theme?.palette, mode } };
201
210
  }
@@ -231,6 +240,12 @@ export function ThemeManagerSessionMixin(_pluginManager) {
231
240
  self.systemThemeOverride = undefined;
232
241
  }
233
242
  },
243
+ /**
244
+ * #action
245
+ */
246
+ noteDarkReader() {
247
+ self.darkReaderDark = darkReaderIsDark();
248
+ },
234
249
  /**
235
250
  * #action
236
251
  */
@@ -273,6 +288,9 @@ export function ThemeManagerSessionMixin(_pluginManager) {
273
288
  addDisposer(self, onColorSchemeChange(() => {
274
289
  self.setSystemPrefersDark(prefersDarkColorScheme());
275
290
  }));
291
+ addDisposer(self, onDarkReaderChange(() => {
292
+ self.noteDarkReader();
293
+ }));
276
294
  addDisposer(self, autorun(function themeNameAutorun() {
277
295
  // persist the raw selection, not the coerced themeName, so a
278
296
  // theme registered later isn't clobbered with 'default'
@@ -1,5 +1,5 @@
1
1
  import type PluginManager from '@jbrowse/core/PluginManager';
2
- import type { AnyConfigurationModel } from '@jbrowse/core/configuration';
2
+ import type { AnyConfigurationModel, AnyTrackConfig } from '@jbrowse/core/configuration';
3
3
  import type { BaseTrackConfig } from '@jbrowse/core/pluggableElementTypes';
4
4
  import type { MenuItem } from '@jbrowse/core/ui';
5
5
  import type { DialogComponentType } from '@jbrowse/core/util';
@@ -11,7 +11,7 @@ interface TrackActionSession<C> {
11
11
  expandedDisplayId?: string;
12
12
  }) => void;
13
13
  publishTrackConf: (conf: C) => unknown;
14
- deleteTrackConf: (conf: AnyConfigurationModel) => void;
14
+ deleteTrackConf: (conf: AnyTrackConfig) => void;
15
15
  resetTrackConfiguration?: (trackId: string) => void;
16
16
  /**
17
17
  * Declared here, though only the copy guard below reads it, so a session that
@@ -41,7 +41,7 @@ export declare function trackActionItems<C extends {
41
41
  trackId: string;
42
42
  }>({ session, config, view, canEdit, isSessionOverride, makeCopy, }: {
43
43
  session: TrackActionSession<C>;
44
- config: BaseTrackConfig;
44
+ config: AnyTrackConfig;
45
45
  view?: TrackActionView;
46
46
  canEdit: boolean;
47
47
  isSessionOverride?: boolean;
@@ -75,7 +75,7 @@ export declare function TrackMenuItemsSessionMixin(pluginManager: PluginManager)
75
75
  * #method
76
76
  * flattened menu items for use in hierarchical track selector
77
77
  */
78
- getTrackListMenuItems(config: BaseTrackConfig, view?: TrackActionView): MenuItem[];
78
+ getTrackListMenuItems(config: AnyTrackConfig, view?: TrackActionView): MenuItem[];
79
79
  /**
80
80
  * #method
81
81
  * track menu with About + "Track actions" submenu for the in-view label
@@ -1,5 +1,5 @@
1
1
  import type PluginManager from '@jbrowse/core/PluginManager';
2
- import type { AnyConfigurationModel } from '@jbrowse/core/configuration';
2
+ import type { AnyConfigurationModel, AnyTrackConfig } from '@jbrowse/core/configuration';
3
3
  import type { MenuItem } from '@jbrowse/core/ui';
4
4
  import type { TrackActionView } from '@jbrowse/core/util/types';
5
5
  /**
@@ -16,7 +16,7 @@ export declare function TrackMenuSessionMixin(pluginManager: PluginManager): imp
16
16
  * #method
17
17
  * flattened menu items for use in hierarchical track selector
18
18
  */
19
- getTrackListMenuItems(config: AnyConfigurationModel, view?: TrackActionView): MenuItem[];
19
+ getTrackListMenuItems(config: AnyTrackConfig, view?: TrackActionView): MenuItem[];
20
20
  /**
21
21
  * #method
22
22
  */
@@ -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, AnyTrackConfig, TrackConfigEntry } from '@jbrowse/core/configuration';
3
3
  import type { IAnyStateTreeNode, Instance } from '@jbrowse/mobx-state-tree';
4
4
  /**
5
5
  * #stateModel TracksManagerSessionMixin
@@ -376,8 +376,8 @@ export declare function TracksManagerSessionMixin(pluginManager: PluginManager):
376
376
  getRefNameMismatch(adapterCacheKey: string): import("@jbrowse/core/assemblyManager/assembly").RefNameMismatch | undefined;
377
377
  }, import("@jbrowse/mobx-state-tree")._NotCustomized, import("@jbrowse/mobx-state-tree")._NotCustomized>>) | undefined;
378
378
  readonly assemblyNamesList: string[];
379
- readonly confByName: Map<string, AnyConfigurationModel>;
380
- readonly assemblyList: AnyConfigurationModel[];
379
+ readonly confByName: Map<string, import("@jbrowse/core/configuration").AnyConfigurationModel>;
380
+ readonly assemblyList: import("@jbrowse/core/configuration").AnyConfigurationModel[];
381
381
  readonly rpcManager: import("@jbrowse/core/rpc/RpcManager").default;
382
382
  } & {
383
383
  settleAssemblyResolution(assemblyName: string): Promise<void>;
@@ -1031,8 +1031,8 @@ export declare function TracksManagerSessionMixin(pluginManager: PluginManager):
1031
1031
  getRefNameMismatch(adapterCacheKey: string): import("@jbrowse/core/assemblyManager/assembly").RefNameMismatch | undefined;
1032
1032
  }, import("@jbrowse/mobx-state-tree")._NotCustomized, import("@jbrowse/mobx-state-tree")._NotCustomized>>) | undefined;
1033
1033
  readonly assemblyNamesList: string[];
1034
- readonly confByName: Map<string, AnyConfigurationModel>;
1035
- readonly assemblyList: AnyConfigurationModel[];
1034
+ readonly confByName: Map<string, import("@jbrowse/core/configuration").AnyConfigurationModel>;
1035
+ readonly assemblyList: import("@jbrowse/core/configuration").AnyConfigurationModel[];
1036
1036
  readonly rpcManager: import("@jbrowse/core/rpc/RpcManager").default;
1037
1037
  } & {
1038
1038
  settleAssemblyResolution(assemblyName: string): Promise<void>;
@@ -1393,17 +1393,17 @@ export declare function TracksManagerSessionMixin(pluginManager: PluginManager):
1393
1393
  * Each track's base by trackId: the entry its edits diff against. Here
1394
1394
  * the config.json entry, which an edit writes directly.
1395
1395
  */
1396
- readonly trackBasesById: Map<string, AnyConfigurationModel>;
1396
+ readonly trackBasesById: Map<string, TrackConfigEntry>;
1397
1397
  /**
1398
1398
  * #method
1399
1399
  * A track's base as the session resolves it, its edits applied. Here the
1400
1400
  * base itself.
1401
1401
  */
1402
- withTrackEdits(base: AnyConfigurationModel): AnyConfigurationModel;
1402
+ withTrackEdits(base: TrackConfigEntry): TrackConfigEntry;
1403
1403
  /**
1404
1404
  * #getter
1405
1405
  */
1406
- readonly tracks: AnyConfigurationModel[];
1406
+ readonly tracks: TrackConfigEntry[];
1407
1407
  } & {
1408
1408
  afterAttach(): void;
1409
1409
  } & {
@@ -1415,7 +1415,7 @@ export declare function TracksManagerSessionMixin(pluginManager: PluginManager):
1415
1415
  * subscribes only to its own id, so one track's settings edit doesn't
1416
1416
  * re-render the others.
1417
1417
  */
1418
- getTrackById(id: string): AnyConfigurationModel | undefined;
1418
+ getTrackById(id: string): AnyTrackConfig | undefined;
1419
1419
  /**
1420
1420
  * #method
1421
1421
  * Every track config the session can resolve, keyed by trackId.
@@ -1426,7 +1426,7 @@ export declare function TracksManagerSessionMixin(pluginManager: PluginManager):
1426
1426
  *
1427
1427
  * @deprecated
1428
1428
  */
1429
- getTracksById(): Record<string, AnyConfigurationModel>;
1429
+ getTracksById(): Record<string, AnyTrackConfig>;
1430
1430
  } & {
1431
1431
  /**
1432
1432
  * #action
@@ -1487,7 +1487,7 @@ export declare function TracksManagerSessionMixin(pluginManager: PluginManager):
1487
1487
  /**
1488
1488
  * #action
1489
1489
  */
1490
- deleteTrackConf(trackConf: AnyConfigurationModel): any;
1490
+ deleteTrackConf(trackConf: AnyTrackConfig): any;
1491
1491
  }, import("@jbrowse/mobx-state-tree")._NotCustomized, import("@jbrowse/mobx-state-tree")._NotCustomized>;
1492
1492
  /** Session mixin MST type for a session that has tracks */
1493
1493
  export type SessionWithTracksType = ReturnType<typeof TracksManagerSessionMixin>;
@@ -218,8 +218,8 @@ export function TracksManagerSessionMixin(pluginManager) {
218
218
  updateTrackConfiguration(trackConf) {
219
219
  // an opened connection track lives in connectionTrackConfigs, not
220
220
  // jbrowse.tracks; persist its edit there (jbrowse.updateTrackConf would
221
- // no-op, since the track isn't in the config). Desktop uses this base
222
- // mixin, so without this branch a connection-track edit is lost on
221
+ // no-op, since the track isn't in the config). SessionTracks defers a
222
+ // connection track's edit here, so without this branch it is lost on
223
223
  // reload.
224
224
  if (isSessionWithConnections(self) &&
225
225
  trackConf.trackId in self.connectionTrackConfigs) {
@@ -1,4 +1,4 @@
1
- import type { BaseTrackConfig } from '@jbrowse/core/pluggableElementTypes';
1
+ import type { AnyTrackConfig } from '@jbrowse/core/configuration';
2
2
  type TrackCopySnapshot = {
3
3
  trackId: string;
4
4
  name?: string;
@@ -15,7 +15,7 @@ type TrackCopySnapshot = {
15
15
  * `${trackId}-${type}` form baseTrackConfig auto-injects — keeping them unique
16
16
  * (displayId is a types.identifier, so a collision would crash MST).
17
17
  */
18
- export declare function copyTrackSnapshot(config: BaseTrackConfig, opts: {
18
+ export declare function copyTrackSnapshot(config: AnyTrackConfig, opts: {
19
19
  clearCategory: boolean;
20
20
  }): TrackCopySnapshot;
21
21
  export {};
@@ -18,7 +18,7 @@ export { SessionTracksManagerSessionMixin } from './SessionTracks.ts';
18
18
  export type { EditableTrackConfig, PlainTrackConfig, SessionWithSessionTracks, SessionWithSessionTracksType, } from './SessionTracks.ts';
19
19
  export { hydratedForms } from './hydratedForms.ts';
20
20
  export type { HydratedForms } from './hydratedForms.ts';
21
- export { bakeSessionCascades, getShareableSessionSnapshot, } from './shareableSnapshot.ts';
21
+ export { getShareableSessionSnapshot } from './shareableSnapshot.ts';
22
22
  export { TrackMenuItemsSessionMixin, aboutTrackMenuItem, trackActionItems, trackActionMenuItems, trackListMenuItems, } from './TrackMenu.ts';
23
23
  export { copyTrackSnapshot } from './copyTrackSnapshot.ts';
24
24
  export { pluginExtraTrackItems } from './pluginExtraTrackItems.ts';
@@ -8,7 +8,7 @@ export { PreferencesSessionMixin } from './Preferences.js';
8
8
  export { BaseSessionModel, isBaseSession, isSession } from './BaseSession.js';
9
9
  export { SessionTracksManagerSessionMixin } from './SessionTracks.js';
10
10
  export { hydratedForms } from './hydratedForms.js';
11
- export { bakeSessionCascades, getShareableSessionSnapshot, } from './shareableSnapshot.js';
11
+ export { getShareableSessionSnapshot } from './shareableSnapshot.js';
12
12
  export { TrackMenuItemsSessionMixin, aboutTrackMenuItem, trackActionItems, trackActionMenuItems, trackListMenuItems, } from './TrackMenu.js';
13
13
  export { copyTrackSnapshot } from './copyTrackSnapshot.js';
14
14
  export { pluginExtraTrackItems } from './pluginExtraTrackItems.js';
@@ -1,6 +1,6 @@
1
1
  import type { SessionWithDialog } from './TrackMenu.ts';
2
2
  import type PluginManager from '@jbrowse/core/PluginManager';
3
- import type { AnyConfigurationModel } from '@jbrowse/core/configuration';
3
+ import type { AnyTrackConfig } from '@jbrowse/core/configuration';
4
4
  import type { MenuItem } from '@jbrowse/core/ui';
5
5
  import type { TrackActionView } from '@jbrowse/core/util/types';
6
6
  /**
@@ -8,4 +8,4 @@ import type { TrackActionView } from '@jbrowse/core/util/types';
8
8
  * both the hierarchical selector and the in-view label menu so plugins reach
9
9
  * every track menu consistently
10
10
  */
11
- export declare function pluginExtraTrackItems(pluginManager: PluginManager, session: SessionWithDialog, config: AnyConfigurationModel, view?: TrackActionView): MenuItem[];
11
+ export declare function pluginExtraTrackItems(pluginManager: PluginManager, session: SessionWithDialog, config: AnyTrackConfig, view?: TrackActionView): MenuItem[];
@@ -1,23 +1,7 @@
1
1
  import type { AbstractSessionModel } from '@jbrowse/core/util';
2
2
  /**
3
- * The session snapshot to hand to anyone else — a share link, an exported
4
- * `session.json`, a desktop→web export. Snapshotting and baking are one call so
5
- * the pair can't be split: a bare `getSnapshot(session)` is never a correct
6
- * outgoing snapshot (see `bakeSessionCascades`), and three of the four
7
- * boundaries were spelling the two steps out identically.
8
- *
9
- * The fourth (desktop `ExportToWebDialog`) bakes a *transformed* snapshot from
10
- * `planWebExport`, so it calls `bakeSessionCascades` directly.
3
+ * The session snapshot to hand to anyone else: a share link, an exported
4
+ * `session.json`. The one place an outgoing snapshot is taken, so anything the
5
+ * live session resolves against state that stays behind has a place to go.
11
6
  */
12
7
  export declare function getShareableSessionSnapshot(session: AbstractSessionModel): Record<string, unknown>;
13
- /**
14
- * Everything an outgoing snapshot has to resolve because the live session
15
- * resolves it at read time against state that is staying behind — currently the
16
- * workspaces intent alone.
17
- *
18
- * It keeps its own entry point rather than being inlined into the one caller
19
- * because the failure of a boundary that performs half of them is invisible at
20
- * that boundary: the export succeeds, and what is missing only shows up on
21
- * someone else's screen.
22
- */
23
- export declare function bakeSessionCascades(session: AbstractSessionModel, snapshot: Record<string, unknown>): Record<string, unknown>;
@@ -1,66 +1,9 @@
1
1
  import { getSnapshot } from '@jbrowse/mobx-state-tree';
2
2
  /**
3
- * The session snapshot to hand to anyone else — a share link, an exported
4
- * `session.json`, a desktop→web export. Snapshotting and baking are one call so
5
- * the pair can't be split: a bare `getSnapshot(session)` is never a correct
6
- * outgoing snapshot (see `bakeSessionCascades`), and three of the four
7
- * boundaries were spelling the two steps out identically.
8
- *
9
- * The fourth (desktop `ExportToWebDialog`) bakes a *transformed* snapshot from
10
- * `planWebExport`, so it calls `bakeSessionCascades` directly.
3
+ * The session snapshot to hand to anyone else: a share link, an exported
4
+ * `session.json`. The one place an outgoing snapshot is taken, so anything the
5
+ * live session resolves against state that stays behind has a place to go.
11
6
  */
12
7
  export function getShareableSessionSnapshot(session) {
13
- return bakeSessionCascades(session, getSnapshot(session));
14
- }
15
- /**
16
- * Everything an outgoing snapshot has to resolve because the live session
17
- * resolves it at read time against state that is staying behind — currently the
18
- * workspaces intent alone.
19
- *
20
- * It keeps its own entry point rather than being inlined into the one caller
21
- * because the failure of a boundary that performs half of them is invisible at
22
- * that boundary: the export succeeds, and what is missing only shows up on
23
- * someone else's screen.
24
- */
25
- export function bakeSessionCascades(session, snapshot) {
26
- const snap = structuredClone(snapshot);
27
- bakeWorkspacesIntent(session, snap);
28
- return snap;
29
- }
30
- /**
31
- * The workspaces cascade: session property -> user preference -> admin
32
- * `configuration.preferences.useWorkspaces`, of which only the first is in the
33
- * snapshot.
34
- *
35
- * So a sender whose workspace is on because *their admin turned it on* exports
36
- * a fully arranged `layout` with no statement that it is a workspace at all,
37
- * and a recipient resolving their own cascade to false renders the classic
38
- * stack: the arrangement arrives intact and invisible, with nothing to say it
39
- * was dropped.
40
- *
41
- * Only the on case is baked. At `false` there is no arrangement to carry, so
42
- * stamping it would be a sender with nothing to say overriding a recipient who
43
- * prefers workspaces.
44
- *
45
- * The paths that build a layout through an explicit user intent already set the
46
- * property themselves (`setUseWorkspacesPreference`, ViewMenu's move-view-out,
47
- * a spec `layout`), which is exactly what hides this: every arrangement made by
48
- * a *drag* — split a cell, drag a tab into it, open a new tab — goes through
49
- * `WorkspaceLayoutMixin` alone, which owns the tree and knows nothing about the
50
- * preference.
51
- *
52
- * `effectiveUseWorkspaces` is read behind an `in` guard because
53
- * `AbstractSessionModel` cannot name it (it lives on MultipleViewsSessionMixin,
54
- * one layer up), so renaming that getter silently stops the bake rather than
55
- * failing to compile — the hazard app-core/src/WorkspaceLayout/CLAUDE.md describes for
56
- * `setPendingMove`. jbrowse-web's `sessionModel/exportLayout.test.ts` is the
57
- * canary, since the bake needs a real session to have a cascade at all.
58
- */
59
- function bakeWorkspacesIntent(session, snap) {
60
- if (snap.useWorkspaces === undefined &&
61
- 'effectiveUseWorkspaces' in session &&
62
- session.effectiveUseWorkspaces ===
63
- true) {
64
- snap.useWorkspaces = true;
65
- }
8
+ return structuredClone(getSnapshot(session));
66
9
  }
@@ -1,10 +1,10 @@
1
1
  import { getEnv } from '@jbrowse/core/util';
2
2
  import { withPageBaseUri } from '@jbrowse/core/util/addRelativeUris';
3
- import { guessTrackConf } from '@jbrowse/core/util/tracks';
3
+ import { guessTrackConf, isLooseTrackConfig } from '@jbrowse/core/util/tracks';
4
4
  import { isAlive } from '@jbrowse/mobx-state-tree';
5
5
  import { resolveLocalFileUris } from './localFiles.js';
6
6
  export function isLooseTrack(track) {
7
- return typeof track === 'string' || (!('adapter' in track) && 'uri' in track);
7
+ return typeof track === 'string' || isLooseTrackConfig(track);
8
8
  }
9
9
  /**
10
10
  * Stamp the view's assembly onto a full-config track that omits
package/esm/index.d.ts CHANGED
@@ -1,9 +1,9 @@
1
1
  export type { AssertExtends, AssertNotAny } from './assertExtends.ts';
2
2
  export { asRoot, asSession } from './siblingCast.ts';
3
3
  export { scheduleDetachedDestroy } from '@jbrowse/core/util';
4
- export { BaseRootModelFactory, FormatAboutConfigSchemaFactory, FormatDetailsConfigSchemaFactory, HierarchicalConfigSchemaFactory, InternetAccountsRootModelMixin, PreferencesConfigSchemaFactory, createConfigModel, exportSessionMenuItem, importSessionMenuItem, isRootModel, newSessionMenuItem, openConnectionMenuItem, openTrackMenuItem, pluginStoreMenuItem, preferencesMenuItem, redoMenuItem, undoMenuItem, workspacesMenuItem, } from './RootModel/index.ts';
4
+ export { BaseRootModelFactory, FormatAboutConfigSchemaFactory, FormatDetailsConfigSchemaFactory, HierarchicalConfigSchemaFactory, InternetAccountsRootModelMixin, PreferencesConfigSchemaFactory, createConfigModel, exportSessionMenuItem, importSessionMenuItem, isRootModel, newSessionMenuItem, openConnectionMenuItem, openTrackMenuItem, pluginStoreMenuItem, preferencesMenuItem, redoMenuItem, undoMenuItem, } from './RootModel/index.ts';
5
5
  export type { BaseRootModel, BaseRootModelType, RootConfigurationSnapshot, RootModelWithInternetAccounts, RootModelWithInternetAccountsType, } from './RootModel/index.ts';
6
- export { BaseSessionModel, ConnectionManagementSessionMixin, DrawerWidgetSessionMixin, MultipleViewsSessionMixin, PreferencesSessionMixin, ReferenceManagementSessionMixin, SessionTracksManagerSessionMixin, ThemeManagerSessionMixin, TrackMenuItemsSessionMixin, TrackMenuSessionMixin, TracksManagerSessionMixin, aboutTrackMenuItem, bakeSessionCascades, getShareableSessionSnapshot, copyTrackSnapshot, finalizeSession, hydratedForms, isBaseSession, isSession, isSessionWithConnections, isSessionWithDrawerWidgets, isSessionWithMultipleViews, isSessionWithReferenceManagement, isSessionWithThemes, isSessionWithTracks, pluginExtraTrackItems, storedThemeArgs, trackActionItems, trackActionMenuItems, trackListMenuItems, } from './Session/index.ts';
6
+ export { BaseSessionModel, ConnectionManagementSessionMixin, DrawerWidgetSessionMixin, MultipleViewsSessionMixin, PreferencesSessionMixin, ReferenceManagementSessionMixin, SessionTracksManagerSessionMixin, ThemeManagerSessionMixin, TrackMenuItemsSessionMixin, TrackMenuSessionMixin, TracksManagerSessionMixin, aboutTrackMenuItem, getShareableSessionSnapshot, copyTrackSnapshot, finalizeSession, hydratedForms, isBaseSession, isSession, isSessionWithConnections, isSessionWithDrawerWidgets, isSessionWithMultipleViews, isSessionWithReferenceManagement, isSessionWithThemes, isSessionWithTracks, pluginExtraTrackItems, storedThemeArgs, trackActionItems, trackActionMenuItems, trackListMenuItems, } from './Session/index.ts';
7
7
  export type { AssertSessionModel, BaseSession, BaseSessionType, ConnectionTrackConfigEntry, EditableTrackConfig, HydratedForms, PlainTrackConfig, ReferringNode, SessionWithConnections, SessionWithConnectionsType, SessionWithDrawerWidgets, SessionWithDrawerWidgetsType, SessionWithMultipleViews, SessionWithMultipleViewsType, SessionWithReferenceManagement, SessionWithReferenceManagementType, SessionWithSessionTracks, SessionWithSessionTracksType, SessionWithThemes, SessionWithThemesType, SessionWithTracks, SessionWithTracksType, ThemeModeSelection, } from './Session/index.ts';
8
8
  export { AboutDialog, AppReadyMarker, Drawer, DrawerControls, DrawerHeader, DrawerWidget, DrawerWidgetSelector, ModalWidget, ModalWidgetAppBar, PreferencesDialog, WidgetBody, WidgetHeading, drawerGridTemplateColumns, } from './ui/index.ts';
9
9
  export type { AboutPanelProps, PreferencesDialogSession, PreferencesPanelDescriptor, } from './ui/index.ts';
package/esm/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  export { asRoot, asSession } from './siblingCast.js';
2
2
  export { scheduleDetachedDestroy } from '@jbrowse/core/util';
3
- export { BaseRootModelFactory, FormatAboutConfigSchemaFactory, FormatDetailsConfigSchemaFactory, HierarchicalConfigSchemaFactory, InternetAccountsRootModelMixin, PreferencesConfigSchemaFactory, createConfigModel, exportSessionMenuItem, importSessionMenuItem, isRootModel, newSessionMenuItem, openConnectionMenuItem, openTrackMenuItem, pluginStoreMenuItem, preferencesMenuItem, redoMenuItem, undoMenuItem, workspacesMenuItem, } from './RootModel/index.js';
4
- export { BaseSessionModel, ConnectionManagementSessionMixin, DrawerWidgetSessionMixin, MultipleViewsSessionMixin, PreferencesSessionMixin, ReferenceManagementSessionMixin, SessionTracksManagerSessionMixin, ThemeManagerSessionMixin, TrackMenuItemsSessionMixin, TrackMenuSessionMixin, TracksManagerSessionMixin, aboutTrackMenuItem, bakeSessionCascades, getShareableSessionSnapshot, copyTrackSnapshot, finalizeSession, hydratedForms, isBaseSession, isSession, isSessionWithConnections, isSessionWithDrawerWidgets, isSessionWithMultipleViews, isSessionWithReferenceManagement, isSessionWithThemes, isSessionWithTracks, pluginExtraTrackItems, storedThemeArgs, trackActionItems, trackActionMenuItems, trackListMenuItems, } from './Session/index.js';
3
+ export { BaseRootModelFactory, FormatAboutConfigSchemaFactory, FormatDetailsConfigSchemaFactory, HierarchicalConfigSchemaFactory, InternetAccountsRootModelMixin, PreferencesConfigSchemaFactory, createConfigModel, exportSessionMenuItem, importSessionMenuItem, isRootModel, newSessionMenuItem, openConnectionMenuItem, openTrackMenuItem, pluginStoreMenuItem, preferencesMenuItem, redoMenuItem, undoMenuItem, } from './RootModel/index.js';
4
+ export { BaseSessionModel, ConnectionManagementSessionMixin, DrawerWidgetSessionMixin, MultipleViewsSessionMixin, PreferencesSessionMixin, ReferenceManagementSessionMixin, SessionTracksManagerSessionMixin, ThemeManagerSessionMixin, TrackMenuItemsSessionMixin, TrackMenuSessionMixin, TracksManagerSessionMixin, aboutTrackMenuItem, getShareableSessionSnapshot, copyTrackSnapshot, finalizeSession, hydratedForms, isBaseSession, isSession, isSessionWithConnections, isSessionWithDrawerWidgets, isSessionWithMultipleViews, isSessionWithReferenceManagement, isSessionWithThemes, isSessionWithTracks, pluginExtraTrackItems, storedThemeArgs, trackActionItems, trackActionMenuItems, trackListMenuItems, } from './Session/index.js';
5
5
  export { AboutDialog, AppReadyMarker, Drawer, DrawerControls, DrawerHeader, DrawerWidget, DrawerWidgetSelector, ModalWidget, ModalWidgetAppBar, PreferencesDialog, WidgetBody, WidgetHeading, drawerGridTemplateColumns, } from './ui/index.js';
6
6
  export { initializeWorker } from './rpcWorker.js';
7
7
  export { toPluginLoadRecord } from './pluginInput.js';
@@ -12,10 +12,6 @@ export interface SessionSnapshot {
12
12
  * hash fragment. Deflated then base64url-encoded, so it survives a URL intact
13
13
  * and stays far smaller than raw JSON.
14
14
  *
15
- * Not a plain `getSnapshot`: a workspace arrangement turned on by the sender's
16
- * preference is not in the snapshot, so a raw one renders as a classic stack
17
- * for whoever opens the link. `getShareableSessionSnapshot` stamps it first.
18
- *
19
15
  * The session travels but the config does not — the receiving app supplies its
20
16
  * own assembly/tracks. Put the result somewhere the server never sees (the hash
21
17
  * fragment) if it may be long: a query string can exceed the request-line limit
package/esm/sessionUrl.js CHANGED
@@ -5,10 +5,6 @@ import { getShareableSessionSnapshot } from './Session/shareableSnapshot.js';
5
5
  * hash fragment. Deflated then base64url-encoded, so it survives a URL intact
6
6
  * and stays far smaller than raw JSON.
7
7
  *
8
- * Not a plain `getSnapshot`: a workspace arrangement turned on by the sender's
9
- * preference is not in the snapshot, so a raw one renders as a classic stack
10
- * for whoever opens the link. `getShareableSessionSnapshot` stamps it first.
11
- *
12
8
  * The session travels but the config does not — the receiving app supplies its
13
9
  * own assembly/tracks. Put the result somewhere the server never sees (the hash
14
10
  * fragment) if it may be long: a query string can exceed the request-line limit
@@ -312,7 +312,7 @@ function nonPortableUserTracks(report, droppable) {
312
312
  // place, keeping the base trackId, and persists the whole config). So a track the
313
313
  // hub itself changed since then also lands in `editDeltas`, pinning the recipient
314
314
  // to the values the sender is looking at. That is the export's stated intent —
315
- // reproduce the sender's screen, the same reason `bakeSessionCascades` exists —
315
+ // reproduce the sender's screen —
316
316
  // but the delta channel it travels in means "user override" on the far side, and
317
317
  // a delta masks later admin changes to that track. Telling the two apart needs
318
318
  // the base as it was at session creation, which nothing persists.
@@ -1,8 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useState } from 'react';
3
- import Attributes from '@jbrowse/core/BaseFeatureWidget/BaseFeatureDetail/Attributes';
3
+ import Attributes, { hasAttributeRows, withoutLocations, } from '@jbrowse/core/BaseFeatureWidget/BaseFeatureDetail/Attributes';
4
4
  import BaseCard from '@jbrowse/core/BaseFeatureWidget/BaseFeatureDetail/BaseCard';
5
- import { readConfObject } from '@jbrowse/core/configuration';
6
5
  import PluggableComponents from '@jbrowse/core/ui/PluggableComponents';
7
6
  import { getEnv } from '@jbrowse/core/util';
8
7
  import { makeStyles } from '@jbrowse/core/util/tss-react';
@@ -12,6 +11,7 @@ import DescriptionPanel from './DescriptionPanel.js';
12
11
  import FileInfoPanel from './FileInfoPanel.js';
13
12
  import HeaderButtons from './HeaderButtons.js';
14
13
  import RefNameInfoDialog from './RefNameInfoDialog.js';
14
+ import { omitTrackDescription } from './descriptionHtml.js';
15
15
  import { getAboutDialogConfig } from './util.js';
16
16
  const useStyles = makeStyles()({
17
17
  content: {
@@ -23,8 +23,9 @@ const AboutDialogContents = observer(function AboutDialogContents({ config, sess
23
23
  const { classes } = useStyles();
24
24
  const [showRefNames, setShowRefNames] = useState(false);
25
25
  const { pluginManager } = getEnv(session);
26
- const { config: shown, hideUris } = getAboutDialogConfig({ config, session });
27
- return (_jsxs("div", { className: classes.content, children: [_jsxs(BaseCard, { title: "Configuration", children: [_jsx(HeaderButtons, { conf: readConfObject(config), hideUris: hideUris, setShowRefNames: setShowRefNames }), _jsx(Attributes, { attributes: shown, omit: [...hideFields, 'metadata'], hideUris: hideUris })] }), shown.metadata ? (_jsx(BaseCard, { title: "Metadata", children: _jsx(Attributes, { attributes: shown.metadata, hideUris: hideUris }) })) : null, _jsx(DescriptionPanel, { config: config, session: session }), _jsx(AssemblyInfoPanel, { config: config, session: session, hideUris: hideUris }), _jsx(PluggableComponents, { pluginManager: pluginManager,
26
+ const { conf, config: shown, advanced, hideUris, } = getAboutDialogConfig({ config, session });
27
+ const advancedShown = hideUris ? withoutLocations(advanced) : advanced;
28
+ return (_jsxs("div", { className: classes.content, children: [_jsxs(BaseCard, { title: "Configuration", children: [_jsx(HeaderButtons, { conf: conf, hideUris: hideUris, setShowRefNames: setShowRefNames }), _jsx(Attributes, { attributes: shown, omit: [...hideFields, 'metadata'], hideUris: hideUris })] }), hasAttributeRows(advancedShown, hideFields) ? (_jsx(BaseCard, { title: "Advanced", defaultExpanded: false, children: _jsx(Attributes, { attributes: advancedShown, omit: hideFields }) })) : null, shown.metadata ? (_jsx(BaseCard, { title: "Metadata", children: _jsx(Attributes, { attributes: omitTrackDescription(shown.metadata), hideUris: hideUris }) })) : null, _jsx(DescriptionPanel, { config: config, session: session }), _jsx(AssemblyInfoPanel, { config: config, session: session, hideUris: hideUris }), _jsx(PluggableComponents, { pluginManager: pluginManager,
28
29
  /** #extensionPoint Core-extraAboutPanel | sync | Add extra panels to a track's About dialog */
29
30
  name: "Core-extraAboutPanel", props: { session, config } }), hideUris ? null : _jsx(FileInfoPanel, { config: config, session: session }), showRefNames ? (_jsx(RefNameInfoDialog, { session: session, config: config, onClose: () => {
30
31
  setShowRefNames(false);
@@ -1,4 +1,4 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import BaseCard from '@jbrowse/core/BaseFeatureWidget/BaseFeatureDetail/BaseCard';
3
3
  import { readConfObject } from '@jbrowse/core/configuration';
4
4
  import { ErrorBanner, LoadingEllipses, SanitizedHTML } from '@jbrowse/core/ui';
@@ -7,19 +7,56 @@ import { makeStyles } from '@jbrowse/core/util/tss-react';
7
7
  import { useFetch } from '@jbrowse/core/util/useFetch';
8
8
  import { Link, Typography } from '@mui/material';
9
9
  import { observer } from 'mobx-react';
10
- import { getDescriptionHtmlUrl, rebaseDescriptionHtml, } from './descriptionHtml.js';
10
+ import { getTrackDescription, rebaseDescriptionHtml, } from './descriptionHtml.js';
11
11
  const useStyles = makeStyles()(theme => ({
12
12
  provenance: {
13
13
  marginBottom: theme.spacing(1),
14
14
  },
15
+ prose: {
16
+ display: 'block',
17
+ '& h1, & h2': {
18
+ fontSize: theme.typography.pxToRem(16),
19
+ fontWeight: theme.typography.fontWeightBold,
20
+ margin: theme.spacing(2, 0, 0.5),
21
+ },
22
+ '& h3, & h4': {
23
+ fontSize: theme.typography.pxToRem(14),
24
+ fontWeight: theme.typography.fontWeightBold,
25
+ margin: theme.spacing(1.5, 0, 0.5),
26
+ },
27
+ '& > :first-child': {
28
+ marginTop: 0,
29
+ },
30
+ '& p': {
31
+ margin: theme.spacing(0, 0, 1),
32
+ },
33
+ '& table': {
34
+ borderCollapse: 'collapse',
35
+ margin: theme.spacing(1, 0),
36
+ },
37
+ '& th, & td': {
38
+ padding: theme.spacing(0.25, 1),
39
+ border: `1px solid ${theme.palette.divider}`,
40
+ },
41
+ '& img': {
42
+ maxWidth: '100%',
43
+ },
44
+ },
15
45
  }));
16
- const DescriptionCard = observer(function DescriptionCard({ url, }) {
46
+ function Prose({ html }) {
47
+ const { classes } = useStyles();
48
+ return _jsx(SanitizedHTML, { html: html, className: classes.prose });
49
+ }
50
+ function DescriptionCard({ url, children, }) {
17
51
  const { classes } = useStyles();
52
+ return (_jsxs(BaseCard, { title: "Description", children: [_jsxs(Typography, { variant: "caption", color: "textSecondary", component: "div", className: classes.provenance, children: ["The track's description, written for the UCSC Genome Browser \u2014 some display options it describes differ in JBrowse.", url ? (_jsxs(_Fragment, { children: [' ', _jsx(Link, { href: url, target: "_blank", rel: "noopener noreferrer", children: "View original" })] })) : null] }), children] }));
53
+ }
54
+ const FetchedDescription = observer(function FetchedDescription({ url, }) {
18
55
  const { data: html, error, isLoading, } = useFetch(['trackDescriptionHtml', url], async (_name, url) => rebaseDescriptionHtml(await openLocation({ uri: url, locationType: 'UriLocation' }).readFile('utf8'), url));
19
- return (_jsxs(BaseCard, { title: "Description", children: [_jsxs(Typography, { variant: "caption", color: "textSecondary", component: "div", className: classes.provenance, children: ["From the track hub, written for the UCSC Genome Browser \u2014 some display options it describes differ in JBrowse.", ' ', _jsx(Link, { href: url, target: "_blank", rel: "noopener noreferrer", children: "View original" })] }), error ? (_jsx(ErrorBanner, { error: error })) : isLoading || html === undefined ? (_jsx(LoadingEllipses, { message: "Loading description" })) : (_jsx(SanitizedHTML, { html: html }))] }));
56
+ return (_jsx(DescriptionCard, { url: url, children: error ? (_jsx(ErrorBanner, { error: error })) : isLoading || html === undefined ? (_jsx(LoadingEllipses, { message: "Loading description" })) : (_jsx(Prose, { html: html })) }));
20
57
  });
21
58
  const DescriptionPanel = observer(function DescriptionPanel({ config, }) {
22
- const url = getDescriptionHtmlUrl(readConfObject(config, 'metadata'));
23
- return url ? _jsx(DescriptionCard, { url: url }) : null;
59
+ const description = getTrackDescription(readConfObject(config, 'metadata'));
60
+ return !description ? null : 'url' in description ? (_jsx(FetchedDescription, { url: description.url })) : (_jsx(DescriptionCard, { children: _jsx(Prose, { html: description.html }) }));
24
61
  });
25
62
  export default DescriptionPanel;
@@ -7,6 +7,7 @@ export interface GeneralPreferencesSession {
7
7
  setThemeName: (arg: string) => void;
8
8
  themeMode: ThemeModeSelection;
9
9
  setThemeMode: (arg: ThemeModeSelection) => void;
10
+ darkReaderDark?: boolean;
10
11
  animationMode: AnimationMode;
11
12
  numberGrouping: boolean;
12
13
  setPreferenceOverride: (key: string, value: unknown) => void;
@@ -23,7 +23,9 @@ const GeneralPreferencesTab = observer(function GeneralPreferencesTab({ session,
23
23
  const { classes } = useStyles();
24
24
  return (_jsxs(_Fragment, { children: [_jsx(TextField, { select: true, variant: "outlined", className: classes.field, label: "Theme", value: session.themeName, onChange: event => {
25
25
  session.setThemeName(event.target.value);
26
- }, children: Object.entries(session.allThemes()).map(([key, val]) => (_jsx(MenuItem, { value: key, children: val.name || '(Unknown name)' }, key))) }), _jsx(TextField, { select: true, variant: "outlined", className: classes.field, label: "Light/dark", value: session.themeMode, onChange: event => {
26
+ }, children: Object.entries(session.allThemes()).map(([key, val]) => (_jsx(MenuItem, { value: key, children: val.name || '(Unknown name)' }, key))) }), _jsx(TextField, { select: true, variant: "outlined", className: classes.field, label: "Light/dark", value: session.themeMode, helperText: session.darkReaderDark
27
+ ? 'Dark while Dark Reader darkens this page'
28
+ : undefined, onChange: event => {
27
29
  session.setThemeMode(event.target.value);
28
30
  }, children: THEME_MODES.map(opt => (_jsx(MenuItem, { value: opt.value, children: opt.label }, opt.value))) }), _jsx(TextField, { select: true, variant: "outlined", className: classes.field, label: "Animations", value: session.animationMode, onChange: event => {
29
31
  session.setPreferenceOverride('animationMode', event.target.value);
@@ -3,8 +3,6 @@ export interface ViewPreferencesSession {
3
3
  setScrollZoom: (flag: boolean) => void;
4
4
  stickyViewHeaders: boolean;
5
5
  setStickyViewHeaders: (sticky: boolean) => void;
6
- effectiveUseWorkspaces: boolean;
7
- setUseWorkspacesPreference: (useWorkspaces: boolean) => void;
8
6
  }
9
7
  declare const ViewPreferencesTab: ({ session, }: {
10
8
  session: ViewPreferencesSession;
@@ -8,8 +8,6 @@ const ViewPreferencesTab = observer(function ViewPreferencesTab({ session, }) {
8
8
  session.setScrollZoom(checked);
9
9
  } }), _jsx(PreferenceCheckbox, { checked: session.stickyViewHeaders, label: "Keep view header visible", help: "The view header stays at the top of the page while its tracks scroll under it.", onChange: checked => {
10
10
  session.setStickyViewHeaders(checked);
11
- } }), _jsx(PreferenceCheckbox, { checked: session.effectiveUseWorkspaces, label: "Use workspaces", help: "Views open as tabs and tiles instead of stacking down the page.", onChange: checked => {
12
- session.setUseWorkspacesPreference(checked);
13
11
  } })] }));
14
12
  });
15
13
  export default ViewPreferencesTab;