@vuu-ui/vuu-shell 4.0.0-alpha.3 → 4.0.0-alpha.31
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 +20 -19
- package/src/app-header/AppHeader.css.js +1 -1
- package/src/persistence-manager/PersistenceProvider.js +5 -7
- package/src/persistence-manager/index.js +1 -3
- package/src/shell.css.js +1 -1
- package/src/shell.js +2 -2
- package/src/workspace-management/LayoutList.js +1 -1
- package/src/workspace-management/index.js +1 -8
- package/src/workspace-management/useWorkspaceContextMenuItems.js +1 -2
- package/types/app-header/AppHeader.d.ts +1 -1
- package/types/feature/Feature.d.ts +1 -1
- package/types/feature/Loader.d.ts +1 -1
- package/types/feature-list/FeatureList.d.ts +1 -1
- package/types/left-nav/LeftNav.d.ts +1 -1
- package/types/login/LoginPanel.d.ts +1 -1
- package/types/login/VuuLogo.d.ts +1 -1
- package/types/persistence-manager/PersistenceProvider.d.ts +2 -3
- package/types/persistence-manager/index.d.ts +1 -3
- package/types/shell-layout-templates/context-panel/ApplicationSettingsContextPanel.d.ts +1 -1
- package/types/shell-layout-templates/context-panel/ContextPanel.d.ts +1 -1
- package/types/shell-layout-templates/side-panel/SidePanel.d.ts +1 -1
- package/types/shell.d.ts +2 -2
- package/types/theme-switch/ThemeSwitch.d.ts +1 -1
- package/types/workspace-management/LayoutList.d.ts +1 -1
- package/types/workspace-management/LayoutTile.d.ts +1 -1
- package/types/workspace-management/SaveLayoutPanel.d.ts +1 -1
- package/types/workspace-management/WorkspaceHost.d.ts +1 -1
- package/types/workspace-management/WorkspaceProvider.d.ts +50 -61
- package/types/workspace-management/WorkspaceStartPanel.d.ts +1 -1
- package/types/workspace-management/index.d.ts +5 -8
- package/types/workspace-management/shell-workspace-components.d.ts +1 -1
- package/src/persistence-manager/LocalWorkspacePersistenceService.js +0 -129
- package/src/persistence-manager/RemoteWorkspacePersistenceService.js +0 -112
- package/src/persistence-manager/WorkspacePersistenceService.js +0 -9
- package/src/workspace-management/WorkspaceController.js +0 -73
- package/src/workspace-management/WorkspaceHost.js +0 -194
- package/src/workspace-management/WorkspacePersistentState.js +0 -67
- package/src/workspace-management/WorkspaceProvider.js +0 -730
- package/src/workspace-management/WorkspaceRepository.js +0 -127
- package/src/workspace-management/WorkspaceStartPanel.css.js +0 -44
- package/src/workspace-management/WorkspaceStartPanel.js +0 -34
- package/src/workspace-management/workspace-component-registry.js +0 -30
- package/src/workspace-management/workspace-schemas.js +0 -257
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
import { WORKSPACE_SNAPSHOT_RECORD_VERSION, cloneWorkspaceValue, validateWorkspaceSnapshotV1 } from "./workspace-schemas.js";
|
|
2
|
-
class WorkspaceRepositoryDisposedError extends Error {
|
|
3
|
-
constructor(){
|
|
4
|
-
super("Workspace repository has been disposed");
|
|
5
|
-
this.name = "WorkspaceRepositoryDisposedError";
|
|
6
|
-
}
|
|
7
|
-
}
|
|
8
|
-
class WorkspaceRepository {
|
|
9
|
-
#service;
|
|
10
|
-
#workspaceInstanceId;
|
|
11
|
-
#revision = 0;
|
|
12
|
-
#current;
|
|
13
|
-
#active;
|
|
14
|
-
#activeWrite;
|
|
15
|
-
#pending;
|
|
16
|
-
#generation = 0;
|
|
17
|
-
#disposed = false;
|
|
18
|
-
constructor(service, workspaceInstanceId, initial){
|
|
19
|
-
if (!workspaceInstanceId) throw new Error("workspaceInstanceId must not be empty");
|
|
20
|
-
this.#service = service;
|
|
21
|
-
this.#workspaceInstanceId = workspaceInstanceId;
|
|
22
|
-
if (initial) {
|
|
23
|
-
if (initial.workspaceInstanceId !== workspaceInstanceId) throw new Error("Initial snapshot belongs to a different workspace");
|
|
24
|
-
this.#current = cloneWorkspaceValue(initial);
|
|
25
|
-
this.#revision = initial.revision;
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
get current() {
|
|
29
|
-
return void 0 === this.#current ? void 0 : cloneWorkspaceValue(this.#current);
|
|
30
|
-
}
|
|
31
|
-
async load() {
|
|
32
|
-
this.#assertActive();
|
|
33
|
-
const generation = this.#generation;
|
|
34
|
-
const loaded = await this.#service.loadWorkspaceSnapshot(this.#workspaceInstanceId);
|
|
35
|
-
if (this.#disposed || generation !== this.#generation) throw new WorkspaceRepositoryDisposedError();
|
|
36
|
-
if (loaded) {
|
|
37
|
-
this.#revision = Math.max(this.#revision, loaded.revision);
|
|
38
|
-
this.#current = cloneWorkspaceValue(loaded);
|
|
39
|
-
}
|
|
40
|
-
return this.current;
|
|
41
|
-
}
|
|
42
|
-
save(snapshot) {
|
|
43
|
-
this.#assertActive();
|
|
44
|
-
const captured = cloneWorkspaceValue(validateWorkspaceSnapshotV1(snapshot));
|
|
45
|
-
const record = {
|
|
46
|
-
version: WORKSPACE_SNAPSHOT_RECORD_VERSION,
|
|
47
|
-
workspaceInstanceId: this.#workspaceInstanceId,
|
|
48
|
-
revision: ++this.#revision,
|
|
49
|
-
snapshot: captured
|
|
50
|
-
};
|
|
51
|
-
const promise = new Promise((resolve, reject)=>{
|
|
52
|
-
const waiter = {
|
|
53
|
-
reject,
|
|
54
|
-
resolve
|
|
55
|
-
};
|
|
56
|
-
if (this.#active) if (this.#pending) {
|
|
57
|
-
this.#pending.record = record;
|
|
58
|
-
this.#pending.waiters.push(waiter);
|
|
59
|
-
} else this.#pending = {
|
|
60
|
-
record,
|
|
61
|
-
waiters: [
|
|
62
|
-
waiter
|
|
63
|
-
]
|
|
64
|
-
};
|
|
65
|
-
else {
|
|
66
|
-
this.#active = {
|
|
67
|
-
record,
|
|
68
|
-
waiters: [
|
|
69
|
-
waiter
|
|
70
|
-
]
|
|
71
|
-
};
|
|
72
|
-
this.#writeActive();
|
|
73
|
-
}
|
|
74
|
-
});
|
|
75
|
-
return promise;
|
|
76
|
-
}
|
|
77
|
-
dispose() {
|
|
78
|
-
if (this.#disposed) return this.#activeWrite ?? Promise.resolve();
|
|
79
|
-
this.#disposed = true;
|
|
80
|
-
this.#generation += 1;
|
|
81
|
-
const error = new WorkspaceRepositoryDisposedError();
|
|
82
|
-
for (const queued of [
|
|
83
|
-
this.#active,
|
|
84
|
-
this.#pending
|
|
85
|
-
])queued?.waiters.forEach(({ reject })=>{
|
|
86
|
-
reject(error);
|
|
87
|
-
});
|
|
88
|
-
this.#active = void 0;
|
|
89
|
-
this.#pending = void 0;
|
|
90
|
-
this.#current = void 0;
|
|
91
|
-
return this.#activeWrite ?? Promise.resolve();
|
|
92
|
-
}
|
|
93
|
-
#writeActive() {
|
|
94
|
-
const active = this.#active;
|
|
95
|
-
if (!active) return;
|
|
96
|
-
const generation = this.#generation;
|
|
97
|
-
const write = this.#service.saveWorkspaceSnapshot(active.record).then(()=>{
|
|
98
|
-
if (!this.#disposed && generation === this.#generation) {
|
|
99
|
-
this.#current = cloneWorkspaceValue(active.record);
|
|
100
|
-
active.waiters.forEach(({ resolve })=>{
|
|
101
|
-
resolve(cloneWorkspaceValue(active.record));
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
this.#advance(active);
|
|
105
|
-
}, (error)=>{
|
|
106
|
-
const persistenceError = error instanceof Error ? error : new Error("Workspace snapshot persistence failed");
|
|
107
|
-
if (!this.#disposed && generation === this.#generation) active.waiters.forEach(({ reject })=>{
|
|
108
|
-
reject(persistenceError);
|
|
109
|
-
});
|
|
110
|
-
this.#advance(active);
|
|
111
|
-
});
|
|
112
|
-
const trackedWrite = write.finally(()=>{
|
|
113
|
-
if (this.#activeWrite === trackedWrite) this.#activeWrite = void 0;
|
|
114
|
-
});
|
|
115
|
-
this.#activeWrite = trackedWrite;
|
|
116
|
-
}
|
|
117
|
-
#advance(completed) {
|
|
118
|
-
if (this.#disposed || this.#active !== completed) return;
|
|
119
|
-
this.#active = this.#pending;
|
|
120
|
-
this.#pending = void 0;
|
|
121
|
-
this.#writeActive();
|
|
122
|
-
}
|
|
123
|
-
#assertActive() {
|
|
124
|
-
if (this.#disposed) throw new WorkspaceRepositoryDisposedError();
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
export { WorkspaceRepository, WorkspaceRepositoryDisposedError };
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
const css = `
|
|
2
|
-
.vuuWorkspaceStartPanel {
|
|
3
|
-
z-index: 1;
|
|
4
|
-
flex-direction: column;
|
|
5
|
-
justify-content: center;
|
|
6
|
-
align-items: center;
|
|
7
|
-
gap: 12px;
|
|
8
|
-
font-weight: 700;
|
|
9
|
-
display: flex;
|
|
10
|
-
position: absolute;
|
|
11
|
-
inset: 0;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
.vuuWorkspaceStartPanel-title {
|
|
15
|
-
color: var(--vuu-color-gray-80);
|
|
16
|
-
text-align: center;
|
|
17
|
-
font-size: 28px;
|
|
18
|
-
line-height: 1.5;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
.vuuWorkspaceStartPanel-text {
|
|
22
|
-
color: var(--vuu-color-gray-50);
|
|
23
|
-
text-align: center;
|
|
24
|
-
max-width: 460px;
|
|
25
|
-
font-size: 18px;
|
|
26
|
-
line-height: 1.5;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
.vuuWorkspaceStartPanel-addIcon {
|
|
30
|
-
--vuu-icon-size: 20px;
|
|
31
|
-
background: var(--salt-actionable-cta-background);
|
|
32
|
-
color: var(--salt-actionable-cta-foreground);
|
|
33
|
-
border-radius: 28px;
|
|
34
|
-
justify-content: center;
|
|
35
|
-
align-items: center;
|
|
36
|
-
width: 56px;
|
|
37
|
-
height: 56px;
|
|
38
|
-
display: flex;
|
|
39
|
-
box-shadow: 0 4px 4px #00000040;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
`;
|
|
44
|
-
export default css;
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useComponentCssInjection } from "@salt-ds/styles";
|
|
3
|
-
import { useWindow } from "@salt-ds/window";
|
|
4
|
-
import { Icon } from "@vuu-ui/vuu-ui-controls";
|
|
5
|
-
import WorkspaceStartPanel from "./WorkspaceStartPanel.css";
|
|
6
|
-
const WorkspaceStartPanel_WorkspaceStartPanel = ()=>{
|
|
7
|
-
const targetWindow = useWindow();
|
|
8
|
-
useComponentCssInjection({
|
|
9
|
-
testId: "vuu-workspace-start-panel",
|
|
10
|
-
css: WorkspaceStartPanel,
|
|
11
|
-
window: targetWindow
|
|
12
|
-
});
|
|
13
|
-
return /*#__PURE__*/ jsxs("div", {
|
|
14
|
-
className: "vuuWorkspaceStartPanel",
|
|
15
|
-
children: [
|
|
16
|
-
/*#__PURE__*/ jsx("div", {
|
|
17
|
-
className: "vuuWorkspaceStartPanel-title",
|
|
18
|
-
children: "Start by adding a table"
|
|
19
|
-
}),
|
|
20
|
-
/*#__PURE__*/ jsx("div", {
|
|
21
|
-
className: "vuuWorkspaceStartPanel-text",
|
|
22
|
-
children: "To add a table, drag any of the Vuu Tables to this area"
|
|
23
|
-
}),
|
|
24
|
-
/*#__PURE__*/ jsx("div", {
|
|
25
|
-
"aria-hidden": true,
|
|
26
|
-
className: "vuuWorkspaceStartPanel-addIcon",
|
|
27
|
-
children: /*#__PURE__*/ jsx(Icon, {
|
|
28
|
-
name: "add"
|
|
29
|
-
})
|
|
30
|
-
})
|
|
31
|
-
]
|
|
32
|
-
});
|
|
33
|
-
};
|
|
34
|
-
export { WorkspaceStartPanel_WorkspaceStartPanel as WorkspaceStartPanel };
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { GridComponentRendererRegistry, GridComponentSettingsRegistry } from "@vuu-ui/grid-layout";
|
|
2
|
-
const createWorkspaceComponentRegistries = (registrations)=>{
|
|
3
|
-
const renderers = new GridComponentRendererRegistry();
|
|
4
|
-
const settingsCodecs = new GridComponentSettingsRegistry();
|
|
5
|
-
for (const registration of registrations){
|
|
6
|
-
settingsCodecs.register(registration.type, registration.codec);
|
|
7
|
-
renderers.register(registration.type, registration.codec.isSettings, registration.render);
|
|
8
|
-
}
|
|
9
|
-
return {
|
|
10
|
-
renderers,
|
|
11
|
-
settingsCodecs
|
|
12
|
-
};
|
|
13
|
-
};
|
|
14
|
-
const jsonValueWorkspaceComponentCodec = {
|
|
15
|
-
decode: (value)=>({
|
|
16
|
-
ok: true,
|
|
17
|
-
value
|
|
18
|
-
}),
|
|
19
|
-
encode: (value)=>({
|
|
20
|
-
ok: true,
|
|
21
|
-
value
|
|
22
|
-
}),
|
|
23
|
-
isSettings: (value)=>{
|
|
24
|
-
if (null === value || "string" == typeof value || "number" == typeof value || "boolean" == typeof value) return true;
|
|
25
|
-
if (Array.isArray(value)) return value.every(jsonValueWorkspaceComponentCodec.isSettings);
|
|
26
|
-
return "object" == typeof value && Object.values(value).every(jsonValueWorkspaceComponentCodec.isSettings);
|
|
27
|
-
},
|
|
28
|
-
version: 1
|
|
29
|
-
};
|
|
30
|
-
export { createWorkspaceComponentRegistries, jsonValueWorkspaceComponentCodec };
|
|
@@ -1,257 +0,0 @@
|
|
|
1
|
-
import { GRID_LAYOUT_DOCUMENT_VERSION, GridComponentSettingsRegistry, decodeGridLayoutDocument, toJsonValue } from "@vuu-ui/grid-layout";
|
|
2
|
-
const WORKSPACE_SNAPSHOT_VERSION = 1;
|
|
3
|
-
const APPLICATION_SESSION_VERSION = 1;
|
|
4
|
-
const NAMED_WORKSPACE_DEFINITION_VERSION = 1;
|
|
5
|
-
const WORKSPACE_SNAPSHOT_RECORD_VERSION = 1;
|
|
6
|
-
class WorkspaceValidationError extends Error {
|
|
7
|
-
schema;
|
|
8
|
-
issues;
|
|
9
|
-
constructor(schema, issues){
|
|
10
|
-
super(`${schema} validation failed: ${issues[0]?.path ?? "$"}: ${issues[0]?.message ?? "invalid value"}`), this.schema = schema, this.issues = issues;
|
|
11
|
-
this.name = "WorkspaceValidationError";
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
const isRecord = (value)=>"object" == typeof value && null !== value && !Array.isArray(value);
|
|
15
|
-
const issue = (issues, code, path, message)=>{
|
|
16
|
-
issues.push({
|
|
17
|
-
code,
|
|
18
|
-
message,
|
|
19
|
-
path
|
|
20
|
-
});
|
|
21
|
-
};
|
|
22
|
-
const fields = (value, allowed, path, issues)=>{
|
|
23
|
-
for (const field of Object.keys(value))if (!allowed.includes(field)) issue(issues, "UNEXPECTED_FIELD", `${path}.${field}`, `unexpected field "${field}"`);
|
|
24
|
-
};
|
|
25
|
-
const stringField = (value, path, issues)=>{
|
|
26
|
-
if ("string" != typeof value || 0 === value.length) {
|
|
27
|
-
issue(issues, "INVALID_VALUE", path, "must be a non-empty string");
|
|
28
|
-
return false;
|
|
29
|
-
}
|
|
30
|
-
return true;
|
|
31
|
-
};
|
|
32
|
-
const version = (value, expected, path, issues)=>{
|
|
33
|
-
if (value !== expected) issue(issues, "UNSUPPORTED_VERSION", path, `expected version ${expected}, received ${String(value)}`);
|
|
34
|
-
};
|
|
35
|
-
const validateGridLayout = (value, path, issues)=>{
|
|
36
|
-
if (!isRecord(value)) {
|
|
37
|
-
issue(issues, "INVALID_VALUE", path, "must be a grid layout document");
|
|
38
|
-
return false;
|
|
39
|
-
}
|
|
40
|
-
if (value.version !== GRID_LAYOUT_DOCUMENT_VERSION) {
|
|
41
|
-
issue(issues, "UNSUPPORTED_VERSION", `${path}.version`, `expected grid layout version ${GRID_LAYOUT_DOCUMENT_VERSION}, received ${String(value.version)}`);
|
|
42
|
-
return false;
|
|
43
|
-
}
|
|
44
|
-
const registry = new GridComponentSettingsRegistry();
|
|
45
|
-
if (Array.isArray(value.components)) {
|
|
46
|
-
const versions = new Map();
|
|
47
|
-
for (const component of value.components)if (isRecord(component) && "string" == typeof component.type && component.type.length > 0 && "number" == typeof component.version && Number.isInteger(component.version) && component.version >= 1) {
|
|
48
|
-
const previous = versions.get(component.type);
|
|
49
|
-
if (void 0 !== previous && previous !== component.version) {
|
|
50
|
-
issue(issues, "INVALID_VALUE", `${path}.components`, `component type "${component.type}" uses multiple schema versions`);
|
|
51
|
-
return false;
|
|
52
|
-
}
|
|
53
|
-
versions.set(component.type, component.version);
|
|
54
|
-
}
|
|
55
|
-
for (const [type, componentVersion] of versions)registry.register(type, {
|
|
56
|
-
decode: (settings)=>({
|
|
57
|
-
ok: true,
|
|
58
|
-
value: settings
|
|
59
|
-
}),
|
|
60
|
-
encode: (settings)=>({
|
|
61
|
-
ok: true,
|
|
62
|
-
value: settings
|
|
63
|
-
}),
|
|
64
|
-
isSettings: (settings)=>toJsonValue(settings).ok,
|
|
65
|
-
version: componentVersion
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
|
-
const decoded = decodeGridLayoutDocument(value, registry);
|
|
69
|
-
if (!decoded.ok) {
|
|
70
|
-
issue(issues, "INVALID_VALUE", `${path}${decoded.error.path.slice(1)}`, decoded.error.message);
|
|
71
|
-
return false;
|
|
72
|
-
}
|
|
73
|
-
return true;
|
|
74
|
-
};
|
|
75
|
-
const validateComponentState = (value, path, issues)=>{
|
|
76
|
-
if (!isRecord(value)) {
|
|
77
|
-
issue(issues, "INVALID_VALUE", path, "must be an object");
|
|
78
|
-
return false;
|
|
79
|
-
}
|
|
80
|
-
for (const [id, entry] of Object.entries(value)){
|
|
81
|
-
const entryPath = `${path}.${id}`;
|
|
82
|
-
if (!id) issue(issues, "INVALID_VALUE", entryPath, "component id must not be empty");
|
|
83
|
-
if (!isRecord(entry)) {
|
|
84
|
-
issue(issues, "INVALID_VALUE", entryPath, "must be an object");
|
|
85
|
-
continue;
|
|
86
|
-
}
|
|
87
|
-
fields(entry, [
|
|
88
|
-
"componentType",
|
|
89
|
-
"schemaVersion",
|
|
90
|
-
"value"
|
|
91
|
-
], entryPath, issues);
|
|
92
|
-
stringField(entry.componentType, `${entryPath}.componentType`, issues);
|
|
93
|
-
if ("number" != typeof entry.schemaVersion || !Number.isInteger(entry.schemaVersion) || entry.schemaVersion < 1) issue(issues, "INVALID_VALUE", `${entryPath}.schemaVersion`, "must be a positive integer");
|
|
94
|
-
const json = toJsonValue(entry.value, `${entryPath}.value`);
|
|
95
|
-
if (!json.ok) issue(issues, "INVALID_JSON_VALUE", json.error.path, json.error.message);
|
|
96
|
-
}
|
|
97
|
-
return true;
|
|
98
|
-
};
|
|
99
|
-
const result = (schema, value, issues)=>{
|
|
100
|
-
if (issues.length > 0) throw new WorkspaceValidationError(schema, issues);
|
|
101
|
-
return value;
|
|
102
|
-
};
|
|
103
|
-
const validateWorkspaceSnapshotV1 = (value)=>{
|
|
104
|
-
const issues = [];
|
|
105
|
-
if (!isRecord(value)) {
|
|
106
|
-
issue(issues, "INVALID_VALUE", "$", "must be an object");
|
|
107
|
-
return result("WorkspaceSnapshotV1", value, issues);
|
|
108
|
-
}
|
|
109
|
-
fields(value, [
|
|
110
|
-
"version",
|
|
111
|
-
"layout",
|
|
112
|
-
"componentState"
|
|
113
|
-
], "$", issues);
|
|
114
|
-
version(value.version, WORKSPACE_SNAPSHOT_VERSION, "$.version", issues);
|
|
115
|
-
validateGridLayout(value.layout, "$.layout", issues);
|
|
116
|
-
validateComponentState(value.componentState, "$.componentState", issues);
|
|
117
|
-
return result("WorkspaceSnapshotV1", value, issues);
|
|
118
|
-
};
|
|
119
|
-
const validateSettings = (value, path, issues)=>{
|
|
120
|
-
if (!isRecord(value)) return void issue(issues, "INVALID_VALUE", path, "must be an object");
|
|
121
|
-
for (const [key, setting] of Object.entries(value)){
|
|
122
|
-
const json = toJsonValue(setting, `${path}.${key}`);
|
|
123
|
-
if (!json.ok) issue(issues, "INVALID_JSON_VALUE", json.error.path, json.error.message);
|
|
124
|
-
}
|
|
125
|
-
};
|
|
126
|
-
const validateApplicationSessionV1 = (value)=>{
|
|
127
|
-
const issues = [];
|
|
128
|
-
if (!isRecord(value)) {
|
|
129
|
-
issue(issues, "INVALID_VALUE", "$", "must be an object");
|
|
130
|
-
return result("ApplicationSessionV1", value, issues);
|
|
131
|
-
}
|
|
132
|
-
fields(value, [
|
|
133
|
-
"version",
|
|
134
|
-
"openWorkspaces",
|
|
135
|
-
"workspaceOrder",
|
|
136
|
-
"activeWorkspaceInstanceId",
|
|
137
|
-
"settings"
|
|
138
|
-
], "$", issues);
|
|
139
|
-
version(value.version, APPLICATION_SESSION_VERSION, "$.version", issues);
|
|
140
|
-
const ids = new Set();
|
|
141
|
-
if (Array.isArray(value.openWorkspaces)) value.openWorkspaces.forEach((entry, index)=>{
|
|
142
|
-
const path = `$.openWorkspaces[${index}]`;
|
|
143
|
-
if (!isRecord(entry)) return void issue(issues, "INVALID_VALUE", path, "must be an object");
|
|
144
|
-
fields(entry, [
|
|
145
|
-
"instanceId",
|
|
146
|
-
"definitionId",
|
|
147
|
-
"title",
|
|
148
|
-
"snapshotId"
|
|
149
|
-
], path, issues);
|
|
150
|
-
if (stringField(entry.instanceId, `${path}.instanceId`, issues)) {
|
|
151
|
-
if (ids.has(entry.instanceId)) issue(issues, "INVALID_VALUE", `${path}.instanceId`, "must be unique");
|
|
152
|
-
ids.add(entry.instanceId);
|
|
153
|
-
}
|
|
154
|
-
stringField(entry.snapshotId, `${path}.snapshotId`, issues);
|
|
155
|
-
if (void 0 !== entry.definitionId) stringField(entry.definitionId, `${path}.definitionId`, issues);
|
|
156
|
-
if (void 0 !== entry.title) stringField(entry.title, `${path}.title`, issues);
|
|
157
|
-
});
|
|
158
|
-
else issue(issues, "INVALID_VALUE", "$.openWorkspaces", "must be an array");
|
|
159
|
-
if (!Array.isArray(value.workspaceOrder) || value.workspaceOrder.some((id)=>"string" != typeof id) || value.workspaceOrder.length !== ids.size || new Set(value.workspaceOrder).size !== ids.size || value.workspaceOrder.some((id)=>!ids.has(id))) issue(issues, "INVALID_VALUE", "$.workspaceOrder", "must contain every open workspace instance id exactly once");
|
|
160
|
-
if (null !== value.activeWorkspaceInstanceId && ("string" != typeof value.activeWorkspaceInstanceId || !ids.has(value.activeWorkspaceInstanceId))) issue(issues, "INVALID_VALUE", "$.activeWorkspaceInstanceId", "must be null or identify an open workspace");
|
|
161
|
-
validateSettings(value.settings, "$.settings", issues);
|
|
162
|
-
return result("ApplicationSessionV1", value, issues);
|
|
163
|
-
};
|
|
164
|
-
const validateMetadata = (value, issues, includeSnapshot)=>{
|
|
165
|
-
fields(value, [
|
|
166
|
-
"version",
|
|
167
|
-
"id",
|
|
168
|
-
"name",
|
|
169
|
-
"description",
|
|
170
|
-
"createdAt",
|
|
171
|
-
"updatedAt",
|
|
172
|
-
...includeSnapshot ? [
|
|
173
|
-
"snapshot"
|
|
174
|
-
] : []
|
|
175
|
-
], "$", issues);
|
|
176
|
-
version(value.version, NAMED_WORKSPACE_DEFINITION_VERSION, "$.version", issues);
|
|
177
|
-
stringField(value.id, "$.id", issues);
|
|
178
|
-
stringField(value.name, "$.name", issues);
|
|
179
|
-
stringField(value.createdAt, "$.createdAt", issues);
|
|
180
|
-
stringField(value.updatedAt, "$.updatedAt", issues);
|
|
181
|
-
if (void 0 !== value.description && "string" != typeof value.description) issue(issues, "INVALID_VALUE", "$.description", "must be a string");
|
|
182
|
-
};
|
|
183
|
-
const validateNamedWorkspaceDefinitionV1 = (value)=>{
|
|
184
|
-
const issues = [];
|
|
185
|
-
if (!isRecord(value)) {
|
|
186
|
-
issue(issues, "INVALID_VALUE", "$", "must be an object");
|
|
187
|
-
return result("NamedWorkspaceDefinitionV1", value, issues);
|
|
188
|
-
}
|
|
189
|
-
validateMetadata(value, issues, true);
|
|
190
|
-
try {
|
|
191
|
-
validateWorkspaceSnapshotV1(value.snapshot);
|
|
192
|
-
} catch (error) {
|
|
193
|
-
if (!(error instanceof WorkspaceValidationError)) throw error;
|
|
194
|
-
for (const nested of error.issues)issues.push({
|
|
195
|
-
...nested,
|
|
196
|
-
path: `$.snapshot${nested.path.slice(1)}`
|
|
197
|
-
});
|
|
198
|
-
}
|
|
199
|
-
return result("NamedWorkspaceDefinitionV1", value, issues);
|
|
200
|
-
};
|
|
201
|
-
const validateNamedWorkspaceMetadataV1 = (value)=>{
|
|
202
|
-
const issues = [];
|
|
203
|
-
if (!isRecord(value)) {
|
|
204
|
-
issue(issues, "INVALID_VALUE", "$", "must be an object");
|
|
205
|
-
return result("NamedWorkspaceMetadataV1", value, issues);
|
|
206
|
-
}
|
|
207
|
-
validateMetadata(value, issues, false);
|
|
208
|
-
return result("NamedWorkspaceMetadataV1", value, issues);
|
|
209
|
-
};
|
|
210
|
-
const validateWorkspaceSnapshotRecordV1 = (value)=>{
|
|
211
|
-
const issues = [];
|
|
212
|
-
if (!isRecord(value)) {
|
|
213
|
-
issue(issues, "INVALID_VALUE", "$", "must be an object");
|
|
214
|
-
return result("WorkspaceSnapshotRecordV1", value, issues);
|
|
215
|
-
}
|
|
216
|
-
fields(value, [
|
|
217
|
-
"version",
|
|
218
|
-
"workspaceInstanceId",
|
|
219
|
-
"revision",
|
|
220
|
-
"snapshot"
|
|
221
|
-
], "$", issues);
|
|
222
|
-
version(value.version, WORKSPACE_SNAPSHOT_RECORD_VERSION, "$.version", issues);
|
|
223
|
-
stringField(value.workspaceInstanceId, "$.workspaceInstanceId", issues);
|
|
224
|
-
if ("number" != typeof value.revision || !Number.isSafeInteger(value.revision) || value.revision < 1) issue(issues, "INVALID_VALUE", "$.revision", "must be a positive integer");
|
|
225
|
-
try {
|
|
226
|
-
validateWorkspaceSnapshotV1(value.snapshot);
|
|
227
|
-
} catch (error) {
|
|
228
|
-
if (!(error instanceof WorkspaceValidationError)) throw error;
|
|
229
|
-
for (const nested of error.issues)issues.push({
|
|
230
|
-
...nested,
|
|
231
|
-
path: `$.snapshot${nested.path.slice(1)}`
|
|
232
|
-
});
|
|
233
|
-
}
|
|
234
|
-
return result("WorkspaceSnapshotRecordV1", value, issues);
|
|
235
|
-
};
|
|
236
|
-
const workspaceMetadata = (definition)=>({
|
|
237
|
-
version: NAMED_WORKSPACE_DEFINITION_VERSION,
|
|
238
|
-
id: definition.id,
|
|
239
|
-
name: definition.name,
|
|
240
|
-
...void 0 === definition.description ? {} : {
|
|
241
|
-
description: definition.description
|
|
242
|
-
},
|
|
243
|
-
createdAt: definition.createdAt,
|
|
244
|
-
updatedAt: definition.updatedAt
|
|
245
|
-
});
|
|
246
|
-
const cloneWorkspaceValue = (value)=>{
|
|
247
|
-
const json = toJsonValue(value);
|
|
248
|
-
if (!json.ok) throw new WorkspaceValidationError("WorkspaceSnapshotV1", [
|
|
249
|
-
{
|
|
250
|
-
code: "INVALID_JSON_VALUE",
|
|
251
|
-
message: json.error.message,
|
|
252
|
-
path: json.error.path
|
|
253
|
-
}
|
|
254
|
-
]);
|
|
255
|
-
return JSON.parse(JSON.stringify(json.value));
|
|
256
|
-
};
|
|
257
|
-
export { APPLICATION_SESSION_VERSION, NAMED_WORKSPACE_DEFINITION_VERSION, WORKSPACE_SNAPSHOT_RECORD_VERSION, WORKSPACE_SNAPSHOT_VERSION, WorkspaceValidationError, cloneWorkspaceValue, validateApplicationSessionV1, validateNamedWorkspaceDefinitionV1, validateNamedWorkspaceMetadataV1, validateWorkspaceSnapshotRecordV1, validateWorkspaceSnapshotV1, workspaceMetadata };
|