@jbrowse/product-core 5.0.0-beta.7 → 5.0.0-beta.9

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 (64) hide show
  1. package/esm/RootModel/BaseRootModel.d.ts +1 -4
  2. package/esm/RootModel/HierarchicalConfig.d.ts +21 -47
  3. package/esm/RootModel/PreferencesConfig.d.ts +18 -49
  4. package/esm/RootModel/PreferencesConfig.js +2 -3
  5. package/esm/RootModel/createConfigModel.d.ts +141 -124
  6. package/esm/RootModel/createConfigModel.js +26 -14
  7. package/esm/RootModel/menuItems.js +4 -6
  8. package/esm/Session/BaseSession.d.ts +30 -13
  9. package/esm/Session/BaseSession.js +50 -16
  10. package/esm/Session/Connections.d.ts +4 -3
  11. package/esm/Session/Connections.js +4 -3
  12. package/esm/Session/DrawerWidgets.d.ts +8 -1
  13. package/esm/Session/DrawerWidgets.js +19 -7
  14. package/esm/Session/MultipleViews.d.ts +13 -14
  15. package/esm/Session/Preferences.d.ts +8 -13
  16. package/esm/Session/SessionTracks.d.ts +32 -38
  17. package/esm/Session/SessionTracks.js +52 -115
  18. package/esm/Session/Themes.d.ts +9 -10
  19. package/esm/Session/Themes.js +9 -10
  20. package/esm/Session/TrackMenu.d.ts +1 -26
  21. package/esm/Session/TrackMenu.js +2 -33
  22. package/esm/Session/TrackMenuSessionMixin.js +2 -1
  23. package/esm/Session/Tracks.d.ts +8 -13
  24. package/esm/Session/copyTrackSnapshot.d.ts +21 -0
  25. package/esm/Session/copyTrackSnapshot.js +20 -0
  26. package/esm/Session/hydratedForms.d.ts +16 -0
  27. package/esm/Session/hydratedForms.js +13 -0
  28. package/esm/Session/index.d.ts +5 -1
  29. package/esm/Session/index.js +4 -1
  30. package/esm/Session/pluginExtraTrackItems.d.ts +11 -0
  31. package/esm/Session/pluginExtraTrackItems.js +13 -0
  32. package/esm/controllerTracks.d.ts +13 -8
  33. package/esm/controllerTracks.js +18 -9
  34. package/esm/index.d.ts +6 -6
  35. package/esm/index.js +3 -3
  36. package/esm/loadPlugins.d.ts +7 -2
  37. package/esm/loadPlugins.js +6 -2
  38. package/esm/resolveAssemblies.d.ts +34 -11
  39. package/esm/resolveAssemblies.js +29 -11
  40. package/esm/rpcWorker.d.ts +12 -5
  41. package/esm/rpcWorker.js +1 -1
  42. package/esm/sessionMigrations/index.d.ts +5 -5
  43. package/esm/sessionMigrations/index.js +82 -19
  44. package/esm/sessionUrl.js +1 -1
  45. package/esm/sessionUtils.d.ts +6 -1
  46. package/esm/sessionUtils.js +42 -35
  47. package/esm/ui/AboutDialog.d.ts +10 -2
  48. package/esm/ui/AboutDialog.js +11 -2
  49. package/esm/ui/AboutDialogContents.js +3 -21
  50. package/esm/ui/AppReadyMarker.d.ts +45 -0
  51. package/esm/ui/AppReadyMarker.js +89 -0
  52. package/esm/ui/AssemblyInfoPanel.js +4 -10
  53. package/esm/ui/DescriptionPanel.js +2 -1
  54. package/esm/ui/FileInfoPanel.js +5 -10
  55. package/esm/ui/RefNameInfoDialog.js +10 -23
  56. package/esm/ui/aboutTestUtils.d.ts +140 -0
  57. package/esm/ui/aboutTestUtils.js +25 -0
  58. package/esm/ui/descriptionHtml.d.ts +5 -6
  59. package/esm/ui/descriptionHtml.js +5 -7
  60. package/esm/ui/index.d.ts +2 -0
  61. package/esm/ui/index.js +1 -0
  62. package/esm/ui/util.d.ts +9 -27
  63. package/esm/ui/util.js +12 -31
  64. package/package.json +4 -4
@@ -1,26 +1,20 @@
1
1
  import { readConfObject } from '@jbrowse/core/configuration';
2
2
  import { diffTrackConfig, flattenTrackConfigDelta, mergeTrackConfig, } from '@jbrowse/core/util';
3
3
  import { expandLooseTrackConfig } from '@jbrowse/core/util/tracks';
4
- import { applySnapshot, getSnapshot, isStateTreeNode, types, } from '@jbrowse/mobx-state-tree';
4
+ import { applySnapshot, getSnapshot, types } from '@jbrowse/mobx-state-tree';
5
5
  import { compareStructural } from 'mobx';
6
6
  import { TracksManagerSessionMixin } from './Tracks.js';
7
+ import { hydratedTrackForm } from './hydratedForms.js';
7
8
  import { assertNotReaddedDifferently } from './readdedTrackConf.js';
8
9
  import { assertTrackConfOutlivesItsAssemblies } from './temporaryAssemblyTracks.js';
9
- // jbrowse.tracks holds frozen plain objects (app-core, web/desktop) or MST
10
- // config nodes (product-core, embedded react views); the delta math reads both
11
- // as plain track configs. Single site for that documented cast — per-node
12
- // normalization still happens in toPlainConfig.
10
+ // jbrowse.tracks holds frozen plain objects in every product; single site for
11
+ // the cast from its loose frozen type.
13
12
  function baseTracks(self) {
14
13
  return self.jbrowse.tracks;
15
14
  }
16
- // A delta must not be stored unless it records a real user edit, or it would
17
- // flip isTrackOverride (edited badge + Reset menu) on with nothing actually
18
- // overridden. Two ways an empty edit slips past a key count: diffTrackConfig
19
- // always retains the self-identifying trackId, and a base config that omits
20
- // `displays` diffs against the hydrated snapshot's injected {type, displayId}
21
- // display stubs to yield `{trackId, displays: [...stubs]}` — nonzero keys but no
22
- // changed slot. flattenTrackConfigDelta (which drops identity keys and empty
23
- // display stubs) is the honest test of whether any real setting changed.
15
+ // Not a key count: every delta keeps its trackId, and one can hold nothing but
16
+ // content-free display stubs. A stored delta lights the edited badge, so only a
17
+ // changed slot — a reset included — counts.
24
18
  function deltaHasChanges(base, delta) {
25
19
  return flattenTrackConfigDelta(base, delta).length > 0;
26
20
  }
@@ -52,42 +46,20 @@ function withoutDelta(deltas, trackId) {
52
46
  * #stateModel SessionTracksManagerSessionMixin
53
47
  */
54
48
  export function SessionTracksManagerSessionMixin(pluginManager) {
55
- // A jbrowse.tracks base entry and a shown track's persisted snapshot are in
56
- // two different config "normal forms". A base (app-core web/desktop) is the
57
- // raw config-file object: shorthand `uri`, no injected display stubs. But a
58
- // shown track's snapshot comes from a live hydrated config node, so it is
59
- // post-preProcessSnapshot: the `uri` shorthand is expanded to
60
- // bamLocation/index, `baseUri` is propagated into those locations, and a
61
- // {type, displayId} stub is injected per compatible display type. Diffing or
62
- // merging across those two forms makes every expanded/injected field read as
63
- // a user edit — pinning whole adapters and content-free display stubs into
64
- // deltas, and defeating the delta's purpose (a later admin adapter-URL fix
65
- // would then be masked by the pinned copy). Normalize a base to the hydrated
66
- // form by running it through the same track schema, so diff/merge compare
67
- // like with like and cancel everything untouched. Memoized per frozen-base
68
- // identity (stable until a jbrowse.tracks write). A base that is already an
69
- // MST config node (product-core embedded views) is snapshotted directly — it
70
- // is already in the hydrated form.
71
- //
72
- // The isStateTreeNode/getSnapshot casts are load-bearing, don't "simplify"
73
- // them: our MST fork types `isStateTreeNode`'s parameter as a state-tree node
74
- // (not `unknown`), so `base` (a plain interface) must widen through `unknown`
75
- // to be passed, and `getSnapshot` of that returns `unknown`.
49
+ // A base is the raw config-file object — shorthand `uri`, no display stubs —
50
+ // while a working copy's snapshot is hydrated. Diffing or merging across the
51
+ // two reads every expanded field as an edit, pinning whole adapters into the
52
+ // delta, and every member one form has and the other lacks as a reset. So
53
+ // both sides go through the same schema first; a base is memoized per
54
+ // frozen-base identity, which is stable until a jbrowse.tracks write.
55
+ const hydrate = hydratedTrackForm(pluginManager);
76
56
  const canonicalBaseCache = new WeakMap();
77
57
  function toPlainConfig(base) {
78
- const node = base;
79
- if (isStateTreeNode(node)) {
80
- return getSnapshot(node);
81
- }
82
58
  const cached = canonicalBaseCache.get(base);
83
59
  if (cached) {
84
60
  return cached;
85
61
  }
86
- const schema = pluginManager.pluggableConfigSchemaType('track');
87
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion -- tsc7 sees getSnapshot here as unknown (eslint's TS6 service disagrees; see header note)
88
- /* oxlint-disable typescript/no-unnecessary-type-assertion */
89
- const hydrated = getSnapshot(schema.create(base, { pluginManager }));
90
- /* oxlint-enable typescript/no-unnecessary-type-assertion */
62
+ const hydrated = hydrate(base);
91
63
  canonicalBaseCache.set(base, hydrated);
92
64
  return hydrated;
93
65
  }
@@ -106,9 +78,10 @@ export function SessionTracksManagerSessionMixin(pluginManager) {
106
78
  * Per-track config overrides for a non-admin, keyed by trackId, stored as a
107
79
  * *delta* against the admin-owned base config (jbrowse.tracks entry) rather
108
80
  * than a full copy — so a later admin change to an untouched field still
109
- * flows through (see trackConfigDelta.ts). Frozen (not a typed track array)
110
- * on purpose: a typed create() would fill defaults, erasing the "unset vs
111
- * default" distinction the delta merge relies on.
81
+ * flows through (see trackConfigDelta.ts). A `null` member resets a slot
82
+ * the base sets. Frozen (not a typed track array) on purpose: a typed
83
+ * create() would fill defaults, erasing the "unset vs default"
84
+ * distinction the delta merge relies on.
112
85
  *
113
86
  * `stripDefault` for the reason every other persisted prop beside it has
114
87
  * it: without it the empty map is written into every snapshot and every
@@ -147,10 +120,9 @@ export function SessionTracksManagerSessionMixin(pluginManager) {
147
120
  // Both keys have stable identity until they actually change: a track's
148
121
  // delta only when that track is edited, and the base only on a
149
122
  // jbrowse.tracks write. This relies on a base config never mutating in
150
- // place: app-core's frozen array replaces the entry (new identity) on
151
- // updateTrackConf, and product-core's MST-node bases have no edit path at
152
- // all (no updateTrackConf; embedded sessions are adminMode:false). If an
153
- // in-place base edit is ever added, key this cache on base content too.
123
+ // place: the frozen array replaces the entry (new identity) on
124
+ // updateTrackConf. If an in-place base edit is ever added, key this cache
125
+ // on base content too.
154
126
  const mergeCache = new WeakMap();
155
127
  return {
156
128
  /**
@@ -267,13 +239,10 @@ export function SessionTracksManagerSessionMixin(pluginManager) {
267
239
  // the node identity (existing observers just update); no-op in admin mode
268
240
  // or for a track that was never edited (no working copy).
269
241
  //
270
- // Through toPlainConfig like every other read of a base in this file, not
271
- // the raw entry: in product-core's embedded sessions a base IS a live MST
272
- // config node, and applySnapshot wants a snapshot — handing it a node
273
- // reads nested nodes back out where plain objects belong. (For a frozen
274
- // base the two agree, since applySnapshot re-runs the same
275
- // preProcessSnapshot that toPlainConfig hydrates through, so this only
276
- // makes that reliance explicit.)
242
+ // Through toPlainConfig like every other read of a base in this file. The
243
+ // raw entry would do the same, since applySnapshot re-runs the
244
+ // preProcessSnapshot toPlainConfig hydrates through; this makes that
245
+ // reliance explicit.
277
246
  function revertEditableTrackConfig(trackId) {
278
247
  const entry = self.editableTrackConfigs.get(trackId);
279
248
  const base = baseTracks(self).find(t => t.trackId === trackId);
@@ -293,26 +262,16 @@ export function SessionTracksManagerSessionMixin(pluginManager) {
293
262
  }
294
263
  // Single writer for trackConfigDeltas (pass undefined to clear). Clearing
295
264
  // also reverts the working copy, which is what makes a Reset visible in an
296
- // open view — except where the caller says the working copy IS the edit
297
- // that produced the empty delta (`revertWorkingCopy: false`), where
298
- // reverting undoes it.
299
- function writeDelta(trackId, delta, { revertWorkingCopy = true } = {}) {
265
+ // open view.
266
+ function writeDelta(trackId, delta) {
300
267
  self.trackConfigDeltas = delta
301
268
  ? { ...self.trackConfigDeltas, [trackId]: delta }
302
269
  : withoutDelta(self.trackConfigDeltas, trackId);
303
- if (!delta && revertWorkingCopy) {
270
+ if (!delta) {
304
271
  revertEditableTrackConfig(trackId);
305
272
  }
306
273
  stampEditableTrackConfig(trackId);
307
274
  }
308
- // Whether `trackConf` is the working copy's own current state — i.e. this
309
- // update came from the track's live `setSlot` edits rather than from the
310
- // config editor's separate temporary node. `syncEditableTrackConfig` below
311
- // asks the same question the other way round.
312
- function isWorkingCopyState(trackId, trackConf) {
313
- const entry = self.editableTrackConfigs.get(trackId);
314
- return !!entry && compareStructural(getSnapshot(entry.node), trackConf);
315
- }
316
275
  // Push a *programmatic* update (the config editor's Apply, or any
317
276
  // updateTrackConfiguration not driven by this node's own live edits) into
318
277
  // the working copy. When the node IS the edit source its snapshot already
@@ -388,31 +347,29 @@ export function SessionTracksManagerSessionMixin(pluginManager) {
388
347
  * config.json every visitor is served; everyone else's goes to
389
348
  * `sessionTracks`.
390
349
  *
391
- * **Only the "Add track" workflows.** Those are where an admin adding a
392
- * track means to add it for the whole site. A track a feature stands up
393
- * on the user's behalf — a search result, a computed consensus, a
394
- * reconstruction's segment labels — is not a catalog entry, and one
395
- * admin click on this publishes it to every visitor, again on the next
396
- * click, with a per-launch trackId that defeats the dedupe.
397
- * `addSessionTrackConf` above is the destination for those.
350
+ * **Call it only from the "Add track" workflows**, where an admin
351
+ * adding a track means to add it for the whole site. For a track a
352
+ * feature creates on the user's behalf (a search result, a computed
353
+ * consensus, a reconstruction's segment labels), one admin click on
354
+ * this publishes it to every visitor, and each later click publishes
355
+ * another copy, because the per-launch trackId prevents deduplication.
356
+ * Use `addSessionTrackConf` above for those.
398
357
  *
399
358
  * An admin's track still goes to the session when it names an assembly
400
- * the config.json does not carry — a session spec's, a MAF sample's own
401
- * genome, a comparative view's synthesized pair. The Add-track widget
402
- * takes its assembly from the containing view, so an admin adding a
403
- * track while looking at one of those arrives here with a name no
404
- * visitor can resolve, and publishing it writes an entry the server
405
- * hands everyone and nobody can draw. The session is the one
406
- * destination where that track works, so the click keeps working and
407
- * the dangling entry is never written; a snackbar says which assembly
408
- * moved it.
359
+ * the config.json does not carry: a session spec's assembly, a MAF
360
+ * sample's genome, or a comparative view's synthesized pair. The
361
+ * Add-track widget takes its assembly from the containing view, so an
362
+ * admin adding a track in such a view passes a name no visitor can
363
+ * resolve. Publishing it would write an entry the server sends to every
364
+ * visitor and no visitor can draw. Adding it to the session keeps the
365
+ * track usable and writes no dangling entry; a snackbar names the
366
+ * assembly that caused the fallback.
409
367
  *
410
- * **The snackbar names the assembly and not the track**, which is what
411
- * lets a batch collapse to one message: `pushSnackbarMessage` dedupes on
412
- * the exact text, and `BulkAddTracksWorkflow` publishes in a loop, so
413
- * interpolating the track name stacked one identical-but-for-a-name
414
- * toast per file over an admin adding thirty. The assembly is the whole
415
- * of what an admin has to act on anyway.
368
+ * **The snackbar names the assembly and not the track**, so a batch
369
+ * produces one message: `pushSnackbarMessage` dedupes on the exact
370
+ * text, and `BulkAddTracksWorkflow` publishes in a loop. Including the
371
+ * track name would show one snackbar per file to an admin adding
372
+ * thirty. The assembly is all the admin needs to act on.
416
373
  */
417
374
  publishTrackConf(trackConf) {
418
375
  if (!self.adminMode) {
@@ -460,11 +417,8 @@ export function SessionTracksManagerSessionMixin(pluginManager) {
460
417
  : self.sessionTracks.findIndex(t => t.trackId === trackId);
461
418
  if (base) {
462
419
  const plainBase = toPlainConfig(base);
463
- const delta = diffTrackConfig(plainBase, trackConf);
464
- // an edit that nets back to the base carries no changed slots: clear
465
- // any prior override (implicit reset) instead of pinning a
466
- // content-free delta; skip a no-op write when there's nothing to
467
- // clear, so the tracks getter doesn't needlessly churn identity
420
+ const delta = diffTrackConfig(plainBase, hydrate(trackConf));
421
+ // an edit that nets back to the base clears any prior override
468
422
  if (deltaHasChanges(plainBase, delta)) {
469
423
  // Two views showing the same track each run BaseTrackModel's
470
424
  // persist reaction against the shared config node, so a single edit
@@ -480,24 +434,7 @@ export function SessionTracksManagerSessionMixin(pluginManager) {
480
434
  syncEditableTrackConfig(trackId, trackConf);
481
435
  }
482
436
  else if (trackId in self.trackConfigDeltas) {
483
- // An empty delta is two different situations and only one of them
484
- // is a reset. `diffTrackConfig` records adds and changes, never
485
- // deletions (its module note), so *unsetting* a slot the admin
486
- // base sets diffs to nothing exactly as netting back to the base
487
- // does — and reverting the working copy then undid the edit ~400ms
488
- // after the user watched it land. The reachable case is a size
489
- // row's reset, whose whole job is to unset a slot an admin
490
- // `config.json` declares.
491
- //
492
- // The removal still doesn't survive a reload, which is the
493
- // tombstone-free delta's documented limitation; what it no longer
494
- // does is undo itself on screen. Only the working-copy-driven path
495
- // skips the revert: the config editor edits a separate temporary
496
- // node, so there the revert is the only thing that moves the open
497
- // track back to the base.
498
- writeDelta(trackId, undefined, {
499
- revertWorkingCopy: !isWorkingCopyState(trackId, trackConf),
500
- });
437
+ writeDelta(trackId, undefined);
501
438
  }
502
439
  }
503
440
  else if (sessionIdx !== -1) {
@@ -1,5 +1,5 @@
1
1
  import type PluginManager from '@jbrowse/core/PluginManager';
2
- import type { SerializableThemeArgs, ThemeMap } from '@jbrowse/core/ui';
2
+ import type { SerializableThemeArgs, ThemeMap } from '@jbrowse/core/ui/theme';
3
3
  import type { IAnyStateTreeNode, Instance } from '@jbrowse/mobx-state-tree';
4
4
  import type { ThemeOptions } from '@mui/material';
5
5
  /**
@@ -54,15 +54,14 @@ export declare function ThemeManagerSessionMixin(_pluginManager: PluginManager):
54
54
  * view's SVG export threads into each display's `renderSvg`, which
55
55
  * rebuilds the theme via `createJBrowseTheme` outside React context.
56
56
  *
57
- * The `default` entry is spliced with the config `theme` slot, because
58
- * the preset is only half of what that entry means — the picker calls it
59
- * "Default (from config)" and `resolvePalette` merges the two for every
60
- * other consumer. Returning the bare preset made `view.exportSvg()`
61
- * silently drop a host's configured palette: a config setting
62
- * `primary.main` drew `#123456` on screen and exported the stock
63
- * `#0D233F`, with the export dialog reporting the theme it had not used.
64
- * Every other named theme is a fixed preset that ignores config, which is
65
- * the distinction this ternary keeps.
57
+ * The `default` entry is merged with the config `theme` slot, because
58
+ * the picker labels it "Default (from config)" and `resolvePalette`
59
+ * merges the preset with the slot for every other consumer. The bare
60
+ * preset would make `view.exportSvg()` drop a host's configured
61
+ * palette: a config setting `primary.main` would draw `#123456` on
62
+ * screen and export the stock `#0D233F`, while the export dialog named
63
+ * the default theme. Every other named theme is a fixed preset that
64
+ * ignores config.
66
65
  */
67
66
  getActiveThemeOptions(name?: string): (ThemeOptions & {
68
67
  name?: string;
@@ -1,7 +1,7 @@
1
1
  import { getConf, setConf } from '@jbrowse/core/configuration';
2
- import { createJBrowseThemeFromArgs, defaultThemes } from '@jbrowse/core/ui';
3
2
  import { resolvePalette } from '@jbrowse/core/ui/palette';
4
3
  import { resolveStyleTheme } from '@jbrowse/core/ui/styleTheme';
4
+ import { createJBrowseThemeFromArgs, defaultThemes, } from '@jbrowse/core/ui/theme';
5
5
  import { localStorageGetItem, localStorageSetItem } from '@jbrowse/core/util';
6
6
  import { addDisposer, types } from '@jbrowse/mobx-state-tree';
7
7
  import { autorun } from 'mobx';
@@ -96,15 +96,14 @@ export function ThemeManagerSessionMixin(_pluginManager) {
96
96
  * view's SVG export threads into each display's `renderSvg`, which
97
97
  * rebuilds the theme via `createJBrowseTheme` outside React context.
98
98
  *
99
- * The `default` entry is spliced with the config `theme` slot, because
100
- * the preset is only half of what that entry means — the picker calls it
101
- * "Default (from config)" and `resolvePalette` merges the two for every
102
- * other consumer. Returning the bare preset made `view.exportSvg()`
103
- * silently drop a host's configured palette: a config setting
104
- * `primary.main` drew `#123456` on screen and exported the stock
105
- * `#0D233F`, with the export dialog reporting the theme it had not used.
106
- * Every other named theme is a fixed preset that ignores config, which is
107
- * the distinction this ternary keeps.
99
+ * The `default` entry is merged with the config `theme` slot, because
100
+ * the picker labels it "Default (from config)" and `resolvePalette`
101
+ * merges the preset with the slot for every other consumer. The bare
102
+ * preset would make `view.exportSvg()` drop a host's configured
103
+ * palette: a config setting `primary.main` would draw `#123456` on
104
+ * screen and export the stock `#0D233F`, while the export dialog named
105
+ * the default theme. Every other named theme is a fixed preset that
106
+ * ignores config.
108
107
  */
109
108
  getActiveThemeOptions(name) {
110
109
  const all = this.allThemes();
@@ -4,25 +4,6 @@ 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';
6
6
  import type { TrackActionView } from '@jbrowse/core/util/types';
7
- type TrackCopySnapshot = {
8
- trackId: string;
9
- name: string;
10
- category?: unknown;
11
- displays?: {
12
- type: string;
13
- displayId: string;
14
- }[];
15
- } & Record<string, unknown>;
16
- /**
17
- * Clone a track config for "Copy track": snapshots the config, appends a unique
18
- * timestamp suffix to trackId (so it doesn't collide with the original), tags
19
- * " (copy)" on the name, and regenerates each displayId to the canonical
20
- * `${trackId}-${type}` form baseTrackConfig auto-injects — keeping them unique
21
- * (displayId is a types.identifier, so a collision would crash MST).
22
- */
23
- export declare function copyTrackSnapshot(config: BaseTrackConfig, opts: {
24
- clearCategory: boolean;
25
- }): TrackCopySnapshot;
26
7
  interface TrackActionSession<C> {
27
8
  editConfiguration: (config: AnyConfigurationModel | {
28
9
  trackId: string;
@@ -65,18 +46,12 @@ export declare function trackActionItems<C extends {
65
46
  isSessionOverride?: boolean;
66
47
  makeCopy: () => C;
67
48
  }): MenuItem[];
68
- interface SessionWithDialog {
49
+ export interface SessionWithDialog {
69
50
  queueDialog: (cb: (done: () => void) => [DialogComponentType, Record<string, unknown>]) => void;
70
51
  }
71
52
  type TrackConfig = AnyConfigurationModel | Record<string, unknown>;
72
53
  /** "About track" menu item, shared by every product's track menu */
73
54
  export declare function aboutTrackMenuItem(session: SessionWithDialog, config: TrackConfig): MenuItem;
74
- /**
75
- * plugin-contributed per-track items (`Core-extraTrackMenuItems`), surfaced in
76
- * both the hierarchical selector and the in-view label menu so plugins reach
77
- * every track menu consistently
78
- */
79
- export declare function pluginExtraTrackItems(pluginManager: PluginManager, session: SessionWithDialog, config: AnyConfigurationModel, view?: TrackActionView): MenuItem[];
80
55
  /**
81
56
  * flattened track menu (About + raw actions) for the hierarchical track selector
82
57
  */
@@ -1,33 +1,14 @@
1
1
  import { lazy } from 'react';
2
2
  import { InfoIcon } from '@jbrowse/core/ui/Icons';
3
- import { buildExtraTrackMenuItems } from '@jbrowse/core/ui/buildExtraTrackMenuItems';
4
3
  import { namesTemporaryAssembly } from '@jbrowse/core/util';
5
- import { getSnapshot, isStateTreeNode, types } from '@jbrowse/mobx-state-tree';
4
+ import { types } from '@jbrowse/mobx-state-tree';
6
5
  import DeleteIcon from '@mui/icons-material/Delete';
7
6
  import CopyIcon from '@mui/icons-material/FileCopy';
8
7
  import OpenInNewIcon from '@mui/icons-material/OpenInNew';
9
8
  import SettingsIcon from '@mui/icons-material/Settings';
10
9
  import SettingsBackupRestoreIcon from '@mui/icons-material/SettingsBackupRestore';
10
+ import { pluginExtraTrackItems } from './pluginExtraTrackItems.js';
11
11
  const AboutDialog = lazy(() => import('../ui/AboutDialog.js'));
12
- /**
13
- * Clone a track config for "Copy track": snapshots the config, appends a unique
14
- * timestamp suffix to trackId (so it doesn't collide with the original), tags
15
- * " (copy)" on the name, and regenerates each displayId to the canonical
16
- * `${trackId}-${type}` form baseTrackConfig auto-injects — keeping them unique
17
- * (displayId is a types.identifier, so a collision would crash MST).
18
- */
19
- export function copyTrackSnapshot(config, opts) {
20
- const snap = structuredClone(isStateTreeNode(config) ? getSnapshot(config) : config);
21
- snap.trackId += `-${Date.now()}`;
22
- snap.name += ' (copy)';
23
- if (opts.clearCategory) {
24
- snap.category = undefined;
25
- }
26
- for (const d of snap.displays ?? []) {
27
- d.displayId = `${snap.trackId}-${d.type}`;
28
- }
29
- return snap;
30
- }
31
12
  /**
32
13
  * The shared Settings / Copy / Copy-and-open / Delete track actions. Each
33
14
  * product supplies `makeCopy` (its own session-track/category rules) and
@@ -123,18 +104,6 @@ export function aboutTrackMenuItem(session, config) {
123
104
  },
124
105
  };
125
106
  }
126
- /**
127
- * plugin-contributed per-track items (`Core-extraTrackMenuItems`), surfaced in
128
- * both the hierarchical selector and the in-view label menu so plugins reach
129
- * every track menu consistently
130
- */
131
- export function pluginExtraTrackItems(pluginManager, session, config, view) {
132
- return buildExtraTrackMenuItems(pluginManager, {
133
- session: session,
134
- config,
135
- view,
136
- });
137
- }
138
107
  /**
139
108
  * flattened track menu (About + raw actions) for the hierarchical track selector
140
109
  */
@@ -1,6 +1,7 @@
1
1
  import { types } from '@jbrowse/mobx-state-tree';
2
2
  import { asSession } from '../siblingCast.js';
3
- import { aboutTrackMenuItem, pluginExtraTrackItems, trackListMenuItems, } from './TrackMenu.js';
3
+ import { aboutTrackMenuItem, trackListMenuItems } from './TrackMenu.js';
4
+ import { pluginExtraTrackItems } from './pluginExtraTrackItems.js';
4
5
  /**
5
6
  * #stateModel TrackMenuSessionMixin
6
7
  *
@@ -8,6 +8,7 @@ export declare function TracksManagerSessionMixin(pluginManager: PluginManager):
8
8
  id: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").ISimpleType<string>, [undefined]>;
9
9
  name: import("@jbrowse/mobx-state-tree").ISimpleType<string>;
10
10
  focusedViewId: import("@jbrowse/mobx-state-tree").IMaybe<import("@jbrowse/mobx-state-tree").ISimpleType<string>>;
11
+ highlights: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").IArrayType<import("@jbrowse/mobx-state-tree").IType<import("@jbrowse/core/util/highlights").HighlightType, import("@jbrowse/core/util/highlights").HighlightType, import("@jbrowse/core/util/highlights").HighlightType>>, [undefined]>;
11
12
  highlightsVisible: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").ISimpleType<boolean>, [undefined]>;
12
13
  heldForMissingPlugins: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").IType<import("../pruneUnbuildableNodes.ts").HeldNode[] | undefined, import("../pruneUnbuildableNodes.ts").HeldNode[] | undefined, import("../pruneUnbuildableNodes.ts").HeldNode[] | undefined>, [undefined]>;
13
14
  }, never>, never>, {
@@ -509,10 +510,7 @@ export declare function TracksManagerSessionMixin(pluginManager: PluginManager):
509
510
  }, import("@jbrowse/mobx-state-tree")._NotCustomized, import("@jbrowse/mobx-state-tree")._NotCustomized>>) | undefined;
510
511
  readonly assemblyNamesList: string[];
511
512
  readonly configuredAssemblyNames: Set<string>;
512
- readonly assemblyList: (import("@jbrowse/mobx-state-tree").ModelInstanceTypeProps<Record<string, any>> & {
513
- setSubschema(slotName: string, data: Record<string, unknown>): any;
514
- setSlot(slotName: string, value: unknown): void;
515
- } & import("@jbrowse/mobx-state-tree").IStateTreeNode<import("@jbrowse/core/configuration").AnyConfigurationSchemaType>)[];
513
+ readonly assemblyList: AnyConfigurationModel[];
516
514
  readonly rpcManager: import("@jbrowse/core/rpc/RpcManager").default;
517
515
  } & {
518
516
  settleAssemblyResolution(assemblyName: string): Promise<void>;
@@ -1301,10 +1299,7 @@ export declare function TracksManagerSessionMixin(pluginManager: PluginManager):
1301
1299
  }, import("@jbrowse/mobx-state-tree")._NotCustomized, import("@jbrowse/mobx-state-tree")._NotCustomized>>) | undefined;
1302
1300
  readonly assemblyNamesList: string[];
1303
1301
  readonly configuredAssemblyNames: Set<string>;
1304
- readonly assemblyList: (import("@jbrowse/mobx-state-tree").ModelInstanceTypeProps<Record<string, any>> & {
1305
- setSubschema(slotName: string, data: Record<string, unknown>): any;
1306
- setSlot(slotName: string, value: unknown): void;
1307
- } & import("@jbrowse/mobx-state-tree").IStateTreeNode<import("@jbrowse/core/configuration").AnyConfigurationSchemaType>)[];
1302
+ readonly assemblyList: AnyConfigurationModel[];
1308
1303
  readonly rpcManager: import("@jbrowse/core/rpc/RpcManager").default;
1309
1304
  } & {
1310
1305
  settleAssemblyResolution(assemblyName: string): Promise<void>;
@@ -1604,10 +1599,7 @@ export declare function TracksManagerSessionMixin(pluginManager: PluginManager):
1604
1599
  } & {
1605
1600
  readonly jbrowse: any;
1606
1601
  readonly rpcManager: import("@jbrowse/core/rpc/RpcManager").default;
1607
- readonly configuration: import("@jbrowse/mobx-state-tree").ModelInstanceTypeProps<Record<string, any>> & {
1608
- setSubschema(slotName: string, data: Record<string, unknown>): any;
1609
- setSlot(slotName: string, value: unknown): void;
1610
- } & import("@jbrowse/mobx-state-tree").IStateTreeNode<import("@jbrowse/core/configuration").AnyConfigurationSchemaType>;
1602
+ readonly configuration: import("@jbrowse/core/configuration").ConfigNodeProps<any> & import("@jbrowse/core/configuration").ConfigNodeActions & import("@jbrowse/core/configuration").ConfigNodeBrand<import("@jbrowse/core/configuration").AnyConfigurationSchemaType>;
1611
1603
  readonly adminMode: boolean;
1612
1604
  readonly textSearchManager: import("@jbrowse/core/TextSearch/TextSearchManager").default;
1613
1605
  } & {
@@ -1628,7 +1620,10 @@ export declare function TracksManagerSessionMixin(pluginManager: PluginManager):
1628
1620
  clearSelection(): void;
1629
1621
  setHovered(thing: unknown): void;
1630
1622
  setHighlightsVisible(arg: boolean): void;
1631
- revealHighlights(): void;
1623
+ addHighlight(highlight: import("@jbrowse/core/util/highlights").HighlightType): void;
1624
+ removeHighlight(highlight: import("@jbrowse/core/util/highlights").HighlightType): void;
1625
+ updateHighlight(old: import("@jbrowse/core/util/highlights").HighlightType, updates: Partial<import("@jbrowse/core/util/highlights").HighlightType>): void;
1626
+ setHighlights(highlights: import("@jbrowse/core/util/highlights").HighlightType[]): void;
1632
1627
  setPreferenceOverride(key: string, value: unknown): void;
1633
1628
  clearPreferenceOverrides(): void;
1634
1629
  clearPreferenceOverride(key: string): void;
@@ -0,0 +1,21 @@
1
+ import type { BaseTrackConfig } from '@jbrowse/core/pluggableElementTypes';
2
+ type TrackCopySnapshot = {
3
+ trackId: string;
4
+ name: string;
5
+ category?: unknown;
6
+ displays?: {
7
+ type: string;
8
+ displayId: string;
9
+ }[];
10
+ } & Record<string, unknown>;
11
+ /**
12
+ * Clone a track config for "Copy track": snapshots the config, appends a unique
13
+ * timestamp suffix to trackId (so it doesn't collide with the original), tags
14
+ * " (copy)" on the name, and regenerates each displayId to the canonical
15
+ * `${trackId}-${type}` form baseTrackConfig auto-injects — keeping them unique
16
+ * (displayId is a types.identifier, so a collision would crash MST).
17
+ */
18
+ export declare function copyTrackSnapshot(config: BaseTrackConfig, opts: {
19
+ clearCategory: boolean;
20
+ }): TrackCopySnapshot;
21
+ export {};
@@ -0,0 +1,20 @@
1
+ import { getSnapshot, isStateTreeNode } from '@jbrowse/mobx-state-tree';
2
+ /**
3
+ * Clone a track config for "Copy track": snapshots the config, appends a unique
4
+ * timestamp suffix to trackId (so it doesn't collide with the original), tags
5
+ * " (copy)" on the name, and regenerates each displayId to the canonical
6
+ * `${trackId}-${type}` form baseTrackConfig auto-injects — keeping them unique
7
+ * (displayId is a types.identifier, so a collision would crash MST).
8
+ */
9
+ export function copyTrackSnapshot(config, opts) {
10
+ const snap = structuredClone(isStateTreeNode(config) ? getSnapshot(config) : config);
11
+ snap.trackId += `-${Date.now()}`;
12
+ snap.name += ' (copy)';
13
+ if (opts.clearCategory) {
14
+ snap.category = undefined;
15
+ }
16
+ for (const d of snap.displays ?? []) {
17
+ d.displayId = `${snap.trackId}-${d.type}`;
18
+ }
19
+ return snap;
20
+ }
@@ -0,0 +1,16 @@
1
+ import type { AssemblySnapshot, TrackSnapshot } from '../sessionUtils.ts';
2
+ import type PluginManager from '@jbrowse/core/PluginManager';
3
+ import type { IAnyType } from '@jbrowse/mobx-state-tree';
4
+ /**
5
+ * A config as its own schema writes it back: shorthand expanded, a stub per
6
+ * compatible display injected, every slot at its default left out. A
7
+ * track-config delta is only exact between two configs in this form, because a
8
+ * member one has and the other lacks then means a reset rather than two
9
+ * spellings of one config.
10
+ */
11
+ export interface HydratedForms {
12
+ track: (conf: TrackSnapshot) => TrackSnapshot;
13
+ assembly: (conf: AssemblySnapshot) => AssemblySnapshot;
14
+ }
15
+ export declare function hydratedTrackForm(pluginManager: PluginManager): (conf: TrackSnapshot) => TrackSnapshot;
16
+ export declare function hydratedForms(pluginManager: PluginManager, assemblyConfigSchema: IAnyType): HydratedForms;
@@ -0,0 +1,13 @@
1
+ import { getSnapshot } from '@jbrowse/mobx-state-tree';
2
+ function snapshotThrough(schema, pluginManager) {
3
+ return (conf) => getSnapshot(schema.create(conf, { pluginManager }));
4
+ }
5
+ export function hydratedTrackForm(pluginManager) {
6
+ return snapshotThrough(pluginManager.pluggableConfigSchemaType('track'), pluginManager);
7
+ }
8
+ export function hydratedForms(pluginManager, assemblyConfigSchema) {
9
+ return {
10
+ track: hydratedTrackForm(pluginManager),
11
+ assembly: snapshotThrough(assemblyConfigSchema, pluginManager),
12
+ };
13
+ }
@@ -15,8 +15,12 @@ export { BaseSessionModel, isBaseSession, isSession } from './BaseSession.ts';
15
15
  export type { BaseSession, BaseSessionType } from './BaseSession.ts';
16
16
  export { SessionTracksManagerSessionMixin } from './SessionTracks.ts';
17
17
  export type { EditableTrackConfig, PlainTrackConfig, SessionWithSessionTracks, SessionWithSessionTracksType, } from './SessionTracks.ts';
18
+ export { hydratedForms } from './hydratedForms.ts';
19
+ export type { HydratedForms } from './hydratedForms.ts';
18
20
  export { bakeSessionCascades, getShareableSessionSnapshot, } from './shareableSnapshot.ts';
19
- export { TrackMenuItemsSessionMixin, aboutTrackMenuItem, copyTrackSnapshot, pluginExtraTrackItems, trackActionItems, trackActionMenuItems, trackListMenuItems, } from './TrackMenu.ts';
21
+ export { TrackMenuItemsSessionMixin, aboutTrackMenuItem, trackActionItems, trackActionMenuItems, trackListMenuItems, } from './TrackMenu.ts';
22
+ export { copyTrackSnapshot } from './copyTrackSnapshot.ts';
23
+ export { pluginExtraTrackItems } from './pluginExtraTrackItems.ts';
20
24
  export { TrackMenuSessionMixin } from './TrackMenuSessionMixin.ts';
21
25
  export { finalizeSession } from './finalizeSession.ts';
22
26
  export type { AssertSessionModel } from './assertSessionModel.ts';
@@ -7,7 +7,10 @@ export { MultipleViewsSessionMixin, isSessionWithMultipleViews, } from './Multip
7
7
  export { PreferencesSessionMixin } from './Preferences.js';
8
8
  export { BaseSessionModel, isBaseSession, isSession } from './BaseSession.js';
9
9
  export { SessionTracksManagerSessionMixin } from './SessionTracks.js';
10
+ export { hydratedForms } from './hydratedForms.js';
10
11
  export { bakeSessionCascades, getShareableSessionSnapshot, } from './shareableSnapshot.js';
11
- export { TrackMenuItemsSessionMixin, aboutTrackMenuItem, copyTrackSnapshot, pluginExtraTrackItems, trackActionItems, trackActionMenuItems, trackListMenuItems, } from './TrackMenu.js';
12
+ export { TrackMenuItemsSessionMixin, aboutTrackMenuItem, trackActionItems, trackActionMenuItems, trackListMenuItems, } from './TrackMenu.js';
13
+ export { copyTrackSnapshot } from './copyTrackSnapshot.js';
14
+ export { pluginExtraTrackItems } from './pluginExtraTrackItems.js';
12
15
  export { TrackMenuSessionMixin } from './TrackMenuSessionMixin.js';
13
16
  export { finalizeSession } from './finalizeSession.js';
@@ -0,0 +1,11 @@
1
+ import type { SessionWithDialog } from './TrackMenu.ts';
2
+ import type PluginManager from '@jbrowse/core/PluginManager';
3
+ import type { AnyConfigurationModel } from '@jbrowse/core/configuration';
4
+ import type { MenuItem } from '@jbrowse/core/ui';
5
+ import type { TrackActionView } from '@jbrowse/core/util/types';
6
+ /**
7
+ * plugin-contributed per-track items (`Core-extraTrackMenuItems`), surfaced in
8
+ * both the hierarchical selector and the in-view label menu so plugins reach
9
+ * every track menu consistently
10
+ */
11
+ export declare function pluginExtraTrackItems(pluginManager: PluginManager, session: SessionWithDialog, config: AnyConfigurationModel, view?: TrackActionView): MenuItem[];