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

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 (137) hide show
  1. package/esm/RootModel/BaseRootModel.d.ts +629 -304
  2. package/esm/RootModel/BaseRootModel.js +139 -14
  3. package/esm/RootModel/HierarchicalConfig.d.ts +57 -21
  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 +68 -0
  8. package/esm/RootModel/PreferencesConfig.js +76 -0
  9. package/esm/RootModel/createConfigModel.d.ts +240 -0
  10. package/esm/RootModel/createConfigModel.js +56 -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 +143 -0
  15. package/esm/Session/BaseSession.d.ts +312 -11
  16. package/esm/Session/BaseSession.js +458 -14
  17. package/esm/Session/Connections.d.ts +114 -8
  18. package/esm/Session/Connections.js +195 -74
  19. package/esm/Session/DrawerWidgets.d.ts +115 -12
  20. package/esm/Session/DrawerWidgets.js +161 -42
  21. package/esm/Session/MultipleViews.d.ts +1281 -1128
  22. package/esm/Session/MultipleViews.js +396 -64
  23. package/esm/Session/Preferences.d.ts +1667 -0
  24. package/esm/Session/Preferences.js +59 -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 +1277 -1138
  28. package/esm/Session/SessionTracks.js +540 -35
  29. package/esm/Session/Themes.d.ts +87 -2
  30. package/esm/Session/Themes.js +156 -23
  31. package/esm/Session/TrackMenu.d.ts +112 -0
  32. package/esm/Session/TrackMenu.js +200 -0
  33. package/esm/Session/TrackMenuSessionMixin.d.ts +27 -0
  34. package/esm/Session/TrackMenuSessionMixin.js +41 -0
  35. package/esm/Session/Tracks.d.ts +1171 -1117
  36. package/esm/Session/Tracks.js +183 -20
  37. package/esm/Session/assertSessionModel.d.ts +21 -0
  38. package/esm/Session/assertSessionModel.js +1 -0
  39. package/esm/Session/developerMode.d.ts +7 -0
  40. package/esm/Session/developerMode.js +43 -0
  41. package/esm/Session/finalizeSession.d.ts +16 -0
  42. package/esm/Session/finalizeSession.js +29 -0
  43. package/esm/Session/index.d.ts +22 -10
  44. package/esm/Session/index.js +13 -10
  45. package/esm/Session/readdedTrackConf.d.ts +8 -0
  46. package/esm/Session/readdedTrackConf.js +25 -0
  47. package/esm/Session/shareableSnapshot.d.ts +77 -0
  48. package/esm/Session/shareableSnapshot.js +196 -0
  49. package/esm/Session/temporaryAssemblyTracks.d.ts +24 -0
  50. package/esm/Session/temporaryAssemblyTracks.js +37 -0
  51. package/esm/assertExtends.d.ts +55 -0
  52. package/esm/assertExtends.js +1 -0
  53. package/esm/controllerTracks.d.ts +56 -0
  54. package/esm/controllerTracks.js +90 -0
  55. package/esm/destroyViewState.d.ts +21 -0
  56. package/esm/destroyViewState.js +29 -0
  57. package/esm/index.d.ts +31 -4
  58. package/esm/index.js +31 -4
  59. package/esm/loadPlugins.d.ts +33 -0
  60. package/esm/loadPlugins.js +41 -0
  61. package/esm/localFiles.d.ts +74 -0
  62. package/esm/localFiles.js +156 -0
  63. package/esm/observeSession.d.ts +56 -0
  64. package/esm/observeSession.js +91 -0
  65. package/esm/pluginInput.d.ts +32 -0
  66. package/esm/pluginInput.js +19 -0
  67. package/esm/pruneUnbuildableNodes.d.ts +109 -0
  68. package/esm/pruneUnbuildableNodes.js +568 -0
  69. package/esm/resolveAssemblies.d.ts +44 -0
  70. package/esm/resolveAssemblies.js +55 -0
  71. package/esm/rpcWorker.d.ts +26 -0
  72. package/esm/rpcWorker.js +98 -16
  73. package/esm/scheduleDetachedDestroy.d.ts +18 -0
  74. package/esm/scheduleDetachedDestroy.js +24 -0
  75. package/esm/sessionMigrations/index.d.ts +53 -0
  76. package/esm/sessionMigrations/index.js +432 -0
  77. package/esm/sessionUrl.d.ts +41 -0
  78. package/esm/sessionUrl.js +53 -0
  79. package/esm/sessionUtils.d.ts +69 -0
  80. package/esm/sessionUtils.js +613 -0
  81. package/esm/siblingCast.d.ts +14 -0
  82. package/esm/siblingCast.js +16 -0
  83. package/esm/snapshotUtils.d.ts +8 -0
  84. package/esm/snapshotUtils.js +12 -0
  85. package/esm/ui/AboutDialog.d.ts +3 -6
  86. package/esm/ui/AboutDialog.js +4 -4
  87. package/esm/ui/AboutDialogContents.d.ts +2 -6
  88. package/esm/ui/AboutDialogContents.js +34 -13
  89. package/esm/ui/AssemblyInfoPanel.d.ts +5 -0
  90. package/esm/ui/AssemblyInfoPanel.js +69 -0
  91. package/esm/ui/DisplayDefaultsSection.d.ts +36 -0
  92. package/esm/ui/DisplayDefaultsSection.js +65 -0
  93. package/esm/ui/Drawer.d.ts +21 -0
  94. package/esm/ui/Drawer.js +60 -0
  95. package/esm/ui/DrawerControls.d.ts +5 -0
  96. package/esm/ui/DrawerControls.js +28 -0
  97. package/esm/ui/DrawerHeader.d.ts +6 -0
  98. package/esm/ui/DrawerHeader.js +36 -0
  99. package/esm/ui/DrawerWidget.d.ts +5 -0
  100. package/esm/ui/DrawerWidget.js +12 -0
  101. package/esm/ui/DrawerWidgetSelector.d.ts +5 -0
  102. package/esm/ui/DrawerWidgetSelector.js +40 -0
  103. package/esm/ui/FileInfoPanel.d.ts +3 -6
  104. package/esm/ui/FileInfoPanel.js +35 -26
  105. package/esm/ui/HeaderButtons.d.ts +7 -1
  106. package/esm/ui/HeaderButtons.js +23 -18
  107. package/esm/ui/ModalWidget.d.ts +12 -0
  108. package/esm/ui/ModalWidget.js +33 -0
  109. package/esm/ui/ModalWidgetAppBar.d.ts +8 -0
  110. package/esm/ui/ModalWidgetAppBar.js +9 -0
  111. package/esm/ui/PreferencesDialog.d.ts +56 -0
  112. package/esm/ui/PreferencesDialog.js +145 -0
  113. package/esm/ui/PreferencesResetDialog.d.ts +8 -0
  114. package/esm/ui/PreferencesResetDialog.js +19 -0
  115. package/esm/ui/RefNameAliasesDialog.d.ts +9 -0
  116. package/esm/ui/RefNameAliasesDialog.js +65 -0
  117. package/esm/ui/RefNameInfoDialog.d.ts +3 -6
  118. package/esm/ui/RefNameInfoDialog.js +57 -63
  119. package/esm/ui/WidgetBody.d.ts +18 -0
  120. package/esm/ui/WidgetBody.js +22 -0
  121. package/esm/ui/WidgetHeading.d.ts +7 -0
  122. package/esm/ui/WidgetHeading.js +7 -0
  123. package/esm/ui/drawerLayout.d.ts +18 -0
  124. package/esm/ui/drawerLayout.js +22 -0
  125. package/esm/ui/index.d.ts +13 -1
  126. package/esm/ui/index.js +12 -1
  127. package/esm/ui/util.d.ts +37 -4
  128. package/esm/ui/util.js +35 -38
  129. package/esm/useEngineLifecycle.d.ts +19 -0
  130. package/esm/useEngineLifecycle.js +44 -0
  131. package/package.json +12 -15
  132. package/esm/RootModel/FormatAbout.d.ts +0 -12
  133. package/esm/RootModel/FormatAbout.js +0 -15
  134. package/esm/RootModel/FormatDetails.d.ts +0 -24
  135. package/esm/RootModel/FormatDetails.js +0 -27
  136. package/esm/Session/DialogQueue.d.ts +0 -17
  137. package/esm/Session/DialogQueue.js +0 -31
@@ -2,64 +2,147 @@ 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
+ .views(self => ({
94
+ /**
95
+ * #getter
96
+ * whether the drawer column is on screen: there is something to show, it
97
+ * is not minimized to the FAB, and it is not currently a modal instead.
98
+ *
99
+ * A getter rather than each host's own `&&`, because the hosts drifted --
100
+ * the app shell tested `poppedOut` and the embedded view did not, so the
101
+ * day a popout button reaches the embedded drawer header it would render
102
+ * the modal and the drawer at once.
103
+ */
104
+ get drawerVisible() {
105
+ return Boolean(self.visibleWidget) && !self.minimized && !self.poppedOut;
106
+ },
24
107
  }))
25
108
  .actions(self => ({
109
+ /**
110
+ * #action
111
+ */
26
112
  setDrawerPosition(arg) {
27
113
  self.drawerPosition = arg;
28
- localStorage.setItem('drawerPosition', arg);
29
114
  },
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;
115
+ /**
116
+ * #action
117
+ */
118
+ updateDrawerWidth(drawerWidth, availableWidth = window.innerWidth) {
119
+ self.drawerWidth = clampDrawerWidth(drawerWidth, availableWidth);
120
+ return self.drawerWidth;
40
121
  },
41
- resizeDrawer(distance) {
42
- if (self.drawerPosition === 'left') {
43
- distance *= -1;
44
- }
122
+ /**
123
+ * #action
124
+ */
125
+ resizeDrawer(distance, availableWidth = window.innerWidth) {
126
+ const signed = self.drawerPosition === 'left' ? -distance : distance;
45
127
  const oldDrawerWidth = self.drawerWidth;
46
- const newDrawerWidth = this.updateDrawerWidth(oldDrawerWidth - distance);
47
- return oldDrawerWidth - newDrawerWidth;
128
+ self.drawerWidth = clampDrawerWidth(oldDrawerWidth - signed, availableWidth);
129
+ return oldDrawerWidth - self.drawerWidth;
48
130
  },
131
+ /**
132
+ * #action
133
+ */
49
134
  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 = {
135
+ self.widgets.set(id, {
55
136
  ...initialState,
56
137
  id,
57
138
  type: typeName,
58
- configuration: conf || { type: typeName },
59
- };
60
- self.widgets.set(id, data);
139
+ configuration: conf ?? { type: typeName },
140
+ });
61
141
  return self.widgets.get(id);
62
142
  },
143
+ /**
144
+ * #action
145
+ */
63
146
  showWidget(widget) {
64
147
  if (self.activeWidgets.has(widget.id)) {
65
148
  self.activeWidgets.delete(widget.id);
@@ -67,28 +150,62 @@ export function DrawerWidgetSessionMixin(pluginManager) {
67
150
  self.activeWidgets.set(widget.id, widget);
68
151
  self.minimized = false;
69
152
  },
70
- hasWidget(widget) {
71
- return self.activeWidgets.has(widget.id);
72
- },
153
+ /**
154
+ * #action
155
+ */
73
156
  hideWidget(widget) {
74
157
  self.activeWidgets.delete(widget.id);
158
+ if (self.activeWidgets.size === 0) {
159
+ self.poppedOut = false;
160
+ }
75
161
  },
162
+ /**
163
+ * #action
164
+ */
76
165
  minimizeWidgetDrawer() {
77
166
  self.minimized = true;
78
167
  },
168
+ /**
169
+ * #action
170
+ */
79
171
  showWidgetDrawer() {
80
172
  self.minimized = false;
81
173
  },
174
+ /**
175
+ * #action
176
+ * show the visible widget in a modal dialog, freeing the drawer column
177
+ */
178
+ popoutWidget() {
179
+ self.poppedOut = true;
180
+ },
181
+ /**
182
+ * #action
183
+ */
184
+ returnWidgetToDrawer() {
185
+ self.poppedOut = false;
186
+ },
187
+ /**
188
+ * #action
189
+ */
82
190
  hideAllWidgets() {
83
191
  self.activeWidgets.clear();
192
+ self.poppedOut = false;
84
193
  },
85
- editConfiguration(configuration) {
194
+ /**
195
+ * #action
196
+ * opens a configuration editor to configure the given thing,
197
+ * and sets the current task to be configuring it
198
+ * @param configuration - can be an MST model or a frozen/plain object with trackId
199
+ */
200
+ editConfiguration(configuration, opts) {
86
201
  let targetConfig;
87
202
  if (isStateTreeNode(configuration) &&
88
203
  isConfigurationModel(configuration)) {
204
+ // Already an MST model (e.g., from track.configuration), use directly
89
205
  targetConfig = configuration;
90
206
  }
91
207
  else if ('trackId' in configuration) {
208
+ // Frozen/plain object - create a temporary MST model for editing
92
209
  const trackSchema = pluginManager.pluggableConfigSchemaType('track');
93
210
  targetConfig = trackSchema.create(configuration, getEnv(self));
94
211
  }
@@ -96,7 +213,9 @@ export function DrawerWidgetSessionMixin(pluginManager) {
96
213
  throw new Error('must pass a configuration model or frozen config with trackId to editConfiguration');
97
214
  }
98
215
  const editor = this.addWidget('ConfigurationEditorWidget', 'configEditor', {});
216
+ // Set target via action since it's now volatile
99
217
  editor.setTarget(targetConfig);
218
+ editor.setExpandedDisplayId(opts?.expandedDisplayId);
100
219
  this.showWidget(editor);
101
220
  },
102
221
  afterAttach() {
@@ -106,20 +225,20 @@ export function DrawerWidgetSessionMixin(pluginManager) {
106
225
  },
107
226
  }))
108
227
  .postProcessSnapshot(snap => {
228
+ // drawerPosition is a personal per-browser layout preference, not shared
229
+ // view state: destructure it out so it never lands in the snapshot. It
230
+ // stays localStorage-backed, so each browser keeps its own value.
231
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
109
232
  if (!snap) {
110
233
  return snap;
111
234
  }
112
- const { drawerPosition, drawerWidth, widgets, activeWidgets, minimized, ...rest } = snap;
235
+ const { drawerPosition, ...rest } = snap;
113
236
  return {
114
237
  ...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
238
  };
121
239
  });
122
240
  }
241
+ /** Type guard for SessionWithDrawerWidgets */
123
242
  export function isSessionWithDrawerWidgets(session) {
124
243
  return (isBaseSession(session) &&
125
244
  'widgets' in session &&