@jbrowse/product-core 4.2.1 → 5.0.0-beta.1
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.
- package/esm/RootModel/BaseRootModel.d.ts +629 -304
- package/esm/RootModel/BaseRootModel.js +138 -14
- package/esm/RootModel/HierarchicalConfig.d.ts +57 -21
- package/esm/RootModel/HierarchicalConfig.js +36 -0
- package/esm/RootModel/InternetAccounts.d.ts +18 -1
- package/esm/RootModel/InternetAccounts.js +120 -22
- package/esm/RootModel/PreferencesConfig.d.ts +53 -0
- package/esm/RootModel/PreferencesConfig.js +61 -0
- package/esm/RootModel/createConfigModel.d.ts +232 -0
- package/esm/RootModel/createConfigModel.js +56 -0
- package/esm/RootModel/index.d.ts +10 -5
- package/esm/RootModel/index.js +10 -5
- package/esm/RootModel/menuItems.d.ts +24 -0
- package/esm/RootModel/menuItems.js +143 -0
- package/esm/Session/BaseSession.d.ts +310 -11
- package/esm/Session/BaseSession.js +448 -14
- package/esm/Session/Connections.d.ts +114 -8
- package/esm/Session/Connections.js +195 -74
- package/esm/Session/DrawerWidgets.d.ts +115 -12
- package/esm/Session/DrawerWidgets.js +161 -42
- package/esm/Session/MultipleViews.d.ts +1266 -1128
- package/esm/Session/MultipleViews.js +357 -66
- package/esm/Session/Preferences.d.ts +1665 -0
- package/esm/Session/Preferences.js +54 -0
- package/esm/Session/ReferenceManagement.d.ts +28 -3
- package/esm/Session/ReferenceManagement.js +56 -41
- package/esm/Session/SessionTracks.d.ts +1275 -1138
- package/esm/Session/SessionTracks.js +532 -35
- package/esm/Session/Themes.d.ts +87 -2
- package/esm/Session/Themes.js +156 -23
- package/esm/Session/TrackMenu.d.ts +112 -0
- package/esm/Session/TrackMenu.js +200 -0
- package/esm/Session/TrackMenuSessionMixin.d.ts +27 -0
- package/esm/Session/TrackMenuSessionMixin.js +41 -0
- package/esm/Session/Tracks.d.ts +1169 -1117
- package/esm/Session/Tracks.js +160 -20
- package/esm/Session/assertSessionModel.d.ts +21 -0
- package/esm/Session/assertSessionModel.js +1 -0
- package/esm/Session/finalizeSession.d.ts +16 -0
- package/esm/Session/finalizeSession.js +29 -0
- package/esm/Session/index.d.ts +22 -10
- package/esm/Session/index.js +13 -10
- package/esm/Session/shareableSnapshot.d.ts +77 -0
- package/esm/Session/shareableSnapshot.js +196 -0
- package/esm/Session/temporaryAssemblyTracks.d.ts +23 -0
- package/esm/Session/temporaryAssemblyTracks.js +38 -0
- package/esm/assertExtends.d.ts +55 -0
- package/esm/assertExtends.js +1 -0
- package/esm/controllerTracks.d.ts +56 -0
- package/esm/controllerTracks.js +77 -0
- package/esm/destroyViewState.d.ts +21 -0
- package/esm/destroyViewState.js +29 -0
- package/esm/index.d.ts +31 -4
- package/esm/index.js +31 -4
- package/esm/loadPlugins.d.ts +33 -0
- package/esm/loadPlugins.js +38 -0
- package/esm/localFiles.d.ts +74 -0
- package/esm/localFiles.js +156 -0
- package/esm/observeSession.d.ts +56 -0
- package/esm/observeSession.js +91 -0
- package/esm/pluginInput.d.ts +32 -0
- package/esm/pluginInput.js +19 -0
- package/esm/pruneUnbuildableNodes.d.ts +109 -0
- package/esm/pruneUnbuildableNodes.js +568 -0
- package/esm/resolveAssemblies.d.ts +44 -0
- package/esm/resolveAssemblies.js +55 -0
- package/esm/rpcWorker.d.ts +26 -0
- package/esm/rpcWorker.js +96 -15
- package/esm/scheduleDetachedDestroy.d.ts +18 -0
- package/esm/scheduleDetachedDestroy.js +24 -0
- package/esm/sessionMigrations/index.d.ts +53 -0
- package/esm/sessionMigrations/index.js +432 -0
- package/esm/sessionUrl.d.ts +41 -0
- package/esm/sessionUrl.js +53 -0
- package/esm/sessionUtils.d.ts +69 -0
- package/esm/sessionUtils.js +613 -0
- package/esm/siblingCast.d.ts +14 -0
- package/esm/siblingCast.js +16 -0
- package/esm/snapshotUtils.d.ts +8 -0
- package/esm/snapshotUtils.js +12 -0
- package/esm/ui/AboutDialog.d.ts +3 -6
- package/esm/ui/AboutDialog.js +4 -4
- package/esm/ui/AboutDialogContents.d.ts +2 -6
- package/esm/ui/AboutDialogContents.js +34 -13
- package/esm/ui/AssemblyInfoPanel.d.ts +5 -0
- package/esm/ui/AssemblyInfoPanel.js +69 -0
- package/esm/ui/DisplayDefaultsSection.d.ts +36 -0
- package/esm/ui/DisplayDefaultsSection.js +65 -0
- package/esm/ui/Drawer.d.ts +21 -0
- package/esm/ui/Drawer.js +60 -0
- package/esm/ui/DrawerControls.d.ts +5 -0
- package/esm/ui/DrawerControls.js +28 -0
- package/esm/ui/DrawerHeader.d.ts +6 -0
- package/esm/ui/DrawerHeader.js +36 -0
- package/esm/ui/DrawerWidget.d.ts +5 -0
- package/esm/ui/DrawerWidget.js +12 -0
- package/esm/ui/DrawerWidgetSelector.d.ts +5 -0
- package/esm/ui/DrawerWidgetSelector.js +40 -0
- package/esm/ui/FileInfoPanel.d.ts +3 -6
- package/esm/ui/FileInfoPanel.js +35 -26
- package/esm/ui/HeaderButtons.d.ts +7 -1
- package/esm/ui/HeaderButtons.js +23 -18
- package/esm/ui/ModalWidget.d.ts +12 -0
- package/esm/ui/ModalWidget.js +33 -0
- package/esm/ui/ModalWidgetAppBar.d.ts +8 -0
- package/esm/ui/ModalWidgetAppBar.js +9 -0
- package/esm/ui/PreferencesDialog.d.ts +56 -0
- package/esm/ui/PreferencesDialog.js +145 -0
- package/esm/ui/PreferencesResetDialog.d.ts +8 -0
- package/esm/ui/PreferencesResetDialog.js +19 -0
- package/esm/ui/RefNameAliasesDialog.d.ts +9 -0
- package/esm/ui/RefNameAliasesDialog.js +65 -0
- package/esm/ui/RefNameInfoDialog.d.ts +3 -6
- package/esm/ui/RefNameInfoDialog.js +57 -63
- package/esm/ui/WidgetBody.d.ts +18 -0
- package/esm/ui/WidgetBody.js +22 -0
- package/esm/ui/WidgetHeading.d.ts +7 -0
- package/esm/ui/WidgetHeading.js +7 -0
- package/esm/ui/drawerLayout.d.ts +18 -0
- package/esm/ui/drawerLayout.js +22 -0
- package/esm/ui/index.d.ts +13 -1
- package/esm/ui/index.js +12 -1
- package/esm/ui/util.d.ts +37 -4
- package/esm/ui/util.js +35 -38
- package/esm/useEngineLifecycle.d.ts +13 -0
- package/esm/useEngineLifecycle.js +22 -0
- package/package.json +11 -15
- package/esm/RootModel/FormatAbout.d.ts +0 -12
- package/esm/RootModel/FormatAbout.js +0 -15
- package/esm/RootModel/FormatDetails.d.ts +0 -24
- package/esm/RootModel/FormatDetails.js +0 -27
- package/esm/Session/DialogQueue.d.ts +0 -17
- package/esm/Session/DialogQueue.js +0 -31
package/esm/Session/Tracks.js
CHANGED
|
@@ -1,49 +1,189 @@
|
|
|
1
1
|
import { types } from '@jbrowse/mobx-state-tree';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { computed } from 'mobx';
|
|
3
|
+
import { BaseSessionModel, isBaseSession } from './BaseSession.js';
|
|
4
|
+
import { isSessionWithConnections } from './Connections.js';
|
|
5
|
+
import { ReferenceManagementSessionMixin } from './ReferenceManagement.js';
|
|
6
|
+
import { assertTrackConfOutlivesItsAssemblies } from './temporaryAssemblyTracks.js';
|
|
7
|
+
/**
|
|
8
|
+
* #stateModel TracksManagerSessionMixin
|
|
9
|
+
*/
|
|
4
10
|
export function TracksManagerSessionMixin(pluginManager) {
|
|
5
11
|
return types
|
|
6
12
|
.compose('TracksManagerSessionMixin', BaseSessionModel(pluginManager), ReferenceManagementSessionMixin(pluginManager))
|
|
7
13
|
.views(self => ({
|
|
14
|
+
/**
|
|
15
|
+
* #getter
|
|
16
|
+
*/
|
|
8
17
|
get tracks() {
|
|
9
18
|
return self.jbrowse.tracks;
|
|
10
19
|
},
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
20
|
+
}))
|
|
21
|
+
.views(self => {
|
|
22
|
+
// One index trackId → config for all tracks, assembly sequences, and
|
|
23
|
+
// connection tracks. Frozen jbrowse.tracks entries stay plain objects
|
|
24
|
+
// here; hydration to MST nodes happens lazily in TrackConfigurationReference
|
|
25
|
+
// on first access. Cached, so the N per-id lookups below share one rebuild
|
|
26
|
+
// per change rather than each re-scanning.
|
|
27
|
+
const tracksByIdRecord = computed(() => {
|
|
15
28
|
const temporaryAssemblies = 'temporaryAssemblies' in self
|
|
16
29
|
? self.temporaryAssemblies
|
|
17
30
|
: [];
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
31
|
+
// both come from the connections mixin, which not every session
|
|
32
|
+
// composes. connectionInstances is annotated because its element type
|
|
33
|
+
// is a runtime-pluggable stateModel, so the guard can't infer it.
|
|
34
|
+
const connectionInstances = isSessionWithConnections(self) ? self.connectionInstances : [];
|
|
35
|
+
const connectionTrackConfigs = isSessionWithConnections(self)
|
|
36
|
+
? self.connectionTrackConfigs
|
|
37
|
+
: {};
|
|
21
38
|
return Object.fromEntries([
|
|
22
|
-
...
|
|
23
|
-
|
|
39
|
+
...self.tracks.map(t => [t.trackId, t]),
|
|
40
|
+
// assembly sequence tracks, so they resolve by trackId
|
|
41
|
+
...self.assemblies.map(a => [a.sequence.trackId, a.sequence]),
|
|
24
42
|
...temporaryAssemblies.map(a => [a.sequence.trackId, a.sequence]),
|
|
25
43
|
...connectionInstances.flatMap(c => c.tracks.map(t => [t.trackId, t])),
|
|
44
|
+
// Persisted configs of opened connection tracks. Placed last so they
|
|
45
|
+
// win over the live connection instance: identity-stable across
|
|
46
|
+
// reload, and resolves even when the connection isn't re-established.
|
|
47
|
+
...Object.entries(connectionTrackConfigs).map(([trackId, e]) => [
|
|
48
|
+
trackId,
|
|
49
|
+
e.config,
|
|
50
|
+
]),
|
|
26
51
|
]);
|
|
27
|
-
}
|
|
28
|
-
|
|
52
|
+
});
|
|
53
|
+
// Per-id computed cache backing getTrackById. Resolving one track's config
|
|
54
|
+
// subscribes only to that id's computed, so editing track A leaves track
|
|
55
|
+
// B's observers untouched: an unedited id's entry keeps its object identity
|
|
56
|
+
// across a sibling edit, so its computed re-evaluates equal and MobX
|
|
57
|
+
// short-circuits — B never wakes. Derived on read (no reconcile autorun),
|
|
58
|
+
// so it is never stale mid-action: session hydration and add-and-show
|
|
59
|
+
// resolve straight through it. Not evicted — bounded by the distinct ids
|
|
60
|
+
// resolved this session, and holds no authoritative state.
|
|
61
|
+
const trackByIdComputeds = new Map();
|
|
62
|
+
return {
|
|
63
|
+
/**
|
|
64
|
+
* #method
|
|
65
|
+
* Config for one trackId — a track, assembly sequence, or connection
|
|
66
|
+
* track — or undefined. Per-id reactive: every display resolves its
|
|
67
|
+
* config through this (via TrackConfigurationReference) and subscribes
|
|
68
|
+
* only to its own id, so one track's settings edit doesn't re-render the
|
|
69
|
+
* others.
|
|
70
|
+
*/
|
|
71
|
+
getTrackById(id) {
|
|
72
|
+
let c = trackByIdComputeds.get(id);
|
|
73
|
+
if (!c) {
|
|
74
|
+
c = computed(() => tracksByIdRecord.get()[id]);
|
|
75
|
+
trackByIdComputeds.set(id, c);
|
|
76
|
+
}
|
|
77
|
+
return c.get();
|
|
78
|
+
},
|
|
79
|
+
/**
|
|
80
|
+
* #method
|
|
81
|
+
* Every track config the session can resolve, keyed by trackId. Prefer
|
|
82
|
+
* the per-id reactive `getTrackById(id)`: reading this whole map
|
|
83
|
+
* subscribes the caller to *every* track, so an edit to any one of them
|
|
84
|
+
* wakes it — the reason internal display config resolution moved off
|
|
85
|
+
* it. Kept for plugins that look up ids in a non-reactive context.
|
|
86
|
+
*
|
|
87
|
+
* @deprecated
|
|
88
|
+
*/
|
|
89
|
+
getTracksById() {
|
|
90
|
+
return tracksByIdRecord.get();
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
})
|
|
29
94
|
.actions(self => ({
|
|
95
|
+
/**
|
|
96
|
+
* #action
|
|
97
|
+
* Add a track config to *this session*.
|
|
98
|
+
*
|
|
99
|
+
* This mixin's session has no separate session-track store, so the
|
|
100
|
+
* destination is the jbrowse config — which in the products that compose
|
|
101
|
+
* it (desktop) is the single user's own file rather than something a
|
|
102
|
+
* server hands other visitors, so the two scopes are the same place.
|
|
103
|
+
* Defined here anyway so that every session has it: a feature standing a
|
|
104
|
+
* track up on the user's behalf can then call one action everywhere
|
|
105
|
+
* instead of asking which mixin it landed on.
|
|
106
|
+
* `SessionTracksManagerSessionMixin` overrides it with the real
|
|
107
|
+
* session-scoped store.
|
|
108
|
+
*/
|
|
109
|
+
addSessionTrackConf(trackConf) {
|
|
110
|
+
assertTrackConfOutlivesItsAssemblies(self, trackConf, 'jbrowse.tracks');
|
|
111
|
+
return self.jbrowse.addTrackConf(trackConf);
|
|
112
|
+
},
|
|
113
|
+
/**
|
|
114
|
+
* #action
|
|
115
|
+
* Add a track config wherever *this user's* catalog edits belong — the
|
|
116
|
+
* "Add track" workflows, where an admin adding a track means to add it
|
|
117
|
+
* for the whole site. `SessionTracksManagerSessionMixin` overrides it to
|
|
118
|
+
* send a non-admin's to the session instead; here there is only the one
|
|
119
|
+
* destination.
|
|
120
|
+
*
|
|
121
|
+
* Anything that is not an Add-track workflow wants
|
|
122
|
+
* `addSessionTrackConf`: a track a feature stands up on the user's behalf
|
|
123
|
+
* — a search result, a computed consensus, a reconstruction's labels — is
|
|
124
|
+
* not a catalog entry, and publishing one writes it into the config.json
|
|
125
|
+
* every visitor is served, once per click.
|
|
126
|
+
*/
|
|
127
|
+
publishTrackConf(trackConf) {
|
|
128
|
+
assertTrackConfOutlivesItsAssemblies(self, trackConf, 'jbrowse.tracks');
|
|
129
|
+
return self.jbrowse.addTrackConf(trackConf);
|
|
130
|
+
},
|
|
131
|
+
/**
|
|
132
|
+
* #action
|
|
133
|
+
* Deprecated alias of `addSessionTrackConf`. Call that, or
|
|
134
|
+
* `publishTrackConf`, which say which destination they mean.
|
|
135
|
+
*
|
|
136
|
+
* @deprecated
|
|
137
|
+
*
|
|
138
|
+
* Kept because a prebuilt plugin bundle reaches this by name at runtime
|
|
139
|
+
* and cannot be recompiled — `jbrowse-plugin-protein3d` calls it, and a
|
|
140
|
+
* member lookup that stops resolving throws nothing at all
|
|
141
|
+
* (`pluginFacingSessionApi.test.ts` is the guard). It now means the
|
|
142
|
+
* session, which is the destination every such caller wanted: a track a
|
|
143
|
+
* plugin stands up for one user is not a catalog entry. Nothing in tree
|
|
144
|
+
* may call it — `no-restricted-syntax` says so.
|
|
145
|
+
*
|
|
146
|
+
* Spelled out rather than delegating through `this`, for the reason
|
|
147
|
+
* `SessionTracks.addToSession` is a plain closure: an action whose return
|
|
148
|
+
* type is inferred from a sibling's makes the pair circular.
|
|
149
|
+
*/
|
|
30
150
|
addTrackConf(trackConf) {
|
|
151
|
+
assertTrackConfOutlivesItsAssemblies(self, trackConf, 'jbrowse.tracks');
|
|
31
152
|
return self.jbrowse.addTrackConf(trackConf);
|
|
32
153
|
},
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
154
|
+
/**
|
|
155
|
+
* #action
|
|
156
|
+
* Persist edited track config back to the in-memory jbrowse config. The
|
|
157
|
+
* session-tracks mixin overrides this so a non-admin's edits become a
|
|
158
|
+
* shareable session-track override instead.
|
|
159
|
+
*/
|
|
160
|
+
updateTrackConfiguration(trackConf) {
|
|
161
|
+
// an opened connection track lives in connectionTrackConfigs, not
|
|
162
|
+
// jbrowse.tracks; persist its edit there (jbrowse.updateTrackConf would
|
|
163
|
+
// no-op, since the track isn't in the config). Desktop uses this base
|
|
164
|
+
// mixin, so without this branch a connection-track edit is lost on
|
|
165
|
+
// reload.
|
|
166
|
+
if (isSessionWithConnections(self) &&
|
|
167
|
+
trackConf.trackId in self.connectionTrackConfigs) {
|
|
168
|
+
self.updateConnectionTrackConfig(trackConf);
|
|
40
169
|
}
|
|
170
|
+
else {
|
|
171
|
+
self.jbrowse.updateTrackConf(trackConf);
|
|
172
|
+
}
|
|
173
|
+
},
|
|
174
|
+
/**
|
|
175
|
+
* #action
|
|
176
|
+
*/
|
|
177
|
+
deleteTrackConf(trackConf) {
|
|
178
|
+
const { trackId } = trackConf;
|
|
179
|
+
self.dereferenceTrack(trackId, self.getReferring(trackId));
|
|
41
180
|
if (self.adminMode) {
|
|
42
181
|
return self.jbrowse.deleteTrackConf(trackConf);
|
|
43
182
|
}
|
|
44
183
|
},
|
|
45
184
|
}));
|
|
46
185
|
}
|
|
186
|
+
/** Type guard for SessionWithTracks */
|
|
47
187
|
export function isSessionWithTracks(thing) {
|
|
48
188
|
return isBaseSession(thing) && 'tracks' in thing;
|
|
49
189
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { AssertExtends } from '../assertExtends.ts';
|
|
2
|
+
import type { AbstractSessionModel } from '@jbrowse/core/util/types';
|
|
3
|
+
/**
|
|
4
|
+
* Compile-time assertion that a concrete session-model instance type satisfies
|
|
5
|
+
* `AbstractSessionModel`. Reference it with a product's session instance type
|
|
6
|
+
* to force the check; there is no runtime component, so a missing member
|
|
7
|
+
* surfaces as a type error at the reference site:
|
|
8
|
+
*
|
|
9
|
+
* ```ts
|
|
10
|
+
* type _Check = AssertSessionModel<Instance<WebSessionModelType>>
|
|
11
|
+
* ```
|
|
12
|
+
*
|
|
13
|
+
* Every product's session model pairs this with one `AssertExtends` per
|
|
14
|
+
* capability contract it relies on, because this assertion alone is not enough:
|
|
15
|
+
* `AbstractSessionModel` marks those capabilities **optional**, so it cannot
|
|
16
|
+
* catch a member drifting out of sync with the `SessionWith*` interface plugins
|
|
17
|
+
* actually narrow to. Keep them as one assertion per contract rather than
|
|
18
|
+
* collapsing them into a list — the whole value is the compile error naming the
|
|
19
|
+
* contract that broke.
|
|
20
|
+
*/
|
|
21
|
+
export type AssertSessionModel<T extends AbstractSessionModel> = AssertExtends<T, AbstractSessionModel>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type PluginManager from '@jbrowse/core/PluginManager';
|
|
2
|
+
import type { IAnyModelType, SnapshotIn, SnapshotOut } from '@jbrowse/mobx-state-tree';
|
|
3
|
+
/**
|
|
4
|
+
* Apply the `Core-extendSession` extension point and drop the legacy
|
|
5
|
+
* object-shaped `connectionInstances` from incoming snapshots (the schema
|
|
6
|
+
* changed from an object to an array, so old snapshots must be filtered out,
|
|
7
|
+
* xref https://github.com/GMOD/jbrowse-components/issues/1903).
|
|
8
|
+
*
|
|
9
|
+
* Shared by the web session (`finalizeWebSession`) and the desktop session
|
|
10
|
+
* factory so the extension point + migration live in one place.
|
|
11
|
+
*/
|
|
12
|
+
export declare function finalizeSession<T extends IAnyModelType>(pluginManager: PluginManager, sessionModel: T): import("@jbrowse/mobx-state-tree").ISnapshotProcessor<T, Omit<SnapshotIn<T> & {
|
|
13
|
+
connectionInstances?: unknown;
|
|
14
|
+
}, "connectionInstances">, Omit<SnapshotOut<T> & {
|
|
15
|
+
connectionInstances?: unknown;
|
|
16
|
+
}, "connectionInstances">>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { types } from '@jbrowse/mobx-state-tree';
|
|
2
|
+
/**
|
|
3
|
+
* Apply the `Core-extendSession` extension point and drop the legacy
|
|
4
|
+
* object-shaped `connectionInstances` from incoming snapshots (the schema
|
|
5
|
+
* changed from an object to an array, so old snapshots must be filtered out,
|
|
6
|
+
* xref https://github.com/GMOD/jbrowse-components/issues/1903).
|
|
7
|
+
*
|
|
8
|
+
* Shared by the web session (`finalizeWebSession`) and the desktop session
|
|
9
|
+
* factory so the extension point + migration live in one place.
|
|
10
|
+
*/
|
|
11
|
+
export function finalizeSession(pluginManager, sessionModel) {
|
|
12
|
+
const extendedSessionModel = pluginManager.evaluateExtensionPoint(
|
|
13
|
+
/** #extensionPoint Core-extendSession | sync | Extend the session model with extra state or actions */
|
|
14
|
+
'Core-extendSession', sessionModel);
|
|
15
|
+
return types.snapshotProcessor(extendedSessionModel, {
|
|
16
|
+
preProcessor(snapshot) {
|
|
17
|
+
const { connectionInstances, ...rest } = snapshot;
|
|
18
|
+
return !Array.isArray(connectionInstances) ? rest : snapshot;
|
|
19
|
+
},
|
|
20
|
+
postProcessor(snapshot) {
|
|
21
|
+
// connectionInstances are runtime-only: they hold the whole fetched hub
|
|
22
|
+
// (thousands of tracks), so persisting them bloats the session. Open
|
|
23
|
+
// connection tracks survive reload via `connectionTrackConfigs` instead,
|
|
24
|
+
// which resolves synchronously without re-establishing the connection.
|
|
25
|
+
const { connectionInstances: _connectionInstances, ...rest } = snapshot;
|
|
26
|
+
return rest;
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
}
|
package/esm/Session/index.d.ts
CHANGED
|
@@ -1,10 +1,22 @@
|
|
|
1
|
-
export
|
|
2
|
-
export
|
|
3
|
-
export
|
|
4
|
-
export
|
|
5
|
-
export
|
|
6
|
-
export
|
|
7
|
-
export
|
|
8
|
-
export
|
|
9
|
-
export
|
|
10
|
-
export
|
|
1
|
+
export { ReferenceManagementSessionMixin, isSessionWithReferenceManagement, } from './ReferenceManagement.ts';
|
|
2
|
+
export type { ReferringNode, SessionWithReferenceManagement, SessionWithReferenceManagementType, } from './ReferenceManagement.ts';
|
|
3
|
+
export { ConnectionManagementSessionMixin, isSessionWithConnections, } from './Connections.ts';
|
|
4
|
+
export type { ConnectionTrackConfigEntry, SessionWithConnections, SessionWithConnectionsType, } from './Connections.ts';
|
|
5
|
+
export { DrawerWidgetSessionMixin, isSessionWithDrawerWidgets, } from './DrawerWidgets.ts';
|
|
6
|
+
export type { SessionWithDrawerWidgets, SessionWithDrawerWidgetsType, } from './DrawerWidgets.ts';
|
|
7
|
+
export { ThemeManagerSessionMixin, isSessionWithThemes } from './Themes.ts';
|
|
8
|
+
export type { SessionWithThemes, SessionWithThemesType } from './Themes.ts';
|
|
9
|
+
export { TracksManagerSessionMixin, isSessionWithTracks } from './Tracks.ts';
|
|
10
|
+
export type { SessionWithTracks, SessionWithTracksType } from './Tracks.ts';
|
|
11
|
+
export { MultipleViewsSessionMixin, isSessionWithMultipleViews, } from './MultipleViews.ts';
|
|
12
|
+
export type { SessionWithMultipleViews, SessionWithMultipleViewsType, } from './MultipleViews.ts';
|
|
13
|
+
export { PreferencesSessionMixin } from './Preferences.ts';
|
|
14
|
+
export { BaseSessionModel, isBaseSession, isSession } from './BaseSession.ts';
|
|
15
|
+
export type { BaseSession, BaseSessionType } from './BaseSession.ts';
|
|
16
|
+
export { SessionTracksManagerSessionMixin } from './SessionTracks.ts';
|
|
17
|
+
export type { EditableTrackConfig, PlainTrackConfig, SessionWithSessionTracks, SessionWithSessionTracksType, } from './SessionTracks.ts';
|
|
18
|
+
export { bakePromotedDefaultsIntoSnapshot, bakeSessionCascades, getShareableSessionSnapshot, } from './shareableSnapshot.ts';
|
|
19
|
+
export { TrackMenuItemsSessionMixin, aboutTrackMenuItem, copyTrackSnapshot, pluginExtraTrackItems, trackActionItems, trackActionMenuItems, trackListMenuItems, } from './TrackMenu.ts';
|
|
20
|
+
export { TrackMenuSessionMixin } from './TrackMenuSessionMixin.ts';
|
|
21
|
+
export { finalizeSession } from './finalizeSession.ts';
|
|
22
|
+
export type { AssertSessionModel } from './assertSessionModel.ts';
|
package/esm/Session/index.js
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
export
|
|
2
|
-
export
|
|
3
|
-
export
|
|
4
|
-
export
|
|
5
|
-
export
|
|
6
|
-
export
|
|
7
|
-
export
|
|
8
|
-
export
|
|
9
|
-
export
|
|
10
|
-
export
|
|
1
|
+
export { ReferenceManagementSessionMixin, isSessionWithReferenceManagement, } from './ReferenceManagement.js';
|
|
2
|
+
export { ConnectionManagementSessionMixin, isSessionWithConnections, } from './Connections.js';
|
|
3
|
+
export { DrawerWidgetSessionMixin, isSessionWithDrawerWidgets, } from './DrawerWidgets.js';
|
|
4
|
+
export { ThemeManagerSessionMixin, isSessionWithThemes } from './Themes.js';
|
|
5
|
+
export { TracksManagerSessionMixin, isSessionWithTracks } from './Tracks.js';
|
|
6
|
+
export { MultipleViewsSessionMixin, isSessionWithMultipleViews, } from './MultipleViews.js';
|
|
7
|
+
export { PreferencesSessionMixin } from './Preferences.js';
|
|
8
|
+
export { BaseSessionModel, isBaseSession, isSession } from './BaseSession.js';
|
|
9
|
+
export { SessionTracksManagerSessionMixin } from './SessionTracks.js';
|
|
10
|
+
export { bakePromotedDefaultsIntoSnapshot, bakeSessionCascades, getShareableSessionSnapshot, } from './shareableSnapshot.js';
|
|
11
|
+
export { TrackMenuItemsSessionMixin, aboutTrackMenuItem, copyTrackSnapshot, pluginExtraTrackItems, trackActionItems, trackActionMenuItems, trackListMenuItems, } from './TrackMenu.js';
|
|
12
|
+
export { TrackMenuSessionMixin } from './TrackMenuSessionMixin.js';
|
|
13
|
+
export { finalizeSession } from './finalizeSession.js';
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import type { AbstractSessionModel } from '@jbrowse/core/util';
|
|
2
|
+
/**
|
|
3
|
+
* The session snapshot to hand to anyone else — a share link, an exported
|
|
4
|
+
* `session.json`, a desktop→web export. Snapshotting and baking are one call so
|
|
5
|
+
* the pair can't be split: a bare `getSnapshot(session)` is never a correct
|
|
6
|
+
* outgoing snapshot (see `bakeSessionCascades`), and three of the four
|
|
7
|
+
* boundaries were spelling the two steps out identically.
|
|
8
|
+
*
|
|
9
|
+
* The fourth (desktop `ExportToWebDialog`) bakes a *transformed* snapshot from
|
|
10
|
+
* `planWebExport`, so it calls `bakeSessionCascades` directly.
|
|
11
|
+
*/
|
|
12
|
+
export declare function getShareableSessionSnapshot(session: AbstractSessionModel): Record<string, unknown>;
|
|
13
|
+
/**
|
|
14
|
+
* Everything an outgoing snapshot has to resolve because the live session
|
|
15
|
+
* resolves it at read time against state that is staying behind.
|
|
16
|
+
*
|
|
17
|
+
* Two such cascades, and they have nothing to do with each other — promoted
|
|
18
|
+
* display-type defaults are per-track rendering, workspaces intent is the
|
|
19
|
+
* session's layout mode. What they share is only this: both live partly in the
|
|
20
|
+
* sender's own browser, so a raw `getSnapshot` records neither, and the
|
|
21
|
+
* recipient silently resolves their own.
|
|
22
|
+
*
|
|
23
|
+
* They get one entry point rather than a call each because the failure of a
|
|
24
|
+
* boundary that performs half of them is invisible at that boundary — the
|
|
25
|
+
* export succeeds, and what is missing only shows up on someone else's screen.
|
|
26
|
+
* Adding a third cascade should mean editing this function, not auditing four
|
|
27
|
+
* call sites.
|
|
28
|
+
*/
|
|
29
|
+
export declare function bakeSessionCascades(session: AbstractSessionModel, snapshot: Record<string, unknown>): Record<string, unknown>;
|
|
30
|
+
/**
|
|
31
|
+
* `getComputedStyle` for the promotable-default cascade.
|
|
32
|
+
*
|
|
33
|
+
* A track that "follows" a session-wide promoted display-type default holds no
|
|
34
|
+
* value of its own — its rendered value is resolved at read time from the
|
|
35
|
+
* promoted display-type defaults in `preferencesOverrides`, which are personal,
|
|
36
|
+
* localStorage-backed, and deliberately never serialized into a shared session.
|
|
37
|
+
* So a raw `getSnapshot(session)` records a track as at-default even when the
|
|
38
|
+
* sender is looking at a promoted value, and the recipient (who lacks the sender's
|
|
39
|
+
* preferences) sees something different. This flattens the live cascade into a
|
|
40
|
+
* self-contained snapshot:
|
|
41
|
+
*
|
|
42
|
+
* Every slot an open display *inherits* from a promoted default (i.e.
|
|
43
|
+
* `getDisplayTypeDefaultChanges` — non-customized, differs from base) is baked
|
|
44
|
+
* into that track's config layer: its own config for a user-added or connection
|
|
45
|
+
* track, else a `trackConfigDeltas` entry against the admin base (see
|
|
46
|
+
* `ownTrackConfig`). So the concrete value travels with the document, and
|
|
47
|
+
* because it lands in the track's config the recipient reads it as *customized*
|
|
48
|
+
* — a customized value is the top of the cascade, so their own promoted defaults
|
|
49
|
+
* never get consulted for it.
|
|
50
|
+
*
|
|
51
|
+
* **What this deliberately does not cover**, and the reason there is no flag
|
|
52
|
+
* here: a slot the sender was viewing at its *base* value. Nothing is baked for
|
|
53
|
+
* it (the value equals base, and `stripDefault` drops it from the snapshot
|
|
54
|
+
* regardless), so a recipient who has promoted something else resolves it from
|
|
55
|
+
* their own cascade and sees their value. There is no value that can express "I
|
|
56
|
+
* deliberately saw the default" — at-base and unset are byte-identical once
|
|
57
|
+
* stripped. That case used to be covered by stamping a per-display
|
|
58
|
+
* `ignorePromotedDefaults` on every open display, which cost a second
|
|
59
|
+
* shape-aware walk that had to stay in step with `openPromotableDisplays` by
|
|
60
|
+
* hand, and permanently detached received tracks from the recipient's own pins
|
|
61
|
+
* until they clicked "use this default" on each one. A promoted default is
|
|
62
|
+
* personal and local — the same as the theme a session is viewed in, which this
|
|
63
|
+
* function has never baked either.
|
|
64
|
+
*
|
|
65
|
+
* The live session is untouched; a modified deep copy of `snapshot` is returned.
|
|
66
|
+
* Tracks the sender never opened carry no display state to resolve, so they're
|
|
67
|
+
* left to pick up the recipient's defaults when opened — matching "export the
|
|
68
|
+
* actual state of the (open) tracks".
|
|
69
|
+
*
|
|
70
|
+
* Reach is `openPromotableDisplays` — literally the same walk the cascade's own
|
|
71
|
+
* "apply to open tracks" uses, so the two can't drift. It recurses into a
|
|
72
|
+
* composite view's `views` array (breakpoint-split, the linear-comparative /
|
|
73
|
+
* synteny family), which holds child views rather than tracks of its own —
|
|
74
|
+
* `LGVSyntenyDisplay` is only reachable that way, and before the recursion a
|
|
75
|
+
* shared session containing one rendered differently for the recipient.
|
|
76
|
+
*/
|
|
77
|
+
export declare function bakePromotedDefaultsIntoSnapshot(session: AbstractSessionModel, snapshot: Record<string, unknown>): Record<string, unknown>;
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import { getConf, getDisplayTypeDefaultChanges, } from '@jbrowse/core/configuration';
|
|
2
|
+
import { getContainingTrack, mergeTrackConfig, openPromotableDisplays, } from '@jbrowse/core/util';
|
|
3
|
+
import { getSnapshot } from '@jbrowse/mobx-state-tree';
|
|
4
|
+
import { asArray, isRecord } from '../snapshotUtils.js';
|
|
5
|
+
/**
|
|
6
|
+
* The session snapshot to hand to anyone else — a share link, an exported
|
|
7
|
+
* `session.json`, a desktop→web export. Snapshotting and baking are one call so
|
|
8
|
+
* the pair can't be split: a bare `getSnapshot(session)` is never a correct
|
|
9
|
+
* outgoing snapshot (see `bakeSessionCascades`), and three of the four
|
|
10
|
+
* boundaries were spelling the two steps out identically.
|
|
11
|
+
*
|
|
12
|
+
* The fourth (desktop `ExportToWebDialog`) bakes a *transformed* snapshot from
|
|
13
|
+
* `planWebExport`, so it calls `bakeSessionCascades` directly.
|
|
14
|
+
*/
|
|
15
|
+
export function getShareableSessionSnapshot(session) {
|
|
16
|
+
return bakeSessionCascades(session, getSnapshot(session));
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Everything an outgoing snapshot has to resolve because the live session
|
|
20
|
+
* resolves it at read time against state that is staying behind.
|
|
21
|
+
*
|
|
22
|
+
* Two such cascades, and they have nothing to do with each other — promoted
|
|
23
|
+
* display-type defaults are per-track rendering, workspaces intent is the
|
|
24
|
+
* session's layout mode. What they share is only this: both live partly in the
|
|
25
|
+
* sender's own browser, so a raw `getSnapshot` records neither, and the
|
|
26
|
+
* recipient silently resolves their own.
|
|
27
|
+
*
|
|
28
|
+
* They get one entry point rather than a call each because the failure of a
|
|
29
|
+
* boundary that performs half of them is invisible at that boundary — the
|
|
30
|
+
* export succeeds, and what is missing only shows up on someone else's screen.
|
|
31
|
+
* Adding a third cascade should mean editing this function, not auditing four
|
|
32
|
+
* call sites.
|
|
33
|
+
*/
|
|
34
|
+
export function bakeSessionCascades(session, snapshot) {
|
|
35
|
+
const snap = bakePromotedDefaultsIntoSnapshot(session, snapshot);
|
|
36
|
+
bakeWorkspacesIntent(session, snap);
|
|
37
|
+
return snap;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* The workspaces cascade: session property -> user preference -> admin
|
|
41
|
+
* `configuration.preferences.useWorkspaces`, of which only the first is in the
|
|
42
|
+
* snapshot.
|
|
43
|
+
*
|
|
44
|
+
* So a sender whose workspace is on because *their admin turned it on* exports
|
|
45
|
+
* a fully arranged `layout` with no statement that it is a workspace at all,
|
|
46
|
+
* and a recipient resolving their own cascade to false renders the classic
|
|
47
|
+
* stack: the arrangement arrives intact and invisible, with nothing to say it
|
|
48
|
+
* was dropped.
|
|
49
|
+
*
|
|
50
|
+
* Only the on case is baked. At `false` there is no arrangement to carry, so
|
|
51
|
+
* stamping it would be a sender with nothing to say overriding a recipient who
|
|
52
|
+
* prefers workspaces — the same line the promoted-default bake draws at a slot
|
|
53
|
+
* the sender was viewing at its base value.
|
|
54
|
+
*
|
|
55
|
+
* The paths that build a layout through an explicit user intent already set the
|
|
56
|
+
* property themselves (`setUseWorkspacesPreference`, ViewMenu's move-view-out,
|
|
57
|
+
* a spec `layout`), which is exactly what hides this: every arrangement made by
|
|
58
|
+
* a *drag* — split a cell, drag a tab into it, open a new tab — goes through
|
|
59
|
+
* `WorkspaceLayoutMixin` alone, which owns the tree and knows nothing about the
|
|
60
|
+
* preference.
|
|
61
|
+
*
|
|
62
|
+
* `effectiveUseWorkspaces` is read behind an `in` guard because
|
|
63
|
+
* `AbstractSessionModel` cannot name it (it lives on MultipleViewsSessionMixin,
|
|
64
|
+
* one layer up), so renaming that getter silently stops the bake rather than
|
|
65
|
+
* failing to compile — the hazard app-core/src/WorkspaceLayout/CLAUDE.md describes for
|
|
66
|
+
* `setPendingMove`. jbrowse-web's `sessionModel/exportLayout.test.ts` is the
|
|
67
|
+
* canary, since the bake needs a real session to have a cascade at all.
|
|
68
|
+
*/
|
|
69
|
+
function bakeWorkspacesIntent(session, snap) {
|
|
70
|
+
if (snap.useWorkspaces === undefined &&
|
|
71
|
+
'effectiveUseWorkspaces' in session &&
|
|
72
|
+
session.effectiveUseWorkspaces ===
|
|
73
|
+
true) {
|
|
74
|
+
snap.useWorkspaces = true;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* `getComputedStyle` for the promotable-default cascade.
|
|
79
|
+
*
|
|
80
|
+
* A track that "follows" a session-wide promoted display-type default holds no
|
|
81
|
+
* value of its own — its rendered value is resolved at read time from the
|
|
82
|
+
* promoted display-type defaults in `preferencesOverrides`, which are personal,
|
|
83
|
+
* localStorage-backed, and deliberately never serialized into a shared session.
|
|
84
|
+
* So a raw `getSnapshot(session)` records a track as at-default even when the
|
|
85
|
+
* sender is looking at a promoted value, and the recipient (who lacks the sender's
|
|
86
|
+
* preferences) sees something different. This flattens the live cascade into a
|
|
87
|
+
* self-contained snapshot:
|
|
88
|
+
*
|
|
89
|
+
* Every slot an open display *inherits* from a promoted default (i.e.
|
|
90
|
+
* `getDisplayTypeDefaultChanges` — non-customized, differs from base) is baked
|
|
91
|
+
* into that track's config layer: its own config for a user-added or connection
|
|
92
|
+
* track, else a `trackConfigDeltas` entry against the admin base (see
|
|
93
|
+
* `ownTrackConfig`). So the concrete value travels with the document, and
|
|
94
|
+
* because it lands in the track's config the recipient reads it as *customized*
|
|
95
|
+
* — a customized value is the top of the cascade, so their own promoted defaults
|
|
96
|
+
* never get consulted for it.
|
|
97
|
+
*
|
|
98
|
+
* **What this deliberately does not cover**, and the reason there is no flag
|
|
99
|
+
* here: a slot the sender was viewing at its *base* value. Nothing is baked for
|
|
100
|
+
* it (the value equals base, and `stripDefault` drops it from the snapshot
|
|
101
|
+
* regardless), so a recipient who has promoted something else resolves it from
|
|
102
|
+
* their own cascade and sees their value. There is no value that can express "I
|
|
103
|
+
* deliberately saw the default" — at-base and unset are byte-identical once
|
|
104
|
+
* stripped. That case used to be covered by stamping a per-display
|
|
105
|
+
* `ignorePromotedDefaults` on every open display, which cost a second
|
|
106
|
+
* shape-aware walk that had to stay in step with `openPromotableDisplays` by
|
|
107
|
+
* hand, and permanently detached received tracks from the recipient's own pins
|
|
108
|
+
* until they clicked "use this default" on each one. A promoted default is
|
|
109
|
+
* personal and local — the same as the theme a session is viewed in, which this
|
|
110
|
+
* function has never baked either.
|
|
111
|
+
*
|
|
112
|
+
* The live session is untouched; a modified deep copy of `snapshot` is returned.
|
|
113
|
+
* Tracks the sender never opened carry no display state to resolve, so they're
|
|
114
|
+
* left to pick up the recipient's defaults when opened — matching "export the
|
|
115
|
+
* actual state of the (open) tracks".
|
|
116
|
+
*
|
|
117
|
+
* Reach is `openPromotableDisplays` — literally the same walk the cascade's own
|
|
118
|
+
* "apply to open tracks" uses, so the two can't drift. It recurses into a
|
|
119
|
+
* composite view's `views` array (breakpoint-split, the linear-comparative /
|
|
120
|
+
* synteny family), which holds child views rather than tracks of its own —
|
|
121
|
+
* `LGVSyntenyDisplay` is only reachable that way, and before the recursion a
|
|
122
|
+
* shared session containing one rendered differently for the recipient.
|
|
123
|
+
*/
|
|
124
|
+
export function bakePromotedDefaultsIntoSnapshot(session, snapshot) {
|
|
125
|
+
const snap = structuredClone(snapshot);
|
|
126
|
+
// `openPromotableDisplays` is the one walk that decides reach — shared with
|
|
127
|
+
// the cascade's own "apply to open tracks", so the set this bakes and the set
|
|
128
|
+
// that acts on a promoted default can't drift
|
|
129
|
+
for (const display of openPromotableDisplays(session)) {
|
|
130
|
+
const changes = getDisplayTypeDefaultChanges(display);
|
|
131
|
+
if (changes.length > 0) {
|
|
132
|
+
bakeValues(snap, {
|
|
133
|
+
trackId: getConf(getContainingTrack(display), 'trackId'),
|
|
134
|
+
displayId: getConf(display, 'displayId'),
|
|
135
|
+
displayType: display.type,
|
|
136
|
+
values: Object.fromEntries(changes.map(c => [c.path[0], c.to])),
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return snap;
|
|
141
|
+
}
|
|
142
|
+
// The track's own full config in the snapshot, when it has one: a user-added
|
|
143
|
+
// track's `sessionTracks` entry, or an opened connection track's persisted
|
|
144
|
+
// `connectionTrackConfigs` config. Everything else is an admin-base track,
|
|
145
|
+
// which carries only a delta.
|
|
146
|
+
//
|
|
147
|
+
// The connection case is not optional. `trackConfigDeltas` is merged over
|
|
148
|
+
// `jbrowse.tracks` alone, so a delta written for a connection track resolves
|
|
149
|
+
// nowhere — the recipient would render the base value, which is the exact
|
|
150
|
+
// failure the bake exists to prevent. `updateTrackConfiguration` splits on the
|
|
151
|
+
// same line.
|
|
152
|
+
function ownTrackConfig(snap, trackId) {
|
|
153
|
+
const sessionTrack = asArray(snap.sessionTracks).find(t => isRecord(t) && t.trackId === trackId);
|
|
154
|
+
const connectionEntry = isRecord(snap.connectionTrackConfigs)
|
|
155
|
+
? snap.connectionTrackConfigs[trackId]
|
|
156
|
+
: undefined;
|
|
157
|
+
return isRecord(sessionTrack)
|
|
158
|
+
? sessionTrack
|
|
159
|
+
: isRecord(connectionEntry) && isRecord(connectionEntry.config)
|
|
160
|
+
? connectionEntry.config
|
|
161
|
+
: undefined;
|
|
162
|
+
}
|
|
163
|
+
// Bake one display's inherited values into the config layer: into the matching
|
|
164
|
+
// display of the track's own config when it has one, else merged as a
|
|
165
|
+
// `trackConfigDeltas` entry against the admin base.
|
|
166
|
+
function bakeValues(snap, bake) {
|
|
167
|
+
const partialDisplay = {
|
|
168
|
+
type: bake.displayType,
|
|
169
|
+
displayId: bake.displayId,
|
|
170
|
+
...bake.values,
|
|
171
|
+
};
|
|
172
|
+
const ownConfig = ownTrackConfig(snap, bake.trackId);
|
|
173
|
+
if (ownConfig) {
|
|
174
|
+
const displays = asArray(ownConfig.displays);
|
|
175
|
+
const target = displays.find(d => isRecord(d) && d.displayId === bake.displayId);
|
|
176
|
+
if (isRecord(target)) {
|
|
177
|
+
Object.assign(target, bake.values);
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
ownConfig.displays = [...displays, partialDisplay];
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
const deltas = isRecord(snap.trackConfigDeltas)
|
|
185
|
+
? { ...snap.trackConfigDeltas }
|
|
186
|
+
: {};
|
|
187
|
+
const existing = isRecord(deltas[bake.trackId])
|
|
188
|
+
? deltas[bake.trackId]
|
|
189
|
+
: { trackId: bake.trackId };
|
|
190
|
+
deltas[bake.trackId] = mergeTrackConfig(existing, {
|
|
191
|
+
trackId: bake.trackId,
|
|
192
|
+
displays: [partialDisplay],
|
|
193
|
+
});
|
|
194
|
+
snap.trackConfigDeltas = deltas;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { AnyConfigurationModel } from '@jbrowse/core/configuration';
|
|
2
|
+
/**
|
|
3
|
+
* Dev-only check that a track config being written into a session or config list
|
|
4
|
+
* is one something can still draw tomorrow. No-op in production.
|
|
5
|
+
*
|
|
6
|
+
* A config naming nothing but a temporary assembly is dead the moment its view
|
|
7
|
+
* closes, and no list outside that view has anyone to sweep it — which is the
|
|
8
|
+
* whole of ADR-084. A track only one view can draw carries its config on the
|
|
9
|
+
* track instead (`showTrackGeneric`'s `inlineConf`), so reaching a session list
|
|
10
|
+
* with one is the mistake, not the cleanup afterwards.
|
|
11
|
+
*
|
|
12
|
+
* **This reports a write, not a click.** The two flows a user can drive into it
|
|
13
|
+
* are answered before they get here — the track menu greys its copy actions, and
|
|
14
|
+
* `addTrackFromWidget` opens the track inline instead of adding it — so what
|
|
15
|
+
* survives to report is a caller that had `inlineConf` available and did not
|
|
16
|
+
* take it. That is the reading the message is written for.
|
|
17
|
+
*
|
|
18
|
+
* `console.error` and never `throw`, matching `assertDisplayContract`: these
|
|
19
|
+
* writes happen inside launchers and menu handlers where an exception is caught
|
|
20
|
+
* and reported as a failed track, which would hide the violation. The jest gate
|
|
21
|
+
* (`config/jest/contractGate.js`) is what listens.
|
|
22
|
+
*/
|
|
23
|
+
export declare function assertTrackConfOutlivesItsAssemblies(session: unknown, trackConf: AnyConfigurationModel | Record<string, unknown>, destination: string): void;
|