@workbench-kit/shell-react 0.0.2-prototype.0.2.33 → 0.0.2-prototype.0.2.34
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/README.md +32 -0
- package/package.json +9 -9
- package/src/commands/use-command-descriptors.ts +7 -3
- package/src/commands/use-extension-registry-command-descriptors.ts +23 -6
- package/src/devtools/use-workbench-devtools-snapshot.ts +39 -14
- package/src/devtools/workbench-devtools-snapshot.ts +32 -13
- package/src/editor/area.tsx +3 -2
- package/src/editor/state-storage.ts +31 -0
- package/src/editor/tab-context-menu.ts +8 -8
- package/src/editor/use-editor.ts +6 -6
- package/src/explorer/context-menu.ts +8 -4
- package/src/explorer/view.tsx +4 -3
- package/src/extensions/canonical-extension-descriptions.ts +58 -0
- package/src/extensions/context-menu.ts +9 -6
- package/src/extensions/extension-enablement-context.ts +15 -0
- package/src/extensions/extension-enablement-controller.ts +453 -0
- package/src/extensions/management-model.ts +111 -47
- package/src/extensions/theme-selection-protection.ts +98 -0
- package/src/extensions/uninstall-eligibility.ts +103 -0
- package/src/extensions/use-extension-management.ts +151 -67
- package/src/extensions/view.tsx +4 -0
- package/src/field-remap/chrome-labels.ts +58 -2
- package/src/field-remap/convert-palette.tsx +151 -6
- package/src/field-remap/demo.tsx +31 -2
- package/src/field-remap/flow.tsx +57 -13
- package/src/field-remap/history.ts +99 -0
- package/src/field-remap/index.ts +9 -1
- package/src/field-remap/panel.tsx +371 -97
- package/src/field-remap/preview-controller.ts +122 -0
- package/src/field-remap/preview.tsx +171 -0
- package/src/field-remap/view.css +72 -0
- package/src/index.ts +16 -1
- package/src/management/keybinding-overrides-storage.ts +28 -0
- package/src/management/preference-settings-storage.ts +28 -0
- package/src/management/settings.tsx +2 -0
- package/src/management/use-command-management.ts +31 -26
- package/src/management/use-keybinding-management.ts +25 -12
- package/src/shell/focused-extension-services.ts +138 -0
- package/src/shell/host-shell.tsx +13 -10
- package/src/shell/persistence-diagnostic-context.ts +11 -0
- package/src/shell/provider.tsx +373 -69
- package/src/shell/settings.tsx +25 -16
- package/src/shell/shell.tsx +119 -78
- package/src/shell/view-host.tsx +23 -22
- package/src/storage/local-json-storage.ts +43 -29
- package/src/storage/persistence-diagnostics.ts +72 -0
- package/src/workbench/appearance-storage.ts +28 -0
- package/src/workbench/command-host.tsx +19 -22
- package/src/workbench/command-palette.ts +14 -13
- package/src/workbench/layout-storage.ts +52 -5
- package/src/workbench/use-persisted-appearance.ts +38 -12
|
@@ -1,10 +1,20 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createBrowserWorkbenchStorage,
|
|
3
|
+
readWorkbenchStorageJsonResult,
|
|
4
|
+
writeWorkbenchStorageJsonResult,
|
|
5
|
+
type WorkbenchPersistenceDiagnosticOptions,
|
|
6
|
+
type WorkbenchPersistenceReadResult,
|
|
7
|
+
type WorkbenchPersistenceWriteResult,
|
|
3
8
|
type WorkbenchStorageAdapter,
|
|
4
9
|
type WorkbenchStorageReader,
|
|
5
10
|
type WorkbenchStorageWriter,
|
|
6
11
|
} from '@workbench-kit/workbench-core';
|
|
7
12
|
|
|
13
|
+
export interface WriteLocalJsonStorageOptions<T> extends WorkbenchPersistenceDiagnosticOptions {
|
|
14
|
+
readonly errorMode?: 'ignore' | 'throw';
|
|
15
|
+
readonly toStorageValue?: (value: T) => unknown;
|
|
16
|
+
}
|
|
17
|
+
|
|
8
18
|
export function resolveLocalWorkbenchStorage<
|
|
9
19
|
TStorage extends WorkbenchStorageReader | WorkbenchStorageWriter = WorkbenchStorageAdapter,
|
|
10
20
|
>(storage?: TStorage): TStorage | WorkbenchStorageAdapter | undefined {
|
|
@@ -16,49 +26,53 @@ export function readLocalJsonStorage<T>(
|
|
|
16
26
|
parse: (value: unknown) => T,
|
|
17
27
|
fallback: () => T,
|
|
18
28
|
storage?: WorkbenchStorageReader,
|
|
29
|
+
options: WorkbenchPersistenceDiagnosticOptions = {},
|
|
19
30
|
): T {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
return fallback();
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
try {
|
|
26
|
-
const raw = resolvedStorage.getItem(storageKey);
|
|
27
|
-
if (!raw) {
|
|
28
|
-
return fallback();
|
|
29
|
-
}
|
|
31
|
+
return readLocalJsonStorageResult(storageKey, parse, fallback, storage, options).value;
|
|
32
|
+
}
|
|
30
33
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
34
|
+
export function readLocalJsonStorageResult<T>(
|
|
35
|
+
storageKey: string,
|
|
36
|
+
parse: (value: unknown) => T,
|
|
37
|
+
fallback: () => T,
|
|
38
|
+
storage?: WorkbenchStorageReader,
|
|
39
|
+
options: WorkbenchPersistenceDiagnosticOptions = {},
|
|
40
|
+
): WorkbenchPersistenceReadResult<T> {
|
|
41
|
+
return readWorkbenchStorageJsonResult(storageKey, parse, fallback, storage, options);
|
|
35
42
|
}
|
|
36
43
|
|
|
37
44
|
export function writeLocalJsonStorage<T>(
|
|
38
45
|
storageKey: string,
|
|
39
46
|
value: T,
|
|
40
47
|
storage?: WorkbenchStorageWriter,
|
|
41
|
-
options: {
|
|
42
|
-
readonly errorMode?: 'ignore' | 'throw';
|
|
43
|
-
readonly toStorageValue?: (value: T) => unknown;
|
|
44
|
-
} = {},
|
|
48
|
+
options: WriteLocalJsonStorageOptions<T> = {},
|
|
45
49
|
): void {
|
|
50
|
+
if (options.errorMode !== 'throw') {
|
|
51
|
+
writeLocalJsonStorageResult(storageKey, value, storage, options);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
|
|
46
55
|
const resolvedStorage = resolveLocalWorkbenchStorage(storage);
|
|
47
56
|
if (!resolvedStorage) {
|
|
48
57
|
return;
|
|
49
58
|
}
|
|
50
59
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
}
|
|
60
|
+
resolvedStorage.setItem(
|
|
61
|
+
storageKey,
|
|
62
|
+
JSON.stringify((options.toStorageValue ?? identity)(value), null, 2),
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function writeLocalJsonStorageResult<T>(
|
|
67
|
+
storageKey: string,
|
|
68
|
+
value: T,
|
|
69
|
+
storage?: WorkbenchStorageWriter,
|
|
70
|
+
options: WriteLocalJsonStorageOptions<T> = {},
|
|
71
|
+
): WorkbenchPersistenceWriteResult {
|
|
72
|
+
return writeWorkbenchStorageJsonResult(storageKey, value, storage, {
|
|
73
|
+
onDiagnostic: options.onDiagnostic,
|
|
74
|
+
toStorageValue: options.toStorageValue,
|
|
75
|
+
});
|
|
62
76
|
}
|
|
63
77
|
|
|
64
78
|
function identity<T>(value: T): T {
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { useEffect, useRef, type MutableRefObject } from 'react';
|
|
2
|
+
import type {
|
|
3
|
+
WorkbenchPersistenceDiagnostic,
|
|
4
|
+
WorkbenchPersistenceDiagnosticHandler,
|
|
5
|
+
WorkbenchPersistenceWriteResult,
|
|
6
|
+
} from '@workbench-kit/workbench-core';
|
|
7
|
+
|
|
8
|
+
export type WorkbenchPersistenceDiagnosticHandlerRef = MutableRefObject<
|
|
9
|
+
WorkbenchPersistenceDiagnosticHandler | undefined
|
|
10
|
+
>;
|
|
11
|
+
|
|
12
|
+
export function usePersistenceDiagnosticHandlerRef(
|
|
13
|
+
onDiagnostic: WorkbenchPersistenceDiagnosticHandler | undefined,
|
|
14
|
+
): WorkbenchPersistenceDiagnosticHandlerRef {
|
|
15
|
+
const handlerRef = useRef(onDiagnostic);
|
|
16
|
+
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
handlerRef.current = onDiagnostic;
|
|
19
|
+
}, [onDiagnostic]);
|
|
20
|
+
|
|
21
|
+
return handlerRef;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function useReportPersistenceReadDiagnostic(
|
|
25
|
+
diagnostic: WorkbenchPersistenceDiagnostic | undefined,
|
|
26
|
+
generation: readonly unknown[],
|
|
27
|
+
handlerRef: WorkbenchPersistenceDiagnosticHandlerRef,
|
|
28
|
+
): void {
|
|
29
|
+
const lastGenerationRef = useRef<readonly unknown[] | undefined>(undefined);
|
|
30
|
+
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
if (isSameGeneration(lastGenerationRef.current, generation)) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
lastGenerationRef.current = [...generation];
|
|
37
|
+
if (diagnostic) {
|
|
38
|
+
reportPersistenceDiagnostic(diagnostic, handlerRef);
|
|
39
|
+
}
|
|
40
|
+
}, [diagnostic, generation, handlerRef]);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function reportPersistenceWriteResult(
|
|
44
|
+
result: WorkbenchPersistenceWriteResult,
|
|
45
|
+
handlerRef: WorkbenchPersistenceDiagnosticHandlerRef,
|
|
46
|
+
): void {
|
|
47
|
+
if (!result.committed) {
|
|
48
|
+
reportPersistenceDiagnostic(result.diagnostic, handlerRef);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function reportPersistenceDiagnostic(
|
|
53
|
+
diagnostic: WorkbenchPersistenceDiagnostic,
|
|
54
|
+
handlerRef: WorkbenchPersistenceDiagnosticHandlerRef,
|
|
55
|
+
): void {
|
|
56
|
+
try {
|
|
57
|
+
handlerRef.current?.(diagnostic);
|
|
58
|
+
} catch {
|
|
59
|
+
// Diagnostics are observational and must not change runtime state.
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function isSameGeneration(
|
|
64
|
+
left: readonly unknown[] | undefined,
|
|
65
|
+
right: readonly unknown[],
|
|
66
|
+
): boolean {
|
|
67
|
+
return (
|
|
68
|
+
left !== undefined &&
|
|
69
|
+
left.length === right.length &&
|
|
70
|
+
left.every((value, index) => Object.is(value, right[index]))
|
|
71
|
+
);
|
|
72
|
+
}
|
|
@@ -7,14 +7,19 @@ import {
|
|
|
7
7
|
type WorkbenchColorSchemePreference,
|
|
8
8
|
} from '@workbench-kit/react/workbench';
|
|
9
9
|
import {
|
|
10
|
+
type WorkbenchPersistenceDiagnosticOptions,
|
|
11
|
+
type WorkbenchPersistenceReadResult,
|
|
12
|
+
type WorkbenchPersistenceWriteResult,
|
|
10
13
|
type WorkbenchStorageReader,
|
|
11
14
|
type WorkbenchStorageWriter,
|
|
12
15
|
} from '@workbench-kit/workbench-core';
|
|
13
16
|
|
|
14
17
|
import {
|
|
15
18
|
readLocalJsonStorage,
|
|
19
|
+
readLocalJsonStorageResult,
|
|
16
20
|
resolveLocalWorkbenchStorage,
|
|
17
21
|
writeLocalJsonStorage,
|
|
22
|
+
writeLocalJsonStorageResult,
|
|
18
23
|
} from '../storage/local-json-storage.js';
|
|
19
24
|
|
|
20
25
|
export type { WorkbenchAppearanceSettings } from '@workbench-kit/react/workbench/themePresets';
|
|
@@ -44,6 +49,20 @@ export function readPersistedWorkbenchAppearance(
|
|
|
44
49
|
);
|
|
45
50
|
}
|
|
46
51
|
|
|
52
|
+
export function readPersistedWorkbenchAppearanceResult(
|
|
53
|
+
storageKey = DEFAULT_WORKBENCH_APPEARANCE_STORAGE_KEY,
|
|
54
|
+
storage?: WorkbenchStorageReader,
|
|
55
|
+
options: WorkbenchPersistenceDiagnosticOptions = {},
|
|
56
|
+
): WorkbenchPersistenceReadResult<WorkbenchAppearanceSettings> {
|
|
57
|
+
return readLocalJsonStorageResult(
|
|
58
|
+
storageKey,
|
|
59
|
+
normalizeWorkbenchAppearance,
|
|
60
|
+
() => DEFAULT_WORKBENCH_APPEARANCE,
|
|
61
|
+
storage,
|
|
62
|
+
options,
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
47
66
|
export function writePersistedWorkbenchAppearance(
|
|
48
67
|
settings: WorkbenchAppearanceSettings,
|
|
49
68
|
storageKey = DEFAULT_WORKBENCH_APPEARANCE_STORAGE_KEY,
|
|
@@ -52,6 +71,15 @@ export function writePersistedWorkbenchAppearance(
|
|
|
52
71
|
writeLocalJsonStorage(storageKey, settings, storage);
|
|
53
72
|
}
|
|
54
73
|
|
|
74
|
+
export function writePersistedWorkbenchAppearanceResult(
|
|
75
|
+
settings: WorkbenchAppearanceSettings,
|
|
76
|
+
storageKey = DEFAULT_WORKBENCH_APPEARANCE_STORAGE_KEY,
|
|
77
|
+
storage?: WorkbenchStorageWriter,
|
|
78
|
+
options: WorkbenchPersistenceDiagnosticOptions = {},
|
|
79
|
+
): WorkbenchPersistenceWriteResult {
|
|
80
|
+
return writeLocalJsonStorageResult(storageKey, settings, storage, options);
|
|
81
|
+
}
|
|
82
|
+
|
|
55
83
|
function normalizeWorkbenchAppearance(value: unknown): WorkbenchAppearanceSettings {
|
|
56
84
|
if (typeof value !== 'object' || value === null) {
|
|
57
85
|
return DEFAULT_WORKBENCH_APPEARANCE;
|
|
@@ -101,11 +101,15 @@ export function WorkbenchCommandHost({
|
|
|
101
101
|
quickOpenTitle = 'Quick Open',
|
|
102
102
|
}: WorkbenchCommandHostProps) {
|
|
103
103
|
const {
|
|
104
|
+
activities,
|
|
105
|
+
commands,
|
|
104
106
|
contextKeyService,
|
|
105
107
|
executeCommand,
|
|
106
|
-
|
|
108
|
+
extensionCatalog,
|
|
109
|
+
keybindings,
|
|
107
110
|
keybindingOverrides,
|
|
108
111
|
layoutService,
|
|
112
|
+
views,
|
|
109
113
|
workspaceHostPort,
|
|
110
114
|
} = useWorkbench();
|
|
111
115
|
const [paletteOpen, setPaletteOpen] = useState(false);
|
|
@@ -136,12 +140,12 @@ export function WorkbenchCommandHost({
|
|
|
136
140
|
}, [layoutService]);
|
|
137
141
|
|
|
138
142
|
const managedShellActivities = useMemo(
|
|
139
|
-
() => resolveShellCommandActivities(
|
|
140
|
-
[
|
|
143
|
+
() => resolveShellCommandActivities({ activities, views }),
|
|
144
|
+
[activities, views],
|
|
141
145
|
);
|
|
142
146
|
const visibleShellActivities = useMemo(
|
|
143
|
-
() => resolveShellCommandActivities(
|
|
144
|
-
[contextKeySnapshot,
|
|
147
|
+
() => resolveShellCommandActivities({ activities, views }, contextKeySnapshot),
|
|
148
|
+
[activities, contextKeySnapshot, views],
|
|
145
149
|
);
|
|
146
150
|
const visibleShellActivityIdSet = new Set(visibleShellActivities.map((activity) => activity.id));
|
|
147
151
|
const visibleShellActivitySignature = managedShellActivities
|
|
@@ -203,7 +207,7 @@ export function WorkbenchCommandHost({
|
|
|
203
207
|
|
|
204
208
|
useEffect(() => {
|
|
205
209
|
const registration = registerWorkbenchShellCommandHandlers(
|
|
206
|
-
|
|
210
|
+
commands,
|
|
207
211
|
shellCommandDefinitions,
|
|
208
212
|
() => {
|
|
209
213
|
const context = shellContextRef.current;
|
|
@@ -218,14 +222,16 @@ export function WorkbenchCommandHost({
|
|
|
218
222
|
return () => {
|
|
219
223
|
registration.dispose();
|
|
220
224
|
};
|
|
221
|
-
}, [
|
|
225
|
+
}, [commands, shellCommandDefinitions]);
|
|
222
226
|
|
|
223
227
|
const paletteCommands = useMemo(
|
|
224
228
|
() =>
|
|
225
229
|
buildWorkbenchPaletteCommands({
|
|
226
230
|
additionalCommands,
|
|
227
|
-
extensionCommandFeaturesById: collectExtensionCommandFeaturesById(
|
|
228
|
-
|
|
231
|
+
extensionCommandFeaturesById: collectExtensionCommandFeaturesById(
|
|
232
|
+
extensionCatalog.getFeatureSpecs(),
|
|
233
|
+
),
|
|
234
|
+
extensionCommands: commands
|
|
229
235
|
.getCommands()
|
|
230
236
|
.filter((command) => !managedShellCommandIds.has(command.id)),
|
|
231
237
|
shellCommands: shellCommandDefinitions,
|
|
@@ -233,7 +239,8 @@ export function WorkbenchCommandHost({
|
|
|
233
239
|
}),
|
|
234
240
|
[
|
|
235
241
|
additionalCommands,
|
|
236
|
-
|
|
242
|
+
commands,
|
|
243
|
+
extensionCatalog,
|
|
237
244
|
managedShellCommandIds,
|
|
238
245
|
shellContext,
|
|
239
246
|
shellCommandDefinitions,
|
|
@@ -356,12 +363,7 @@ export function WorkbenchCommandHost({
|
|
|
356
363
|
return;
|
|
357
364
|
}
|
|
358
365
|
|
|
359
|
-
const match = resolveExtensionKeybindingCommand(
|
|
360
|
-
extensionRegistry.keybindings,
|
|
361
|
-
event,
|
|
362
|
-
{},
|
|
363
|
-
keybindingOverrides,
|
|
364
|
-
);
|
|
366
|
+
const match = resolveExtensionKeybindingCommand(keybindings, event, {}, keybindingOverrides);
|
|
365
367
|
if (!match) {
|
|
366
368
|
return;
|
|
367
369
|
}
|
|
@@ -374,12 +376,7 @@ export function WorkbenchCommandHost({
|
|
|
374
376
|
return () => {
|
|
375
377
|
window.removeEventListener('keydown', onKeyDown);
|
|
376
378
|
};
|
|
377
|
-
}, [
|
|
378
|
-
enableExtensionKeybindings,
|
|
379
|
-
executeCommand,
|
|
380
|
-
extensionRegistry.keybindings,
|
|
381
|
-
keybindingOverrides,
|
|
382
|
-
]);
|
|
379
|
+
}, [enableExtensionKeybindings, executeCommand, keybindings, keybindingOverrides]);
|
|
383
380
|
|
|
384
381
|
return (
|
|
385
382
|
<>
|
|
@@ -7,10 +7,13 @@ import type {
|
|
|
7
7
|
import {
|
|
8
8
|
filterActivitiesByWhenClause,
|
|
9
9
|
type ExtensionCommandFeatureSpec,
|
|
10
|
-
type
|
|
10
|
+
type ActivityRegistry,
|
|
11
|
+
type ExtensionFeatureSpec,
|
|
12
|
+
type ViewRegistry,
|
|
11
13
|
} from '@workbench-kit/workbench-core';
|
|
14
|
+
import type { CommandRegistry } from '@workbench-kit/platform';
|
|
12
15
|
|
|
13
|
-
type ExtensionCommand = ReturnType<
|
|
16
|
+
type ExtensionCommand = ReturnType<CommandRegistry['getCommands']>[number];
|
|
14
17
|
|
|
15
18
|
function resolveCommandValue<TContext, TValue>(
|
|
16
19
|
value: CommandDefinition<TContext>[keyof CommandDefinition<TContext>],
|
|
@@ -44,10 +47,10 @@ export function resolveExtensionCommandIcon(icon: ExtensionCommand['icon']): str
|
|
|
44
47
|
}
|
|
45
48
|
|
|
46
49
|
export function resolveShellCommandActivities(
|
|
47
|
-
|
|
50
|
+
registries: { readonly activities: ActivityRegistry; readonly views: ViewRegistry },
|
|
48
51
|
contextKeys?: object | undefined,
|
|
49
52
|
): WorkbenchShellCommandActivity[] {
|
|
50
|
-
const activities =
|
|
53
|
+
const activities = registries.activities.getActivities();
|
|
51
54
|
if (activities.length > 0) {
|
|
52
55
|
const visibleActivities =
|
|
53
56
|
contextKeys === undefined
|
|
@@ -63,13 +66,11 @@ export function resolveShellCommandActivities(
|
|
|
63
66
|
.sort((left, right) => left.label.localeCompare(right.label));
|
|
64
67
|
}
|
|
65
68
|
|
|
66
|
-
const viewContainerIds = new Set(
|
|
67
|
-
extensionRegistry.views.getViews().map((view) => view.containerId),
|
|
68
|
-
);
|
|
69
|
+
const viewContainerIds = new Set(registries.views.getViews().map((view) => view.containerId));
|
|
69
70
|
|
|
70
71
|
return [...viewContainerIds].map((containerId) => {
|
|
71
|
-
const container =
|
|
72
|
-
const firstView =
|
|
72
|
+
const container = registries.views.getViewContainer(containerId);
|
|
73
|
+
const firstView = registries.views.getViews(containerId)[0];
|
|
73
74
|
|
|
74
75
|
return {
|
|
75
76
|
icon: formatWorkbenchCommandIcon(container?.icon ?? 'files'),
|
|
@@ -125,12 +126,12 @@ export function extensionCommandToDescriptor(
|
|
|
125
126
|
}
|
|
126
127
|
|
|
127
128
|
export function collectExtensionCommandFeaturesById(
|
|
128
|
-
|
|
129
|
+
featureSpecs: readonly ExtensionFeatureSpec[],
|
|
129
130
|
): ReadonlyMap<string, ExtensionCommandFeatureSpec> {
|
|
130
131
|
return new Map(
|
|
131
|
-
|
|
132
|
-
.
|
|
133
|
-
|
|
132
|
+
featureSpecs.flatMap((feature) =>
|
|
133
|
+
feature.commands.map((command) => [command.id, command] as const),
|
|
134
|
+
),
|
|
134
135
|
);
|
|
135
136
|
}
|
|
136
137
|
|
|
@@ -7,6 +7,11 @@ import {
|
|
|
7
7
|
type WorkbenchLayoutState,
|
|
8
8
|
type WorkbenchLayoutStateInput,
|
|
9
9
|
} from '@workbench-kit/workbench-core/layout';
|
|
10
|
+
import type {
|
|
11
|
+
WorkbenchPersistenceDiagnosticOptions,
|
|
12
|
+
WorkbenchPersistenceReadResult,
|
|
13
|
+
WorkbenchPersistenceWriteResult,
|
|
14
|
+
} from '@workbench-kit/workbench-core';
|
|
10
15
|
import type {
|
|
11
16
|
WorkbenchStorageReader,
|
|
12
17
|
WorkbenchStorageWriter,
|
|
@@ -14,8 +19,10 @@ import type {
|
|
|
14
19
|
|
|
15
20
|
import {
|
|
16
21
|
readLocalJsonStorage,
|
|
22
|
+
readLocalJsonStorageResult,
|
|
17
23
|
resolveLocalWorkbenchStorage,
|
|
18
24
|
writeLocalJsonStorage,
|
|
25
|
+
writeLocalJsonStorageResult,
|
|
19
26
|
} from '../storage/local-json-storage.js';
|
|
20
27
|
|
|
21
28
|
export const DEFAULT_WORKBENCH_LAYOUT_STORAGE_KEY = 'workbench-kit/.workbench/layout';
|
|
@@ -96,6 +103,20 @@ export function readPersistedWorkbenchLayout(
|
|
|
96
103
|
);
|
|
97
104
|
}
|
|
98
105
|
|
|
106
|
+
export function readPersistedWorkbenchLayoutResult(
|
|
107
|
+
storageKey = DEFAULT_WORKBENCH_LAYOUT_STORAGE_KEY,
|
|
108
|
+
storage?: WorkbenchStorageReader,
|
|
109
|
+
options: WorkbenchPersistenceDiagnosticOptions = {},
|
|
110
|
+
): WorkbenchPersistenceReadResult<WorkbenchLayoutStateInput | undefined> {
|
|
111
|
+
return readLocalJsonStorageResult(
|
|
112
|
+
storageKey,
|
|
113
|
+
(value) => workbenchLayoutConfigToInput(parseWorkbenchLayoutConfig(value)),
|
|
114
|
+
() => undefined,
|
|
115
|
+
storage,
|
|
116
|
+
options,
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
|
|
99
120
|
export function writePersistedWorkbenchLayout(
|
|
100
121
|
state: WorkbenchLayoutState,
|
|
101
122
|
storageKey = DEFAULT_WORKBENCH_LAYOUT_STORAGE_KEY,
|
|
@@ -106,6 +127,18 @@ export function writePersistedWorkbenchLayout(
|
|
|
106
127
|
});
|
|
107
128
|
}
|
|
108
129
|
|
|
130
|
+
export function writePersistedWorkbenchLayoutResult(
|
|
131
|
+
state: WorkbenchLayoutState,
|
|
132
|
+
storageKey = DEFAULT_WORKBENCH_LAYOUT_STORAGE_KEY,
|
|
133
|
+
storage?: WorkbenchStorageWriter,
|
|
134
|
+
options: WorkbenchPersistenceDiagnosticOptions = {},
|
|
135
|
+
): WorkbenchPersistenceWriteResult {
|
|
136
|
+
return writeLocalJsonStorageResult(storageKey, state, storage, {
|
|
137
|
+
...options,
|
|
138
|
+
toStorageValue: workbenchLayoutStateToStorageValue,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
|
|
109
142
|
export function resolvePersistedWorkbenchLayout(
|
|
110
143
|
initialLayout: WorkbenchLayoutStateInput | undefined,
|
|
111
144
|
options: {
|
|
@@ -114,6 +147,17 @@ export function resolvePersistedWorkbenchLayout(
|
|
|
114
147
|
storageKey?: string | undefined;
|
|
115
148
|
} = {},
|
|
116
149
|
): WorkbenchLayoutStateInput | undefined {
|
|
150
|
+
return resolvePersistedWorkbenchLayoutResult(initialLayout, options).value;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export function resolvePersistedWorkbenchLayoutResult(
|
|
154
|
+
initialLayout: WorkbenchLayoutStateInput | undefined,
|
|
155
|
+
options: {
|
|
156
|
+
persistLayout?: boolean | undefined;
|
|
157
|
+
storage?: WorkbenchStorageReader | undefined;
|
|
158
|
+
storageKey?: string | undefined;
|
|
159
|
+
} = {},
|
|
160
|
+
): WorkbenchPersistenceReadResult<WorkbenchLayoutStateInput | undefined> {
|
|
117
161
|
const {
|
|
118
162
|
initialLayout: baseLayout,
|
|
119
163
|
persistLayout = options.storage !== undefined || isWorkbenchLayoutPersistenceAvailable(),
|
|
@@ -122,13 +166,16 @@ export function resolvePersistedWorkbenchLayout(
|
|
|
122
166
|
} = { initialLayout, ...options };
|
|
123
167
|
|
|
124
168
|
if (!persistLayout) {
|
|
125
|
-
return baseLayout;
|
|
169
|
+
return { value: baseLayout };
|
|
126
170
|
}
|
|
127
171
|
|
|
128
|
-
const
|
|
129
|
-
if (!
|
|
130
|
-
return baseLayout;
|
|
172
|
+
const result = readPersistedWorkbenchLayoutResult(storageKey, storage);
|
|
173
|
+
if (!result.value) {
|
|
174
|
+
return { ...result, value: baseLayout };
|
|
131
175
|
}
|
|
132
176
|
|
|
133
|
-
return
|
|
177
|
+
return {
|
|
178
|
+
...result,
|
|
179
|
+
value: createWorkbenchLayoutState(result.value, createWorkbenchLayoutState(baseLayout ?? {})),
|
|
180
|
+
};
|
|
134
181
|
}
|
|
@@ -1,33 +1,59 @@
|
|
|
1
|
-
import { useEffect, useState } from 'react';
|
|
2
|
-
import type {
|
|
1
|
+
import { useCallback, useEffect, useState } from 'react';
|
|
2
|
+
import type {
|
|
3
|
+
WorkbenchPersistenceDiagnosticHandler,
|
|
4
|
+
WorkbenchStorageAdapter,
|
|
5
|
+
} from '@workbench-kit/workbench-core';
|
|
3
6
|
|
|
4
7
|
import {
|
|
5
|
-
|
|
6
|
-
|
|
8
|
+
readPersistedWorkbenchAppearanceResult,
|
|
9
|
+
writePersistedWorkbenchAppearanceResult,
|
|
7
10
|
type WorkbenchAppearanceSettings,
|
|
8
11
|
} from './appearance-storage.js';
|
|
12
|
+
import {
|
|
13
|
+
reportPersistenceWriteResult,
|
|
14
|
+
usePersistenceDiagnosticHandlerRef,
|
|
15
|
+
useReportPersistenceReadDiagnostic,
|
|
16
|
+
} from '../storage/persistence-diagnostics.js';
|
|
9
17
|
|
|
10
18
|
export interface UsePersistedWorkbenchAppearanceOptions {
|
|
19
|
+
onPersistenceDiagnostic?: WorkbenchPersistenceDiagnosticHandler | undefined;
|
|
11
20
|
persist?: boolean | undefined;
|
|
12
21
|
storage?: WorkbenchStorageAdapter | undefined;
|
|
13
22
|
storageKey?: string | undefined;
|
|
14
23
|
}
|
|
15
24
|
|
|
25
|
+
interface PersistedWorkbenchAppearanceState {
|
|
26
|
+
readonly appearance: WorkbenchAppearanceSettings;
|
|
27
|
+
readonly writeEligible: boolean;
|
|
28
|
+
}
|
|
29
|
+
|
|
16
30
|
export function usePersistedWorkbenchAppearance(
|
|
17
31
|
options: UsePersistedWorkbenchAppearanceOptions = {},
|
|
18
32
|
): [WorkbenchAppearanceSettings, (settings: WorkbenchAppearanceSettings) => void] {
|
|
19
|
-
const { persist = true, storage, storageKey } = options;
|
|
20
|
-
const [
|
|
21
|
-
|
|
22
|
-
|
|
33
|
+
const { onPersistenceDiagnostic, persist = true, storage, storageKey } = options;
|
|
34
|
+
const [initialRead] = useState(() => readPersistedWorkbenchAppearanceResult(storageKey, storage));
|
|
35
|
+
const [state, setState] = useState<PersistedWorkbenchAppearanceState>(() => ({
|
|
36
|
+
appearance: initialRead.value,
|
|
37
|
+
writeEligible: initialRead.diagnostic === undefined,
|
|
38
|
+
}));
|
|
39
|
+
const diagnosticHandlerRef = usePersistenceDiagnosticHandlerRef(onPersistenceDiagnostic);
|
|
40
|
+
|
|
41
|
+
useReportPersistenceReadDiagnostic(initialRead.diagnostic, [], diagnosticHandlerRef);
|
|
23
42
|
|
|
24
43
|
useEffect(() => {
|
|
25
|
-
if (!persist) {
|
|
44
|
+
if (!persist || !state.writeEligible) {
|
|
26
45
|
return;
|
|
27
46
|
}
|
|
28
47
|
|
|
29
|
-
|
|
30
|
-
|
|
48
|
+
reportPersistenceWriteResult(
|
|
49
|
+
writePersistedWorkbenchAppearanceResult(state.appearance, storageKey, storage),
|
|
50
|
+
diagnosticHandlerRef,
|
|
51
|
+
);
|
|
52
|
+
}, [diagnosticHandlerRef, persist, state, storage, storageKey]);
|
|
53
|
+
|
|
54
|
+
const setAppearance = useCallback((appearance: WorkbenchAppearanceSettings) => {
|
|
55
|
+
setState({ appearance, writeEligible: true });
|
|
56
|
+
}, []);
|
|
31
57
|
|
|
32
|
-
return [appearance, setAppearance];
|
|
58
|
+
return [state.appearance, setAppearance];
|
|
33
59
|
}
|