@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
@@ -2,64 +2,166 @@ import { isConfigurationModel } from '@jbrowse/core/configuration';
2
2
  import { localStorageGetItem, localStorageSetItem } from '@jbrowse/core/util';
3
3
  import { addDisposer, getEnv, isAlive, isStateTreeNode, types, } from '@jbrowse/mobx-state-tree';
4
4
  import { autorun } from 'mobx';
5
- import { isBaseSession } from "./BaseSession.js";
5
+ import { isBaseSession } from './BaseSession.js';
6
6
  const minDrawerWidth = 128;
7
+ const minMainWidth = 150;
8
+ const drawerPositions = ['left', 'right'];
9
+ // localStorage holds whatever a previous version, another tab, or a hand-edit
10
+ // left there, and `drawerPosition` is now an enumeration that throws on a value
11
+ // outside the set.
12
+ function storedDrawerPosition() {
13
+ const stored = localStorageGetItem('drawerPosition');
14
+ return drawerPositions.find(position => position === stored) ?? 'right';
15
+ }
16
+ // The one clamp both resize paths share. `drawerWidth` is a
17
+ // `types.refinement(types.integer, >= minDrawerWidth)`, so the three things this
18
+ // does are load-bearing rather than cosmetic — MST throws on an assignment that
19
+ // misses either bound:
20
+ //
21
+ // - Rounded, because a drag delta is fractional whenever `clientX` is (browser
22
+ // zoom, fractional devicePixelRatio, pen/touch), and ResizeHandle passes that
23
+ // delta straight through.
24
+ // - Bounded by the width the drawer and the main area actually share, which the
25
+ // caller measures. `window.innerWidth` is the default and is right only for a
26
+ // full-window app: an embedded view is whatever box the host gave it, and
27
+ // clamping a 600px embed's drawer against a 1600px window let a drag collapse
28
+ // the view beside it to nothing and overflow the embed.
29
+ // - The minimum applied *last*, because a container narrower than
30
+ // minDrawerWidth + minMainWidth has no width satisfying both bounds. The
31
+ // floor has to win there; the drawer simply crowds the main area.
32
+ function clampDrawerWidth(width, availableWidth) {
33
+ const max = availableWidth - minMainWidth;
34
+ return Math.max(minDrawerWidth, Math.min(Math.round(width), max));
35
+ }
36
+ /**
37
+ * #stateModel DrawerWidgetSessionMixin
38
+ */
7
39
  export function DrawerWidgetSessionMixin(pluginManager) {
8
40
  const widgetStateModelType = pluginManager.pluggableMstType('widget', 'stateModel');
9
41
  return types
10
42
  .model({
11
- drawerPosition: types.optional(types.string, () => localStorageGetItem('drawerPosition') || 'right'),
12
- drawerWidth: types.optional(types.refinement(types.integer, width => width >= minDrawerWidth), 384),
13
- widgets: types.map(widgetStateModelType),
14
- activeWidgets: types.map(types.safeReference(widgetStateModelType)),
15
- minimized: types.optional(types.boolean, false),
43
+ /**
44
+ * #property
45
+ */
46
+ drawerPosition: types.optional(types.enumeration('DrawerPosition', [
47
+ ...drawerPositions,
48
+ ]), storedDrawerPosition),
49
+ /**
50
+ * #property
51
+ */
52
+ drawerWidth: types.stripDefault(types.refinement(types.integer, width => width >= minDrawerWidth), 384),
53
+ /**
54
+ * #property
55
+ */
56
+ widgets: types.stripDefault(types.map(widgetStateModelType), {}),
57
+ /**
58
+ * #property
59
+ */
60
+ activeWidgets: types.stripDefault(types.map(types.safeReference(widgetStateModelType)), {}),
61
+ /**
62
+ * #property
63
+ */
64
+ minimized: types.stripDefault(types.boolean, false),
16
65
  })
17
66
  .views(self => ({
67
+ /**
68
+ * #getter
69
+ */
70
+ // annotated rather than inferred: a widget's state model comes from a
71
+ // plugin, so `pluggableMstType` is `IAnyType` and its Instance is `any` —
72
+ // which silently made this getter, and every read of it off a concrete
73
+ // session, unchecked. `Widget` is the contract `SessionWithWidgets`
74
+ // already declares, so this only brings the concrete model into line with
75
+ // what plugins narrowing to that interface have always seen.
18
76
  get visibleWidget() {
19
77
  if (isAlive(self)) {
20
- return [...self.activeWidgets.values()][self.activeWidgets.size - 1];
78
+ // returns most recently added item in active widgets
79
+ return [...self.activeWidgets.values()].at(-1);
21
80
  }
22
81
  return undefined;
23
82
  },
83
+ }))
84
+ .volatile(() => ({
85
+ /**
86
+ * #volatile
87
+ * true while the visible widget is shown in a modal dialog instead of the
88
+ * drawer. Volatile because a restored session that opened straight into a
89
+ * modal, with no drawer behind it, is disorienting
90
+ */
91
+ poppedOut: false,
92
+ /**
93
+ * #volatile
94
+ * set by a host with no room for a drawer column beside its views (a
95
+ * phone), so every widget shows in a modal instead
96
+ */
97
+ modalWidgets: false,
98
+ }))
99
+ .views(self => ({
100
+ /**
101
+ * #getter
102
+ * whether the drawer column is on screen: there is something to show, it
103
+ * is not minimized to the FAB, and it is not currently a modal instead.
104
+ *
105
+ * A getter rather than each host's own `&&`, because the hosts drifted --
106
+ * the app shell tested `poppedOut` and the embedded view did not, so the
107
+ * day a popout button reaches the embedded drawer header it would render
108
+ * the modal and the drawer at once.
109
+ */
110
+ get drawerVisible() {
111
+ return (Boolean(self.visibleWidget) &&
112
+ !self.minimized &&
113
+ !self.poppedOut &&
114
+ !self.modalWidgets);
115
+ },
116
+ /**
117
+ * #getter
118
+ * whether the visible widget shows in a modal: popped out of the drawer,
119
+ * or on a host with no room for one
120
+ */
121
+ get modalWidgetVisible() {
122
+ return (Boolean(self.visibleWidget) &&
123
+ !self.minimized &&
124
+ (self.poppedOut || self.modalWidgets));
125
+ },
24
126
  }))
25
127
  .actions(self => ({
128
+ /**
129
+ * #action
130
+ */
26
131
  setDrawerPosition(arg) {
27
132
  self.drawerPosition = arg;
28
- localStorage.setItem('drawerPosition', arg);
29
133
  },
30
- updateDrawerWidth(drawerWidth) {
31
- if (drawerWidth === self.drawerWidth) {
32
- return self.drawerWidth;
33
- }
34
- let newDrawerWidth = drawerWidth;
35
- if (newDrawerWidth < minDrawerWidth) {
36
- newDrawerWidth = minDrawerWidth;
37
- }
38
- self.drawerWidth = newDrawerWidth;
39
- return newDrawerWidth;
134
+ /**
135
+ * #action
136
+ */
137
+ updateDrawerWidth(drawerWidth, availableWidth = window.innerWidth) {
138
+ self.drawerWidth = clampDrawerWidth(drawerWidth, availableWidth);
139
+ return self.drawerWidth;
40
140
  },
41
- resizeDrawer(distance) {
42
- if (self.drawerPosition === 'left') {
43
- distance *= -1;
44
- }
141
+ /**
142
+ * #action
143
+ */
144
+ resizeDrawer(distance, availableWidth = window.innerWidth) {
145
+ const signed = self.drawerPosition === 'left' ? -distance : distance;
45
146
  const oldDrawerWidth = self.drawerWidth;
46
- const newDrawerWidth = this.updateDrawerWidth(oldDrawerWidth - distance);
47
- return oldDrawerWidth - newDrawerWidth;
147
+ self.drawerWidth = clampDrawerWidth(oldDrawerWidth - signed, availableWidth);
148
+ return oldDrawerWidth - self.drawerWidth;
48
149
  },
150
+ /**
151
+ * #action
152
+ */
49
153
  addWidget(typeName, id, initialState = {}, conf) {
50
- const typeDefinition = pluginManager.getElementType('widget', typeName);
51
- if (!typeDefinition) {
52
- throw new Error(`unknown widget type ${typeName}`);
53
- }
54
- const data = {
154
+ self.widgets.set(id, {
55
155
  ...initialState,
56
156
  id,
57
157
  type: typeName,
58
- configuration: conf || { type: typeName },
59
- };
60
- self.widgets.set(id, data);
158
+ configuration: conf ?? { type: typeName },
159
+ });
61
160
  return self.widgets.get(id);
62
161
  },
162
+ /**
163
+ * #action
164
+ */
63
165
  showWidget(widget) {
64
166
  if (self.activeWidgets.has(widget.id)) {
65
167
  self.activeWidgets.delete(widget.id);
@@ -67,59 +169,127 @@ export function DrawerWidgetSessionMixin(pluginManager) {
67
169
  self.activeWidgets.set(widget.id, widget);
68
170
  self.minimized = false;
69
171
  },
70
- hasWidget(widget) {
71
- return self.activeWidgets.has(widget.id);
72
- },
172
+ /**
173
+ * #action
174
+ */
73
175
  hideWidget(widget) {
74
176
  self.activeWidgets.delete(widget.id);
177
+ if (self.activeWidgets.size === 0) {
178
+ self.poppedOut = false;
179
+ }
75
180
  },
181
+ /**
182
+ * #action
183
+ */
76
184
  minimizeWidgetDrawer() {
77
185
  self.minimized = true;
78
186
  },
187
+ /**
188
+ * #action
189
+ */
79
190
  showWidgetDrawer() {
80
191
  self.minimized = false;
81
192
  },
193
+ /**
194
+ * #action
195
+ * show the visible widget in a modal dialog, freeing the drawer column
196
+ */
197
+ popoutWidget() {
198
+ self.poppedOut = true;
199
+ },
200
+ /**
201
+ * #action
202
+ */
203
+ returnWidgetToDrawer() {
204
+ self.poppedOut = false;
205
+ },
206
+ /**
207
+ * #action
208
+ */
209
+ setModalWidgets(flag) {
210
+ self.modalWidgets = flag;
211
+ },
212
+ /**
213
+ * #action
214
+ */
82
215
  hideAllWidgets() {
83
216
  self.activeWidgets.clear();
217
+ self.poppedOut = false;
84
218
  },
85
- editConfiguration(configuration) {
219
+ afterAttach() {
220
+ addDisposer(self, autorun(function drawerPositionAutorun() {
221
+ localStorageSetItem('drawerPosition', self.drawerPosition);
222
+ }, { name: 'DrawerPosition' }));
223
+ },
224
+ }))
225
+ .actions(self => ({
226
+ /**
227
+ * #action
228
+ * the modal's close button: a popped-out widget goes back to the drawer,
229
+ * and with no drawer to go back to the widget closes
230
+ */
231
+ closeModalWidget() {
232
+ const widget = self.visibleWidget;
233
+ if (self.modalWidgets && widget) {
234
+ self.hideWidget(widget);
235
+ }
236
+ else {
237
+ self.returnWidgetToDrawer();
238
+ }
239
+ },
240
+ /**
241
+ * #action
242
+ * adds the widget, replacing one with the same id, and shows it
243
+ */
244
+ openWidget(typeName, id, initialState = {}, conf) {
245
+ const widget = self.addWidget(typeName, id, initialState, conf);
246
+ self.showWidget(widget);
247
+ return widget;
248
+ },
249
+ }))
250
+ .actions(self => ({
251
+ /**
252
+ * #action
253
+ * opens a configuration editor to configure the given thing,
254
+ * and sets the current task to be configuring it
255
+ * @param configuration - can be an MST model or a frozen/plain object with trackId
256
+ */
257
+ editConfiguration(configuration, opts) {
86
258
  let targetConfig;
87
259
  if (isStateTreeNode(configuration) &&
88
260
  isConfigurationModel(configuration)) {
261
+ // Already an MST model (e.g., from track.configuration), use directly
89
262
  targetConfig = configuration;
90
263
  }
91
264
  else if ('trackId' in configuration) {
265
+ // Frozen/plain object - create a temporary MST model for editing
92
266
  const trackSchema = pluginManager.pluggableConfigSchemaType('track');
93
267
  targetConfig = trackSchema.create(configuration, getEnv(self));
94
268
  }
95
269
  else {
96
270
  throw new Error('must pass a configuration model or frozen config with trackId to editConfiguration');
97
271
  }
98
- const editor = this.addWidget('ConfigurationEditorWidget', 'configEditor', {});
272
+ const editor = self.openWidget('ConfigurationEditorWidget', 'configEditor');
273
+ // Set target via action since it's now volatile
99
274
  editor.setTarget(targetConfig);
100
- this.showWidget(editor);
101
- },
102
- afterAttach() {
103
- addDisposer(self, autorun(function drawerPositionAutorun() {
104
- localStorageSetItem('drawerPosition', self.drawerPosition);
105
- }, { name: 'DrawerPosition' }));
275
+ editor.setExpandedDisplayId(opts?.expandedDisplayId);
106
276
  },
107
277
  }))
108
278
  .postProcessSnapshot(snap => {
279
+ // drawerPosition is a personal per-browser layout preference, not shared
280
+ // view state: destructure it out so it never lands in the snapshot. It
281
+ // stays localStorage-backed, so each browser keeps its own value.
282
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
109
283
  if (!snap) {
110
284
  return snap;
111
285
  }
112
- const { drawerPosition, drawerWidth, widgets, activeWidgets, minimized, ...rest } = snap;
286
+ const { drawerPosition, ...rest } = snap;
113
287
  return {
114
288
  ...rest,
115
- ...(drawerPosition !== 'right' ? { drawerPosition } : {}),
116
- ...(drawerWidth !== 384 ? { drawerWidth } : {}),
117
- ...(Object.keys(widgets ?? {}).length ? { widgets } : {}),
118
- ...(Object.keys(activeWidgets ?? {}).length ? { activeWidgets } : {}),
119
- ...(minimized ? { minimized } : {}),
120
289
  };
121
290
  });
122
291
  }
292
+ /** Type guard for SessionWithDrawerWidgets */
123
293
  export function isSessionWithDrawerWidgets(session) {
124
294
  return (isBaseSession(session) &&
125
295
  'widgets' in session &&