@jbrowse/app-core 5.0.0-beta.11 → 5.0.0-beta.14

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 (78) hide show
  1. package/esm/AppSession/AppSessionMixin.d.ts +110 -92
  2. package/esm/Assemblies/AssembliesMixin.d.ts +30 -0
  3. package/esm/HistoryManagement/index.d.ts +2 -0
  4. package/esm/HistoryManagement/index.js +2 -0
  5. package/esm/JBrowseConfig/RootConfiguration.d.ts +4 -10
  6. package/esm/JBrowseConfig/RootConfiguration.js +5 -8
  7. package/esm/JBrowseConfig/index.d.ts +3 -11
  8. package/esm/JBrowseConfig/index.js +2 -3
  9. package/esm/JBrowseModel/index.d.ts +10 -9
  10. package/esm/JBrowseModel/index.js +8 -7
  11. package/esm/JbApi/jbApi.d.ts +2 -2
  12. package/esm/JbApi/jbApi.js +16 -11
  13. package/esm/RootMenu/index.d.ts +2 -0
  14. package/esm/RootMenu/index.js +2 -0
  15. package/esm/SessionSpec/index.d.ts +2 -2
  16. package/esm/SessionSpec/index.js +1 -1
  17. package/esm/SessionSpec/loadSessionSpec.js +2 -12
  18. package/esm/SessionSpec/parseSessionSpecUrl.d.ts +19 -0
  19. package/esm/SessionSpec/parseSessionSpecUrl.js +29 -0
  20. package/esm/WorkspaceLayout/LayoutRenderer.d.ts +0 -10
  21. package/esm/WorkspaceLayout/LayoutRenderer.js +34 -101
  22. package/esm/WorkspaceLayout/PanelView.js +19 -45
  23. package/esm/WorkspaceLayout/TabStrip.d.ts +2 -2
  24. package/esm/WorkspaceLayout/TabStrip.js +36 -104
  25. package/esm/WorkspaceLayout/WorkspaceContainer.d.ts +0 -9
  26. package/esm/WorkspaceLayout/WorkspaceContainer.js +9 -42
  27. package/esm/WorkspaceLayout/WorkspacePanelActions.d.ts +1 -16
  28. package/esm/WorkspaceLayout/WorkspacePanelActions.js +46 -51
  29. package/esm/WorkspaceLayout/WorkspaceTab.d.ts +3 -19
  30. package/esm/WorkspaceLayout/WorkspaceTab.js +12 -48
  31. package/esm/WorkspaceLayout/dropZone.d.ts +7 -37
  32. package/esm/WorkspaceLayout/dropZone.js +7 -44
  33. package/esm/WorkspaceLayout/model.d.ts +45 -120
  34. package/esm/WorkspaceLayout/model.js +145 -303
  35. package/esm/WorkspaceLayout/panelChrome.d.ts +4 -7
  36. package/esm/WorkspaceLayout/panelChrome.js +0 -2
  37. package/esm/WorkspaceLayout/spec.d.ts +10 -51
  38. package/esm/WorkspaceLayout/spec.js +12 -80
  39. package/esm/WorkspaceLayout/splitter.d.ts +3 -19
  40. package/esm/WorkspaceLayout/splitter.js +5 -21
  41. package/esm/WorkspaceLayout/tabName.d.ts +8 -0
  42. package/esm/WorkspaceLayout/tabName.js +14 -0
  43. package/esm/WorkspaceLayout/tree.d.ts +19 -79
  44. package/esm/WorkspaceLayout/tree.js +34 -131
  45. package/esm/WorkspaceLayout/useLayoutDrag.d.ts +4 -22
  46. package/esm/WorkspaceLayout/useLayoutDrag.js +55 -177
  47. package/esm/WorkspaceLayout/usePointerGesture.d.ts +24 -0
  48. package/esm/WorkspaceLayout/usePointerGesture.js +83 -0
  49. package/esm/WorkspaceLayout/workspaceTheme.d.ts +27 -0
  50. package/esm/WorkspaceLayout/workspaceTheme.js +37 -0
  51. package/esm/index.d.ts +5 -3
  52. package/esm/index.js +3 -2
  53. package/esm/queryParams.d.ts +2 -0
  54. package/esm/queryParams.js +16 -5
  55. package/esm/sessionSummary.d.ts +16 -0
  56. package/esm/sessionSummary.js +57 -0
  57. package/esm/ui/App/App.js +3 -0
  58. package/esm/ui/App/DrawerHeaderHelpDialog.d.ts +3 -2
  59. package/esm/ui/App/DrawerHeaderHelpDialog.js +4 -2
  60. package/esm/ui/App/JBrowseTabMenu.d.ts +3 -2
  61. package/esm/ui/App/JBrowseTabMenu.js +5 -3
  62. package/esm/ui/App/ThemeModeButton.d.ts +4 -5
  63. package/esm/ui/App/ThemeModeButton.js +22 -14
  64. package/esm/ui/App/ViewContainer.js +7 -1
  65. package/esm/ui/App/ViewMenu.js +69 -42
  66. package/esm/ui/App/ViewWrapper.js +2 -2
  67. package/esm/ui/App/ViewsContainer.js +3 -4
  68. package/esm/ui/App/lazyParts.d.ts +0 -5
  69. package/esm/ui/App/lazyParts.js +0 -1
  70. package/esm/ui/App/preloadAppShell.js +3 -6
  71. package/esm/ui/App/types.d.ts +3 -2
  72. package/esm/ui/App/viewTitle.d.ts +6 -1
  73. package/esm/ui/App/viewTitle.js +7 -2
  74. package/package.json +7 -7
  75. package/esm/WorkspaceLayout/dockviewTheme.d.ts +0 -69
  76. package/esm/WorkspaceLayout/dockviewTheme.js +0 -82
  77. package/esm/ui/App/ClassicViewsContainer.d.ts +0 -6
  78. package/esm/ui/App/ClassicViewsContainer.js +0 -22
@@ -29,6 +29,11 @@ export declare function AssembliesMixin(_pluginManager: PluginManager, assemblyC
29
29
  } & {
30
30
  defaultValue: unknown;
31
31
  };
32
+ readonly circularRefNames: {
33
+ type: "stringArray";
34
+ } & {
35
+ defaultValue: unknown;
36
+ };
32
37
  readonly geneticCodesLocation: {
33
38
  type: "maybeFileLocation";
34
39
  };
@@ -69,6 +74,11 @@ export declare function AssembliesMixin(_pluginManager: PluginManager, assemblyC
69
74
  } & {
70
75
  defaultValue: unknown;
71
76
  };
77
+ readonly circularRefNames: {
78
+ type: "stringArray";
79
+ } & {
80
+ defaultValue: unknown;
81
+ };
72
82
  readonly geneticCodesLocation: {
73
83
  type: "maybeFileLocation";
74
84
  };
@@ -128,6 +138,11 @@ export declare function AssembliesMixin(_pluginManager: PluginManager, assemblyC
128
138
  } & {
129
139
  defaultValue: unknown;
130
140
  };
141
+ readonly circularRefNames: {
142
+ type: "stringArray";
143
+ } & {
144
+ defaultValue: unknown;
145
+ };
131
146
  readonly geneticCodesLocation: {
132
147
  type: "maybeFileLocation";
133
148
  };
@@ -164,6 +179,11 @@ export declare function AssembliesMixin(_pluginManager: PluginManager, assemblyC
164
179
  } & {
165
180
  defaultValue: unknown;
166
181
  };
182
+ readonly circularRefNames: {
183
+ type: "stringArray";
184
+ } & {
185
+ defaultValue: unknown;
186
+ };
167
187
  readonly geneticCodesLocation: {
168
188
  type: "maybeFileLocation";
169
189
  };
@@ -217,6 +237,11 @@ export declare function AssembliesMixin(_pluginManager: PluginManager, assemblyC
217
237
  } & {
218
238
  defaultValue: unknown;
219
239
  };
240
+ readonly circularRefNames: {
241
+ type: "stringArray";
242
+ } & {
243
+ defaultValue: unknown;
244
+ };
220
245
  readonly geneticCodesLocation: {
221
246
  type: "maybeFileLocation";
222
247
  };
@@ -253,6 +278,11 @@ export declare function AssembliesMixin(_pluginManager: PluginManager, assemblyC
253
278
  } & {
254
279
  defaultValue: unknown;
255
280
  };
281
+ readonly circularRefNames: {
282
+ type: "stringArray";
283
+ } & {
284
+ defaultValue: unknown;
285
+ };
256
286
  readonly geneticCodesLocation: {
257
287
  type: "maybeFileLocation";
258
288
  };
@@ -3,6 +3,8 @@ export declare function historyShortcut(e: ShortcutKeys): "redo" | "undo" | unde
3
3
  /**
4
4
  * #stateModel HistoryManagementMixin
5
5
  * #category root
6
+ * Adds undo and redo of session changes to the root model, bound to Ctrl+Z
7
+ * and Ctrl+Y (Cmd on macOS).
6
8
  */
7
9
  export declare function HistoryManagementMixin(): import("@jbrowse/mobx-state-tree").IModelType<{
8
10
  /**
@@ -28,6 +28,8 @@ export function historyShortcut(e) {
28
28
  /**
29
29
  * #stateModel HistoryManagementMixin
30
30
  * #category root
31
+ * Adds undo and redo of session changes to the root model, bound to Ctrl+Z
32
+ * and Ctrl+Y (Cmd on macOS).
31
33
  */
32
34
  export function HistoryManagementMixin() {
33
35
  return types
@@ -3,8 +3,9 @@ import type { ConfigurationSchemaDefinition } from '@jbrowse/core/configuration'
3
3
  /**
4
4
  * #config JBrowseConfiguration
5
5
  * #category root
6
- * this is the entry under the `configuration` key
7
- * e.g.
6
+ * Holds the app-wide settings in the `configuration` key of a config file,
7
+ * beside `assemblies` and `tracks`.
8
+ *
8
9
  * ```json
9
10
  * {
10
11
  * assemblies,
@@ -123,11 +124,6 @@ export default function RootConfiguration({ pluginManager, extraConfigSlots, }:
123
124
  } & {
124
125
  defaultValue: boolean;
125
126
  };
126
- readonly useWorkspaces: {
127
- type: "boolean";
128
- } & {
129
- defaultValue: boolean;
130
- };
131
127
  readonly developerMode: {
132
128
  type: "boolean";
133
129
  } & {
@@ -145,8 +141,6 @@ export default function RootConfiguration({ pluginManager, extraConfigSlots, }:
145
141
  defaultValue: unknown;
146
142
  };
147
143
  readonly logoPath: {
148
- type: "fileLocation";
149
- } & {
150
- defaultValue: unknown;
144
+ type: "maybeFileLocation";
151
145
  };
152
146
  }, import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaOptions<undefined, undefined, undefined, import("@jbrowse/core/configuration").ConfigurationSchemaRequirement<Partial<Record<string, string[]>>, string>, any>>;
@@ -5,8 +5,9 @@ import { DEFAULT_SHARE_URL } from './defaultShareUrl.js';
5
5
  /**
6
6
  * #config JBrowseConfiguration
7
7
  * #category root
8
- * this is the entry under the `configuration` key
9
- * e.g.
8
+ * Holds the app-wide settings in the `configuration` key of a config file,
9
+ * beside `assemblies` and `tracks`.
10
+ *
10
11
  * ```json
11
12
  * {
12
13
  * assemblies,
@@ -90,12 +91,8 @@ export default function RootConfiguration({ pluginManager, extraConfigSlots = {}
90
91
  * #slot configuration.logoPath
91
92
  */
92
93
  logoPath: {
93
- type: 'fileLocation',
94
- description: 'path to a custom logo image displayed in the app header',
95
- defaultValue: {
96
- uri: '',
97
- locationType: 'UriLocation',
98
- },
94
+ type: 'maybeFileLocation',
95
+ description: 'a custom logo image displayed in the app header; unset, the JBrowse logo',
99
96
  advanced: true,
100
97
  },
101
98
  /**
@@ -6,9 +6,8 @@ export { DEFAULT_SHARE_URL } from './defaultShareUrl.ts';
6
6
  * #config JBrowseRootConfig
7
7
  * #category root
8
8
  *
9
- * this is a config model representing a config.json (for jbrowse-web) or
10
- * somefile.jbrowse (for jbrowse-desktop, where configs have the .jbrowse
11
- * extension)
9
+ * Holds a whole JBrowse config file: the `config.json` of jbrowse-web, or a
10
+ * file with the `.jbrowse` extension in jbrowse-desktop.
12
11
  *
13
12
  * also includes any pluginManager.pluginConfigurationSchemas(), so plugins
14
13
  * that have a configurationSchema field on their class are mixed into this
@@ -126,11 +125,6 @@ export declare function JBrowseConfigF({ pluginManager, assemblyConfigSchema, ex
126
125
  } & {
127
126
  defaultValue: boolean;
128
127
  };
129
- readonly useWorkspaces: {
130
- type: "boolean";
131
- } & {
132
- defaultValue: boolean;
133
- };
134
128
  readonly developerMode: {
135
129
  type: "boolean";
136
130
  } & {
@@ -148,9 +142,7 @@ export declare function JBrowseConfigF({ pluginManager, assemblyConfigSchema, ex
148
142
  defaultValue: unknown;
149
143
  };
150
144
  readonly logoPath: {
151
- type: "fileLocation";
152
- } & {
153
- defaultValue: unknown;
145
+ type: "maybeFileLocation";
154
146
  };
155
147
  }, import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaOptions<undefined, undefined, undefined, import("@jbrowse/core/configuration").ConfigurationSchemaRequirement<Partial<Record<string, string[]>>, string>, any>>;
156
148
  /**
@@ -5,9 +5,8 @@ export { DEFAULT_SHARE_URL } from './defaultShareUrl.js';
5
5
  * #config JBrowseRootConfig
6
6
  * #category root
7
7
  *
8
- * this is a config model representing a config.json (for jbrowse-web) or
9
- * somefile.jbrowse (for jbrowse-desktop, where configs have the .jbrowse
10
- * extension)
8
+ * Holds a whole JBrowse config file: the `config.json` of jbrowse-web, or a
9
+ * file with the `.jbrowse` extension in jbrowse-desktop.
11
10
  *
12
11
  * also includes any pluginManager.pluginConfigurationSchemas(), so plugins
13
12
  * that have a configurationSchema field on their class are mixed into this
@@ -3,6 +3,14 @@ import type { BaseAssemblyConfigSchema } from '@jbrowse/core/assemblyManager';
3
3
  import type { AnyConfiguration, AnyConfigurationModel, ConfigurationSchemaDefinition } from '@jbrowse/core/configuration';
4
4
  import type { PluginDefinition } from '@jbrowse/core/pluginDefinitions';
5
5
  import type RpcManager from '@jbrowse/core/rpc/RpcManager';
6
+ /**
7
+ * #stateModel AppCoreJBrowseModel
8
+ * #category root
9
+ * Holds the loaded config file, usually at `rootModel.jbrowse`, with actions
10
+ * that add and remove its assemblies and tracks. The model builds on the
11
+ * [JBrowseRootConfig](/docs/config/jbrowserootconfig) config model, which a
12
+ * state model can do because a config model is itself an MST tree.
13
+ */
6
14
  export declare function JBrowseModelF({ pluginManager, assemblyConfigSchema, extraConfigSlots, }: {
7
15
  pluginManager: PluginManager;
8
16
  assemblyConfigSchema: BaseAssemblyConfigSchema;
@@ -115,11 +123,6 @@ export declare function JBrowseModelF({ pluginManager, assemblyConfigSchema, ext
115
123
  } & {
116
124
  defaultValue: boolean;
117
125
  };
118
- readonly useWorkspaces: {
119
- type: "boolean";
120
- } & {
121
- defaultValue: boolean;
122
- };
123
126
  readonly developerMode: {
124
127
  type: "boolean";
125
128
  } & {
@@ -137,9 +140,7 @@ export declare function JBrowseModelF({ pluginManager, assemblyConfigSchema, ext
137
140
  defaultValue: unknown;
138
141
  };
139
142
  readonly logoPath: {
140
- type: "fileLocation";
141
- } & {
142
- defaultValue: unknown;
143
+ type: "maybeFileLocation";
143
144
  };
144
145
  }, import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaOptions<undefined, undefined, undefined, import("@jbrowse/core/configuration").ConfigurationSchemaRequirement<Partial<Record<string, string[]>>, string>, any>>;
145
146
  plugins: import("@jbrowse/mobx-state-tree").IArrayType<import("@jbrowse/mobx-state-tree").IType<PluginDefinition, PluginDefinition, PluginDefinition>>;
@@ -172,7 +173,7 @@ export declare function JBrowseModelF({ pluginManager, assemblyConfigSchema, ext
172
173
  /**
173
174
  * #action
174
175
  */
175
- addAssemblyConf(conf: AnyConfigurationModel): (import("@jbrowse/core/configuration").ConfigNodeProps<any> & import("@jbrowse/core/configuration").ConfigNodeActions & import("@jbrowse/core/configuration").ConfigNodeBrand<import("@jbrowse/core/configuration").AnyConfigurationSchemaType>) | undefined;
176
+ addAssemblyConf(conf: AnyConfiguration): (import("@jbrowse/core/configuration").ConfigNodeProps<any> & import("@jbrowse/core/configuration").ConfigNodeActions & import("@jbrowse/core/configuration").ConfigNodeBrand<import("@jbrowse/core/configuration").AnyConfigurationSchemaType>) | undefined;
176
177
  /**
177
178
  * #action
178
179
  */
@@ -6,13 +6,6 @@ import { expandLooseTrackConfig } from '@jbrowse/core/util/tracks';
6
6
  import { cast, getParent, getSnapshot, isStateTreeNode, types, } from '@jbrowse/mobx-state-tree';
7
7
  import { toJS } from 'mobx';
8
8
  import { JBrowseConfigF } from '../JBrowseConfig/index.js';
9
- /**
10
- * #stateModel AppCoreJBrowseModel
11
- * #category root
12
- * built on the [JBrowseRootConfig](/docs/config/jbrowserootconfig) config model —
13
- * config models are MST trees themselves, which is why this state model is
14
- * allowed to build on one. Generally found on a property named rootModel.jbrowse
15
- */
16
9
  // A config with exactly one assembly is what every loose track and search index
17
10
  // is on, so `assemblyNames` may be left off; with several, each has to say.
18
11
  function expandLooseTracks(snapshot, pluginManager) {
@@ -42,6 +35,14 @@ function expandLooseTracks(snapshot, pluginManager) {
42
35
  : {}),
43
36
  };
44
37
  }
38
+ /**
39
+ * #stateModel AppCoreJBrowseModel
40
+ * #category root
41
+ * Holds the loaded config file, usually at `rootModel.jbrowse`, with actions
42
+ * that add and remove its assemblies and tracks. The model builds on the
43
+ * [JBrowseRootConfig](/docs/config/jbrowserootconfig) config model, which a
44
+ * state model can do because a config model is itself an MST tree.
45
+ */
45
46
  export function JBrowseModelF({ pluginManager, assemblyConfigSchema, extraConfigSlots, }) {
46
47
  const model = JBrowseConfigF({
47
48
  pluginManager,
@@ -1018,9 +1018,9 @@ export declare function createJbApi(pluginManager: PluginManager, options?: JbAp
1018
1018
  total: number;
1019
1019
  note?: string | undefined;
1020
1020
  tracks: {
1021
- trackId: string;
1021
+ trackId: any;
1022
1022
  name: string;
1023
- type: string;
1023
+ type: any;
1024
1024
  assemblyNames: string[];
1025
1025
  }[];
1026
1026
  };
@@ -1,5 +1,5 @@
1
1
  import { getReExportRegistry, setReExportRegistry, } from '@jbrowse/core/ReExports/registry';
2
- import { getConf, getConfigurationSchemaDefinition, getConfigurationSchemaMetadata, isSlotDefinitionEntry, readConfObject, shorthandTargets, } from '@jbrowse/core/configuration';
2
+ import { getConf, getConfigurationSchemaDefinition, getConfigurationSchemaMetadata, hydrateTrackConfig, isSlotDefinitionEntry, readConfObject, shorthandTargets, } from '@jbrowse/core/configuration';
3
3
  import { releaseAdapterSession, retainAdapterSession, } from '@jbrowse/core/data_adapters/adapterSessionRefcount';
4
4
  import { adapterByteLimit } from '@jbrowse/core/rpc/byteBudget';
5
5
  import { isElectron, isSessionWithAddSessionTrack, objectHash, parseLocString, sum, } from '@jbrowse/core/util';
@@ -72,6 +72,9 @@ function displayState(track) {
72
72
  return { display: display.type, error: String(e) };
73
73
  }
74
74
  }
75
+ function raisesPicker(views) {
76
+ return !!views?.some(view => view.searchPicker || raisesPicker(view.ownViews));
77
+ }
75
78
  /**
76
79
  * The drawer and any modal, for the same reason `offscreen` is reported: both
77
80
  * are on top of the views in a screenshot that otherwise looks right.
@@ -94,7 +97,7 @@ function sessionChrome(session) {
94
97
  },
95
98
  }
96
99
  : {};
97
- const dialog = s.DialogComponent
100
+ const dialog = s.DialogComponent || raisesPicker(s.views)
98
101
  ? {
99
102
  dialog: {
100
103
  note: 'a modal dialog is open over the app, so a screenshot is of the dialog',
@@ -594,7 +597,7 @@ async function fitToWindow(session, settleMs, root = document) {
594
597
  function trackEntry(conf) {
595
598
  return {
596
599
  trackId: conf.trackId,
597
- name: readConfObject(conf, 'name'),
600
+ name: conf.name ?? '',
598
601
  type: conf.type,
599
602
  // getConfAssemblyNamesOrNone, not the slot: an assembly's sequence track
600
603
  // has no assemblyNames slot and answers through its parent assembly
@@ -826,8 +829,13 @@ async function visibleRegionsOf(session, viewId, preferTrackId, trackAssemblies
826
829
  // file's own refNames during serialization (RpcMethodTypeWithRenameRegions),
827
830
  // and the features come back rebuilt as SimpleFeature. What crosses the worker
828
831
  // boundary is bounded by the byte gate that runs first.
829
- async function fetchFeatures(session, trackId, regions, requestedByteLimit) {
830
- const conf = session.getTrackById(trackId);
832
+ async function fetchFeatures(pluginManager, session, trackId, regions, requestedByteLimit) {
833
+ const entry = session.getTrackById(trackId);
834
+ // the node a shown track reads: its adapter is in the hydrated form, which is
835
+ // what the shown track's session id hashes
836
+ const conf = isStateTreeNode(entry)
837
+ ? entry
838
+ : entry && hydrateTrackConfig(pluginManager, entry);
831
839
  if (!conf) {
832
840
  throw new Error(`No track with trackId "${trackId}" — jb.listTracks() shows what is available`);
833
841
  }
@@ -1019,7 +1027,7 @@ const JB_HELP = `jb drives this JBrowse app programmatically (window.jb in a bro
1019
1027
 
1020
1028
  Orient first: jb.sessionSummary(). Introspect, never guess: jb.listTracks(search?, limit?) answers { total, tracks } with the trackIds; jb.describeSlots(jb.trackModel('someTrackId').activeDisplay.configuration) for the settings keys a display accepts — an unknown settings key is not an error, it lands in applyDisplaySettings' "unapplied" list as { key, reason }, so read the report; jb.inspect(node) — jb.view(), jb.trackModel('someTrackId'), session.views[0] — for its getters, actions and modelType.
1021
1029
 
1022
- The model is mobx-state-tree: mutate only through actions (raw assignment throws), and write display settings with track.applyDisplaySettings(settings). A display's grammar settings are its plot, activeDisplay.plot, by slot name: facet ('strand' or { field, domain? }), color (a CSS color or { field: 'type', domain?, range? }), rows, scales, filter (['jexl:feature.score > 10']), and on a mark display marks and transform. Edit structuredClone(activeDisplay.plot), check it with activeDisplay.plotProblems(draft), which throws what a config refuses, and write it with activeDisplay.applyPlot(draft): each setting replaced whole, null resetting one. An alignments track takes the same facet, its field a read dimension ('pairOrientation', 'mapq', ...) or a tag ('tags.HP'). LinearMarkDisplay plots a track's features as ggplot2 does, on a feature, alignments, variant or quantitative track, in seven settings: marks, a list drawn in order of { mark: 'bar' | 'point' | 'rule' | 'line' | 'span' | 'text' | 'link', encoding: { y: 'score', x?, x2?, row?, color?, shape?, text?, size? }, each a feature field or a jexl: expression, a constant written { value: 'red' }, transform?: steps such as { type: 'coverage' } or a bin then an aggregate, which fill the y they write, minBpPerPx?, maxBpPerPx? }, beside transform, facet, rows, rowColor, scales ({ y: { type, domainMin, domainMax, autoscaleGroup, title } }) and filter. await view.launchTrack(trackId, {}, { type: 'LinearMarkDisplay', marks: [...] }) draws a track with it, shown already or not (on a GWASTrack, type 'LinearManhattanDisplay'). activeDisplay.notices names a mark the config cannot draw, or one whose field no loaded feature holds. Build views declaratively with jb.loadSessionSpec({ views: [{ type: 'LinearGenomeView', assembly, loc, tracks: [...] }] }), which replaces the session; jb.addView(oneViewSpec) opens one more view beside what is open; jb.setSession(document) rewrites the session as a document — what jb.mst.getSnapshot(jb.session) answers, edited: a view keeps its id and is patched in place, loc on it navigates, a { trackId } entry in its tracks opens that track. Act on a view with await view.navToLocString('BRCA1' or 'chr1:1-1000'), which also SHOWS the track whose search index answered a gene name unless a 4th arg { showHitTrack: false } says not to; await view.launchTrack(trackId, {}, settings) shows a track with settings, view.hideTrack(trackId) hides it. Arrange open views into panels with session.layoutViews({ direction: 'horizontal', children: [{ views: [viewId] }, ...] }), a leaf naming view ids or session.views indexes; await jb.fitToWindow() shrinks what is open until the session fits the window; add data with jb.addTrack({ location }) (an absolute path or a URL), or show a track the catalog already holds with jb.addTrack({ trackId, settings? }); read data with await jb.getFeatures({ trackId, loc?, assembly?, viewId?, regions?, byteLimit? }), which renames refNames ("chr1" vs "1") so the file answers and reads on the worker the track's display uses. Anything lower level is jb.require('@jbrowse/core/util') and friends, the module registry plugins link against. After changing anything, await jb.waitReady(ms) and read its notifications and notReady lists before trusting the screen.
1030
+ The model is mobx-state-tree: mutate only through actions (raw assignment throws), and write display settings with track.applyDisplaySettings(settings). A display's grammar settings are its plot, activeDisplay.plot, by slot name: facet ('strand' or { field, domain? }), color (a CSS color or { field: 'type', domain?, range? }), rows, unit (what a row stands for: 'read' | 'chain' on alignments, 'sample' | 'haplotype' on multi-sample variants), sort (an alignments row order: 'split', or { type: 'strand', pos, refName }), scales, filter (['jexl:feature.score > 10']), and on a mark display marks and transform. Edit structuredClone(activeDisplay.plot), check it with activeDisplay.plotProblems(draft), which throws what a config refuses, and write it with activeDisplay.applyPlot(draft): each setting replaced whole, null resetting one. An alignments track takes the same facet, its field a read dimension ('pairOrientation', 'mapq', ...) or a tag ('tags.HP'). LinearMarkDisplay plots a track's features as ggplot2 does, on a feature, alignments, variant or quantitative track, in seven settings: marks, a list drawn in order of { mark: 'bar' | 'point' | 'rule' | 'line' | 'span' | 'text' | 'link', encoding: { y: 'score', x?, x2?, row?, color?, shape?, text?, size? }, each a feature field or a jexl: expression, a constant written { value: 'red' }, transform?: steps such as { type: 'coverage' } or a bin then an aggregate, which fill the y they write, minBpPerPx?, maxBpPerPx? }, beside transform, facet, rows, rowColor, scales ({ y: { type, domainMin, domainMax, autoscaleGroup, title } }) and filter. await view.launchTrack(trackId, {}, { type: 'LinearMarkDisplay', marks: [...] }) draws a track with it, shown already or not (on a GWASTrack, type 'LinearManhattanDisplay'). activeDisplay.notices names a mark the config cannot draw, or one whose field no loaded feature holds. Build views declaratively with jb.loadSessionSpec({ views: [{ type: 'LinearGenomeView', assembly, loc, tracks: [...] }] }), which replaces the session; jb.addView(oneViewSpec) opens one more view beside what is open; jb.setSession(document) rewrites the session as a document — what jb.mst.getSnapshot(jb.session) answers, edited: a view keeps its id and is patched in place, loc on it navigates, a { trackId } entry in its tracks opens that track. Act on a view with await view.navToLocString('BRCA1' or 'chr1:1-1000'), which also SHOWS the track whose search index answered a gene name unless a 4th arg { showHitTrack: false } says not to; await view.launchTrack(trackId, {}, settings) shows a track with settings, view.hideTrack(trackId) hides it. Arrange open views into panels with session.layoutViews({ direction: 'horizontal', children: [{ views: [viewId] }, ...] }), a leaf naming view ids or session.views indexes; await jb.fitToWindow() shrinks what is open until the session fits the window; add data with jb.addTrack({ location }) (an absolute path or a URL), or show a track the catalog already holds with jb.addTrack({ trackId, settings? }); read data with await jb.getFeatures({ trackId, loc?, assembly?, viewId?, regions?, byteLimit? }), which renames refNames ("chr1" vs "1") so the file answers and reads on the worker the track's display uses. Anything lower level is jb.require('@jbrowse/core/util') and friends, the module registry plugins link against. After changing anything, await jb.waitReady(ms) and read its notifications and notReady lists before trusting the screen.
1023
1031
 
1024
1032
  Views nest and several can be open. jb.view(viewId?) is the open view, and jb.view(), jb.trackModel(trackId), jb.visibleRegions(), jb.addTrack and jb.getFeatures over a visible region throw naming the candidates rather than picking one when more than one view could answer — pass viewId (from jb.sessionSummary()) to say which. A synteny or breakpoint view's viewId also covers its rows: the named view answers when it can, and otherwise its rows do.
1025
1033
 
@@ -1107,7 +1115,7 @@ export function createJbApi(pluginManager, options = {}) {
1107
1115
  await locToRegion(session, conf, fetchArgs.loc, fetchArgs.assembly),
1108
1116
  ]
1109
1117
  : await visibleRegionsOf(session, fetchArgs.viewId, fetchArgs.trackId, getConfAssemblyNamesOrNone(conf));
1110
- return fetchFeatures(session, fetchArgs.trackId, regions, fetchArgs.byteLimit);
1118
+ return fetchFeatures(pluginManager, session, fetchArgs.trackId, regions, fetchArgs.byteLimit);
1111
1119
  },
1112
1120
  };
1113
1121
  return jb;
@@ -1192,9 +1200,6 @@ async function addTrack(pluginManager, session, args) {
1192
1200
  }
1193
1201
  // A track already in the catalog, shown: the same view choice and the same
1194
1202
  // settle the file route ends in.
1195
- // `conf` is whatever `session.getTrackById` answered, which is a track config
1196
- // but not necessarily a `BaseTrackConfig` — an assembly's ReferenceSequenceTrack
1197
- // declares a subset of those slots. The four reads below are all ones it has.
1198
1203
  async function showCatalogTrack(pluginManager, session, conf, args) {
1199
1204
  // index, assembly and name describe the file being added, and the catalog's
1200
1205
  // copy already has all three — taking them here would drop them in silence
@@ -1207,7 +1212,7 @@ async function showCatalogTrack(pluginManager, session, conf, args) {
1207
1212
  trackType: conf.type,
1208
1213
  assembly: getConfAssemblyNamesOrNone(conf)[0],
1209
1214
  };
1210
- const adapterType = readConfObject(conf, ['adapter', 'type']);
1215
+ const adapterType = conf.adapter?.type;
1211
1216
  const summary = { ...track, ...(adapterType ? { adapterType } : {}) };
1212
1217
  // show:false over a catalog trackId asks for nothing — there is no file to
1213
1218
  // add — and showing it anyway would contradict the flag
@@ -2,6 +2,8 @@ import type { MenuAction } from '../menus.ts';
2
2
  import type { MenuItem } from '@jbrowse/core/ui/menuItems';
3
3
  /**
4
4
  * #stateModel RootAppMenuMixin
5
+ * Adds actions to the root model that let plugins add menus and menu items to
6
+ * the app bar.
5
7
  */
6
8
  export declare function RootAppMenuMixin(): import("@jbrowse/mobx-state-tree").IModelType<{}, {
7
9
  mutableMenuActions: MenuAction[];
@@ -1,6 +1,8 @@
1
1
  import { types } from '@jbrowse/mobx-state-tree';
2
2
  /**
3
3
  * #stateModel RootAppMenuMixin
4
+ * Adds actions to the root model that let plugins add menus and menu items to
5
+ * the app bar.
4
6
  */
5
7
  export function RootAppMenuMixin() {
6
8
  return types
@@ -1,6 +1,6 @@
1
1
  export { buildLgvInit, buildLgvInitFromParams, hubConnectionSpec, readHubUrlParam, readNavParam, readTracklistParam, shortHubLabel, splitHighlights, } from './lgvUrlInit.ts';
2
2
  export { addSessionTracks, launchSpecView, launchableSpecView, loadSessionSpec, viewTypeProblem, } from './loadSessionSpec.ts';
3
- export { parseSessionSpecUrl } from './parseSessionSpecUrl.ts';
3
+ export { parseSessionSnapshotUrl, parseSessionSpecUrl, } from './parseSessionSpecUrl.ts';
4
4
  export type { LgvUrlInit } from './lgvUrlInit.ts';
5
- export type { ParsedSessionSpec } from './parseSessionSpecUrl.ts';
5
+ export type { ParsedSessionSnapshotUrl, ParsedSessionSpec, } from './parseSessionSpecUrl.ts';
6
6
  export type { LayoutNode, ViewSpec } from './types.ts';
@@ -1,3 +1,3 @@
1
1
  export { buildLgvInit, buildLgvInitFromParams, hubConnectionSpec, readHubUrlParam, readNavParam, readTracklistParam, shortHubLabel, splitHighlights, } from './lgvUrlInit.js';
2
2
  export { addSessionTracks, launchSpecView, launchableSpecView, loadSessionSpec, viewTypeProblem, } from './loadSessionSpec.js';
3
- export { parseSessionSpecUrl } from './parseSessionSpecUrl.js';
3
+ export { parseSessionSnapshotUrl, parseSessionSpecUrl, } from './parseSessionSpecUrl.js';
@@ -132,18 +132,8 @@ function unresolvedLayoutRefs(node, viewCount, knownIds) {
132
132
  : []),
133
133
  ];
134
134
  }
135
- // A `tabs` node shares one cell between its children rather than dividing the
136
- // space, so a `size` on one of them describes nothing. This is the ONLY case
137
- // left where a stated size is dropped.
138
- //
139
- // It used to be far wider — dockview forces its branches to alternate
140
- // orientation by depth, so a nested container had no branch to size against and
141
- // the whole sizing pass bailed, top-level numbers included. That is gone
142
- // (ADR-068): the spec's nesting is the tree's nesting, `size` applies wherever
143
- // it is written, and a bare sibling takes an equal share of the remainder. The
144
- // wider check outlived the limitation it reported and told an author their
145
- // nested or partial sizes had been ignored while the layout honoured them —
146
- // which is also what website/docs/urlparams.md promises.
135
+ // A `tabs` node shares one cell between its children, so a `size` on one of
136
+ // them describes nothing; it is the only stated size the layout drops.
147
137
  function unsizeableLayoutNodes(layout) {
148
138
  const children = Array.isArray(layout.children) ? layout.children : [];
149
139
  const sizedTabsChild = layout.direction === 'tabs' && children.some(c => c.size !== undefined);
@@ -4,4 +4,23 @@ export interface ParsedSessionSpec {
4
4
  spec: Omit<SessionSpec, 'sessionName'>;
5
5
  sessionName?: string;
6
6
  }
7
+ export interface ParsedSessionSnapshotUrl {
8
+ configUrl: string;
9
+ /** the `session=` value as it is in the link, prefix included, undecoded */
10
+ session: string;
11
+ /** a `share-` link's key; the share service never sees it */
12
+ password?: string;
13
+ /** the JBrowse Web page the link points at, which a relative shareURL is relative to */
14
+ pageUrl: string;
15
+ }
16
+ /**
17
+ * The session snapshot a link hands over whole — carried in it (`encoded-…`,
18
+ * `json-…`) or stored by the share service under the id it names (`share-…`) —
19
+ * with the config it applies to. Undefined for any other link.
20
+ *
21
+ * A link with no `config=` means the instance's own `config.json`, as it does
22
+ * to the JBrowse Web page the link points at. A snapshot names assemblies and
23
+ * tracks by id and holds none of them, so there is always a config to fetch.
24
+ */
25
+ export declare function parseSessionSnapshotUrl(input: string): ParsedSessionSnapshotUrl | undefined;
7
26
  export declare function parseSessionSpecUrl(input: string): ParsedSessionSpec;
@@ -134,6 +134,35 @@ function readSessionTracks(params) {
134
134
  }
135
135
  return parsed;
136
136
  }
137
+ /**
138
+ * The session snapshot a link hands over whole — carried in it (`encoded-…`,
139
+ * `json-…`) or stored by the share service under the id it names (`share-…`) —
140
+ * with the config it applies to. Undefined for any other link.
141
+ *
142
+ * A link with no `config=` means the instance's own `config.json`, as it does
143
+ * to the JBrowse Web page the link points at. A snapshot names assemblies and
144
+ * tracks by id and holds none of them, so there is always a config to fetch.
145
+ */
146
+ export function parseSessionSnapshotUrl(input) {
147
+ let url;
148
+ try {
149
+ url = unwrapProtocolUrl(new URL(input.trim()));
150
+ }
151
+ catch {
152
+ return undefined;
153
+ }
154
+ const params = readAllQueryParams(url);
155
+ const session = params.get('session');
156
+ return session && /^(share|encoded|json)-/.test(session)
157
+ ? {
158
+ configUrl: new URL(params.get('config') ?? 'config.json', url.href)
159
+ .href,
160
+ session,
161
+ password: params.get('password') ?? undefined,
162
+ pageUrl: url.href,
163
+ }
164
+ : undefined;
165
+ }
137
166
  export function parseSessionSpecUrl(input) {
138
167
  let url;
139
168
  try {
@@ -2,16 +2,6 @@ import type { WorkspaceLayout } from './model.ts';
2
2
  import type { PanelChrome } from './panelChrome.ts';
3
3
  import type { LayoutTree } from './tree.ts';
4
4
  import type { DragState } from './useLayoutDrag.ts';
5
- /**
6
- * The layout, rendered. There is no imperative api and no event to listen to:
7
- * the tree is state, this is a function of it, and a gesture is an action.
8
- *
9
- * Sizes are `flex-grow`, which is why there is no resize handling anywhere in
10
- * here. A branch's children divide its space in proportion to their `size`
11
- * whatever that space becomes, so a window resize is the browser's problem —
12
- * this is the layout maths dockview does in pixels, and it is the part of a
13
- * grid engine most likely to be got subtly wrong.
14
- */
15
5
  interface Props {
16
6
  node: LayoutTree;
17
7
  layout: WorkspaceLayout;