@konitif/workbench-runtime 0.284.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.
Files changed (57) hide show
  1. package/LICENSE.md +22 -0
  2. package/README.md +60 -0
  3. package/dist/boot/createDemoWorkbenchBootGraph.d.ts +9 -0
  4. package/dist/boot/createDemoWorkbenchBootGraph.js +180 -0
  5. package/dist/boot/createLegacyWorkbenchBootGraph.d.ts +34 -0
  6. package/dist/boot/createLegacyWorkbenchBootGraph.js +321 -0
  7. package/dist/boot/createWorkbenchBootSession.d.ts +23 -0
  8. package/dist/boot/createWorkbenchBootSession.js +90 -0
  9. package/dist/boot/index.d.ts +3 -0
  10. package/dist/boot/index.js +3 -0
  11. package/dist/index.d.ts +10 -0
  12. package/dist/index.js +9 -0
  13. package/dist/runtime.d.ts +7 -0
  14. package/dist/runtime.js +2 -0
  15. package/dist/workbench/browserDetachedWindowHost.d.ts +3 -0
  16. package/dist/workbench/browserDetachedWindowHost.js +69 -0
  17. package/dist/workbench/browserWorkbenchHostEvents.d.ts +3 -0
  18. package/dist/workbench/browserWorkbenchHostEvents.js +35 -0
  19. package/dist/workbench/createWorkbenchStore.d.ts +129 -0
  20. package/dist/workbench/createWorkbenchStore.js +50 -0
  21. package/dist/workbench/createWorkbenchStoreRuntime.d.ts +154 -0
  22. package/dist/workbench/createWorkbenchStoreRuntime.js +242 -0
  23. package/dist/workbench/createWorkspaceModeController.d.ts +36 -0
  24. package/dist/workbench/createWorkspaceModeController.js +168 -0
  25. package/dist/workbench/workbenchDetachedWindowHost.d.ts +16 -0
  26. package/dist/workbench/workbenchDetachedWindowHost.js +1 -0
  27. package/dist/workbench/workbenchFocusPersistence.d.ts +15 -0
  28. package/dist/workbench/workbenchFocusPersistence.js +44 -0
  29. package/dist/workbench/workbenchHistoryActions.d.ts +21 -0
  30. package/dist/workbench/workbenchHistoryActions.js +45 -0
  31. package/dist/workbench/workbenchHistoryRuntime.d.ts +16 -0
  32. package/dist/workbench/workbenchHistoryRuntime.js +42 -0
  33. package/dist/workbench/workbenchHostEvents.d.ts +13 -0
  34. package/dist/workbench/workbenchHostEvents.js +1 -0
  35. package/dist/workbench/workbenchLayoutActions.d.ts +84 -0
  36. package/dist/workbench/workbenchLayoutActions.js +191 -0
  37. package/dist/workbench/workbenchPersistenceRuntime.d.ts +39 -0
  38. package/dist/workbench/workbenchPersistenceRuntime.js +168 -0
  39. package/dist/workbench/workbenchShellActions.d.ts +24 -0
  40. package/dist/workbench/workbenchShellActions.js +63 -0
  41. package/dist/workbench/workbenchShellPersistence.d.ts +18 -0
  42. package/dist/workbench/workbenchShellPersistence.js +124 -0
  43. package/dist/workbench/workbenchStateFactory.d.ts +22 -0
  44. package/dist/workbench/workbenchStateFactory.js +47 -0
  45. package/dist/workbench/workbenchToolRuntimeActions.d.ts +23 -0
  46. package/dist/workbench/workbenchToolRuntimeActions.js +98 -0
  47. package/dist/workbench/workbenchToolRuntimeUiStore.d.ts +17 -0
  48. package/dist/workbench/workbenchToolRuntimeUiStore.js +85 -0
  49. package/dist/workbench/workbenchWindowRuntime.d.ts +19 -0
  50. package/dist/workbench/workbenchWindowRuntime.js +85 -0
  51. package/dist/workbench/workbenchWorkspaceActions.d.ts +30 -0
  52. package/dist/workbench/workbenchWorkspaceActions.js +55 -0
  53. package/dist/workbench/workspaceHistoryController.d.ts +28 -0
  54. package/dist/workbench/workspaceHistoryController.js +126 -0
  55. package/dist/workbench/workspaceSyncController.d.ts +20 -0
  56. package/dist/workbench/workspaceSyncController.js +105 -0
  57. package/package.json +49 -0
@@ -0,0 +1,124 @@
1
+ export function createLocalWorkbenchShellPersistence(options) {
2
+ return {
3
+ load(fallback) {
4
+ if (!isEnabled(options) || typeof localStorage === 'undefined') {
5
+ return fallback;
6
+ }
7
+ try {
8
+ const rawShell = localStorage.getItem(options.storageKey);
9
+ if (!rawShell) {
10
+ return fallback;
11
+ }
12
+ return normalizePersistedShellState(JSON.parse(rawShell), fallback, {
13
+ shellWidgetCatalog: options.shellWidgetCatalog
14
+ });
15
+ }
16
+ catch {
17
+ return fallback;
18
+ }
19
+ },
20
+ save(shell) {
21
+ if (!isEnabled(options) || typeof localStorage === 'undefined') {
22
+ return;
23
+ }
24
+ localStorage.setItem(options.storageKey, serializeShellState(shell));
25
+ },
26
+ serialize: serializeShellState,
27
+ normalize(input, fallback) {
28
+ return normalizePersistedShellState(input, fallback, {
29
+ shellWidgetCatalog: options.shellWidgetCatalog
30
+ });
31
+ }
32
+ };
33
+ }
34
+ export function serializeShellState(shell) {
35
+ return JSON.stringify(shell);
36
+ }
37
+ export function normalizePersistedShellState(input, fallback, options = {}) {
38
+ if (!input || typeof input !== 'object' || Array.isArray(input)) {
39
+ return fallback;
40
+ }
41
+ const persistedRegions = input.regions;
42
+ if (!persistedRegions || typeof persistedRegions !== 'object' || Array.isArray(persistedRegions)) {
43
+ return fallback;
44
+ }
45
+ const regionIds = ['left', 'right', 'bottom'];
46
+ return {
47
+ regions: Object.fromEntries(regionIds.map((regionId) => {
48
+ const fallbackRegion = fallback.regions[regionId];
49
+ const persistedRegion = persistedRegions[regionId];
50
+ if (!persistedRegion || typeof persistedRegion !== 'object' || Array.isArray(persistedRegion)) {
51
+ return [regionId, fallbackRegion];
52
+ }
53
+ const nextWidgetIds = normalizePersistedShellWidgetIds(persistedRegion.widgetIds, fallbackRegion.widgetIds, options.shellWidgetCatalog);
54
+ const isVisible = typeof persistedRegion.isVisible === 'boolean'
55
+ ? persistedRegion.isVisible
56
+ : fallbackRegion.isVisible;
57
+ const activeWidgetId = typeof persistedRegion.activeWidgetId === 'string' && nextWidgetIds.includes(persistedRegion.activeWidgetId)
58
+ ? persistedRegion.activeWidgetId
59
+ : nextWidgetIds.includes(fallbackRegion.activeWidgetId ?? '')
60
+ ? fallbackRegion.activeWidgetId
61
+ : nextWidgetIds[0] ?? null;
62
+ const minimumSize = regionId === 'bottom' ? 140 : 180;
63
+ const size = typeof persistedRegion.size === 'number' && Number.isFinite(persistedRegion.size)
64
+ ? Math.max(minimumSize, Math.round(persistedRegion.size))
65
+ : fallbackRegion.size;
66
+ const hiddenWidgetIds = normalizePersistedShellWidgetIds(persistedRegion.hiddenWidgetIds, [], options.shellWidgetCatalog).filter((widgetId) => nextWidgetIds.includes(widgetId));
67
+ const presentation = persistedRegion.presentation === 'stack' || persistedRegion.presentation === 'tabs'
68
+ ? persistedRegion.presentation
69
+ : fallbackRegion.presentation;
70
+ const axis = persistedRegion.axis === 'horizontal' || persistedRegion.axis === 'vertical'
71
+ ? persistedRegion.axis
72
+ : fallbackRegion.axis;
73
+ const visibleWidgetIds = nextWidgetIds.filter((widgetId) => !hiddenWidgetIds.includes(widgetId));
74
+ const visibleActiveWidgetId = activeWidgetId && visibleWidgetIds.includes(activeWidgetId)
75
+ ? activeWidgetId
76
+ : visibleWidgetIds[0] ?? null;
77
+ return [
78
+ regionId,
79
+ {
80
+ ...fallbackRegion,
81
+ isVisible: visibleWidgetIds.length > 0 && isVisible,
82
+ isOpen: visibleWidgetIds.length > 0 && isVisible
83
+ ? typeof persistedRegion.isOpen === 'boolean'
84
+ ? persistedRegion.isOpen
85
+ : fallbackRegion.isOpen
86
+ : false,
87
+ size,
88
+ activeWidgetId: visibleActiveWidgetId,
89
+ widgetIds: nextWidgetIds,
90
+ hiddenWidgetIds,
91
+ presentation,
92
+ axis
93
+ }
94
+ ];
95
+ }))
96
+ };
97
+ }
98
+ function isEnabled(options) {
99
+ return options.isEnabled?.() ?? true;
100
+ }
101
+ function normalizePersistedShellWidgetIds(input, fallbackWidgetIds, shellWidgetCatalog) {
102
+ if (!Array.isArray(input)) {
103
+ return fallbackWidgetIds;
104
+ }
105
+ const normalizedWidgetIds = [];
106
+ for (const value of input) {
107
+ if (typeof value !== 'string') {
108
+ continue;
109
+ }
110
+ const widgetId = value.trim();
111
+ if (widgetId &&
112
+ !normalizedWidgetIds.includes(widgetId) &&
113
+ isKnownShellWidgetId(widgetId, fallbackWidgetIds, shellWidgetCatalog)) {
114
+ normalizedWidgetIds.push(widgetId);
115
+ }
116
+ }
117
+ return normalizedWidgetIds;
118
+ }
119
+ function isKnownShellWidgetId(widgetId, fallbackWidgetIds, shellWidgetCatalog) {
120
+ if (fallbackWidgetIds.includes(widgetId)) {
121
+ return true;
122
+ }
123
+ return Boolean(shellWidgetCatalog?.getDefinition(widgetId));
124
+ }
@@ -0,0 +1,22 @@
1
+ import { type LayoutInteractionState, type ShellRegionId, type ShellState, type ShellWidgetCatalog, type ToolCatalog, type Workspace, type WorkspaceSessionState } from '@konitif/workbench/workspace-contracts';
2
+ import type { InitialWorkbenchWorkspaceMode } from "./workbenchWorkspaceActions.js";
3
+ export interface WorkbenchState {
4
+ workspace: WorkspaceSessionState['workspace'];
5
+ focus: WorkspaceSessionState['focus'];
6
+ shell: ShellState;
7
+ layoutInteraction: LayoutInteractionState;
8
+ }
9
+ export interface CreateWorkbenchStateFactoryInput {
10
+ initialToolId: string;
11
+ toolCatalog: ToolCatalog;
12
+ shellWidgetCatalog: ShellWidgetCatalog;
13
+ initialWorkspaceMode?: InitialWorkbenchWorkspaceMode;
14
+ initialStackHeaderVisible?: boolean;
15
+ defaultOpenShellRegions?: ShellRegionId[];
16
+ }
17
+ export interface WorkbenchStateFactory {
18
+ createInitialWorkspace(mode?: InitialWorkbenchWorkspaceMode): Workspace;
19
+ createShellFallback(): ShellState;
20
+ createWorkbenchState(workspaceSession?: WorkspaceSessionState, shellState?: ShellState, layoutInteraction?: LayoutInteractionState): WorkbenchState;
21
+ }
22
+ export declare function createWorkbenchStateFactory(input: CreateWorkbenchStateFactoryInput): WorkbenchStateFactory;
@@ -0,0 +1,47 @@
1
+ import { createLayoutInteractionState, createShellState, createWorkspace, createWorkspaceSessionState, normalizeWorkspaceFullscreenPanel } from '@konitif/workbench/workspace-contracts';
2
+ export function createWorkbenchStateFactory(input) {
3
+ function createInitialWorkspace(mode = input.initialWorkspaceMode ?? 'tool') {
4
+ const workspace = mode === 'empty'
5
+ ? createWorkspace()
6
+ : createWorkspace(input.toolCatalog, { initialToolId: input.initialToolId });
7
+ return applyInitialWorkspacePreferences(workspace);
8
+ }
9
+ function createShellFallback() {
10
+ return createShellState(input.shellWidgetCatalog, { openRegionIds: input.defaultOpenShellRegions });
11
+ }
12
+ function createWorkbenchState(workspaceSession = createWorkspaceSessionState(createInitialWorkspace()), shellState = createShellFallback(), layoutInteraction = createLayoutInteractionState()) {
13
+ const normalizedWorkspace = normalizeWorkspaceFullscreenPanel(workspaceSession.workspace);
14
+ const normalizedSession = createWorkspaceSessionState(normalizedWorkspace, workspaceSession.focus);
15
+ return {
16
+ workspace: normalizedSession.workspace,
17
+ focus: normalizedSession.focus,
18
+ shell: shellState,
19
+ layoutInteraction
20
+ };
21
+ }
22
+ function applyInitialWorkspacePreferences(workspace) {
23
+ if (typeof input.initialStackHeaderVisible !== 'boolean') {
24
+ return workspace;
25
+ }
26
+ return {
27
+ ...workspace,
28
+ windows: workspace.windows.map((window) => {
29
+ if (window.id !== workspace.activeWindowId || window.root.kind !== 'stack') {
30
+ return window;
31
+ }
32
+ return {
33
+ ...window,
34
+ root: {
35
+ ...window.root,
36
+ headerVisible: input.initialStackHeaderVisible
37
+ }
38
+ };
39
+ })
40
+ };
41
+ }
42
+ return {
43
+ createInitialWorkspace,
44
+ createShellFallback,
45
+ createWorkbenchState
46
+ };
47
+ }
@@ -0,0 +1,23 @@
1
+ import { createWorkspaceSessionState, type LayoutInteractionState, type ShellState, type ToolCatalog, type ToolPanelLoadingState, type ToolResourceLoadingState, type ToolRuntimeHostActions, type ToolShellStatus, type Workspace, type WorkspaceFocus } from '@konitif/workbench/workspace-contracts';
2
+ import type { WorkbenchHistoryScope, WorkspaceHistoryController } from "./workspaceHistoryController.js";
3
+ export interface WorkbenchToolRuntimeState {
4
+ workspace: Workspace;
5
+ focus: WorkspaceFocus;
6
+ shell: ShellState;
7
+ layoutInteraction: LayoutInteractionState;
8
+ }
9
+ export interface CreateWorkbenchToolRuntimeActionsInput<TState extends WorkbenchToolRuntimeState, TSnapshot> {
10
+ toolCatalog: ToolCatalog;
11
+ workspaceHistory: WorkspaceHistoryController<TSnapshot>;
12
+ getWorkbenchState(): TState;
13
+ createHistorySnapshot(state: TState): TSnapshot;
14
+ restoreHistorySnapshot(snapshot: TSnapshot): TState;
15
+ createWorkbenchState(workspaceSession: ReturnType<typeof createWorkspaceSessionState>, shell: ShellState, layoutInteraction: LayoutInteractionState): TState;
16
+ updateWorkbenchState(updater: (state: TState) => TState, historyScope?: WorkbenchHistoryScope): void;
17
+ setWorkbenchState(nextState: TState, historyScope?: WorkbenchHistoryScope): void;
18
+ syncHistoryStatus(): void;
19
+ setToolPanelLoadingState(toolInstanceId: string, nextLoading: ToolPanelLoadingState | null): boolean;
20
+ setToolResourceLoadingState(toolInstanceId: string, nextLoading: ToolResourceLoadingState | null): boolean;
21
+ setToolShellStatusState(toolInstanceId: string, nextStatus: ToolShellStatus | null): boolean;
22
+ }
23
+ export declare function createWorkbenchToolRuntimeActions<TState extends WorkbenchToolRuntimeState, TSnapshot>(input: CreateWorkbenchToolRuntimeActionsInput<TState, TSnapshot>): ToolRuntimeHostActions;
@@ -0,0 +1,98 @@
1
+ import { createWorkspaceSessionState, dispatchWorkspaceCommand, runToolShellCommand, setToolPanelTitleOverride, updateToolState } from '@konitif/workbench/workspace-contracts';
2
+ export function createWorkbenchToolRuntimeActions(input) {
3
+ return {
4
+ updateToolState(toolInstanceId, nextState) {
5
+ let didUpdate = false;
6
+ input.updateWorkbenchState((state) => {
7
+ const nextWorkspace = updateToolState(state.workspace, { toolInstanceId, nextState });
8
+ didUpdate = nextWorkspace !== state.workspace;
9
+ return didUpdate
10
+ ? input.createWorkbenchState(createWorkspaceSessionState(nextWorkspace, state.focus), state.shell, state.layoutInteraction)
11
+ : state;
12
+ }, 'app');
13
+ return didUpdate;
14
+ },
15
+ setToolPanelTitleOverride(panelId, toolInstanceId, nextTitle) {
16
+ let didUpdate = false;
17
+ input.updateWorkbenchState((state) => {
18
+ const nextWorkspace = setToolPanelTitleOverride(state.workspace, {
19
+ panelId,
20
+ toolInstanceId,
21
+ panelTitleOverride: nextTitle
22
+ }, input.toolCatalog);
23
+ didUpdate = nextWorkspace !== state.workspace;
24
+ return didUpdate
25
+ ? input.createWorkbenchState(createWorkspaceSessionState(nextWorkspace, state.focus), state.shell, state.layoutInteraction)
26
+ : state;
27
+ }, 'app');
28
+ return didUpdate;
29
+ },
30
+ setToolShellStatus(toolInstanceId, nextStatus) {
31
+ const toolInstance = input.getWorkbenchState().workspace.toolInstances[toolInstanceId];
32
+ if (!toolInstance)
33
+ return false;
34
+ const definition = input.toolCatalog.getDefinition(toolInstance.toolId);
35
+ // A status rendered by the Tool itself has no shell consumer. Publishing
36
+ // it globally would invalidate every panel for a purely local projection.
37
+ if (definition?.shell?.statusPlacement === 'tool-header')
38
+ return true;
39
+ return input.setToolShellStatusState(toolInstanceId, nextStatus);
40
+ },
41
+ setToolPanelLoading(toolInstanceId, nextLoading) {
42
+ return input.setToolPanelLoadingState(toolInstanceId, nextLoading);
43
+ },
44
+ setToolResourceLoading(toolInstanceId, nextLoading) {
45
+ return input.setToolResourceLoadingState(toolInstanceId, nextLoading);
46
+ },
47
+ runToolCommand(panelId, toolInstanceId, commandId) {
48
+ let didUpdate = false;
49
+ input.updateWorkbenchState((state) => {
50
+ const nextWorkspace = runToolShellCommand(state.workspace, {
51
+ panelId,
52
+ toolInstanceId,
53
+ commandId
54
+ }, input.toolCatalog);
55
+ didUpdate = nextWorkspace !== state.workspace;
56
+ return didUpdate
57
+ ? input.createWorkbenchState(createWorkspaceSessionState(nextWorkspace, state.focus), state.shell, state.layoutInteraction)
58
+ : state;
59
+ }, 'app');
60
+ return didUpdate;
61
+ },
62
+ openTool(toolId) {
63
+ let didUpdate = false;
64
+ input.updateWorkbenchState((state) => {
65
+ const nextSession = dispatchWorkspaceCommand(state, { type: 'open-tool', toolId }, { toolCatalog: input.toolCatalog });
66
+ didUpdate = nextSession.workspace !== state.workspace || nextSession.focus !== state.focus;
67
+ return didUpdate
68
+ ? input.createWorkbenchState(nextSession, state.shell, state.layoutInteraction)
69
+ : state;
70
+ }, 'app');
71
+ return didUpdate;
72
+ },
73
+ canUndoHistory() {
74
+ return input.workspaceHistory.getStatus().app.canUndo;
75
+ },
76
+ canRedoHistory() {
77
+ return input.workspaceHistory.getStatus().app.canRedo;
78
+ },
79
+ undoHistory() {
80
+ const snapshot = input.workspaceHistory.undo('app', input.createHistorySnapshot(input.getWorkbenchState()));
81
+ if (!snapshot) {
82
+ return false;
83
+ }
84
+ input.setWorkbenchState(input.restoreHistorySnapshot(snapshot), 'none');
85
+ input.syncHistoryStatus();
86
+ return true;
87
+ },
88
+ redoHistory() {
89
+ const snapshot = input.workspaceHistory.redo('app', input.createHistorySnapshot(input.getWorkbenchState()));
90
+ if (!snapshot) {
91
+ return false;
92
+ }
93
+ input.setWorkbenchState(input.restoreHistorySnapshot(snapshot), 'none');
94
+ input.syncHistoryStatus();
95
+ return true;
96
+ }
97
+ };
98
+ }
@@ -0,0 +1,17 @@
1
+ import { writable } from 'svelte/store';
2
+ import { type ToolPanelLoadingState, type ToolResourceLoadingState, type ToolShellStatus, type Workspace } from '@konitif/workbench/workspace-contracts';
3
+ export interface ToolRuntimeUiState {
4
+ panelLoading: ToolPanelLoadingState | null;
5
+ resourceLoading: ToolResourceLoadingState | null;
6
+ shellStatus?: ToolShellStatus | null;
7
+ }
8
+ export type ToolRuntimeUiStateMap = Record<string, ToolRuntimeUiState | undefined>;
9
+ export interface WorkbenchToolRuntimeUiStore {
10
+ store: ReturnType<typeof writable<ToolRuntimeUiStateMap>>;
11
+ reset(): void;
12
+ prune(toolInstances: Workspace['toolInstances']): void;
13
+ setToolPanelLoadingState(toolInstanceId: string, nextLoading: ToolPanelLoadingState | null): boolean;
14
+ setToolResourceLoadingState(toolInstanceId: string, nextLoading: ToolResourceLoadingState | null): boolean;
15
+ setToolShellStatus(toolInstanceId: string, nextStatus: ToolShellStatus | null): boolean;
16
+ }
17
+ export declare function createWorkbenchToolRuntimeUiStore(getWorkspace: () => Workspace): WorkbenchToolRuntimeUiStore;
@@ -0,0 +1,85 @@
1
+ import { get, writable } from 'svelte/store';
2
+ import { normalizeToolShellStatus, normalizeToolPanelLoadingState, normalizeToolResourceLoadingState } from '@konitif/workbench/workspace-contracts';
3
+ function samePanelLoadingState(left, right) {
4
+ return left?.label === right?.label && left?.detail === right?.detail;
5
+ }
6
+ function sameResourceLoadingState(left, right) {
7
+ return (left?.label === right?.label &&
8
+ left?.detail === right?.detail &&
9
+ left?.progress === right?.progress);
10
+ }
11
+ export function createWorkbenchToolRuntimeUiStore(getWorkspace) {
12
+ const store = writable({});
13
+ function updateToolRuntimeUiState(toolInstanceId, updater) {
14
+ const workspace = getWorkspace();
15
+ if (!workspace.toolInstances[toolInstanceId]) {
16
+ return false;
17
+ }
18
+ const entries = get(store);
19
+ const nextEntry = updater(entries[toolInstanceId] ?? { panelLoading: null, resourceLoading: null });
20
+ if (!nextEntry.panelLoading && !nextEntry.resourceLoading && nextEntry.shellStatus === undefined) {
21
+ if (!(toolInstanceId in entries)) {
22
+ return false;
23
+ }
24
+ const { [toolInstanceId]: _removed, ...rest } = entries;
25
+ store.set(rest);
26
+ return true;
27
+ }
28
+ const previousEntry = entries[toolInstanceId];
29
+ if (samePanelLoadingState(previousEntry?.panelLoading ?? null, nextEntry.panelLoading) &&
30
+ sameResourceLoadingState(previousEntry?.resourceLoading ?? null, nextEntry.resourceLoading) &&
31
+ previousEntry?.shellStatus?.label === nextEntry.shellStatus?.label &&
32
+ previousEntry?.shellStatus?.tone === nextEntry.shellStatus?.tone &&
33
+ (previousEntry ? 'shellStatus' in previousEntry : false) === ('shellStatus' in nextEntry)) {
34
+ return false;
35
+ }
36
+ store.set({
37
+ ...entries,
38
+ [toolInstanceId]: nextEntry
39
+ });
40
+ return true;
41
+ }
42
+ return {
43
+ store,
44
+ reset() {
45
+ store.set({});
46
+ },
47
+ prune(toolInstances) {
48
+ const activeToolInstanceIds = new Set(Object.keys(toolInstances));
49
+ store.update((entries) => {
50
+ let didChange = false;
51
+ const nextEntries = {};
52
+ for (const [toolInstanceId, entry] of Object.entries(entries)) {
53
+ if (activeToolInstanceIds.has(toolInstanceId)) {
54
+ nextEntries[toolInstanceId] = entry;
55
+ }
56
+ else {
57
+ didChange = true;
58
+ }
59
+ }
60
+ return didChange ? nextEntries : entries;
61
+ });
62
+ },
63
+ setToolPanelLoadingState(toolInstanceId, nextLoading) {
64
+ return updateToolRuntimeUiState(toolInstanceId, (state) => ({
65
+ ...state,
66
+ panelLoading: normalizeToolPanelLoadingState(nextLoading)
67
+ }));
68
+ },
69
+ setToolResourceLoadingState(toolInstanceId, nextLoading) {
70
+ return updateToolRuntimeUiState(toolInstanceId, (state) => ({
71
+ ...state,
72
+ resourceLoading: normalizeToolResourceLoadingState(nextLoading)
73
+ }));
74
+ },
75
+ setToolShellStatus(toolInstanceId, nextStatus) {
76
+ const normalizedStatus = normalizeToolShellStatus(nextStatus);
77
+ if (nextStatus !== null && normalizedStatus === null)
78
+ return false;
79
+ return updateToolRuntimeUiState(toolInstanceId, (state) => ({
80
+ ...state,
81
+ shellStatus: normalizedStatus
82
+ }));
83
+ }
84
+ };
85
+ }
@@ -0,0 +1,19 @@
1
+ import type { WorkbenchDetachedWindowHost } from "./workbenchDetachedWindowHost.js";
2
+ import { createWorkspaceSessionState, type LayoutInteractionState, type ShellState, type Workspace, type WorkspaceFocus } from '@konitif/workbench/workspace-contracts';
3
+ import type { WorkbenchHistoryScope } from "./workspaceHistoryController.js";
4
+ export interface WorkbenchWindowActionState {
5
+ workspace: Workspace;
6
+ focus: WorkspaceFocus;
7
+ shell: ShellState;
8
+ layoutInteraction: LayoutInteractionState;
9
+ }
10
+ export interface CreateWorkbenchWindowRuntimeInput<TState extends WorkbenchWindowActionState> {
11
+ detachedWindows: WorkbenchDetachedWindowHost | null;
12
+ createWorkbenchState(workspaceSession: ReturnType<typeof createWorkspaceSessionState>, shellState: ShellState, layoutInteraction: LayoutInteractionState): TState;
13
+ updateWorkbenchState(updater: (state: TState) => TState, historyScope?: WorkbenchHistoryScope): void;
14
+ flushWorkspacePersistence(): void;
15
+ }
16
+ export declare function createWorkbenchWindowRuntime<TState extends WorkbenchWindowActionState>(input: CreateWorkbenchWindowRuntimeInput<TState>): {
17
+ disposeDetachedWindowTracking(): void;
18
+ detachPanelToWindow(panelId: string): string | null;
19
+ };
@@ -0,0 +1,85 @@
1
+ import { createWorkspaceSessionState, detachPanelToWindow as detachPanelToWindowCore, dismissLayoutInteraction, getPreferredFocusedPanelId, reattachWorkspaceWindow } from '@konitif/workbench/workspace-contracts';
2
+ export function createWorkbenchWindowRuntime(input) {
3
+ if (input.detachedWindows === undefined)
4
+ throw new TypeError('detachedWindows must be supplied explicitly.');
5
+ const subscriptions = new Set();
6
+ function recover(target) {
7
+ input.updateWorkbenchState((state) => {
8
+ const workspace = reattachWorkspaceWindow(state.workspace, target);
9
+ if (workspace === state.workspace)
10
+ return state;
11
+ return input.createWorkbenchState(createWorkspaceSessionState(workspace, { activePanelId: getPreferredFocusedPanelId(workspace) }), state.shell, dismissLayoutInteraction());
12
+ }, 'app');
13
+ input.flushWorkspacePersistence();
14
+ }
15
+ function observeClosed(opening, target) {
16
+ let active = true;
17
+ let unsubscribe;
18
+ const stop = () => {
19
+ if (!active)
20
+ return;
21
+ active = false;
22
+ subscriptions.delete(stop);
23
+ unsubscribe?.();
24
+ };
25
+ subscriptions.add(stop);
26
+ try {
27
+ unsubscribe = opening.observeClosed(() => {
28
+ if (!active)
29
+ return;
30
+ stop();
31
+ recover(target);
32
+ });
33
+ // A provider may notify synchronously during subscription.
34
+ if (!active)
35
+ unsubscribe();
36
+ }
37
+ catch (error) {
38
+ stop();
39
+ throw error;
40
+ }
41
+ }
42
+ return {
43
+ disposeDetachedWindowTracking() {
44
+ for (const stop of [...subscriptions])
45
+ stop();
46
+ },
47
+ detachPanelToWindow(panelId) {
48
+ if (input.detachedWindows === null)
49
+ return null;
50
+ let detachedWindowId = null;
51
+ let recoveryTarget = null;
52
+ input.updateWorkbenchState((state) => {
53
+ const result = detachPanelToWindowCore(state.workspace, { panelId });
54
+ if (!result) {
55
+ return state;
56
+ }
57
+ detachedWindowId = result.windowId;
58
+ recoveryTarget = result;
59
+ const nextFocusedPanelId = state.focus.activePanelId === panelId
60
+ ? getPreferredFocusedPanelId(result.workspace)
61
+ : state.focus.activePanelId;
62
+ return input.createWorkbenchState(createWorkspaceSessionState(result.workspace, { activePanelId: nextFocusedPanelId ?? null }), state.shell, dismissLayoutInteraction());
63
+ }, 'app');
64
+ if (detachedWindowId) {
65
+ input.flushWorkspacePersistence();
66
+ let opening;
67
+ try {
68
+ opening = input.detachedWindows.open(detachedWindowId);
69
+ }
70
+ catch (error) {
71
+ if (recoveryTarget)
72
+ recover(recoveryTarget);
73
+ throw error;
74
+ }
75
+ if (recoveryTarget && opening.status === 'blocked') {
76
+ recover(recoveryTarget);
77
+ detachedWindowId = null;
78
+ }
79
+ else if (recoveryTarget && opening.status === 'opened')
80
+ observeClosed(opening, recoveryTarget);
81
+ }
82
+ return detachedWindowId;
83
+ }
84
+ };
85
+ }
@@ -0,0 +1,30 @@
1
+ import { type DesignSystemThemeSession, type LayoutInteractionState, type ShellState, type ToolCatalog, type Workspace, type WorkspaceCommand, type WorkspaceFocus, type WorkspacePresetId, type WorkspacePresetArtifact, type WorkspaceSessionState, type WorkspaceSnapshotImportResult } from '@konitif/workbench/workspace-contracts';
2
+ import type { WorkbenchHistoryScope } from "./workspaceHistoryController.js";
3
+ export type InitialWorkbenchWorkspaceMode = 'tool' | 'empty';
4
+ export interface WorkbenchWorkspaceActionState {
5
+ workspace: Workspace;
6
+ focus: WorkspaceFocus;
7
+ shell: ShellState;
8
+ layoutInteraction: LayoutInteractionState;
9
+ }
10
+ export interface CreateWorkbenchWorkspaceActionsInput<TState extends WorkbenchWorkspaceActionState> {
11
+ toolCatalog: ToolCatalog;
12
+ initialWorkspaceMode?: InitialWorkbenchWorkspaceMode;
13
+ createInitialWorkspace(mode?: InitialWorkbenchWorkspaceMode): Workspace;
14
+ getWorkbenchState(): TState;
15
+ createWorkbenchState(workspaceSession?: WorkspaceSessionState, shellState?: ShellState, layoutInteraction?: LayoutInteractionState): TState;
16
+ updateWorkbenchState(updater: (state: TState) => TState, historyScope?: WorkbenchHistoryScope): void;
17
+ setWorkbenchState(nextState: TState, historyScope?: WorkbenchHistoryScope): void;
18
+ resolveWorkspaceCommandHistoryScope(command: WorkspaceCommand): WorkbenchHistoryScope;
19
+ }
20
+ export declare function createWorkbenchWorkspaceActions<TState extends WorkbenchWorkspaceActionState>(input: CreateWorkbenchWorkspaceActionsInput<TState>): {
21
+ applyWorkspaceSession(workspaceSession: WorkspaceSessionState, historyScope?: WorkbenchHistoryScope): void;
22
+ applyWorkspacePresetArtifact(artifact: WorkspacePresetArtifact): void;
23
+ dispatchCommand(command: WorkspaceCommand): void;
24
+ resetWorkspace(mode?: InitialWorkbenchWorkspaceMode | "initial"): void;
25
+ loadPreset(presetId: WorkspacePresetId): void;
26
+ exportWorkspaceSnapshot(): string;
27
+ importWorkspaceSnapshot(source: string): WorkspaceSnapshotImportResult;
28
+ setFullscreenPanel(panelId: string | null): void;
29
+ setDesignSystemThemeSession(nextSession: DesignSystemThemeSession | null): void;
30
+ };
@@ -0,0 +1,55 @@
1
+ import { createWorkspaceSessionFromPreset, createWorkspaceSessionState, dismissLayoutInteraction, dispatchWorkspaceCommand, exportWorkspaceSnapshot as serializeWorkspaceSnapshot, importWorkspaceSnapshot as parseWorkspaceSnapshotSource, setDesignSystemThemeSession, setWorkspaceFullscreenPanel } from '@konitif/workbench/workspace-contracts';
2
+ export function createWorkbenchWorkspaceActions(input) {
3
+ return {
4
+ applyWorkspaceSession(workspaceSession, historyScope = 'both') {
5
+ input.updateWorkbenchState((state) => input.createWorkbenchState(workspaceSession, state.shell, state.layoutInteraction), historyScope);
6
+ },
7
+ applyWorkspacePresetArtifact(artifact) {
8
+ const workspaceSession = createWorkspaceSessionState({
9
+ ...artifact.workspaceSession.workspace,
10
+ presetProvenance: {
11
+ id: artifact.id,
12
+ version: artifact.version,
13
+ status: 'exact'
14
+ }
15
+ }, artifact.workspaceSession.focus);
16
+ input.setWorkbenchState(input.createWorkbenchState(workspaceSession, artifact.shellState), 'both');
17
+ },
18
+ dispatchCommand(command) {
19
+ input.updateWorkbenchState((state) => input.createWorkbenchState(dispatchWorkspaceCommand(state, command, { toolCatalog: input.toolCatalog }), state.shell, dismissLayoutInteraction()), input.resolveWorkspaceCommandHistoryScope(command));
20
+ },
21
+ resetWorkspace(mode = 'initial') {
22
+ const workspaceMode = mode === 'initial' ? (input.initialWorkspaceMode ?? 'tool') : mode;
23
+ input.setWorkbenchState(input.createWorkbenchState(createWorkspaceSessionState(input.createInitialWorkspace(workspaceMode))), 'core');
24
+ },
25
+ loadPreset(presetId) {
26
+ if (presetId === 'default') {
27
+ input.setWorkbenchState(input.createWorkbenchState(createWorkspaceSessionState(input.createInitialWorkspace('tool'))), 'core');
28
+ return;
29
+ }
30
+ input.setWorkbenchState(input.createWorkbenchState(createWorkspaceSessionFromPreset(input.toolCatalog, presetId)), 'core');
31
+ },
32
+ exportWorkspaceSnapshot() {
33
+ return serializeWorkspaceSnapshot(input.getWorkbenchState().workspace);
34
+ },
35
+ importWorkspaceSnapshot(source) {
36
+ const result = parseWorkspaceSnapshotSource(source);
37
+ if (result.ok && result.workspace) {
38
+ const importedWorkspace = result.workspace;
39
+ input.updateWorkbenchState((state) => input.createWorkbenchState(createWorkspaceSessionState(importedWorkspace), state.shell, dismissLayoutInteraction()), 'core');
40
+ }
41
+ return result;
42
+ },
43
+ setFullscreenPanel(panelId) {
44
+ input.updateWorkbenchState((state) => input.createWorkbenchState(createWorkspaceSessionState(setWorkspaceFullscreenPanel(state.workspace, panelId), state.focus), state.shell, state.layoutInteraction), 'none');
45
+ },
46
+ setDesignSystemThemeSession(nextSession) {
47
+ input.updateWorkbenchState((state) => {
48
+ const nextWorkspace = setDesignSystemThemeSession(state.workspace, nextSession);
49
+ return nextWorkspace === state.workspace
50
+ ? state
51
+ : input.createWorkbenchState(createWorkspaceSessionState(nextWorkspace, state.focus), state.shell, state.layoutInteraction);
52
+ }, 'app');
53
+ }
54
+ };
55
+ }
@@ -0,0 +1,28 @@
1
+ export type WorkbenchHistoryScope = 'none' | 'app' | 'core' | 'both';
2
+ export type WorkbenchHistoryChannel = 'app' | 'core';
3
+ export interface WorkbenchHistoryStatus {
4
+ app: {
5
+ canUndo: boolean;
6
+ canRedo: boolean;
7
+ };
8
+ core: {
9
+ canUndo: boolean;
10
+ canRedo: boolean;
11
+ };
12
+ }
13
+ export interface WorkspaceHistoryController<TSnapshot> {
14
+ getStatus(): WorkbenchHistoryStatus;
15
+ reset(): void;
16
+ recordTransition(previousSnapshot: TSnapshot, nextSnapshot: TSnapshot, scope: WorkbenchHistoryScope): void;
17
+ beginTransaction(channel: WorkbenchHistoryChannel, snapshot: TSnapshot): void;
18
+ commitTransaction(channel: WorkbenchHistoryChannel, currentSnapshot: TSnapshot): void;
19
+ cancelTransaction(channel: WorkbenchHistoryChannel): TSnapshot | null;
20
+ undo(channel: WorkbenchHistoryChannel, currentSnapshot: TSnapshot): TSnapshot | null;
21
+ redo(channel: WorkbenchHistoryChannel, currentSnapshot: TSnapshot): TSnapshot | null;
22
+ }
23
+ interface WorkspaceHistoryControllerOptions<TSnapshot> {
24
+ isChanged: (left: TSnapshot, right: TSnapshot) => boolean;
25
+ maxEntries?: number;
26
+ }
27
+ export declare function createWorkspaceHistoryController<TSnapshot>(options: WorkspaceHistoryControllerOptions<TSnapshot>): WorkspaceHistoryController<TSnapshot>;
28
+ export {};