@vuu-ui/vuu-shell 3.3.10 → 4.0.0-alpha.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/package.json +18 -16
- package/src/app-header/AppHeader.js +36 -26
- package/src/application-provider/ApplicationContext.js +2 -5
- package/src/application-provider/ApplicationProvider.js +8 -59
- package/src/feature/Feature.js +3 -34
- package/src/feature/index.js +1 -0
- package/src/feature-list/FeatureList.css.js +27 -5
- package/src/feature-list/FeatureList.js +117 -96
- package/src/index.js +3 -3
- package/src/left-nav/LeftNav.css.js +2 -4
- package/src/left-nav/LeftNav.js +139 -100
- package/src/module-registry/getRegisteredModules.js +12 -0
- package/src/persistence-manager/LocalWorkspacePersistenceService.js +129 -0
- package/src/persistence-manager/PersistenceProvider.js +10 -3
- package/src/persistence-manager/RemoteWorkspacePersistenceService.js +112 -0
- package/src/persistence-manager/WorkspacePersistenceService.js +9 -0
- package/src/persistence-manager/index.js +3 -0
- package/src/shell-layout-templates/context-panel/ApplicationSettingsContextPanel.js +24 -0
- package/src/shell-layout-templates/context-panel/ContextPanel.css.js +8 -8
- package/src/shell-layout-templates/context-panel/ContextPanel.js +17 -35
- package/src/shell-layout-templates/context-panel/index.js +1 -0
- package/src/shell-layout-templates/full-height-left-panel/useFullHeightLeftPanel.js +54 -40
- package/src/shell-layout-templates/inlay-left-panel/useInlayLeftPanel.js +54 -64
- package/src/shell-layout-templates/left-main-tabs/useLeftMainTabs.js +49 -28
- package/src/shell-layout-templates/side-panel/SidePanel.css.js +3 -1
- package/src/shell-layout-templates/simple-content-pane/useSimpleContentPane.js +43 -35
- package/src/shell.css.js +85 -2
- package/src/shell.js +148 -70
- package/src/workspace-management/LayoutList.js +59 -99
- package/src/workspace-management/SaveLayoutPanel.js +3 -3
- package/src/workspace-management/WorkspaceController.js +73 -0
- package/src/workspace-management/WorkspaceHost.js +194 -0
- package/src/workspace-management/WorkspacePersistentState.js +67 -0
- package/src/workspace-management/WorkspaceProvider.js +699 -178
- package/src/workspace-management/WorkspaceRepository.js +127 -0
- package/src/workspace-management/WorkspaceStartPanel.css.js +44 -0
- package/src/workspace-management/WorkspaceStartPanel.js +34 -0
- package/src/workspace-management/index.js +8 -0
- package/src/workspace-management/shell-workspace-components.js +59 -0
- package/src/workspace-management/useWorkspaceContextMenuItems.js +12 -6
- package/src/workspace-management/workspace-component-registry.js +30 -0
- package/src/workspace-management/workspace-schemas.js +257 -0
- package/types/app-header/AppHeader.d.ts +2 -2
- package/types/application-provider/ApplicationContext.d.ts +1 -6
- package/types/application-provider/ApplicationProvider.d.ts +5 -14
- package/types/feature/Feature.d.ts +2 -10
- package/types/feature/Loader.d.ts +1 -1
- package/types/feature/index.d.ts +2 -1
- package/types/feature-list/FeatureList.d.ts +4 -4
- package/types/index.d.ts +3 -3
- package/types/left-nav/LeftNav.d.ts +2 -1
- package/types/login/LoginPanel.d.ts +1 -1
- package/types/login/VuuLogo.d.ts +1 -1
- package/types/persistence-manager/PersistenceProvider.d.ts +7 -3
- package/types/persistence-manager/index.d.ts +3 -0
- package/types/shell-layout-templates/context-panel/ContextPanel.d.ts +9 -11
- package/types/shell-layout-templates/context-panel/index.d.ts +1 -0
- package/types/shell-layout-templates/full-height-left-panel/useFullHeightLeftPanel.d.ts +1 -1
- package/types/shell-layout-templates/inlay-left-panel/useInlayLeftPanel.d.ts +1 -1
- package/types/shell-layout-templates/left-main-tabs/useLeftMainTabs.d.ts +1 -1
- package/types/shell-layout-templates/side-panel/SidePanel.d.ts +1 -1
- package/types/shell-layout-templates/simple-content-pane/useSimpleContentPane.d.ts +1 -1
- package/types/shell-layout-templates/useShellLayout.d.ts +4 -2
- package/types/shell.d.ts +19 -15
- package/types/theme-switch/ThemeSwitch.d.ts +1 -1
- package/types/workspace-management/LayoutList.d.ts +2 -2
- package/types/workspace-management/LayoutTile.d.ts +1 -1
- package/types/workspace-management/SaveLayoutPanel.d.ts +2 -2
- package/types/workspace-management/WorkspaceProvider.d.ts +61 -50
- package/types/workspace-management/defaultWorkspaceJSON.d.ts +7 -6
- package/types/workspace-management/index.d.ts +8 -0
- package/types/workspace-management/useWorkspaceContextMenuItems.d.ts +1 -1
- package/src/feature/FeatureErrorBoundary.js +0 -33
- package/src/user-settings/SettingsForm.css.js +0 -10
- package/src/user-settings/SettingsForm.js +0 -141
- package/src/user-settings/UserSettingsPanel.css.js +0 -9
- package/src/user-settings/UserSettingsPanel.js +0 -29
- package/src/user-settings/index.js +0 -2
|
@@ -1,209 +1,730 @@
|
|
|
1
1
|
import { jsx } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
2
|
+
import { GRID_LAYOUT_DOCUMENT_KIND, GRID_LAYOUT_DOCUMENT_VERSION, createSequentialGridLayoutIdAllocator, remapGridLayoutDocumentIds } from "@heswell/grid-layout";
|
|
3
3
|
import { useNotifications } from "@vuu-ui/vuu-notifications";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
4
|
+
import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
|
|
5
|
+
import { useOptionalWorkspacePersistenceService } from "../persistence-manager/index.js";
|
|
6
|
+
import { WorkspaceController } from "./WorkspaceController.js";
|
|
7
|
+
import { APPLICATION_SESSION_VERSION, NAMED_WORKSPACE_DEFINITION_VERSION, WORKSPACE_SNAPSHOT_VERSION, cloneWorkspaceValue } from "./workspace-schemas.js";
|
|
8
|
+
const emptyLayout = {
|
|
9
|
+
components: [],
|
|
10
|
+
kind: GRID_LAYOUT_DOCUMENT_KIND,
|
|
11
|
+
layout: {
|
|
12
|
+
columns: [
|
|
13
|
+
"1fr"
|
|
14
|
+
],
|
|
15
|
+
id: "empty-workspace",
|
|
16
|
+
items: [
|
|
17
|
+
{
|
|
18
|
+
column: {
|
|
19
|
+
span: 1,
|
|
20
|
+
start: 1
|
|
21
|
+
},
|
|
22
|
+
id: "empty-workspace-placeholder",
|
|
23
|
+
row: {
|
|
24
|
+
span: 1,
|
|
25
|
+
start: 1
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
],
|
|
29
|
+
placeholderIds: [
|
|
30
|
+
"empty-workspace-placeholder"
|
|
31
|
+
],
|
|
32
|
+
rows: [
|
|
33
|
+
"1fr"
|
|
34
|
+
],
|
|
35
|
+
stacks: []
|
|
36
|
+
},
|
|
37
|
+
version: GRID_LAYOUT_DOCUMENT_VERSION
|
|
38
|
+
};
|
|
39
|
+
const emptyWorkspaceSnapshot = {
|
|
40
|
+
componentState: {},
|
|
41
|
+
layout: emptyLayout,
|
|
42
|
+
version: WORKSPACE_SNAPSHOT_VERSION
|
|
43
|
+
};
|
|
44
|
+
const missing = async ()=>{
|
|
45
|
+
throw new Error("WorkspaceProvider is not mounted");
|
|
46
|
+
};
|
|
47
|
+
const WorkspaceContext = /*#__PURE__*/ createContext({
|
|
48
|
+
activeWorkspaceInstanceId: null,
|
|
49
|
+
closeWorkspace: missing,
|
|
50
|
+
createWorkspaceFromSnapshot: async ()=>{
|
|
51
|
+
throw new Error("WorkspaceProvider is not mounted");
|
|
52
|
+
},
|
|
53
|
+
controllers: [],
|
|
54
|
+
deleteNamedWorkspace: missing,
|
|
55
|
+
getApplicationSetting: ()=>void 0,
|
|
56
|
+
getApplicationSettings: ()=>void 0,
|
|
57
|
+
namedWorkspaces: [],
|
|
58
|
+
openNamedWorkspace: missing,
|
|
59
|
+
openSystemWorkspace: missing,
|
|
60
|
+
renameWorkspace: missing,
|
|
61
|
+
saveActiveWorkspaceAs: missing,
|
|
62
|
+
saveApplicationSettings: missing,
|
|
63
|
+
selectWorkspace: missing,
|
|
64
|
+
setApplicationSetting: missing,
|
|
65
|
+
settings: {},
|
|
66
|
+
scopeIdentity: "missing",
|
|
67
|
+
status: "loading",
|
|
68
|
+
systemWorkspaces: [],
|
|
69
|
+
resetApplication: missing
|
|
70
|
+
});
|
|
71
|
+
let nextWorkspaceInstance = 1;
|
|
72
|
+
const createInstanceId = ()=>`workspace-${Date.now().toString(36)}-${nextWorkspaceInstance++}`;
|
|
73
|
+
const errorFrom = (cause, message)=>cause instanceof Error ? cause : new Error(message);
|
|
74
|
+
class StaleWorkspaceScopeError extends Error {
|
|
75
|
+
constructor(){
|
|
76
|
+
super("Workspace operation belongs to an inactive persistence scope");
|
|
77
|
+
this.name = "StaleWorkspaceScopeError";
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
const remapSnapshot = (source, instanceId)=>{
|
|
81
|
+
const { document, mappings } = remapGridLayoutDocumentIds(source.layout, createSequentialGridLayoutIdAllocator(instanceId));
|
|
82
|
+
const componentIds = new Map(mappings.filter(({ kind })=>"component" === kind).map(({ newId, oldId })=>[
|
|
83
|
+
oldId,
|
|
84
|
+
newId
|
|
85
|
+
]));
|
|
11
86
|
return {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
87
|
+
version: WORKSPACE_SNAPSHOT_VERSION,
|
|
88
|
+
layout: document,
|
|
89
|
+
componentState: Object.fromEntries(Object.entries(source.componentState).map(([id, state])=>[
|
|
90
|
+
componentIds.get(id) ?? id,
|
|
91
|
+
cloneWorkspaceValue(state)
|
|
92
|
+
]))
|
|
17
93
|
};
|
|
18
94
|
};
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const WorkspaceProvider = ({ TabstripProps, children, layoutJSON, activeLayoutIndex, layoutPlaceholderJSON, showTabs, workspaceJSON: customWorkspaceJSON })=>{
|
|
23
|
-
const [layoutMetadata, setLayoutMetadata] = useState([]);
|
|
24
|
-
const [, forceRefresh] = useState({});
|
|
95
|
+
const WorkspaceProvider = ({ activeLayoutIndex, children, componentRenderers, defaultWorkspace, layoutJSON, layoutPlaceholderJSON, persistenceService: serviceProp, settingsCodecs, showTabs, systemWorkspaces = [], TabstripProps, userId, workspaceJSON })=>{
|
|
96
|
+
const inheritedService = useOptionalWorkspacePersistenceService();
|
|
97
|
+
const service = serviceProp ?? inheritedService;
|
|
25
98
|
const { showNotification } = useNotifications();
|
|
26
|
-
const
|
|
27
|
-
const
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
99
|
+
const [controllers, setControllers] = useState([]);
|
|
100
|
+
const controllersRef = useRef([]);
|
|
101
|
+
const [session, setSession] = useState();
|
|
102
|
+
const sessionRef = useRef(void 0);
|
|
103
|
+
const [namedWorkspaces, setNamedWorkspaces] = useState([]);
|
|
104
|
+
const [loadedScope, setLoadedScope] = useState();
|
|
105
|
+
const [loadError, setLoadError] = useState();
|
|
106
|
+
const generation = useRef(0);
|
|
107
|
+
const operationQueue = useRef(Promise.resolve());
|
|
108
|
+
const resetGeneration = useRef(0);
|
|
109
|
+
const resetPending = useRef(false);
|
|
110
|
+
const scopeKey = service ? `${service.scope.applicationNamespace}/${service.scope.applicationId}/${service.scope.userId}/authenticated:${userId ?? service.scope.userId}` : "missing";
|
|
111
|
+
const scopeIsValid = void 0 !== service && (!userId || service.scope.userId === userId);
|
|
112
|
+
const activeScope = useRef({
|
|
113
|
+
generation: 0,
|
|
114
|
+
scopeKey,
|
|
115
|
+
service
|
|
116
|
+
});
|
|
117
|
+
if (activeScope.current.scopeKey !== scopeKey || activeScope.current.service !== service) activeScope.current = {
|
|
118
|
+
generation: ++generation.current,
|
|
119
|
+
scopeKey,
|
|
120
|
+
service
|
|
121
|
+
};
|
|
122
|
+
const status = loadedScope !== scopeKey ? "loading" : loadError ? "error" : 0 === controllers.length ? "empty" : "ready";
|
|
123
|
+
const notifyError = useCallback((header, cause)=>{
|
|
124
|
+
const error = errorFrom(cause, header);
|
|
125
|
+
showNotification({
|
|
126
|
+
content: error.message,
|
|
127
|
+
header,
|
|
128
|
+
status: "error",
|
|
129
|
+
type: "toast"
|
|
130
|
+
});
|
|
131
|
+
return error;
|
|
132
|
+
}, [
|
|
133
|
+
showNotification
|
|
134
|
+
]);
|
|
135
|
+
const captureScope = useCallback((expectedService = service, expectedScopeKey = scopeKey)=>{
|
|
136
|
+
const active = activeScope.current;
|
|
137
|
+
if (!expectedService || active.service !== expectedService || active.scopeKey !== expectedScopeKey || active.generation !== generation.current) throw new StaleWorkspaceScopeError();
|
|
138
|
+
return {
|
|
139
|
+
generation: active.generation,
|
|
140
|
+
scopeKey: active.scopeKey,
|
|
141
|
+
service: expectedService
|
|
142
|
+
};
|
|
48
143
|
}, [
|
|
49
|
-
|
|
144
|
+
scopeKey,
|
|
145
|
+
service
|
|
50
146
|
]);
|
|
147
|
+
const assertScope = useCallback((guard)=>{
|
|
148
|
+
const active = activeScope.current;
|
|
149
|
+
if (generation.current !== guard.generation || active.generation !== guard.generation || active.scopeKey !== guard.scopeKey || active.service !== guard.service) throw new StaleWorkspaceScopeError();
|
|
150
|
+
}, []);
|
|
151
|
+
const replaceControllers = useCallback((next)=>{
|
|
152
|
+
controllersRef.current = next;
|
|
153
|
+
setControllers(next);
|
|
154
|
+
}, []);
|
|
51
155
|
useEffect(()=>{
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
156
|
+
for (const controller of controllersRef.current)controller.dispose();
|
|
157
|
+
controllersRef.current = [];
|
|
158
|
+
setControllers([]);
|
|
159
|
+
setSession(void 0);
|
|
160
|
+
sessionRef.current = void 0;
|
|
161
|
+
setNamedWorkspaces([]);
|
|
162
|
+
setLoadError(void 0);
|
|
163
|
+
setLoadedScope(void 0);
|
|
164
|
+
operationQueue.current = Promise.resolve();
|
|
165
|
+
resetGeneration.current = 0;
|
|
166
|
+
resetPending.current = false;
|
|
167
|
+
if (!service) {
|
|
168
|
+
const error = notifyError("Workspace Persistence Is Not Configured", new Error("Shell requires an injected WorkspacePersistenceService"));
|
|
169
|
+
setLoadError(error);
|
|
170
|
+
setLoadedScope(scopeKey);
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
const legacyProps = [
|
|
174
|
+
void 0 === activeLayoutIndex ? void 0 : "activeLayoutIndex",
|
|
175
|
+
void 0 === layoutJSON ? void 0 : "layoutJSON",
|
|
176
|
+
void 0 === layoutPlaceholderJSON ? void 0 : "layoutPlaceholderJSON",
|
|
177
|
+
void 0 === showTabs ? void 0 : "showTabs",
|
|
178
|
+
void 0 === TabstripProps ? void 0 : "TabstripProps",
|
|
179
|
+
void 0 === workspaceJSON ? void 0 : "workspaceJSON"
|
|
180
|
+
].filter((name)=>void 0 !== name);
|
|
181
|
+
if (legacyProps.length > 0) {
|
|
182
|
+
const error = notifyError("Legacy Workspace Configuration Is Not Supported", new Error(`WorkspaceProvider no longer accepts ${legacyProps.join(", ")}; inject a WorkspacePersistenceService and provide defaultWorkspace as a versioned snapshot`));
|
|
183
|
+
setLoadError(error);
|
|
184
|
+
setLoadedScope(scopeKey);
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
if (!scopeIsValid) {
|
|
188
|
+
const error = notifyError("Workspace Scope Does Not Match", new Error(`Workspace persistence scope "${service.scope.userId}" does not match authenticated user "${userId}"`));
|
|
189
|
+
setLoadError(error);
|
|
190
|
+
setLoadedScope(scopeKey);
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
const guard = captureScope();
|
|
194
|
+
const load = async ()=>{
|
|
195
|
+
const restored = [];
|
|
196
|
+
try {
|
|
197
|
+
assertScope(guard);
|
|
198
|
+
const [loadedSession, metadata] = await Promise.all([
|
|
199
|
+
guard.service.loadApplicationSession(),
|
|
200
|
+
guard.service.listNamedWorkspaceMetadata()
|
|
201
|
+
]);
|
|
202
|
+
assertScope(guard);
|
|
203
|
+
if (loadedSession) {
|
|
204
|
+
const descriptors = new Map(loadedSession.openWorkspaces.map((entry)=>[
|
|
205
|
+
entry.instanceId,
|
|
206
|
+
entry
|
|
207
|
+
]));
|
|
208
|
+
for (const instanceId of loadedSession.workspaceOrder){
|
|
209
|
+
const descriptor = descriptors.get(instanceId);
|
|
210
|
+
if (!descriptor) throw new Error(`Session references missing workspace "${instanceId}"`);
|
|
211
|
+
assertScope(guard);
|
|
212
|
+
const record = await guard.service.loadWorkspaceSnapshot(descriptor.snapshotId);
|
|
213
|
+
assertScope(guard);
|
|
214
|
+
if (!record) throw new Error(`Snapshot for workspace "${instanceId}" was not found`);
|
|
215
|
+
const definitionMetadata = metadata.find(({ id })=>id === descriptor.definitionId);
|
|
216
|
+
restored.push(new WorkspaceController({
|
|
217
|
+
definitionId: descriptor.definitionId,
|
|
218
|
+
instanceId,
|
|
219
|
+
name: descriptor.title ?? definitionMetadata?.name ?? instanceId,
|
|
220
|
+
onError: (error)=>{
|
|
221
|
+
try {
|
|
222
|
+
assertScope(guard);
|
|
223
|
+
notifyError("Failed to Save Workspace", error);
|
|
224
|
+
} catch {}
|
|
225
|
+
},
|
|
226
|
+
renderers: componentRenderers ?? (()=>{
|
|
227
|
+
throw new Error("Workspace component renderers are required");
|
|
228
|
+
})(),
|
|
229
|
+
service: guard.service,
|
|
230
|
+
revision: record.revision,
|
|
231
|
+
settingsCodecs: settingsCodecs ?? (()=>{
|
|
232
|
+
throw new Error("Workspace settings codecs are required");
|
|
233
|
+
})(),
|
|
234
|
+
snapshot: record.snapshot
|
|
235
|
+
}));
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
let resolvedSession = loadedSession ?? {
|
|
239
|
+
activeWorkspaceInstanceId: null,
|
|
240
|
+
openWorkspaces: [],
|
|
241
|
+
settings: {},
|
|
242
|
+
version: APPLICATION_SESSION_VERSION,
|
|
243
|
+
workspaceOrder: []
|
|
244
|
+
};
|
|
245
|
+
if (!loadedSession && defaultWorkspace) {
|
|
246
|
+
if (!componentRenderers || !settingsCodecs) throw new Error("Default workspace requires component renderers and settings codecs");
|
|
247
|
+
const instanceId = createInstanceId();
|
|
248
|
+
const initialSnapshot = remapSnapshot(defaultWorkspace, instanceId);
|
|
249
|
+
const controller = new WorkspaceController({
|
|
250
|
+
instanceId,
|
|
251
|
+
name: "Workspace",
|
|
252
|
+
onError: (error)=>{
|
|
253
|
+
try {
|
|
254
|
+
assertScope(guard);
|
|
255
|
+
notifyError("Failed to Save Workspace", error);
|
|
256
|
+
} catch {}
|
|
257
|
+
},
|
|
258
|
+
renderers: componentRenderers,
|
|
259
|
+
service: guard.service,
|
|
260
|
+
settingsCodecs,
|
|
261
|
+
snapshot: initialSnapshot
|
|
262
|
+
});
|
|
263
|
+
assertScope(guard);
|
|
264
|
+
await controller.repository.save(initialSnapshot);
|
|
265
|
+
assertScope(guard);
|
|
266
|
+
restored.push(controller);
|
|
267
|
+
resolvedSession = {
|
|
268
|
+
activeWorkspaceInstanceId: instanceId,
|
|
269
|
+
openWorkspaces: [
|
|
270
|
+
{
|
|
271
|
+
instanceId,
|
|
272
|
+
snapshotId: instanceId,
|
|
273
|
+
title: "Workspace"
|
|
274
|
+
}
|
|
275
|
+
],
|
|
276
|
+
settings: {},
|
|
277
|
+
version: APPLICATION_SESSION_VERSION,
|
|
278
|
+
workspaceOrder: [
|
|
279
|
+
instanceId
|
|
280
|
+
]
|
|
281
|
+
};
|
|
282
|
+
await guard.service.saveApplicationSession(resolvedSession);
|
|
283
|
+
assertScope(guard);
|
|
284
|
+
}
|
|
285
|
+
assertScope(guard);
|
|
286
|
+
replaceControllers(restored);
|
|
287
|
+
sessionRef.current = resolvedSession;
|
|
288
|
+
setSession(resolvedSession);
|
|
289
|
+
setNamedWorkspaces(metadata);
|
|
290
|
+
setLoadedScope(scopeKey);
|
|
291
|
+
} catch (cause) {
|
|
292
|
+
restored.forEach((controller)=>{
|
|
293
|
+
controller.dispose();
|
|
77
294
|
});
|
|
295
|
+
if (!(cause instanceof StaleWorkspaceScopeError)) try {
|
|
296
|
+
assertScope(guard);
|
|
297
|
+
const error = notifyError("Failed to Load Workspaces", cause);
|
|
298
|
+
setLoadError(error);
|
|
299
|
+
setLoadedScope(scopeKey);
|
|
300
|
+
} catch {}
|
|
78
301
|
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
|
|
302
|
+
};
|
|
303
|
+
load();
|
|
304
|
+
return ()=>{
|
|
305
|
+
if (activeScope.current.generation === guard.generation) activeScope.current = {
|
|
306
|
+
...activeScope.current,
|
|
307
|
+
generation: ++generation.current
|
|
308
|
+
};
|
|
309
|
+
for (const controller of controllersRef.current)controller.dispose();
|
|
310
|
+
controllersRef.current = [];
|
|
311
|
+
};
|
|
88
312
|
}, [
|
|
89
|
-
|
|
313
|
+
componentRenderers,
|
|
90
314
|
activeLayoutIndex,
|
|
91
|
-
|
|
315
|
+
assertScope,
|
|
316
|
+
captureScope,
|
|
317
|
+
defaultWorkspace,
|
|
92
318
|
layoutJSON,
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
319
|
+
layoutPlaceholderJSON,
|
|
320
|
+
notifyError,
|
|
321
|
+
replaceControllers,
|
|
322
|
+
scopeIsValid,
|
|
323
|
+
scopeKey,
|
|
324
|
+
service,
|
|
325
|
+
settingsCodecs,
|
|
326
|
+
showTabs,
|
|
327
|
+
TabstripProps,
|
|
328
|
+
userId,
|
|
329
|
+
workspaceJSON
|
|
330
|
+
]);
|
|
331
|
+
const writeSession = useCallback(async (next, guard)=>{
|
|
332
|
+
assertScope(guard);
|
|
333
|
+
await guard.service.saveApplicationSession(next);
|
|
334
|
+
assertScope(guard);
|
|
335
|
+
sessionRef.current = next;
|
|
336
|
+
setSession(next);
|
|
337
|
+
}, [
|
|
338
|
+
assertScope
|
|
339
|
+
]);
|
|
340
|
+
const enqueueOperation = useCallback((guard, operation)=>{
|
|
341
|
+
assertScope(guard);
|
|
342
|
+
if (resetPending.current) return Promise.reject(new Error("Workspace operation was blocked by application reset"));
|
|
343
|
+
const expectedResetGeneration = resetGeneration.current;
|
|
344
|
+
const result = operationQueue.current.catch(()=>void 0).then(async ()=>{
|
|
345
|
+
assertScope(guard);
|
|
346
|
+
if (resetGeneration.current !== expectedResetGeneration) throw new Error("Workspace operation was invalidated by application reset");
|
|
347
|
+
return operation();
|
|
348
|
+
});
|
|
349
|
+
operationQueue.current = result.then(()=>void 0, ()=>void 0);
|
|
350
|
+
return result;
|
|
351
|
+
}, [
|
|
352
|
+
assertScope
|
|
353
|
+
]);
|
|
354
|
+
const addWorkspace = useCallback(async (sourceSnapshot, name, definitionId, operationGuard)=>{
|
|
355
|
+
if (!service || !componentRenderers || !settingsCodecs) throw new Error("Workspace runtime is not configured");
|
|
356
|
+
const guard = operationGuard ?? captureScope();
|
|
357
|
+
return enqueueOperation(guard, async ()=>{
|
|
358
|
+
assertScope(guard);
|
|
359
|
+
const instanceId = createInstanceId();
|
|
360
|
+
const snapshot = remapSnapshot(sourceSnapshot, instanceId);
|
|
361
|
+
const controller = new WorkspaceController({
|
|
362
|
+
definitionId,
|
|
363
|
+
instanceId,
|
|
364
|
+
name,
|
|
365
|
+
onError: (error)=>void notifyError("Failed to Save Workspace", error),
|
|
366
|
+
renderers: componentRenderers,
|
|
367
|
+
service: guard.service,
|
|
368
|
+
settingsCodecs,
|
|
369
|
+
snapshot
|
|
120
370
|
});
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
371
|
+
await controller.repository.save(snapshot);
|
|
372
|
+
assertScope(guard);
|
|
373
|
+
const current = sessionRef.current ?? {
|
|
374
|
+
activeWorkspaceInstanceId: null,
|
|
375
|
+
openWorkspaces: [],
|
|
376
|
+
settings: {},
|
|
377
|
+
version: APPLICATION_SESSION_VERSION,
|
|
378
|
+
workspaceOrder: []
|
|
379
|
+
};
|
|
380
|
+
try {
|
|
381
|
+
await writeSession({
|
|
382
|
+
...current,
|
|
383
|
+
activeWorkspaceInstanceId: instanceId,
|
|
384
|
+
openWorkspaces: [
|
|
385
|
+
...current.openWorkspaces,
|
|
386
|
+
{
|
|
387
|
+
...void 0 === definitionId ? {} : {
|
|
388
|
+
definitionId
|
|
389
|
+
},
|
|
390
|
+
instanceId,
|
|
391
|
+
snapshotId: instanceId,
|
|
392
|
+
title: name
|
|
393
|
+
}
|
|
394
|
+
],
|
|
395
|
+
workspaceOrder: [
|
|
396
|
+
...current.workspaceOrder,
|
|
397
|
+
instanceId
|
|
398
|
+
]
|
|
399
|
+
}, guard);
|
|
400
|
+
assertScope(guard);
|
|
401
|
+
replaceControllers([
|
|
402
|
+
...controllersRef.current,
|
|
403
|
+
controller
|
|
124
404
|
]);
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
}
|
|
132
|
-
|
|
405
|
+
} catch (cause) {
|
|
406
|
+
await controller.dispose();
|
|
407
|
+
assertScope(guard);
|
|
408
|
+
await guard.service.deleteWorkspaceSnapshot(instanceId);
|
|
409
|
+
assertScope(guard);
|
|
410
|
+
throw errorFrom(cause, "Failed to save application session");
|
|
411
|
+
}
|
|
412
|
+
return instanceId;
|
|
133
413
|
});
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
414
|
+
}, [
|
|
415
|
+
componentRenderers,
|
|
416
|
+
assertScope,
|
|
417
|
+
captureScope,
|
|
418
|
+
enqueueOperation,
|
|
419
|
+
notifyError,
|
|
420
|
+
replaceControllers,
|
|
421
|
+
service,
|
|
422
|
+
settingsCodecs,
|
|
423
|
+
writeSession
|
|
424
|
+
]);
|
|
425
|
+
const addDefinition = useCallback((definition, operationGuard)=>addWorkspace(definition.snapshot, definition.name, definition.id, operationGuard), [
|
|
426
|
+
addWorkspace
|
|
427
|
+
]);
|
|
428
|
+
const openSystemWorkspace = useCallback(async (definition)=>{
|
|
429
|
+
await addDefinition(definition);
|
|
430
|
+
}, [
|
|
431
|
+
addDefinition
|
|
432
|
+
]);
|
|
433
|
+
const createWorkspaceFromSnapshot = useCallback(async (snapshot, title = "Untitled")=>{
|
|
434
|
+
try {
|
|
435
|
+
return await addWorkspace(snapshot, title);
|
|
436
|
+
} catch (cause) {
|
|
437
|
+
if (!(cause instanceof StaleWorkspaceScopeError)) notifyError("Failed to Create Workspace", cause);
|
|
438
|
+
throw cause;
|
|
439
|
+
}
|
|
440
|
+
}, [
|
|
441
|
+
addWorkspace,
|
|
442
|
+
notifyError
|
|
443
|
+
]);
|
|
444
|
+
const openNamedWorkspace = useCallback(async (definitionId)=>{
|
|
445
|
+
if (!service) throw new Error("Workspace persistence service is not configured");
|
|
446
|
+
const guard = captureScope();
|
|
447
|
+
const expectedResetGeneration = resetGeneration.current;
|
|
448
|
+
try {
|
|
449
|
+
assertScope(guard);
|
|
450
|
+
const definition = await guard.service.loadNamedWorkspaceDefinition(definitionId);
|
|
451
|
+
assertScope(guard);
|
|
452
|
+
if (resetGeneration.current !== expectedResetGeneration) throw new Error("Workspace operation was invalidated by application reset");
|
|
453
|
+
if (!definition) throw new Error(`Workspace definition "${definitionId}" was not found`);
|
|
454
|
+
await addDefinition(definition, guard);
|
|
455
|
+
} catch (cause) {
|
|
456
|
+
if (!(cause instanceof StaleWorkspaceScopeError)) notifyError("Failed to Open Workspace", cause);
|
|
457
|
+
}
|
|
458
|
+
}, [
|
|
459
|
+
addDefinition,
|
|
460
|
+
assertScope,
|
|
461
|
+
captureScope,
|
|
462
|
+
notifyError,
|
|
463
|
+
service
|
|
464
|
+
]);
|
|
465
|
+
const selectWorkspace = useCallback(async (instanceId)=>{
|
|
466
|
+
const guard = captureScope();
|
|
467
|
+
await enqueueOperation(guard, async ()=>{
|
|
468
|
+
const current = sessionRef.current;
|
|
469
|
+
if (!current || !current.workspaceOrder.includes(instanceId)) throw new Error(`Workspace "${instanceId}" is not open`);
|
|
470
|
+
await writeSession({
|
|
471
|
+
...current,
|
|
472
|
+
activeWorkspaceInstanceId: instanceId
|
|
473
|
+
}, guard);
|
|
474
|
+
});
|
|
475
|
+
}, [
|
|
476
|
+
captureScope,
|
|
477
|
+
enqueueOperation,
|
|
478
|
+
writeSession
|
|
479
|
+
]);
|
|
480
|
+
const renameWorkspace = useCallback(async (instanceId, title)=>{
|
|
481
|
+
const trimmedTitle = title.trim();
|
|
482
|
+
if (!trimmedTitle) throw new Error("Workspace title must not be empty");
|
|
483
|
+
const guard = captureScope();
|
|
484
|
+
try {
|
|
485
|
+
await enqueueOperation(guard, async ()=>{
|
|
486
|
+
const current = sessionRef.current;
|
|
487
|
+
const controller = controllersRef.current.find((candidate)=>candidate.instanceId === instanceId);
|
|
488
|
+
if (!current || !controller) throw new Error(`Workspace "${instanceId}" is not open`);
|
|
489
|
+
await writeSession({
|
|
490
|
+
...current,
|
|
491
|
+
openWorkspaces: current.openWorkspaces.map((workspace)=>workspace.instanceId === instanceId ? {
|
|
492
|
+
...workspace,
|
|
493
|
+
title: trimmedTitle
|
|
494
|
+
} : workspace)
|
|
495
|
+
}, guard);
|
|
496
|
+
assertScope(guard);
|
|
497
|
+
controller.rename(trimmedTitle);
|
|
498
|
+
replaceControllers([
|
|
499
|
+
...controllersRef.current
|
|
500
|
+
]);
|
|
141
501
|
});
|
|
502
|
+
} catch (cause) {
|
|
503
|
+
if (!(cause instanceof StaleWorkspaceScopeError)) notifyError("Failed to Rename Workspace", cause);
|
|
504
|
+
throw cause;
|
|
142
505
|
}
|
|
143
506
|
}, [
|
|
144
|
-
|
|
145
|
-
|
|
507
|
+
assertScope,
|
|
508
|
+
captureScope,
|
|
509
|
+
enqueueOperation,
|
|
510
|
+
notifyError,
|
|
511
|
+
replaceControllers,
|
|
512
|
+
writeSession
|
|
513
|
+
]);
|
|
514
|
+
const closeWorkspace = useCallback(async (instanceId)=>{
|
|
515
|
+
if (!service) throw new Error("Workspace persistence service is not configured");
|
|
516
|
+
const guard = captureScope();
|
|
517
|
+
await enqueueOperation(guard, async ()=>{
|
|
518
|
+
const current = sessionRef.current;
|
|
519
|
+
const controller = controllersRef.current.find((candidate)=>candidate.instanceId === instanceId);
|
|
520
|
+
if (!current || !controller) return;
|
|
521
|
+
const nextControllers = controllersRef.current.filter((candidate)=>candidate !== controller);
|
|
522
|
+
const closedIndex = current.workspaceOrder.indexOf(instanceId);
|
|
523
|
+
const order = current.workspaceOrder.filter((id)=>id !== instanceId);
|
|
524
|
+
const active = current.activeWorkspaceInstanceId === instanceId ? order[Math.min(closedIndex, order.length - 1)] ?? null : current.activeWorkspaceInstanceId;
|
|
525
|
+
await writeSession({
|
|
526
|
+
...current,
|
|
527
|
+
activeWorkspaceInstanceId: active,
|
|
528
|
+
openWorkspaces: current.openWorkspaces.filter(({ instanceId: id })=>id !== instanceId),
|
|
529
|
+
workspaceOrder: order
|
|
530
|
+
}, guard);
|
|
531
|
+
assertScope(guard);
|
|
532
|
+
await controller.dispose();
|
|
533
|
+
replaceControllers(nextControllers);
|
|
534
|
+
await guard.service.deleteWorkspaceSnapshot(instanceId);
|
|
535
|
+
assertScope(guard);
|
|
536
|
+
});
|
|
537
|
+
}, [
|
|
538
|
+
assertScope,
|
|
539
|
+
captureScope,
|
|
540
|
+
enqueueOperation,
|
|
541
|
+
replaceControllers,
|
|
542
|
+
service,
|
|
543
|
+
writeSession
|
|
146
544
|
]);
|
|
147
|
-
const
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
545
|
+
const deleteNamedWorkspace = useCallback(async (definitionId)=>{
|
|
546
|
+
if (!service) throw new Error("Workspace persistence service is not configured");
|
|
547
|
+
const guard = captureScope();
|
|
548
|
+
assertScope(guard);
|
|
549
|
+
await guard.service.deleteNamedWorkspaceDefinition(definitionId);
|
|
550
|
+
assertScope(guard);
|
|
551
|
+
setNamedWorkspaces((current)=>current.filter(({ id })=>id !== definitionId));
|
|
154
552
|
}, [
|
|
155
|
-
|
|
156
|
-
|
|
553
|
+
assertScope,
|
|
554
|
+
captureScope,
|
|
555
|
+
service
|
|
157
556
|
]);
|
|
158
|
-
const
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
557
|
+
const saveActiveWorkspaceAs = useCallback(async (name, description)=>{
|
|
558
|
+
if (!service) throw new Error("Workspace persistence service is not configured");
|
|
559
|
+
const guard = captureScope();
|
|
560
|
+
assertScope(guard);
|
|
561
|
+
const activeId = sessionRef.current?.activeWorkspaceInstanceId;
|
|
562
|
+
const active = controllersRef.current.find(({ instanceId })=>instanceId === activeId);
|
|
563
|
+
if (!active) throw new Error("There is no active workspace to save");
|
|
564
|
+
const now = new Date().toISOString();
|
|
565
|
+
const id = createInstanceId();
|
|
566
|
+
const definition = {
|
|
567
|
+
createdAt: now,
|
|
568
|
+
...void 0 === description ? {} : {
|
|
569
|
+
description
|
|
570
|
+
},
|
|
571
|
+
id,
|
|
572
|
+
name,
|
|
573
|
+
snapshot: active.snapshot,
|
|
574
|
+
updatedAt: now,
|
|
575
|
+
version: NAMED_WORKSPACE_DEFINITION_VERSION
|
|
576
|
+
};
|
|
577
|
+
await guard.service.saveNamedWorkspaceDefinition(definition);
|
|
578
|
+
assertScope(guard);
|
|
579
|
+
setNamedWorkspaces((current)=>[
|
|
580
|
+
...current,
|
|
581
|
+
{
|
|
582
|
+
createdAt: now,
|
|
583
|
+
...void 0 === description ? {} : {
|
|
584
|
+
description
|
|
585
|
+
},
|
|
586
|
+
id,
|
|
587
|
+
name,
|
|
588
|
+
updatedAt: now,
|
|
589
|
+
version: NAMED_WORKSPACE_DEFINITION_VERSION
|
|
172
590
|
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
591
|
+
]);
|
|
592
|
+
}, [
|
|
593
|
+
assertScope,
|
|
594
|
+
captureScope,
|
|
595
|
+
service
|
|
596
|
+
]);
|
|
597
|
+
const setApplicationSetting = useCallback(async (key, value)=>{
|
|
598
|
+
const guard = captureScope();
|
|
599
|
+
await enqueueOperation(guard, async ()=>{
|
|
600
|
+
const current = sessionRef.current;
|
|
601
|
+
if (!current) throw new Error("Application session has not loaded");
|
|
602
|
+
await writeSession({
|
|
603
|
+
...current,
|
|
604
|
+
settings: {
|
|
605
|
+
...current.settings,
|
|
606
|
+
[key]: value
|
|
607
|
+
}
|
|
608
|
+
}, guard);
|
|
182
609
|
});
|
|
183
610
|
}, [
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
611
|
+
captureScope,
|
|
612
|
+
enqueueOperation,
|
|
613
|
+
writeSession
|
|
187
614
|
]);
|
|
188
|
-
|
|
189
|
-
value
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
615
|
+
const saveApplicationSettings = useCallback(async (value, key)=>{
|
|
616
|
+
if (void 0 !== key) return void await setApplicationSetting(key, value);
|
|
617
|
+
if ("object" != typeof value || null === value || Array.isArray(value)) throw new Error("Application settings must be a JSON object");
|
|
618
|
+
const guard = captureScope();
|
|
619
|
+
await enqueueOperation(guard, async ()=>{
|
|
620
|
+
const current = sessionRef.current;
|
|
621
|
+
if (!current) throw new Error("Application session has not loaded");
|
|
622
|
+
await writeSession({
|
|
623
|
+
...current,
|
|
624
|
+
settings: value
|
|
625
|
+
}, guard);
|
|
626
|
+
});
|
|
627
|
+
}, [
|
|
628
|
+
captureScope,
|
|
629
|
+
enqueueOperation,
|
|
630
|
+
setApplicationSetting,
|
|
631
|
+
writeSession
|
|
632
|
+
]);
|
|
633
|
+
const resetApplication = useCallback(async ()=>{
|
|
634
|
+
const guard = captureScope();
|
|
635
|
+
assertScope(guard);
|
|
636
|
+
if (resetPending.current) throw new Error("Application reset is already in progress");
|
|
637
|
+
resetPending.current = true;
|
|
638
|
+
resetGeneration.current += 1;
|
|
639
|
+
const reset = operationQueue.current.catch(()=>void 0).then(async ()=>{
|
|
640
|
+
assertScope(guard);
|
|
641
|
+
const instanceIds = sessionRef.current?.openWorkspaces.map(({ snapshotId })=>snapshotId) ?? [];
|
|
642
|
+
await guard.service.deleteApplicationSession();
|
|
643
|
+
assertScope(guard);
|
|
644
|
+
await Promise.all(controllersRef.current.map((controller)=>controller.dispose()));
|
|
645
|
+
replaceControllers([]);
|
|
646
|
+
const emptySession = {
|
|
647
|
+
activeWorkspaceInstanceId: null,
|
|
648
|
+
openWorkspaces: [],
|
|
649
|
+
settings: {},
|
|
650
|
+
version: APPLICATION_SESSION_VERSION,
|
|
651
|
+
workspaceOrder: []
|
|
652
|
+
};
|
|
653
|
+
sessionRef.current = emptySession;
|
|
654
|
+
setSession(emptySession);
|
|
655
|
+
for (const snapshotId of instanceIds){
|
|
656
|
+
assertScope(guard);
|
|
657
|
+
await guard.service.deleteWorkspaceSnapshot(snapshotId);
|
|
658
|
+
assertScope(guard);
|
|
659
|
+
}
|
|
660
|
+
});
|
|
661
|
+
operationQueue.current = reset.then(()=>void 0, ()=>void 0);
|
|
662
|
+
try {
|
|
663
|
+
await reset;
|
|
664
|
+
} finally{
|
|
665
|
+
if (activeScope.current.generation === guard.generation && activeScope.current.scopeKey === guard.scopeKey) resetPending.current = false;
|
|
666
|
+
}
|
|
667
|
+
}, [
|
|
668
|
+
assertScope,
|
|
669
|
+
captureScope,
|
|
670
|
+
replaceControllers
|
|
671
|
+
]);
|
|
672
|
+
const value = useMemo(()=>{
|
|
673
|
+
const settings = session?.settings ?? {};
|
|
674
|
+
const visibleControllers = "loading" === status ? [] : controllers;
|
|
675
|
+
const activeWorkspace = visibleControllers.find(({ instanceId })=>instanceId === session?.activeWorkspaceInstanceId);
|
|
676
|
+
return {
|
|
677
|
+
activeWorkspace,
|
|
678
|
+
activeWorkspaceInstanceId: session?.activeWorkspaceInstanceId ?? null,
|
|
679
|
+
closeWorkspace,
|
|
680
|
+
componentRenderers,
|
|
681
|
+
controllers: visibleControllers,
|
|
682
|
+
createWorkspaceFromSnapshot,
|
|
683
|
+
deleteNamedWorkspace,
|
|
684
|
+
error: loadError,
|
|
685
|
+
getApplicationSetting: (key)=>settings[key],
|
|
686
|
+
getApplicationSettings: (key)=>void 0 === key ? settings : settings[key],
|
|
687
|
+
namedWorkspaces,
|
|
688
|
+
openNamedWorkspace,
|
|
689
|
+
openSystemWorkspace,
|
|
690
|
+
renameWorkspace,
|
|
691
|
+
saveActiveWorkspaceAs,
|
|
196
692
|
saveApplicationSettings,
|
|
197
|
-
|
|
198
|
-
|
|
693
|
+
selectWorkspace,
|
|
694
|
+
setApplicationSetting,
|
|
695
|
+
settings,
|
|
696
|
+
settingsCodecs,
|
|
697
|
+
scopeIdentity: scopeKey,
|
|
698
|
+
status,
|
|
699
|
+
systemWorkspaces,
|
|
700
|
+
resetApplication
|
|
701
|
+
};
|
|
702
|
+
}, [
|
|
703
|
+
closeWorkspace,
|
|
704
|
+
componentRenderers,
|
|
705
|
+
controllers,
|
|
706
|
+
createWorkspaceFromSnapshot,
|
|
707
|
+
deleteNamedWorkspace,
|
|
708
|
+
loadError,
|
|
709
|
+
namedWorkspaces,
|
|
710
|
+
openNamedWorkspace,
|
|
711
|
+
openSystemWorkspace,
|
|
712
|
+
renameWorkspace,
|
|
713
|
+
saveActiveWorkspaceAs,
|
|
714
|
+
saveApplicationSettings,
|
|
715
|
+
selectWorkspace,
|
|
716
|
+
session,
|
|
717
|
+
setApplicationSetting,
|
|
718
|
+
settingsCodecs,
|
|
719
|
+
scopeKey,
|
|
720
|
+
status,
|
|
721
|
+
systemWorkspaces,
|
|
722
|
+
resetApplication
|
|
723
|
+
]);
|
|
724
|
+
return /*#__PURE__*/ jsx(WorkspaceContext.Provider, {
|
|
725
|
+
value: value,
|
|
199
726
|
children: children
|
|
200
727
|
});
|
|
201
728
|
};
|
|
202
|
-
const useWorkspace = ()=>
|
|
203
|
-
|
|
204
|
-
return {
|
|
205
|
-
...contextProps,
|
|
206
|
-
workspaceJSON
|
|
207
|
-
};
|
|
208
|
-
};
|
|
209
|
-
export { WorkspaceProvider, useWorkspace };
|
|
729
|
+
const useWorkspace = ()=>useContext(WorkspaceContext);
|
|
730
|
+
export { StaleWorkspaceScopeError, WorkspaceProvider, emptyWorkspaceSnapshot, useWorkspace };
|