@kispace-io/core 0.7.0
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/dist/api/base-classes.d.ts +7 -0
- package/dist/api/base-classes.d.ts.map +1 -0
- package/dist/api/constants.d.ts +2 -0
- package/dist/api/constants.d.ts.map +1 -0
- package/dist/api/index.d.ts +6 -0
- package/dist/api/index.d.ts.map +1 -0
- package/dist/api/index.js +80 -0
- package/dist/api/index.js.map +1 -0
- package/dist/api/services.d.ts +27 -0
- package/dist/api/services.d.ts.map +1 -0
- package/dist/api/types.d.ts +11 -0
- package/dist/api/types.d.ts.map +1 -0
- package/dist/commands/files.d.ts +2 -0
- package/dist/commands/files.d.ts.map +1 -0
- package/dist/commands/global.d.ts +1 -0
- package/dist/commands/global.d.ts.map +1 -0
- package/dist/commands/index.d.ts +1 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/version-info.d.ts +2 -0
- package/dist/commands/version-info.d.ts.map +1 -0
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/k-app-selector.d.ts +17 -0
- package/dist/components/k-app-selector.d.ts.map +1 -0
- package/dist/components/k-app-switcher.d.ts +13 -0
- package/dist/components/k-app-switcher.d.ts.map +1 -0
- package/dist/components/k-command.d.ts +31 -0
- package/dist/components/k-command.d.ts.map +1 -0
- package/dist/components/k-extensions.d.ts +32 -0
- package/dist/components/k-extensions.d.ts.map +1 -0
- package/dist/components/k-fastviews.d.ts +34 -0
- package/dist/components/k-fastviews.d.ts.map +1 -0
- package/dist/components/k-filebrowser.d.ts +40 -0
- package/dist/components/k-filebrowser.d.ts.map +1 -0
- package/dist/components/k-language-selector.d.ts +12 -0
- package/dist/components/k-language-selector.d.ts.map +1 -0
- package/dist/components/k-log-terminal.d.ts +36 -0
- package/dist/components/k-log-terminal.d.ts.map +1 -0
- package/dist/components/k-part-name.d.ts +12 -0
- package/dist/components/k-part-name.d.ts.map +1 -0
- package/dist/components/k-tasks.d.ts +13 -0
- package/dist/components/k-tasks.d.ts.map +1 -0
- package/dist/components/k-workspace-name.d.ts +14 -0
- package/dist/components/k-workspace-name.d.ts.map +1 -0
- package/dist/contributions/default-ui-contributions.d.ts +2 -0
- package/dist/contributions/default-ui-contributions.d.ts.map +1 -0
- package/dist/contributions/index.d.ts +1 -0
- package/dist/contributions/index.d.ts.map +1 -0
- package/dist/contributions/marketplace-catalog-contributions.d.ts +2 -0
- package/dist/contributions/marketplace-catalog-contributions.d.ts.map +1 -0
- package/dist/core/app-host-config.d.ts +7 -0
- package/dist/core/app-host-config.d.ts.map +1 -0
- package/dist/core/apploader.d.ts +214 -0
- package/dist/core/apploader.d.ts.map +1 -0
- package/dist/core/appstate.d.ts +12 -0
- package/dist/core/appstate.d.ts.map +1 -0
- package/dist/core/commandregistry.d.ts +79 -0
- package/dist/core/commandregistry.d.ts.map +1 -0
- package/dist/core/config.d.ts +15 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/constants.d.ts +21 -0
- package/dist/core/constants.d.ts.map +1 -0
- package/dist/core/contributionregistry.d.ts +49 -0
- package/dist/core/contributionregistry.d.ts.map +1 -0
- package/dist/core/di.d.ts +18 -0
- package/dist/core/di.d.ts.map +1 -0
- package/dist/core/dialogservice.d.ts +33 -0
- package/dist/core/dialogservice.d.ts.map +1 -0
- package/dist/core/editorregistry.d.ts +73 -0
- package/dist/core/editorregistry.d.ts.map +1 -0
- package/dist/core/esmsh-service.d.ts +40 -0
- package/dist/core/esmsh-service.d.ts.map +1 -0
- package/dist/core/events.d.ts +7 -0
- package/dist/core/events.d.ts.map +1 -0
- package/dist/core/events.js +63 -0
- package/dist/core/events.js.map +1 -0
- package/dist/core/extensionregistry.d.ts +98 -0
- package/dist/core/extensionregistry.d.ts.map +1 -0
- package/dist/core/filesys.d.ts +139 -0
- package/dist/core/filesys.d.ts.map +1 -0
- package/dist/core/i18n.d.ts +50 -0
- package/dist/core/i18n.d.ts.map +1 -0
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/k-utils.d.ts +2 -0
- package/dist/core/k-utils.d.ts.map +1 -0
- package/dist/core/keybindings.d.ts +67 -0
- package/dist/core/keybindings.d.ts.map +1 -0
- package/dist/core/logger.d.ts +44 -0
- package/dist/core/logger.d.ts.map +1 -0
- package/dist/core/marketplaceregistry.d.ts +25 -0
- package/dist/core/marketplaceregistry.d.ts.map +1 -0
- package/dist/core/packageinfoservice.d.ts +16 -0
- package/dist/core/packageinfoservice.d.ts.map +1 -0
- package/dist/core/persistenceservice.d.ts +6 -0
- package/dist/core/persistenceservice.d.ts.map +1 -0
- package/dist/core/settingsservice.d.ts +19 -0
- package/dist/core/settingsservice.d.ts.map +1 -0
- package/dist/core/signals.d.ts +3 -0
- package/dist/core/signals.d.ts.map +1 -0
- package/dist/core/taskservice.d.ts +20 -0
- package/dist/core/taskservice.d.ts.map +1 -0
- package/dist/core/toast.d.ts +4 -0
- package/dist/core/toast.d.ts.map +1 -0
- package/dist/core/tree-utils.d.ts +16 -0
- package/dist/core/tree-utils.d.ts.map +1 -0
- package/dist/dialogs/confirm-dialog.d.ts +14 -0
- package/dist/dialogs/confirm-dialog.d.ts.map +1 -0
- package/dist/dialogs/index.d.ts +5 -0
- package/dist/dialogs/index.d.ts.map +1 -0
- package/dist/dialogs/info-dialog.d.ts +13 -0
- package/dist/dialogs/info-dialog.d.ts.map +1 -0
- package/dist/dialogs/navigable-info-dialog.d.ts +33 -0
- package/dist/dialogs/navigable-info-dialog.d.ts.map +1 -0
- package/dist/dialogs/prompt-dialog.d.ts +21 -0
- package/dist/dialogs/prompt-dialog.d.ts.map +1 -0
- package/dist/externals/lit.d.ts +20 -0
- package/dist/externals/lit.d.ts.map +1 -0
- package/dist/externals/lit.js +15 -0
- package/dist/externals/lit.js.map +1 -0
- package/dist/externals/third-party.d.ts +7 -0
- package/dist/externals/third-party.d.ts.map +1 -0
- package/dist/externals/third-party.js +2 -0
- package/dist/externals/third-party.js.map +1 -0
- package/dist/externals/webawesome.d.ts +1 -0
- package/dist/externals/webawesome.d.ts.map +1 -0
- package/dist/externals/webawesome.js +52 -0
- package/dist/externals/webawesome.js.map +1 -0
- package/dist/i18n/extensions.json.d.ts +42 -0
- package/dist/i18n/fastviews.json.d.ts +13 -0
- package/dist/i18n/filebrowser.json.d.ts +35 -0
- package/dist/i18n/index.d.ts +2 -0
- package/dist/i18n/index.d.ts.map +1 -0
- package/dist/i18n/logterminal.json.d.ts +45 -0
- package/dist/i18n/partname.json.d.ts +15 -0
- package/dist/i18n/tasks.json.d.ts +15 -0
- package/dist/i18n/workspace.json.d.ts +15 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +80 -0
- package/dist/index.js.map +1 -0
- package/dist/k-icon-BZC7dQV0.js +492 -0
- package/dist/k-icon-BZC7dQV0.js.map +1 -0
- package/dist/k-nocontent-Bh_yToGh.js +48 -0
- package/dist/k-nocontent-Bh_yToGh.js.map +1 -0
- package/dist/k-resizable-grid-Ch3iWZaL.js +3157 -0
- package/dist/k-resizable-grid-Ch3iWZaL.js.map +1 -0
- package/dist/k-standard-layout-CQ1VZoxa.js +5011 -0
- package/dist/k-standard-layout-CQ1VZoxa.js.map +1 -0
- package/dist/layouts/k-standard-layout.d.ts +16 -0
- package/dist/layouts/k-standard-layout.d.ts.map +1 -0
- package/dist/parts/index.d.ts +1 -0
- package/dist/parts/index.d.ts.map +1 -0
- package/dist/parts/index.js +53 -0
- package/dist/parts/index.js.map +1 -0
- package/dist/parts/k-app.d.ts +11 -0
- package/dist/parts/k-app.d.ts.map +1 -0
- package/dist/parts/k-container.d.ts +4 -0
- package/dist/parts/k-container.d.ts.map +1 -0
- package/dist/parts/k-contextmenu.d.ts +38 -0
- package/dist/parts/k-contextmenu.d.ts.map +1 -0
- package/dist/parts/k-dialog-content.d.ts +9 -0
- package/dist/parts/k-dialog-content.d.ts.map +1 -0
- package/dist/parts/k-element.d.ts +36 -0
- package/dist/parts/k-element.d.ts.map +1 -0
- package/dist/parts/k-part.d.ts +96 -0
- package/dist/parts/k-part.d.ts.map +1 -0
- package/dist/parts/k-resizable-grid.d.ts +31 -0
- package/dist/parts/k-resizable-grid.d.ts.map +1 -0
- package/dist/parts/k-tabs.d.ts +74 -0
- package/dist/parts/k-tabs.d.ts.map +1 -0
- package/dist/parts/k-toolbar.d.ts +21 -0
- package/dist/parts/k-toolbar.d.ts.map +1 -0
- package/dist/widgets/index.d.ts +1 -0
- package/dist/widgets/index.d.ts.map +1 -0
- package/dist/widgets/index.js +3 -0
- package/dist/widgets/index.js.map +1 -0
- package/dist/widgets/k-icon.d.ts +10 -0
- package/dist/widgets/k-icon.d.ts.map +1 -0
- package/dist/widgets/k-nocontent.d.ts +13 -0
- package/dist/widgets/k-nocontent.d.ts.map +1 -0
- package/dist/widgets/k-widget.d.ts +25 -0
- package/dist/widgets/k-widget.d.ts.map +1 -0
- package/package.json +81 -0
- package/src/api/base-classes.ts +10 -0
- package/src/api/constants.ts +3 -0
- package/src/api/index.ts +31 -0
- package/src/api/services.ts +52 -0
- package/src/api/types.ts +46 -0
- package/src/commands/files.ts +829 -0
- package/src/commands/global.ts +225 -0
- package/src/commands/index.ts +4 -0
- package/src/commands/version-info.ts +214 -0
- package/src/components/index.ts +10 -0
- package/src/components/k-app-selector.ts +233 -0
- package/src/components/k-app-switcher.ts +126 -0
- package/src/components/k-command.ts +236 -0
- package/src/components/k-extensions.ts +615 -0
- package/src/components/k-fastviews.ts +314 -0
- package/src/components/k-filebrowser.ts +442 -0
- package/src/components/k-language-selector.ts +166 -0
- package/src/components/k-log-terminal.ts +337 -0
- package/src/components/k-part-name.ts +54 -0
- package/src/components/k-tasks.ts +267 -0
- package/src/components/k-workspace-name.ts +56 -0
- package/src/contributions/default-ui-contributions.ts +51 -0
- package/src/contributions/index.ts +3 -0
- package/src/contributions/marketplace-catalog-contributions.ts +6 -0
- package/src/core/app-host-config.ts +23 -0
- package/src/core/apploader.ts +630 -0
- package/src/core/appstate.ts +15 -0
- package/src/core/commandregistry.ts +210 -0
- package/src/core/config.ts +29 -0
- package/src/core/constants.ts +27 -0
- package/src/core/contributionregistry.ts +77 -0
- package/src/core/di.ts +54 -0
- package/src/core/dialogservice.ts +266 -0
- package/src/core/editorregistry.ts +303 -0
- package/src/core/esmsh-service.ts +404 -0
- package/src/core/events.ts +68 -0
- package/src/core/extensionregistry.ts +399 -0
- package/src/core/filesys.ts +618 -0
- package/src/core/i18n.ts +221 -0
- package/src/core/index.ts +51 -0
- package/src/core/k-utils.ts +11 -0
- package/src/core/keybindings.ts +274 -0
- package/src/core/logger.ts +187 -0
- package/src/core/marketplaceregistry.ts +197 -0
- package/src/core/packageinfoservice.ts +56 -0
- package/src/core/persistenceservice.ts +15 -0
- package/src/core/settingsservice.ts +70 -0
- package/src/core/signals.ts +18 -0
- package/src/core/taskservice.ts +72 -0
- package/src/core/toast.ts +11 -0
- package/src/core/tree-utils.ts +24 -0
- package/src/dialogs/confirm-dialog.ts +72 -0
- package/src/dialogs/index.ts +4 -0
- package/src/dialogs/info-dialog.ts +67 -0
- package/src/dialogs/navigable-info-dialog.ts +256 -0
- package/src/dialogs/prompt-dialog.ts +123 -0
- package/src/externals/lit.ts +26 -0
- package/src/externals/third-party.ts +9 -0
- package/src/externals/webawesome.ts +54 -0
- package/src/i18n/extensions.json +39 -0
- package/src/i18n/fastviews.json +10 -0
- package/src/i18n/filebrowser.json +33 -0
- package/src/i18n/index.ts +25 -0
- package/src/i18n/logterminal.json +42 -0
- package/src/i18n/partname.json +12 -0
- package/src/i18n/tasks.json +12 -0
- package/src/i18n/workspace.json +12 -0
- package/src/icons/icons.txt +3 -0
- package/src/icons/js.svg +6 -0
- package/src/icons/jupyter.svg +18 -0
- package/src/icons/python.svg +15 -0
- package/src/index.ts +3 -0
- package/src/layouts/k-standard-layout.ts +174 -0
- package/src/parts/index.ts +6 -0
- package/src/parts/k-app.ts +29 -0
- package/src/parts/k-container.ts +4 -0
- package/src/parts/k-contextmenu.ts +245 -0
- package/src/parts/k-dialog-content.ts +31 -0
- package/src/parts/k-element.ts +100 -0
- package/src/parts/k-part.ts +158 -0
- package/src/parts/k-resizable-grid.ts +366 -0
- package/src/parts/k-tabs.ts +574 -0
- package/src/parts/k-toolbar.ts +158 -0
- package/src/vite-env.d.ts +2 -0
- package/src/widgets/index.ts +2 -0
- package/src/widgets/k-icon.ts +39 -0
- package/src/widgets/k-nocontent.ts +40 -0
- package/src/widgets/k-widget.ts +90 -0
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import logger from "./logger";
|
|
2
|
+
import { publish } from "./events";
|
|
3
|
+
import { CommandContribution, Contribution, contributionRegistry } from "./contributionregistry";
|
|
4
|
+
import { rootContext } from "./di";
|
|
5
|
+
import { activePartSignal, activeEditorSignal } from "./appstate";
|
|
6
|
+
|
|
7
|
+
export const TOPIC_COMMAND_REGISTERED = "events/commandregistry/commandRegistered";
|
|
8
|
+
|
|
9
|
+
export interface Parameter {
|
|
10
|
+
name: string;
|
|
11
|
+
description: string;
|
|
12
|
+
type?: string;
|
|
13
|
+
required: boolean;
|
|
14
|
+
allowedValues?: string[];
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface Variable {
|
|
18
|
+
name: string;
|
|
19
|
+
description: string;
|
|
20
|
+
type?: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface LLMOptions {
|
|
24
|
+
prompt?: string;
|
|
25
|
+
model?: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export class Command {
|
|
29
|
+
id: string;
|
|
30
|
+
name: string;
|
|
31
|
+
description: string;
|
|
32
|
+
icon?: string;
|
|
33
|
+
keyBinding?: string;
|
|
34
|
+
parameters?: Parameter[];
|
|
35
|
+
output?: Variable[];
|
|
36
|
+
llm?: LLMOptions;
|
|
37
|
+
|
|
38
|
+
constructor(id: string, name: string, description: string, parameters?: Parameter[], output?: Variable[]) {
|
|
39
|
+
this.id = id;
|
|
40
|
+
this.name = name;
|
|
41
|
+
this.description = description;
|
|
42
|
+
this.parameters = parameters || [];
|
|
43
|
+
this.output = output || [];
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface ExecutionContext {
|
|
48
|
+
[key: string]: any;
|
|
49
|
+
|
|
50
|
+
params?: ExecuteParams;
|
|
51
|
+
activePart?: any;
|
|
52
|
+
activeEditor?: any;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export interface ExecuteParams {
|
|
56
|
+
[key: string]: any;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface Handler {
|
|
60
|
+
canExecute?: (context: ExecutionContext) => boolean;
|
|
61
|
+
execute: (context: ExecutionContext) => any;
|
|
62
|
+
ranking?: number; // Higher ranking = higher priority (default: 0)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface Commands {
|
|
66
|
+
[commandId: string]: Command
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export class CommandStack {
|
|
70
|
+
//private stack: any[] = []
|
|
71
|
+
|
|
72
|
+
public async execute(commandId: any, context: ExecutionContext) {
|
|
73
|
+
return commandRegistry.execute(commandId, context);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
public async undo() {
|
|
77
|
+
// TODO undo last command on stack
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
public async redo() {
|
|
81
|
+
// TODO redo last command on stack
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export class CommandRegistry {
|
|
86
|
+
private commands: Commands = {};
|
|
87
|
+
private handlers: Map<string, Handler[]> = new Map();
|
|
88
|
+
|
|
89
|
+
registerHandler(commandId: string, handler: Handler) {
|
|
90
|
+
if (!this.handlers.has(commandId)) {
|
|
91
|
+
this.handlers.set(commandId, []);
|
|
92
|
+
}
|
|
93
|
+
const handlerList = this.handlers.get(commandId) as Handler[];
|
|
94
|
+
handlerList.push(handler);
|
|
95
|
+
// Sort by ranking (higher ranking first), default ranking is 0
|
|
96
|
+
handlerList.sort((a, b) => (b.ranking ?? 0) - (a.ranking ?? 0));
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
getHandler(commandId: string): Handler[] | undefined {
|
|
100
|
+
return this.handlers.get(commandId)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Creates an ExecutionContext with the current application state
|
|
105
|
+
*
|
|
106
|
+
* @param params Optional command parameters
|
|
107
|
+
* @returns ExecutionContext with captured application state
|
|
108
|
+
*/
|
|
109
|
+
createExecutionContext(params?: ExecuteParams): ExecutionContext {
|
|
110
|
+
const context: ExecutionContext = {
|
|
111
|
+
params: params || {},
|
|
112
|
+
activePart: activePartSignal.get(),
|
|
113
|
+
activeEditor: activeEditorSignal.get()
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
return context;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
execute(commandId: string, context: ExecutionContext = {}) {
|
|
120
|
+
const handlers = this.getHandler(commandId);
|
|
121
|
+
|
|
122
|
+
if (!handlers) {
|
|
123
|
+
logger.debug(`[CommandRegistry] No handlers registered for command: ${commandId}`);
|
|
124
|
+
throw new Error(`No handlers registered for command: ${commandId}`);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const command = this.getCommand(commandId);
|
|
128
|
+
const paramsStr = context.params ? ` params: ${JSON.stringify(context.params)}` : '';
|
|
129
|
+
logger.debug(`[CommandRegistry] Executing command: ${commandId}${command ? ` (${command.name})` : ''}${paramsStr}`);
|
|
130
|
+
|
|
131
|
+
// Handlers are already sorted by ranking, so iterate in order
|
|
132
|
+
for (const handler of handlers) {
|
|
133
|
+
if (handler.canExecute === undefined || handler.canExecute(context)) {
|
|
134
|
+
try {
|
|
135
|
+
const result: any | Promise<any> = handler.execute(context);
|
|
136
|
+
logger.debug(`[CommandRegistry] Command executed successfully: ${commandId} (result: ${result})`);
|
|
137
|
+
return result;
|
|
138
|
+
} catch (error) {
|
|
139
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
140
|
+
logger.error(`[CommandRegistry] Command execution failed: ${commandId} - ${errorMsg}`);
|
|
141
|
+
throw error;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
logger.error(`[CommandRegistry] No handler found to execute command: ${commandId}`);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
createAndRegisterCommand(id: string, name: string, description: string, parameters: Parameter[], handler?: Handler) {
|
|
149
|
+
const command = new Command(id, name, description, parameters);
|
|
150
|
+
this.registerCommand(command)
|
|
151
|
+
if (handler) {
|
|
152
|
+
this.registerHandler(id, handler)
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
registerCommand(command: Command): void {
|
|
157
|
+
this.commands[command.id] = command;
|
|
158
|
+
logger.debug(`Command registered: ${command.id}`);
|
|
159
|
+
publish(TOPIC_COMMAND_REGISTERED, command);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
hasCommand(commandId: string): boolean {
|
|
163
|
+
return commandId in this.commands
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
listCommands(context?: ExecutionContext): Commands {
|
|
167
|
+
if (context) {
|
|
168
|
+
// filter by commands which have at least one executable handler
|
|
169
|
+
return Object.values(this.commands).filter(command => {
|
|
170
|
+
const handlers = commandRegistry.getHandler(command.id) || []
|
|
171
|
+
return handlers.some(handler => handler.canExecute === undefined || handler.canExecute(context))
|
|
172
|
+
}).reduce((acc: any, command) => {
|
|
173
|
+
acc[command.id] = command
|
|
174
|
+
return acc
|
|
175
|
+
}, {})
|
|
176
|
+
}
|
|
177
|
+
return this.commands
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
getCommand(commandId: string): Command {
|
|
181
|
+
return <Command>this.commands[commandId]
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
registerAll(options: RegisterOptions) {
|
|
185
|
+
const commandId = options.command.id
|
|
186
|
+
this.registerCommand(options.command)
|
|
187
|
+
if (options.handler) {
|
|
188
|
+
this.registerHandler(commandId, options.handler)
|
|
189
|
+
}
|
|
190
|
+
if (options.contribution && options.contribution.target) {
|
|
191
|
+
contributionRegistry.registerContribution(options.contribution.target, {
|
|
192
|
+
command: commandId,
|
|
193
|
+
...options.contribution
|
|
194
|
+
} as CommandContribution)
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
export const commandRegistry = new CommandRegistry();
|
|
200
|
+
rootContext.put("commandRegistry", commandRegistry);
|
|
201
|
+
|
|
202
|
+
export interface RegisterOptions {
|
|
203
|
+
command: Command,
|
|
204
|
+
handler?: Handler,
|
|
205
|
+
contribution?: Contribution
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
export const registerAll = (options: RegisterOptions) => {
|
|
209
|
+
commandRegistry.registerAll(options);
|
|
210
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// Framework Configuration
|
|
2
|
+
//
|
|
3
|
+
// This module provides framework-wide configuration that can be customized
|
|
4
|
+
// by applications built on the framework.
|
|
5
|
+
|
|
6
|
+
export interface FrameworkConfig {
|
|
7
|
+
// Logger configuration
|
|
8
|
+
logger?: {
|
|
9
|
+
level?: 'debug' | 'info' | 'warning' | 'error';
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
let frameworkConfig: FrameworkConfig = {};
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Initialize framework configuration
|
|
17
|
+
* This should be called before framework bootstrap (if custom config is needed)
|
|
18
|
+
*/
|
|
19
|
+
export function configureFramework(config: FrameworkConfig): void {
|
|
20
|
+
frameworkConfig = { ...frameworkConfig, ...config };
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Get current framework configuration
|
|
25
|
+
*/
|
|
26
|
+
export function getFrameworkConfig(): Readonly<FrameworkConfig> {
|
|
27
|
+
return { ...frameworkConfig };
|
|
28
|
+
}
|
|
29
|
+
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// Toolbars
|
|
2
|
+
export const TOOLBAR_MAIN = "app-toolbars-main"
|
|
3
|
+
export const TOOLBAR_MAIN_RIGHT = "app-toolbars-main-right"
|
|
4
|
+
export const TOOLBAR_MAIN_CENTER = "app-toolbars-main-center"
|
|
5
|
+
export const TOOLBAR_BOTTOM = "app-toolbars-bottom"
|
|
6
|
+
export const TOOLBAR_BOTTOM_CENTER = "app-toolbars-bottom-center"
|
|
7
|
+
export const TOOLBAR_BOTTOM_END = "app-toolbars-bottom-end"
|
|
8
|
+
|
|
9
|
+
// VS Code-style layout containers
|
|
10
|
+
export const EDITOR_AREA_MAIN = "editor-area-main"
|
|
11
|
+
export const SIDEBAR_MAIN = "sidebar-main"
|
|
12
|
+
export const SIDEBAR_MAIN_BOTTOM = "sidebar-main-bottom"
|
|
13
|
+
export const SIDEBAR_AUXILIARY = "sidebar-auxiliary"
|
|
14
|
+
export const PANEL_BOTTOM = "panel-bottom"
|
|
15
|
+
|
|
16
|
+
export const COMMAND_SAVE = "command-save"
|
|
17
|
+
|
|
18
|
+
export const HIDE_DOT_RESOURCE = false
|
|
19
|
+
|
|
20
|
+
// Mouse button constants
|
|
21
|
+
export enum MouseButton {
|
|
22
|
+
LEFT = 0,
|
|
23
|
+
MIDDLE = 1,
|
|
24
|
+
RIGHT = 2,
|
|
25
|
+
BACK = 3,
|
|
26
|
+
FORWARD = 4
|
|
27
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import {Signal} from "@lit-labs/signals";
|
|
2
|
+
import {TemplateResult} from "lit";
|
|
3
|
+
import {publish} from "./events";
|
|
4
|
+
import {rootContext} from "./di";
|
|
5
|
+
|
|
6
|
+
export const TOPIC_CONTRIBUTEIONS_CHANGED = "events/contributionregistry/contributionsChanged"
|
|
7
|
+
|
|
8
|
+
export interface ContributionChangeEvent {
|
|
9
|
+
target: string;
|
|
10
|
+
contributions: Contribution[];
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface Contribution {
|
|
14
|
+
target?: string;
|
|
15
|
+
label: string;
|
|
16
|
+
icon?: string;
|
|
17
|
+
slot?: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface CommandContribution extends Contribution {
|
|
21
|
+
command: string;
|
|
22
|
+
params?: Record<string, any>;
|
|
23
|
+
showLabel?: boolean;
|
|
24
|
+
disabled?: (() => boolean) | Signal.Computed<boolean>;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface HTMLContribution extends Contribution {
|
|
28
|
+
html: string | (() => TemplateResult)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface TabContribution extends Contribution {
|
|
32
|
+
name: string;
|
|
33
|
+
editorId?: string;
|
|
34
|
+
closable?: boolean;
|
|
35
|
+
noOverflow?: boolean;
|
|
36
|
+
component?: (id: string) => TemplateResult;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface PaneContribution extends Contribution {
|
|
40
|
+
name: string;
|
|
41
|
+
size?: number;
|
|
42
|
+
minSize?: number;
|
|
43
|
+
maxSize?: number;
|
|
44
|
+
order?: number;
|
|
45
|
+
component: () => TemplateResult;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface IconContribution extends Contribution {
|
|
49
|
+
mappings: Record<string, string>;
|
|
50
|
+
priority?: number;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
class ContributionRegistry {
|
|
54
|
+
private contributions: Map<string, Contribution[]> = new Map();
|
|
55
|
+
|
|
56
|
+
registerContribution<T extends Contribution>(target: string, contribution: T) {
|
|
57
|
+
const targetSlot = this.getContributions(target)!
|
|
58
|
+
if ("command" in contribution) {
|
|
59
|
+
const cmd = contribution as unknown as CommandContribution
|
|
60
|
+
if (cmd.disabled instanceof Function) {
|
|
61
|
+
cmd.disabled = new Signal.Computed<boolean>(cmd.disabled)
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
targetSlot.push(contribution);
|
|
65
|
+
publish(TOPIC_CONTRIBUTEIONS_CHANGED, { target, contributions: targetSlot } as ContributionChangeEvent)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
getContributions<T extends Contribution>(target: string): T[] {
|
|
69
|
+
if (!this.contributions.has(target)) {
|
|
70
|
+
this.contributions.set(target, [])
|
|
71
|
+
}
|
|
72
|
+
return this.contributions.get(target)! as T[]
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export const contributionRegistry = new ContributionRegistry()
|
|
77
|
+
rootContext.put("contributionRegistry", contributionRegistry)
|
package/src/core/di.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
export class DependencyContext {
|
|
2
|
+
private variables: any;
|
|
3
|
+
private proxy: any;
|
|
4
|
+
private children: DependencyContext[] = [];
|
|
5
|
+
private parent?: DependencyContext;
|
|
6
|
+
|
|
7
|
+
constructor(variables: any) {
|
|
8
|
+
this.variables = variables
|
|
9
|
+
// @ts-ignore
|
|
10
|
+
this.proxy = new Proxy(variables, this)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
get(target: any, prop: string): any {
|
|
14
|
+
return target[prop] || this.parent?.getProxy()[prop];
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
set(target: any, prop: string, value: any) {
|
|
18
|
+
target[prop] = value;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
put(prop: string, value: any) {
|
|
22
|
+
this.variables[prop] = value;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
public getProxy() {
|
|
26
|
+
return this.proxy;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
public createChild(variables: any = {}): DependencyContext {
|
|
30
|
+
const child = new DependencyContext(variables)
|
|
31
|
+
child.parent = this
|
|
32
|
+
this.children.push(child)
|
|
33
|
+
return child
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
getChildren() {
|
|
37
|
+
return this.children;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
getParent() {
|
|
41
|
+
return this.parent;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
destroy() {
|
|
45
|
+
const index = this.parent?.children.indexOf(this)
|
|
46
|
+
if (index !== undefined && index >= 0) {
|
|
47
|
+
this.parent?.children.splice(index, 1)
|
|
48
|
+
}
|
|
49
|
+
this.parent = undefined
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export const rootContext = new DependencyContext({});
|
|
54
|
+
export const uiContext = rootContext.createChild({});
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
import { html, render, TemplateResult } from "lit";
|
|
2
|
+
import { contributionRegistry, Contribution, TOPIC_CONTRIBUTEIONS_CHANGED } from "./contributionregistry";
|
|
3
|
+
import { subscribe } from "./events";
|
|
4
|
+
import { createLogger } from "./logger";
|
|
5
|
+
import { rootContext } from "./di";
|
|
6
|
+
import { KDialogContent } from "../parts/k-dialog-content";
|
|
7
|
+
|
|
8
|
+
const logger = createLogger('DialogService');
|
|
9
|
+
|
|
10
|
+
export const DIALOG_CONTRIBUTION_TARGET = "dialogs";
|
|
11
|
+
|
|
12
|
+
export interface DialogButton {
|
|
13
|
+
id: string;
|
|
14
|
+
label: string;
|
|
15
|
+
variant?: 'default' | 'primary' | 'success' | 'neutral' | 'warning' | 'danger';
|
|
16
|
+
disabled?: boolean;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const OK_BUTTON: DialogButton = {
|
|
20
|
+
id: 'ok',
|
|
21
|
+
label: 'OK',
|
|
22
|
+
variant: 'primary'
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export const CANCEL_BUTTON: DialogButton = {
|
|
26
|
+
id: 'cancel',
|
|
27
|
+
label: 'Cancel',
|
|
28
|
+
variant: 'default'
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export const YES_BUTTON: DialogButton = {
|
|
32
|
+
id: 'yes',
|
|
33
|
+
label: 'Yes',
|
|
34
|
+
variant: 'primary'
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export const NO_BUTTON: DialogButton = {
|
|
38
|
+
id: 'no',
|
|
39
|
+
label: 'No',
|
|
40
|
+
variant: 'default'
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export const CLOSE_BUTTON: DialogButton = {
|
|
44
|
+
id: 'close',
|
|
45
|
+
label: 'Close',
|
|
46
|
+
variant: 'default'
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export const SAVE_BUTTON: DialogButton = {
|
|
50
|
+
id: 'save',
|
|
51
|
+
label: 'Save',
|
|
52
|
+
variant: 'primary'
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export const DELETE_BUTTON: DialogButton = {
|
|
56
|
+
id: 'delete',
|
|
57
|
+
label: 'Delete',
|
|
58
|
+
variant: 'danger'
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export interface DialogContribution extends Contribution {
|
|
62
|
+
id: string;
|
|
63
|
+
buttons?: DialogButton[];
|
|
64
|
+
component: (state?: any) => TemplateResult;
|
|
65
|
+
onButton: (id: string, result: any, state?: any) => boolean | Promise<boolean> | void | Promise<void>;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
let dialogContainer: HTMLElement | null = null;
|
|
69
|
+
|
|
70
|
+
function getDialogContainer(): HTMLElement {
|
|
71
|
+
if (!dialogContainer) {
|
|
72
|
+
dialogContainer = document.createElement('div');
|
|
73
|
+
dialogContainer.id = 'global-dialog-container';
|
|
74
|
+
document.body.appendChild(dialogContainer);
|
|
75
|
+
}
|
|
76
|
+
return dialogContainer;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
class DialogService {
|
|
80
|
+
private contributions: Map<string, DialogContribution> = new Map();
|
|
81
|
+
|
|
82
|
+
constructor() {
|
|
83
|
+
this.loadContributions();
|
|
84
|
+
|
|
85
|
+
subscribe(TOPIC_CONTRIBUTEIONS_CHANGED, (event: any) => {
|
|
86
|
+
if (event.target === DIALOG_CONTRIBUTION_TARGET) {
|
|
87
|
+
this.loadContributions();
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
private loadContributions(): void {
|
|
93
|
+
const contributions = contributionRegistry.getContributions<DialogContribution>(DIALOG_CONTRIBUTION_TARGET);
|
|
94
|
+
|
|
95
|
+
this.contributions.clear();
|
|
96
|
+
|
|
97
|
+
for (const contribution of contributions) {
|
|
98
|
+
if (!contribution.id) {
|
|
99
|
+
logger.warn('Dialog contribution missing id, skipping');
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
if (!contribution.component) {
|
|
105
|
+
logger.warn(`Dialog contribution "${contribution.id}" has no component function, skipping`);
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (!contribution.onButton) {
|
|
110
|
+
logger.warn(`Dialog contribution "${contribution.id}" has no onButton callback, skipping`);
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
this.contributions.set(contribution.id, contribution);
|
|
115
|
+
logger.debug(`Loaded dialog contribution: ${contribution.id}`);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
logger.info(`Loaded ${this.contributions.size} dialog contributions`);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
async open(dialogId: string, state?: any): Promise<void> {
|
|
122
|
+
const contribution = this.contributions.get(dialogId);
|
|
123
|
+
|
|
124
|
+
if (!contribution) {
|
|
125
|
+
logger.error(`Dialog "${dialogId}" not found`);
|
|
126
|
+
throw new Error(`Dialog "${dialogId}" not found`);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return new Promise((resolve) => {
|
|
130
|
+
const container = getDialogContainer();
|
|
131
|
+
let isOpen = true;
|
|
132
|
+
let dialogContentElement: KDialogContent | null = null;
|
|
133
|
+
|
|
134
|
+
const cleanup = async () => {
|
|
135
|
+
if (!isOpen) return;
|
|
136
|
+
isOpen = false;
|
|
137
|
+
|
|
138
|
+
if (dialogContentElement) {
|
|
139
|
+
try {
|
|
140
|
+
await dialogContentElement.dispose();
|
|
141
|
+
} catch (error) {
|
|
142
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
143
|
+
logger.error(`Error disposing dialog content for "${dialogId}": ${errorMessage}`);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
try {
|
|
148
|
+
const result = dialogContentElement ? dialogContentElement.getResult() : undefined;
|
|
149
|
+
await contribution.onButton('close', result, stateWithClose);
|
|
150
|
+
} catch (error) {
|
|
151
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
152
|
+
logger.error(`Error executing close callback for dialog "${dialogId}": ${errorMessage}`);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
render(html``, container);
|
|
156
|
+
resolve();
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
const handleButtonClick = async (buttonId: string) => {
|
|
160
|
+
try {
|
|
161
|
+
const result = dialogContentElement ? dialogContentElement.getResult() : undefined;
|
|
162
|
+
const shouldClose = await contribution.onButton(buttonId, result, stateWithClose);
|
|
163
|
+
|
|
164
|
+
if (shouldClose !== false) {
|
|
165
|
+
cleanup();
|
|
166
|
+
}
|
|
167
|
+
} catch (error) {
|
|
168
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
169
|
+
logger.error(`Error executing button callback for dialog "${dialogId}": ${errorMessage}`);
|
|
170
|
+
cleanup();
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
const buttons = contribution.buttons && contribution.buttons.length > 0
|
|
175
|
+
? contribution.buttons
|
|
176
|
+
: [OK_BUTTON];
|
|
177
|
+
|
|
178
|
+
if (state && typeof state === 'object') {
|
|
179
|
+
(state as any).close = cleanup;
|
|
180
|
+
}
|
|
181
|
+
const stateWithClose = { ...state, close: cleanup };
|
|
182
|
+
|
|
183
|
+
const template = html`
|
|
184
|
+
<wa-dialog label="${contribution.label || dialogId}" open @wa-request-close=${cleanup}>
|
|
185
|
+
<style>
|
|
186
|
+
.dialog-service-content {
|
|
187
|
+
display: flex;
|
|
188
|
+
flex-direction: column;
|
|
189
|
+
gap: 1rem;
|
|
190
|
+
padding: 1rem;
|
|
191
|
+
min-width: 400px;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
.dialog-service-footer {
|
|
195
|
+
display: flex;
|
|
196
|
+
gap: 0.5rem;
|
|
197
|
+
justify-content: flex-end;
|
|
198
|
+
margin-top: 1rem;
|
|
199
|
+
padding-top: 1rem;
|
|
200
|
+
border-top: 1px solid var(--wa-color-neutral-20);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
:host-context(.wa-light) .dialog-service-footer {
|
|
204
|
+
border-top-color: var(--wa-color-neutral-80);
|
|
205
|
+
}
|
|
206
|
+
</style>
|
|
207
|
+
|
|
208
|
+
<div class="dialog-service-content"
|
|
209
|
+
@dialog-ok=${() => {
|
|
210
|
+
const okButton = buttons.find(b => b.id === 'ok');
|
|
211
|
+
if (okButton) {
|
|
212
|
+
handleButtonClick(okButton.id);
|
|
213
|
+
}
|
|
214
|
+
}}
|
|
215
|
+
@dialog-cancel=${() => {
|
|
216
|
+
const cancelButton = buttons.find(b => b.id === 'cancel');
|
|
217
|
+
if (cancelButton) {
|
|
218
|
+
handleButtonClick(cancelButton.id);
|
|
219
|
+
} else {
|
|
220
|
+
cleanup();
|
|
221
|
+
}
|
|
222
|
+
}}>
|
|
223
|
+
${contribution.component(state)}
|
|
224
|
+
|
|
225
|
+
<div class="dialog-service-footer">
|
|
226
|
+
${buttons.map(button => html`
|
|
227
|
+
<wa-button
|
|
228
|
+
variant="${button.variant || 'default'}"
|
|
229
|
+
?disabled=${button.disabled}
|
|
230
|
+
@click=${() => handleButtonClick(button.id)}
|
|
231
|
+
>
|
|
232
|
+
${button.label}
|
|
233
|
+
</wa-button>
|
|
234
|
+
`)}
|
|
235
|
+
</div>
|
|
236
|
+
</div>
|
|
237
|
+
</wa-dialog>
|
|
238
|
+
`;
|
|
239
|
+
|
|
240
|
+
render(template, container);
|
|
241
|
+
|
|
242
|
+
(async () => {
|
|
243
|
+
const allElements = Array.from(container.querySelectorAll('*'));
|
|
244
|
+
for (const element of allElements) {
|
|
245
|
+
if (element instanceof KDialogContent) {
|
|
246
|
+
await element.updateComplete;
|
|
247
|
+
dialogContentElement = element;
|
|
248
|
+
break;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
})();
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
getDialogIds(): string[] {
|
|
256
|
+
return Array.from(this.contributions.keys());
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
hasDialog(dialogId: string): boolean {
|
|
260
|
+
return this.contributions.has(dialogId);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
export const dialogService = new DialogService();
|
|
265
|
+
rootContext.put("dialogService", dialogService);
|
|
266
|
+
|