@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.
- package/LICENSE.md +22 -0
- package/README.md +60 -0
- package/dist/boot/createDemoWorkbenchBootGraph.d.ts +9 -0
- package/dist/boot/createDemoWorkbenchBootGraph.js +180 -0
- package/dist/boot/createLegacyWorkbenchBootGraph.d.ts +34 -0
- package/dist/boot/createLegacyWorkbenchBootGraph.js +321 -0
- package/dist/boot/createWorkbenchBootSession.d.ts +23 -0
- package/dist/boot/createWorkbenchBootSession.js +90 -0
- package/dist/boot/index.d.ts +3 -0
- package/dist/boot/index.js +3 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +9 -0
- package/dist/runtime.d.ts +7 -0
- package/dist/runtime.js +2 -0
- package/dist/workbench/browserDetachedWindowHost.d.ts +3 -0
- package/dist/workbench/browserDetachedWindowHost.js +69 -0
- package/dist/workbench/browserWorkbenchHostEvents.d.ts +3 -0
- package/dist/workbench/browserWorkbenchHostEvents.js +35 -0
- package/dist/workbench/createWorkbenchStore.d.ts +129 -0
- package/dist/workbench/createWorkbenchStore.js +50 -0
- package/dist/workbench/createWorkbenchStoreRuntime.d.ts +154 -0
- package/dist/workbench/createWorkbenchStoreRuntime.js +242 -0
- package/dist/workbench/createWorkspaceModeController.d.ts +36 -0
- package/dist/workbench/createWorkspaceModeController.js +168 -0
- package/dist/workbench/workbenchDetachedWindowHost.d.ts +16 -0
- package/dist/workbench/workbenchDetachedWindowHost.js +1 -0
- package/dist/workbench/workbenchFocusPersistence.d.ts +15 -0
- package/dist/workbench/workbenchFocusPersistence.js +44 -0
- package/dist/workbench/workbenchHistoryActions.d.ts +21 -0
- package/dist/workbench/workbenchHistoryActions.js +45 -0
- package/dist/workbench/workbenchHistoryRuntime.d.ts +16 -0
- package/dist/workbench/workbenchHistoryRuntime.js +42 -0
- package/dist/workbench/workbenchHostEvents.d.ts +13 -0
- package/dist/workbench/workbenchHostEvents.js +1 -0
- package/dist/workbench/workbenchLayoutActions.d.ts +84 -0
- package/dist/workbench/workbenchLayoutActions.js +191 -0
- package/dist/workbench/workbenchPersistenceRuntime.d.ts +39 -0
- package/dist/workbench/workbenchPersistenceRuntime.js +168 -0
- package/dist/workbench/workbenchShellActions.d.ts +24 -0
- package/dist/workbench/workbenchShellActions.js +63 -0
- package/dist/workbench/workbenchShellPersistence.d.ts +18 -0
- package/dist/workbench/workbenchShellPersistence.js +124 -0
- package/dist/workbench/workbenchStateFactory.d.ts +22 -0
- package/dist/workbench/workbenchStateFactory.js +47 -0
- package/dist/workbench/workbenchToolRuntimeActions.d.ts +23 -0
- package/dist/workbench/workbenchToolRuntimeActions.js +98 -0
- package/dist/workbench/workbenchToolRuntimeUiStore.d.ts +17 -0
- package/dist/workbench/workbenchToolRuntimeUiStore.js +85 -0
- package/dist/workbench/workbenchWindowRuntime.d.ts +19 -0
- package/dist/workbench/workbenchWindowRuntime.js +85 -0
- package/dist/workbench/workbenchWorkspaceActions.d.ts +30 -0
- package/dist/workbench/workbenchWorkspaceActions.js +55 -0
- package/dist/workbench/workspaceHistoryController.d.ts +28 -0
- package/dist/workbench/workspaceHistoryController.js +126 -0
- package/dist/workbench/workspaceSyncController.d.ts +20 -0
- package/dist/workbench/workspaceSyncController.js +105 -0
- 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 {};
|