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

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 (157) hide show
  1. package/esm/RootModel/BaseRootModel.d.ts +514 -323
  2. package/esm/RootModel/BaseRootModel.js +141 -14
  3. package/esm/RootModel/HierarchicalConfig.d.ts +30 -20
  4. package/esm/RootModel/HierarchicalConfig.js +36 -0
  5. package/esm/RootModel/InternetAccounts.d.ts +18 -1
  6. package/esm/RootModel/InternetAccounts.js +120 -22
  7. package/esm/RootModel/PreferencesConfig.d.ts +37 -0
  8. package/esm/RootModel/PreferencesConfig.js +75 -0
  9. package/esm/RootModel/createConfigModel.d.ts +257 -0
  10. package/esm/RootModel/createConfigModel.js +77 -0
  11. package/esm/RootModel/index.d.ts +10 -5
  12. package/esm/RootModel/index.js +10 -5
  13. package/esm/RootModel/menuItems.d.ts +24 -0
  14. package/esm/RootModel/menuItems.js +141 -0
  15. package/esm/Session/BaseSession.d.ts +285 -11
  16. package/esm/Session/BaseSession.js +383 -15
  17. package/esm/Session/Connections.d.ts +115 -8
  18. package/esm/Session/Connections.js +196 -74
  19. package/esm/Session/DrawerWidgets.d.ts +145 -13
  20. package/esm/Session/DrawerWidgets.js +219 -49
  21. package/esm/Session/MultipleViews.d.ts +1067 -1177
  22. package/esm/Session/MultipleViews.js +395 -64
  23. package/esm/Session/Preferences.d.ts +1389 -0
  24. package/esm/Session/Preferences.js +58 -0
  25. package/esm/Session/ReferenceManagement.d.ts +28 -3
  26. package/esm/Session/ReferenceManagement.js +56 -41
  27. package/esm/Session/SessionTracks.d.ts +1101 -1180
  28. package/esm/Session/SessionTracks.js +584 -34
  29. package/esm/Session/Themes.d.ts +136 -2
  30. package/esm/Session/Themes.js +267 -21
  31. package/esm/Session/TrackMenu.d.ts +88 -0
  32. package/esm/Session/TrackMenu.js +175 -0
  33. package/esm/Session/TrackMenuSessionMixin.d.ts +27 -0
  34. package/esm/Session/TrackMenuSessionMixin.js +42 -0
  35. package/esm/Session/Tracks.d.ts +945 -1159
  36. package/esm/Session/Tracks.js +229 -30
  37. package/esm/Session/assertSessionModel.d.ts +21 -0
  38. package/esm/Session/assertSessionModel.js +1 -0
  39. package/esm/Session/copyTrackSnapshot.d.ts +21 -0
  40. package/esm/Session/copyTrackSnapshot.js +20 -0
  41. package/esm/Session/developerMode.d.ts +7 -0
  42. package/esm/Session/developerMode.js +43 -0
  43. package/esm/Session/finalizeSession.d.ts +15 -0
  44. package/esm/Session/finalizeSession.js +28 -0
  45. package/esm/Session/hydratedForms.d.ts +16 -0
  46. package/esm/Session/hydratedForms.js +13 -0
  47. package/esm/Session/index.d.ts +27 -10
  48. package/esm/Session/index.js +16 -10
  49. package/esm/Session/pluginExtraTrackItems.d.ts +11 -0
  50. package/esm/Session/pluginExtraTrackItems.js +13 -0
  51. package/esm/Session/readdedTrackConf.d.ts +8 -0
  52. package/esm/Session/readdedTrackConf.js +24 -0
  53. package/esm/Session/shareableSnapshot.d.ts +23 -0
  54. package/esm/Session/shareableSnapshot.js +66 -0
  55. package/esm/Session/temporaryAssemblyTracks.d.ts +24 -0
  56. package/esm/Session/temporaryAssemblyTracks.js +37 -0
  57. package/esm/assertExtends.d.ts +55 -0
  58. package/esm/assertExtends.js +1 -0
  59. package/esm/controllerTracks.d.ts +76 -0
  60. package/esm/controllerTracks.js +125 -0
  61. package/esm/destroyViewState.d.ts +21 -0
  62. package/esm/destroyViewState.js +29 -0
  63. package/esm/embeddedController.d.ts +57 -0
  64. package/esm/embeddedController.js +100 -0
  65. package/esm/index.d.ts +32 -4
  66. package/esm/index.js +31 -4
  67. package/esm/loadPlugins.d.ts +38 -0
  68. package/esm/loadPlugins.js +45 -0
  69. package/esm/localFiles.d.ts +74 -0
  70. package/esm/localFiles.js +156 -0
  71. package/esm/observeSession.d.ts +55 -0
  72. package/esm/observeSession.js +90 -0
  73. package/esm/parallelChunkLoading.d.ts +30 -0
  74. package/esm/parallelChunkLoading.js +71 -0
  75. package/esm/pluginInput.d.ts +32 -0
  76. package/esm/pluginInput.js +19 -0
  77. package/esm/pruneUnbuildableNodes.d.ts +109 -0
  78. package/esm/pruneUnbuildableNodes.js +562 -0
  79. package/esm/resolveAssemblies.d.ts +68 -0
  80. package/esm/resolveAssemblies.js +77 -0
  81. package/esm/rpcWorker.d.ts +36 -4
  82. package/esm/rpcWorker.js +126 -20
  83. package/esm/sessionMigrations/index.d.ts +15 -0
  84. package/esm/sessionMigrations/index.js +178 -0
  85. package/esm/sessionUrl.d.ts +40 -0
  86. package/esm/sessionUrl.js +66 -0
  87. package/esm/sessionUtils.d.ts +74 -0
  88. package/esm/sessionUtils.js +599 -0
  89. package/esm/siblingCast.d.ts +14 -0
  90. package/esm/siblingCast.js +16 -0
  91. package/esm/snapshotUtils.d.ts +8 -0
  92. package/esm/snapshotUtils.js +12 -0
  93. package/esm/ui/AboutDialog.d.ts +8 -3
  94. package/esm/ui/AboutDialog.js +14 -5
  95. package/esm/ui/AboutDialogContents.d.ts +2 -6
  96. package/esm/ui/AboutDialogContents.js +13 -17
  97. package/esm/ui/AssemblyInfoPanel.d.ts +5 -0
  98. package/esm/ui/AssemblyInfoPanel.js +63 -0
  99. package/esm/ui/DescriptionPanel.d.ts +3 -0
  100. package/esm/ui/DescriptionPanel.js +25 -0
  101. package/esm/ui/Drawer.d.ts +21 -0
  102. package/esm/ui/Drawer.js +60 -0
  103. package/esm/ui/DrawerControls.d.ts +5 -0
  104. package/esm/ui/DrawerControls.js +28 -0
  105. package/esm/ui/DrawerHeader.d.ts +6 -0
  106. package/esm/ui/DrawerHeader.js +36 -0
  107. package/esm/ui/DrawerWidget.d.ts +5 -0
  108. package/esm/ui/DrawerWidget.js +12 -0
  109. package/esm/ui/DrawerWidgetSelector.d.ts +5 -0
  110. package/esm/ui/DrawerWidgetSelector.js +40 -0
  111. package/esm/ui/FileInfoPanel.d.ts +3 -6
  112. package/esm/ui/FileInfoPanel.js +36 -26
  113. package/esm/ui/GeneralPreferencesTab.d.ts +17 -0
  114. package/esm/ui/GeneralPreferencesTab.js +34 -0
  115. package/esm/ui/HeaderButtons.d.ts +2 -1
  116. package/esm/ui/HeaderButtons.js +15 -17
  117. package/esm/ui/ModalWidget.d.ts +13 -0
  118. package/esm/ui/ModalWidget.js +48 -0
  119. package/esm/ui/ModalWidgetAppBar.d.ts +8 -0
  120. package/esm/ui/ModalWidgetAppBar.js +9 -0
  121. package/esm/ui/PreferenceCheckbox.d.ts +6 -0
  122. package/esm/ui/PreferenceCheckbox.js +16 -0
  123. package/esm/ui/PreferencesDialog.d.ts +34 -0
  124. package/esm/ui/PreferencesDialog.js +55 -0
  125. package/esm/ui/PreferencesResetDialog.d.ts +8 -0
  126. package/esm/ui/PreferencesResetDialog.js +19 -0
  127. package/esm/ui/RefNameAliasesDialog.d.ts +9 -0
  128. package/esm/ui/RefNameAliasesDialog.js +65 -0
  129. package/esm/ui/RefNameInfoDialog.d.ts +3 -6
  130. package/esm/ui/RefNameInfoDialog.js +45 -63
  131. package/esm/ui/ViewPreferencesTab.d.ts +12 -0
  132. package/esm/ui/ViewPreferencesTab.js +15 -0
  133. package/esm/ui/WidgetBody.d.ts +18 -0
  134. package/esm/ui/WidgetBody.js +22 -0
  135. package/esm/ui/WidgetHeading.d.ts +7 -0
  136. package/esm/ui/WidgetHeading.js +7 -0
  137. package/esm/ui/aboutTestUtils.d.ts +140 -0
  138. package/esm/ui/aboutTestUtils.js +25 -0
  139. package/esm/ui/descriptionHtml.d.ts +25 -0
  140. package/esm/ui/descriptionHtml.js +64 -0
  141. package/esm/ui/drawerLayout.d.ts +18 -0
  142. package/esm/ui/drawerLayout.js +22 -0
  143. package/esm/ui/index.d.ts +15 -1
  144. package/esm/ui/index.js +13 -1
  145. package/esm/ui/preferencesReset.d.ts +18 -0
  146. package/esm/ui/preferencesReset.js +69 -0
  147. package/esm/ui/util.d.ts +22 -7
  148. package/esm/ui/util.js +19 -41
  149. package/esm/useEngineLifecycle.d.ts +19 -0
  150. package/esm/useEngineLifecycle.js +44 -0
  151. package/package.json +15 -18
  152. package/esm/RootModel/FormatAbout.d.ts +0 -12
  153. package/esm/RootModel/FormatAbout.js +0 -15
  154. package/esm/RootModel/FormatDetails.d.ts +0 -24
  155. package/esm/RootModel/FormatDetails.js +0 -27
  156. package/esm/Session/DialogQueue.d.ts +0 -17
  157. package/esm/Session/DialogQueue.js +0 -31
@@ -1,68 +1,436 @@
1
+ import { readConfObject } from '@jbrowse/core/configuration';
2
+ import SnackbarModel from '@jbrowse/core/ui/SnackbarModel';
3
+ import { setNumberGrouping } from '@jbrowse/core/util';
4
+ import { freezeDeep } from '@jbrowse/core/util/freezeDeep';
5
+ import { isSameHighlight } from '@jbrowse/core/util/highlights';
6
+ import { isFeature, unwrapFeature } from '@jbrowse/core/util/simpleFeature';
1
7
  import { ElementId } from '@jbrowse/core/util/types/mst';
2
- import { getParent, isStateTreeNode, types } from '@jbrowse/mobx-state-tree';
8
+ import { cast, getParent, isStateTreeNode, types, } from '@jbrowse/mobx-state-tree';
9
+ import { observable } from 'mobx';
10
+ import { applyDeveloperMode } from './developerMode.js';
11
+ function isAnimationMode(val) {
12
+ return val === 'system' || val === 'enabled' || val === 'disabled';
13
+ }
14
+ /**
15
+ * #stateModel BaseSessionModel
16
+ *
17
+ * base session shared by all JBrowse products. Be careful what you include
18
+ * here, everything will use it.
19
+ */
3
20
  export function BaseSessionModel(_pluginManager) {
4
- return types
21
+ const baseModel = types
5
22
  .model({
23
+ /**
24
+ * #property
25
+ */
6
26
  id: ElementId,
27
+ /**
28
+ * #property
29
+ */
7
30
  name: types.string,
8
- margin: 0,
31
+ /**
32
+ * #property
33
+ * used to keep track of which view is in focus
34
+ */
35
+ focusedViewId: types.maybe(types.string),
36
+ /**
37
+ * #property
38
+ * translucent bands over genomic regions; every view draws the ones on
39
+ * its own assemblies
40
+ */
41
+ highlights: types.stripDefault(types.array(types.frozen()), []),
42
+ /**
43
+ * #property
44
+ */
45
+ highlightsVisible: types.stripDefault(types.boolean, true),
46
+ /**
47
+ * #property
48
+ * whether a band's label is written on it
49
+ */
50
+ highlightLabelsVisible: types.stripDefault(types.boolean, true),
51
+ /**
52
+ * #property
53
+ * views, tracks, displays and widgets `pruneUnbuildableNodes` took out of
54
+ * the tree because this build has no plugin for their type, each with the
55
+ * anchor that puts it back. Nothing in the session reads its contents,
56
+ * and `pruneUnbuildableNodes` defines their structure.
57
+ *
58
+ * It is a **declared property** because MST drops undeclared snapshot
59
+ * keys without error. Without this declaration the held nodes survive
60
+ * the prune and are then discarded when `setSession` builds the tree,
61
+ * while every unit test of the prune still passes.
62
+ * `heldNodesSurviveTheSession.test.ts` tests that they survive.
63
+ */
64
+ heldForMissingPlugins: types.stripDefault(types.frozen(), undefined),
9
65
  })
10
66
  .volatile(() => ({
67
+ /**
68
+ * #volatile
69
+ * this is the globally "selected" object. can be anything. code that
70
+ * wants to deal with this should examine it to see what kind of thing it
71
+ * is.
72
+ */
73
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
11
74
  selection: undefined,
75
+ /**
76
+ * #volatile
77
+ * this is the globally "hovered" object. can be anything. code that
78
+ * wants to deal with this should examine it to see what kind of thing it
79
+ * is.
80
+ */
81
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
12
82
  hovered: undefined,
83
+ /**
84
+ * #volatile
85
+ */
86
+ queueOfDialogs: [],
87
+ /**
88
+ * #volatile
89
+ * runtime user-preference overrides keyed by preference id, resolved by
90
+ * `getPreference` against the `configuration.preferences` admin defaults.
91
+ * Empty here (config-only); products that let users edit preferences load
92
+ * and persist these via localStorage. A runtime override map layered over
93
+ * config defaults, kept off the snapshot since prefs are local UI.
94
+ *
95
+ * An `observable.map` (not a plain object reassigned wholesale) so each
96
+ * preference is its own tracked key: writing one (`setScrollZoom`) can't
97
+ * invalidate a reader of another. A single spread-replaced object made
98
+ * every setter wake every reader, so toggling scroll-to-zoom re-fetched
99
+ * every track.
100
+ *
101
+ * `deep: false` keeps an object-valued preference a plain object rather
102
+ * than a MobX Proxy, which V8's structured-clone serializer rejects. The
103
+ * map still notifies per key on `set`, so shallow values lose no
104
+ * reactivity — and nothing can mutate a preference in place, because
105
+ * `setPreferenceOverride` freezes what it stores.
106
+ */
107
+ preferencesOverrides: observable.map(undefined, {
108
+ deep: false,
109
+ }),
13
110
  }))
14
111
  .views(self => ({
112
+ /**
113
+ * #getter
114
+ */
15
115
  get root() {
16
116
  return getParent(self);
17
117
  },
18
118
  }))
19
119
  .views(self => ({
120
+ /**
121
+ * #getter
122
+ */
20
123
  get jbrowse() {
21
124
  return self.root.jbrowse;
22
125
  },
126
+ /**
127
+ * #getter
128
+ */
23
129
  get rpcManager() {
24
130
  return self.root.rpcManager;
25
131
  },
132
+ /**
133
+ * #getter
134
+ */
26
135
  get configuration() {
27
136
  return this.jbrowse.configuration;
28
137
  },
138
+ /**
139
+ * #getter
140
+ */
29
141
  get adminMode() {
30
142
  return self.root.adminMode;
31
143
  },
144
+ /**
145
+ * #getter
146
+ */
32
147
  get textSearchManager() {
33
148
  return self.root.textSearchManager;
34
149
  },
35
150
  }))
36
151
  .views(self => ({
152
+ /**
153
+ * #getter
154
+ */
37
155
  get assemblies() {
38
156
  return self.jbrowse.assemblies;
39
157
  },
158
+ /**
159
+ * #getter
160
+ */
161
+ get DialogComponent() {
162
+ return self.queueOfDialogs[0]?.[0];
163
+ },
164
+ /**
165
+ * #getter
166
+ */
167
+ get DialogProps() {
168
+ return self.queueOfDialogs[0]?.[1];
169
+ },
170
+ }))
171
+ .views(self => ({
172
+ /**
173
+ * #method
174
+ * the admin/embedder `configuration.preferences` value for a key, ignoring
175
+ * any runtime override — i.e. what a reset falls back to. Exposed rather
176
+ * than inlined because "differs from the default" is a question the
177
+ * Preferences reset diff asks about settings this map doesn't hold (see
178
+ * `defaultUseWorkspaces`).
179
+ */
180
+ getPreferenceDefault(key) {
181
+ const { preferences } = self.configuration;
182
+ return preferences ? readConfObject(preferences, key) : undefined;
183
+ },
184
+ /**
185
+ * #method
186
+ * resolved value of a user preference: a runtime override if the user set
187
+ * one, otherwise the admin/embedder `configuration.preferences` default.
188
+ * The override map is empty unless the product loads it (web/desktop).
189
+ */
190
+ getPreference(key) {
191
+ const override = self.preferencesOverrides.get(key);
192
+ return override === undefined
193
+ ? this.getPreferenceDefault(key)
194
+ : override;
195
+ },
196
+ /**
197
+ * #method
198
+ * every scalar preference override that currently differs from its
199
+ * config/admin default, as `{ path, from, to }` rows whose path is the
200
+ * override's own key. A scalar pref (animationMode, scrollZoom) whose
201
+ * override equals the default is omitted, since reverting it is a no-op.
202
+ */
203
+ getPreferenceChanges() {
204
+ const changes = [];
205
+ for (const [key, value] of self.preferencesOverrides.entries()) {
206
+ const dflt = this.getPreferenceDefault(key);
207
+ if (value !== dflt) {
208
+ changes.push({
209
+ path: [key],
210
+ from: dflt,
211
+ to: value,
212
+ });
213
+ }
214
+ }
215
+ return changes;
216
+ },
217
+ }))
218
+ .views(self => ({
219
+ /**
220
+ * #getter
221
+ * resolved feature-layout animation mode (never undefined)
222
+ */
223
+ get animationMode() {
224
+ const mode = self.getPreference('animationMode');
225
+ return isAnimationMode(mode) ? mode : 'enabled';
226
+ },
227
+ /**
228
+ * #getter
229
+ * resolved scroll-to-zoom preference. Global and personal (never shared in
230
+ * a session snapshot); every wheel-zoom view reads this single value.
231
+ */
232
+ get scrollZoom() {
233
+ return self.getPreference('scrollZoom') === true;
234
+ },
235
+ /**
236
+ * #getter
237
+ * resolved thousand-separator preference. Read for display in the
238
+ * Preferences dialog; the formatter itself reads a plain module variable
239
+ * set at startup in each realm (see `setNumberGrouping`), because worker-
240
+ * built strings can't see a main-thread observable.
241
+ */
242
+ get numberGrouping() {
243
+ return self.getPreference('numberGrouping') !== false;
244
+ },
40
245
  }))
41
246
  .actions(self => ({
247
+ afterAttach() {
248
+ // push the admin/embedder default down to the formatter, which is a
249
+ // plain module variable rather than an observable (see
250
+ // `setNumberGrouping`). Embedded products stop here; web and desktop
251
+ // compose PreferencesSessionMixin, whose own afterAttach runs after
252
+ // this one and re-applies the value once the user's stored overrides
253
+ // are loaded, so a user override still wins over the config default.
254
+ setNumberGrouping(self.numberGrouping);
255
+ },
256
+ /**
257
+ * #action
258
+ * set the global selection, i.e. the globally-selected object. can be a
259
+ * feature, a view, just about anything
260
+ *
261
+ * A feature is unwrapped on the way in, so app state never holds a
262
+ * jexlFeatureProxy. `isFeature` accepts a proxy, but on one `id` is a
263
+ * data field rather than the method the Feature type promises — every
264
+ * consumer doing `isFeature(selection) ? selection.id() : …` would throw.
265
+ */
42
266
  setSelection(thing) {
43
- self.selection = thing;
267
+ self.selection = isFeature(thing) ? unwrapFeature(thing) : thing;
44
268
  },
269
+ /**
270
+ * #action
271
+ * clears the global selection
272
+ */
45
273
  clearSelection() {
46
274
  self.selection = undefined;
47
275
  },
276
+ /**
277
+ * #action
278
+ */
48
279
  setHovered(thing) {
49
280
  self.hovered = thing;
50
281
  },
51
- }))
52
- .postProcessSnapshot(snap => {
53
- if (!snap) {
54
- return snap;
55
- }
56
- const { margin, ...rest } = snap;
57
- return {
58
- ...rest,
59
- ...(margin ? { margin } : {}),
60
- };
61
- });
282
+ /**
283
+ * #action
284
+ */
285
+ setHighlightsVisible(arg) {
286
+ self.highlightsVisible = arg;
287
+ },
288
+ /**
289
+ * #action
290
+ */
291
+ setHighlightLabelsVisible(arg) {
292
+ self.highlightLabelsVisible = arg;
293
+ },
294
+ /**
295
+ * #action
296
+ * an identical entry is not added twice, so a spec launched again does not
297
+ * stack its bands. Adding shows the bands again, since a highlight made
298
+ * while they are off would otherwise read as nothing happening
299
+ */
300
+ addHighlight(highlight) {
301
+ if (!self.highlights.some(h => isSameHighlight(h, highlight))) {
302
+ self.highlights.push(highlight);
303
+ }
304
+ self.highlightsVisible = true;
305
+ },
306
+ /**
307
+ * #action
308
+ */
309
+ removeHighlight(highlight) {
310
+ self.highlights.remove(highlight);
311
+ },
312
+ /**
313
+ * #action
314
+ */
315
+ updateHighlight(old, updates) {
316
+ const idx = self.highlights.indexOf(old);
317
+ if (idx !== -1) {
318
+ self.highlights[idx] = { ...old, ...updates };
319
+ self.highlightsVisible = true;
320
+ }
321
+ },
322
+ /**
323
+ * #action
324
+ */
325
+ setHighlights(highlights) {
326
+ self.highlights = cast(highlights);
327
+ if (highlights.length) {
328
+ self.highlightsVisible = true;
329
+ }
330
+ },
331
+ /**
332
+ * #action
333
+ * set a runtime user-preference override (see `getPreference`). Mutates
334
+ * volatile state; products persist these to localStorage. An `undefined`
335
+ * value deletes the key (rather than leaving a phantom entry that
336
+ * `getPreference` reads as absent) so the store never holds dead keys.
337
+ */
338
+ setPreferenceOverride(key, value) {
339
+ if (value === undefined) {
340
+ self.preferencesOverrides.delete(key);
341
+ }
342
+ else {
343
+ // frozen because `deep: false` hands an object-valued preference
344
+ // straight back out by reference, so the "nothing mutates a
345
+ // preference in place" this store relies on is enforced rather than
346
+ // assumed
347
+ self.preferencesOverrides.set(key, freezeDeep(value));
348
+ }
349
+ },
350
+ /**
351
+ * #action
352
+ * clear every runtime preference override at once, so each falls back to
353
+ * its config/admin default. Backs the Preferences dialog "Reset to
354
+ * defaults" button.
355
+ */
356
+ clearPreferenceOverrides() {
357
+ self.preferencesOverrides.clear();
358
+ },
359
+ /**
360
+ * #action
361
+ * clear a single runtime preference override (see `getPreference`) so it
362
+ * falls back to its config/admin default. Backs the per-entry reset in the
363
+ * Preferences dialog "Reset to defaults" confirmation.
364
+ */
365
+ clearPreferenceOverride(key) {
366
+ self.preferencesOverrides.delete(key);
367
+ },
368
+ /**
369
+ * #action
370
+ * set the global scroll-to-zoom preference (see the `scrollZoom` getter)
371
+ */
372
+ setScrollZoom(flag) {
373
+ this.setPreferenceOverride('scrollZoom', flag);
374
+ },
375
+ /**
376
+ * #action
377
+ */
378
+ setName(str) {
379
+ self.name = str;
380
+ },
381
+ /**
382
+ * #action
383
+ * `undefined` is "no view is focused", which the property has always been
384
+ * able to hold (`types.maybe`) and this had no way to spell. Nothing
385
+ * cleared it on teardown as a result: a view that was focused when it left
386
+ * the session left its id behind, and since every consumer compares
387
+ * `focusedViewId === view.id`, the id matched nothing, the focus ring
388
+ * vanished with nothing to say why, and the dead id persisted into a saved
389
+ * or shared session. `takeOut` clears it now.
390
+ */
391
+ setFocusedViewId(viewId) {
392
+ self.focusedViewId = viewId;
393
+ },
394
+ /**
395
+ * #action
396
+ */
397
+ removeActiveDialog() {
398
+ self.queueOfDialogs = self.queueOfDialogs.slice(1);
399
+ },
400
+ /**
401
+ * #action
402
+ */
403
+ queueDialog(doneCallback) {
404
+ // its own entry, not the head: a late second call must not close the
405
+ // dialog queued behind it
406
+ const entry = doneCallback(() => {
407
+ this.removeDialog(entry);
408
+ });
409
+ self.queueOfDialogs = [...self.queueOfDialogs, entry];
410
+ },
411
+ /**
412
+ * #action
413
+ */
414
+ removeDialog(entry) {
415
+ self.queueOfDialogs = self.queueOfDialogs.filter(d => d !== entry);
416
+ },
417
+ }));
418
+ return types.compose(baseModel, SnackbarModel()).actions(self => ({
419
+ // after the compose rather than in the afterAttach above, because the
420
+ // notices land in the snackbar this line is the first place to hold both
421
+ // halves of. Web and desktop reach it a second time once the user's stored
422
+ // overrides are loaded (`PreferencesSessionMixin`), and our MST fork
423
+ // auto-chains both hooks.
424
+ afterAttach() {
425
+ applyDeveloperMode(self);
426
+ },
427
+ }));
62
428
  }
429
+ /** Type guard for BaseSession */
63
430
  export function isBaseSession(thing) {
64
431
  return 'id' in thing && 'name' in thing && 'root' in thing;
65
432
  }
433
+ /** Type guard for whether a thing is JBrowse session */
66
434
  export function isSession(thing) {
67
435
  return isStateTreeNode(thing) && isBaseSession(thing);
68
436
  }
@@ -1,21 +1,128 @@
1
1
  import type PluginManager from '@jbrowse/core/PluginManager';
2
- import type { AnyConfigurationModel } from '@jbrowse/core/configuration';
2
+ import type { AnyConfiguration, AnyConfigurationModel } from '@jbrowse/core/configuration';
3
3
  import type { BaseConnectionConfigModel } from '@jbrowse/core/pluggableElementTypes/models/baseConnectionConfig';
4
4
  import type { IAnyStateTreeNode, Instance } from '@jbrowse/mobx-state-tree';
5
+ /**
6
+ * Persisted config of a connection track the user has opened. Keyed by trackId
7
+ * in `connectionTrackConfigs`. `connectionId` records provenance so the track
8
+ * can be grouped under its connection and re-hydrated on demand.
9
+ */
10
+ export interface ConnectionTrackConfigEntry {
11
+ connectionId: string;
12
+ config: Record<string, unknown>;
13
+ }
14
+ /**
15
+ * #stateModel ConnectionManagementSessionMixin
16
+ */
5
17
  export declare function ConnectionManagementSessionMixin(pluginManager: PluginManager): import("@jbrowse/mobx-state-tree").IModelType<{
6
- connectionInstances: import("@jbrowse/mobx-state-tree").IArrayType<import("@jbrowse/mobx-state-tree").IAnyType>;
18
+ /**
19
+ * #property
20
+ */
21
+ connectionInstances: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").IArrayType<import("@jbrowse/mobx-state-tree").IAnyType>, [undefined]>;
22
+ /**
23
+ * #property
24
+ * Persisted configs of connection tracks the user has opened, keyed by
25
+ * trackId. Unlike `connectionInstances` (stripped from snapshots, holds
26
+ * the whole fetched hub), this holds only the tracks in use, so an open
27
+ * connection track resolves synchronously on session load without
28
+ * re-establishing the connection.
29
+ */
30
+ connectionTrackConfigs: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").IType<Record<string, ConnectionTrackConfigEntry>, Record<string, ConnectionTrackConfigEntry>, Record<string, ConnectionTrackConfigEntry>>, [undefined]>;
7
31
  }, {
32
+ /**
33
+ * #getter
34
+ */
8
35
  readonly connections: BaseConnectionConfigModel[];
9
36
  } & {
10
- makeConnection(configuration: AnyConfigurationModel, initialSnapshot?: {}): any;
11
- prepareToBreakConnection(configuration: AnyConfigurationModel): [() => void, Record<string, number>] | undefined;
37
+ /**
38
+ * #action
39
+ */
40
+ makeConnection(configuration: AnyConfigurationModel, initialSnapshot?: object): any;
41
+ /**
42
+ * #action
43
+ * Remove a live connection instance. Tolerant of an already-dormant
44
+ * connection (its instance is stripped from the session on reload).
45
+ * Leaves persisted open-track configs alone — the connect() error path
46
+ * calls this and the user's already-open tracks must survive a transient
47
+ * failure. Full removal goes through `deleteConnection`.
48
+ */
12
49
  breakConnection(configuration: AnyConfigurationModel): void;
50
+ /**
51
+ * #action
52
+ * Close every track a connection contributed — the live instance's
53
+ * tracks plus any persisted open-track configs (a dormant connection,
54
+ * never expanded this session, still renders its opened tracks from
55
+ * `connectionTrackConfigs`) — from all views/widgets, drop the live
56
+ * instance, and drop the persisted configs. The session is left as if the
57
+ * connection had never loaded.
58
+ */
59
+ teardownConnection(configuration: AnyConfigurationModel): void;
60
+ /**
61
+ * #action
62
+ * Fully remove a connection: tear down its tracks and live instance, then
63
+ * delete its config.
64
+ */
13
65
  deleteConnection(configuration: AnyConfigurationModel): any;
14
- addConnectionConf(connectionConf: AnyConfigurationModel): any;
66
+ /**
67
+ * #action
68
+ * Adds to the **config**, not the session: `jbrowse.connections`, which
69
+ * every visitor to this instance loads. jbrowse-web overrides this so a
70
+ * non-admin's connection lands in `sessionConnections` instead — see
71
+ * WebSessionConnectionsMixin, whose `addSessionConnectionConf` is what
72
+ * to call when you mean the session specifically rather than "wherever
73
+ * this user's edits go".
74
+ *
75
+ * Applications without that override (Desktop, the embedded products)
76
+ * have only this one destination, and it is the right one there: their
77
+ * config and session are saved as a single document.
78
+ */
79
+ addConnectionConf(connectionConf: AnyConfiguration): any;
80
+ /**
81
+ * #action
82
+ */
15
83
  clearConnections(): void;
16
- }, import("@jbrowse/mobx-state-tree")._NotCustomized, import("@jbrowse/mobx-state-tree").ModelSnapshotType<{
17
- connectionInstances: import("@jbrowse/mobx-state-tree").IArrayType<import("@jbrowse/mobx-state-tree").IAnyType>;
18
- }>>;
84
+ /**
85
+ * #action
86
+ * Snapshot a just-opened connection track's config into
87
+ * `connectionTrackConfigs` so it survives session reload. No-op if the
88
+ * track isn't connection-provided or is already captured (edits go
89
+ * through `updateConnectionTrackConfig`).
90
+ */
91
+ captureConnectionTrack(trackId: string): void;
92
+ /**
93
+ * #action
94
+ * Persist an edit to an opened connection track. The full config is
95
+ * stored (not a delta): the connection's fetched "base" isn't present at
96
+ * load, so only a complete config resolves synchronously.
97
+ */
98
+ updateConnectionTrackConfig(trackConf: Record<string, unknown> & {
99
+ trackId: string;
100
+ }): void;
101
+ /**
102
+ * #action
103
+ * Upsert one opened connection track's persisted config.
104
+ */
105
+ setConnectionTrackConfig(trackId: string, connectionId: string, config: Record<string, unknown>): void;
106
+ /**
107
+ * #action
108
+ * Drop a connection track's persisted config once no open view still
109
+ * references it, so the session doesn't accumulate closed tracks.
110
+ */
111
+ pruneConnectionTrackConfig(trackId: string): void;
112
+ /**
113
+ * #action
114
+ * Lazily establish a single connection by id if it isn't already live;
115
+ * the track selector calls it when the connection's category is
116
+ * expanded. Fetches without launching a view or showing a success
117
+ * snackbar; already-open tracks keep
118
+ * rendering from `connectionTrackConfigs` meanwhile. Idempotent.
119
+ */
120
+ hydrateConnection(connectionId: string): void;
121
+ }, import("@jbrowse/mobx-state-tree")._NotCustomized, import("@jbrowse/mobx-state-tree")._NotCustomized>;
122
+ /** Session mixin MST type for a session that has connections */
19
123
  export type SessionWithConnectionsType = ReturnType<typeof ConnectionManagementSessionMixin>;
124
+ /** Instance of a session that has connections: `connectionInstances`,
125
+ * `makeConnection()`, etc. */
20
126
  export type SessionWithConnections = Instance<SessionWithConnectionsType>;
127
+ /** Type guard for SessionWithConnections */
21
128
  export declare function isSessionWithConnections(session: IAnyStateTreeNode): session is SessionWithConnections;