@kispace-io/extension-command-palette 0.8.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/package.json +18 -0
- package/src/command-palette-extension.ts +530 -0
- package/src/commandpalette.json +28 -0
- package/src/i18n.json +11 -0
- package/src/index.ts +16 -0
- package/tsconfig.json +12 -0
package/package.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@kispace-io/extension-command-palette",
|
|
3
|
+
"version": "0.8.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./src/index.ts",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"import": "./src/index.ts",
|
|
9
|
+
"types": "./src/index.ts"
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"@kispace-io/core": "*"
|
|
14
|
+
},
|
|
15
|
+
"devDependencies": {
|
|
16
|
+
"typescript": "^5.9.3"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,530 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Command Palette Extension for geo!space
|
|
3
|
+
*
|
|
4
|
+
* Provides a VS Code-style command palette at the top center of the interface
|
|
5
|
+
* for quick command execution.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { html } from "lit";
|
|
9
|
+
import { customElement, state } from "lit/decorators.js";
|
|
10
|
+
import { css } from "lit";
|
|
11
|
+
import { createRef, ref, Ref } from "lit/directives/ref.js";
|
|
12
|
+
import { KPart } from "@kispace-io/core";
|
|
13
|
+
import { TOOLBAR_MAIN_CENTER } from "@kispace-io/core";
|
|
14
|
+
import { subscribe } from "@kispace-io/core";
|
|
15
|
+
import { CommandRegistry, ExecutionContext, commandRegistry } from "@kispace-io/core";
|
|
16
|
+
import { SYSTEM_LANGUAGE_BUNDLES, i18n } from "@kispace-io/core";
|
|
17
|
+
import commandpaletteBundle from "./commandpalette.json";
|
|
18
|
+
|
|
19
|
+
const t = i18n('commandpalette');
|
|
20
|
+
|
|
21
|
+
// Event topic for opening the command palette
|
|
22
|
+
const TOPIC_OPEN_COMMAND_PALETTE = "commandpalette/open";
|
|
23
|
+
|
|
24
|
+
@customElement('k-command-palette')
|
|
25
|
+
export class KCommandPalette extends KPart {
|
|
26
|
+
@state()
|
|
27
|
+
private inputValue: string = '';
|
|
28
|
+
|
|
29
|
+
@state()
|
|
30
|
+
private filteredCommands: any[] = [];
|
|
31
|
+
|
|
32
|
+
@state()
|
|
33
|
+
private allCommands: any[] = [];
|
|
34
|
+
|
|
35
|
+
@state()
|
|
36
|
+
private showParameterPrompt: boolean = false;
|
|
37
|
+
|
|
38
|
+
@state()
|
|
39
|
+
private selectedCommand: any = null;
|
|
40
|
+
|
|
41
|
+
@state()
|
|
42
|
+
private parameterValues: { [key: string]: string } = {};
|
|
43
|
+
|
|
44
|
+
@state()
|
|
45
|
+
private isPaletteOpen: boolean = false;
|
|
46
|
+
|
|
47
|
+
private inputRef: Ref<any> = createRef();
|
|
48
|
+
private dialogRef: Ref<any> = createRef();
|
|
49
|
+
private boundDocumentClickHandler?: (e: MouseEvent) => void;
|
|
50
|
+
private executionContext: ExecutionContext | undefined;
|
|
51
|
+
|
|
52
|
+
protected async doInitUI() {
|
|
53
|
+
// Subscribe to open command palette event
|
|
54
|
+
subscribe(TOPIC_OPEN_COMMAND_PALETTE, () => {
|
|
55
|
+
this.openPalette();
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
// Add click-outside listener to close palette
|
|
59
|
+
this.boundDocumentClickHandler = this.handleDocumentClick.bind(this);
|
|
60
|
+
document.addEventListener('click', this.boundDocumentClickHandler);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
private async handleDocumentClick(e: MouseEvent) {
|
|
64
|
+
if (!this.isPaletteOpen && !this.showParameterPrompt) return;
|
|
65
|
+
|
|
66
|
+
await this.updateComplete;
|
|
67
|
+
const target = e.target as Node;
|
|
68
|
+
|
|
69
|
+
// Check if click is inside the component
|
|
70
|
+
if (this.contains(target)) return;
|
|
71
|
+
|
|
72
|
+
// Check if click is inside the dialog element
|
|
73
|
+
if (this.dialogRef.value) {
|
|
74
|
+
const dialog = this.dialogRef.value as HTMLElement;
|
|
75
|
+
if (dialog.contains(target)) return;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Check if the target is inside any wa-dialog (in case of shadow DOM)
|
|
79
|
+
let element = target as HTMLElement;
|
|
80
|
+
while (element) {
|
|
81
|
+
if (element.tagName === 'WA-DIALOG') return;
|
|
82
|
+
element = element.parentElement as HTMLElement;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Click is outside, close everything
|
|
86
|
+
this.closePalette();
|
|
87
|
+
this.closeParameterPrompt();
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
private handleDialogClick(e: Event) {
|
|
91
|
+
e.stopPropagation();
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
private handleInputFocus() {
|
|
95
|
+
// Use requestAnimationFrame to prevent interrupting the focus
|
|
96
|
+
requestAnimationFrame(() => {
|
|
97
|
+
this.isPaletteOpen = true;
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
private handleInputClick(e: Event) {
|
|
102
|
+
e.stopPropagation();
|
|
103
|
+
this.openPalette();
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
private handleInputMouseDown(e: Event) {
|
|
107
|
+
e.stopPropagation();
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
private updateCommandList() {
|
|
111
|
+
const commands = commandRegistry.listCommands(this.executionContext || {});
|
|
112
|
+
this.allCommands = Object.values(commands)
|
|
113
|
+
.filter((cmd: any) => cmd.id !== 'commandpalette.open')
|
|
114
|
+
.map((cmd: any) => ({
|
|
115
|
+
id: cmd.id,
|
|
116
|
+
name: cmd.name,
|
|
117
|
+
description: cmd.description,
|
|
118
|
+
icon: cmd.icon,
|
|
119
|
+
keyBinding: cmd.keyBinding
|
|
120
|
+
}));
|
|
121
|
+
|
|
122
|
+
this.filteredCommands = [...this.allCommands];
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
public async openPalette() {
|
|
126
|
+
this.executionContext = commandRegistry.createExecutionContext();
|
|
127
|
+
this.inputValue = '';
|
|
128
|
+
this.updateCommandList();
|
|
129
|
+
this.showParameterPrompt = false;
|
|
130
|
+
this.isPaletteOpen = true;
|
|
131
|
+
|
|
132
|
+
await this.updateComplete;
|
|
133
|
+
|
|
134
|
+
if (this.inputRef.value) {
|
|
135
|
+
this.inputRef.value.focus();
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
private closePalette() {
|
|
140
|
+
this.isPaletteOpen = false;
|
|
141
|
+
this.inputValue = '';
|
|
142
|
+
this.showParameterPrompt = false;
|
|
143
|
+
this.executionContext = undefined;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
private handleInputChange(e: Event) {
|
|
147
|
+
const input = e.target as any;
|
|
148
|
+
this.inputValue = input.value;
|
|
149
|
+
this.filterCommands();
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
private filterCommands() {
|
|
153
|
+
if (!this.inputValue.trim()) {
|
|
154
|
+
this.filteredCommands = [...this.allCommands];
|
|
155
|
+
} else {
|
|
156
|
+
const searchLower = this.inputValue.toLowerCase();
|
|
157
|
+
this.filteredCommands = this.allCommands.filter(cmd =>
|
|
158
|
+
cmd.name.toLowerCase().includes(searchLower) ||
|
|
159
|
+
cmd.id.toLowerCase().includes(searchLower) ||
|
|
160
|
+
(cmd.description && cmd.description.toLowerCase().includes(searchLower))
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
private handleKeyDown(e: KeyboardEvent) {
|
|
166
|
+
if (e.key === 'Escape') {
|
|
167
|
+
e.preventDefault();
|
|
168
|
+
this.closePalette();
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
private handleCommandClick(e: Event, command: any) {
|
|
173
|
+
if (!command) return;
|
|
174
|
+
e.stopPropagation();
|
|
175
|
+
this.inputValue = '';
|
|
176
|
+
this.filterCommands();
|
|
177
|
+
this.runCommand(command);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
private handleContainerClick(e: Event) {
|
|
181
|
+
e.stopPropagation();
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
private runCommand(command: any) {
|
|
185
|
+
if (!command || !commandRegistry) return;
|
|
186
|
+
|
|
187
|
+
// Get the full command details from registry
|
|
188
|
+
const fullCommand = commandRegistry.getCommand(command.id);
|
|
189
|
+
|
|
190
|
+
// Check if command has any parameters (required or optional)
|
|
191
|
+
const hasParameters = fullCommand?.parameters && fullCommand.parameters.length > 0;
|
|
192
|
+
|
|
193
|
+
if (hasParameters) {
|
|
194
|
+
// Show parameter prompt for any command with parameters
|
|
195
|
+
this.selectedCommand = fullCommand;
|
|
196
|
+
this.parameterValues = {};
|
|
197
|
+
this.showParameterPrompt = true;
|
|
198
|
+
} else {
|
|
199
|
+
// Execute directly without parameters
|
|
200
|
+
this.executeCommandWithParams(command.id, {});
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
private executeCommandWithParams(commandId: string, params: any) {
|
|
205
|
+
try {
|
|
206
|
+
commandRegistry.execute(commandId, { ...(this.executionContext || {}), params });
|
|
207
|
+
this.closePalette();
|
|
208
|
+
this.closeParameterPrompt();
|
|
209
|
+
} catch (error: any) {
|
|
210
|
+
console.error('Failed to execute command:', error);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
private closeParameterPrompt() {
|
|
215
|
+
this.showParameterPrompt = false;
|
|
216
|
+
this.selectedCommand = null;
|
|
217
|
+
this.parameterValues = {};
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
private handleParameterInput(paramName: string, value: string) {
|
|
221
|
+
this.parameterValues = {
|
|
222
|
+
...this.parameterValues,
|
|
223
|
+
[paramName]: value
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
private executeWithParameters() {
|
|
228
|
+
if (!this.selectedCommand) return;
|
|
229
|
+
|
|
230
|
+
// Validate required parameters
|
|
231
|
+
const missingParams = this.selectedCommand.parameters
|
|
232
|
+
?.filter((p: any) => p.required && !this.parameterValues[p.name])
|
|
233
|
+
.map((p: any) => p.name);
|
|
234
|
+
|
|
235
|
+
if (missingParams && missingParams.length > 0) {
|
|
236
|
+
if ((this as any).toastError) {
|
|
237
|
+
(this as any).toastError(t('MISSING_REQUIRED_PARAMS', { params: missingParams.join(', ') }));
|
|
238
|
+
}
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
this.executeCommandWithParams(this.selectedCommand.id, this.parameterValues);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
protected doClose() {
|
|
246
|
+
if (this.boundDocumentClickHandler) {
|
|
247
|
+
document.removeEventListener('click', this.boundDocumentClickHandler);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
static styles = css`
|
|
252
|
+
:host {
|
|
253
|
+
display: block;
|
|
254
|
+
width: 100%;
|
|
255
|
+
max-width: 600px;
|
|
256
|
+
position: relative;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
wa-input {
|
|
260
|
+
max-width: 300px;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
.commands-container {
|
|
264
|
+
position: absolute;
|
|
265
|
+
top: 100%;
|
|
266
|
+
left: 0;
|
|
267
|
+
right: 0;
|
|
268
|
+
margin-top: 4px;
|
|
269
|
+
background: var(--wa-color-neutral-05);
|
|
270
|
+
border: 1px solid var(--wa-color-neutral-25);
|
|
271
|
+
border-radius: 4px;
|
|
272
|
+
max-height: 400px;
|
|
273
|
+
overflow-y: auto;
|
|
274
|
+
z-index: 1000;
|
|
275
|
+
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.8);
|
|
276
|
+
display: none;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
:host-context(.wa-light) .commands-container {
|
|
280
|
+
background: var(--wa-color-neutral-95);
|
|
281
|
+
border: 1px solid var(--wa-color-neutral-75);
|
|
282
|
+
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.2);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
.commands-container.open {
|
|
286
|
+
display: block;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
.command-item {
|
|
290
|
+
display: flex;
|
|
291
|
+
align-items: center;
|
|
292
|
+
gap: 12px;
|
|
293
|
+
padding: 10px 16px;
|
|
294
|
+
cursor: pointer;
|
|
295
|
+
transition: background-color 0.15s;
|
|
296
|
+
border-bottom: 1px solid var(--wa-color-neutral-15);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
:host-context(.wa-light) .command-item {
|
|
300
|
+
border-bottom: 1px solid var(--wa-color-neutral-85);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
.command-item:last-child {
|
|
304
|
+
border-bottom: none;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
.command-item:hover {
|
|
308
|
+
background: var(--wa-color-neutral-20);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
:host-context(.wa-light) .command-item:hover {
|
|
312
|
+
background: var(--wa-color-neutral-80);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
.command-icon {
|
|
316
|
+
flex-shrink: 0;
|
|
317
|
+
width: 20px;
|
|
318
|
+
height: 20px;
|
|
319
|
+
display: flex;
|
|
320
|
+
align-items: center;
|
|
321
|
+
justify-content: center;
|
|
322
|
+
opacity: 0.7;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
.command-info {
|
|
326
|
+
flex: 1;
|
|
327
|
+
min-width: 0;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
.command-name {
|
|
331
|
+
font-size: 14px;
|
|
332
|
+
font-weight: 500;
|
|
333
|
+
margin-bottom: 2px;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
.command-id {
|
|
337
|
+
font-size: 11px;
|
|
338
|
+
opacity: 0.5;
|
|
339
|
+
font-family: monospace;
|
|
340
|
+
margin-bottom: 2px;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
.command-description {
|
|
344
|
+
font-size: 12px;
|
|
345
|
+
opacity: 0.7;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
.command-keybinding {
|
|
349
|
+
flex-shrink: 0;
|
|
350
|
+
margin-left: auto;
|
|
351
|
+
padding: 2px 8px;
|
|
352
|
+
background: var(--wa-color-neutral-15);
|
|
353
|
+
border: 1px solid var(--wa-color-neutral-25);
|
|
354
|
+
border-radius: 3px;
|
|
355
|
+
font-size: 11px;
|
|
356
|
+
font-family: monospace;
|
|
357
|
+
opacity: 0.7;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
:host-context(.wa-light) .command-keybinding {
|
|
361
|
+
background: var(--wa-color-neutral-85);
|
|
362
|
+
border: 1px solid var(--wa-color-neutral-75);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
.no-results {
|
|
366
|
+
padding: 20px;
|
|
367
|
+
text-align: center;
|
|
368
|
+
color: var(--wa-color-neutral-60);
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
:host-context(.wa-light) .no-results {
|
|
372
|
+
color: var(--wa-color-neutral-40);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
wa-dialog::part(panel) {
|
|
376
|
+
max-width: 600px;
|
|
377
|
+
width: 90vw;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
wa-dialog::part(body) {
|
|
381
|
+
padding: 20px;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
.parameter-prompt-title {
|
|
385
|
+
font-size: 16px;
|
|
386
|
+
font-weight: 600;
|
|
387
|
+
margin-bottom: 16px;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
.parameter-field {
|
|
391
|
+
margin-bottom: 12px;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
.parameter-field wa-input {
|
|
395
|
+
width: 100%;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
.parameter-actions {
|
|
399
|
+
display: flex;
|
|
400
|
+
gap: 8px;
|
|
401
|
+
justify-content: flex-end;
|
|
402
|
+
margin-top: 20px;
|
|
403
|
+
}
|
|
404
|
+
`;
|
|
405
|
+
|
|
406
|
+
render() {
|
|
407
|
+
return html`
|
|
408
|
+
<wa-input
|
|
409
|
+
${ref(this.inputRef)}
|
|
410
|
+
placeholder="${t('PLACEHOLDER')}"
|
|
411
|
+
.value=${this.inputValue}
|
|
412
|
+
@input=${this.handleInputChange}
|
|
413
|
+
@keydown=${this.handleKeyDown}
|
|
414
|
+
@focus=${this.handleInputFocus}
|
|
415
|
+
@click=${this.handleInputClick}
|
|
416
|
+
@mousedown=${this.handleInputMouseDown}
|
|
417
|
+
autocomplete="off"
|
|
418
|
+
size="small"
|
|
419
|
+
>
|
|
420
|
+
<wa-icon slot="start" name="terminal" label="Terminal"></wa-icon>
|
|
421
|
+
</wa-input>
|
|
422
|
+
|
|
423
|
+
<div class="commands-container ${this.isPaletteOpen ? 'open' : ''}" @click=${this.handleContainerClick}>
|
|
424
|
+
${this.filteredCommands.length > 0 ? html`
|
|
425
|
+
${this.filteredCommands.map(cmd => html`
|
|
426
|
+
<div class="command-item" @click=${(e: Event) => this.handleCommandClick(e, cmd)}>
|
|
427
|
+
${cmd.icon ? html`
|
|
428
|
+
<div class="command-icon">
|
|
429
|
+
<wa-icon name="${cmd.icon}" label="${cmd.name}"></wa-icon>
|
|
430
|
+
</div>
|
|
431
|
+
` : html`
|
|
432
|
+
<div class="command-icon">
|
|
433
|
+
<wa-icon name="terminal" label="Command"></wa-icon>
|
|
434
|
+
</div>
|
|
435
|
+
`}
|
|
436
|
+
<div class="command-info">
|
|
437
|
+
<div class="command-name">${cmd.name}</div>
|
|
438
|
+
<div class="command-id">${cmd.id}</div>
|
|
439
|
+
${cmd.description ? html`
|
|
440
|
+
<div class="command-description">${cmd.description}</div>
|
|
441
|
+
` : ''}
|
|
442
|
+
</div>
|
|
443
|
+
${cmd.keyBinding ? html`
|
|
444
|
+
<div class="command-keybinding">${cmd.keyBinding}</div>
|
|
445
|
+
` : ''}
|
|
446
|
+
</div>
|
|
447
|
+
`)}
|
|
448
|
+
` : html`
|
|
449
|
+
<div class="no-results">
|
|
450
|
+
<wa-icon name="search" label="${t('NO_COMMANDS_FOUND')}" style="font-size: 24px; margin-bottom: 4px; opacity: 0.3;"></wa-icon>
|
|
451
|
+
<div>${t('NO_COMMANDS_FOUND')}</div>
|
|
452
|
+
</div>
|
|
453
|
+
`}
|
|
454
|
+
</div>
|
|
455
|
+
|
|
456
|
+
${this.showParameterPrompt && this.selectedCommand ? html`
|
|
457
|
+
<wa-dialog
|
|
458
|
+
${ref(this.dialogRef)}
|
|
459
|
+
label="${this.selectedCommand.name} - ${t('PARAMETERS')}"
|
|
460
|
+
open
|
|
461
|
+
@wa-request-close=${this.closeParameterPrompt}
|
|
462
|
+
@click=${this.handleDialogClick}
|
|
463
|
+
>
|
|
464
|
+
<div class="parameter-prompt-title">
|
|
465
|
+
${t('ENTER_PARAMETERS', { commandName: this.selectedCommand.name })}
|
|
466
|
+
</div>
|
|
467
|
+
${this.selectedCommand.parameters?.map((param: any) => html`
|
|
468
|
+
<div class="parameter-field">
|
|
469
|
+
<wa-input
|
|
470
|
+
label="${param.name}${param.required ? ' *' : ''}"
|
|
471
|
+
hint=${param.description || ''}
|
|
472
|
+
placeholder=${param.description || t('ENTER_PARAM', { paramName: param.name })}
|
|
473
|
+
.value=${this.parameterValues[param.name] || ''}
|
|
474
|
+
@input=${(e: Event) => this.handleParameterInput(param.name, (e.target as any).value)}
|
|
475
|
+
></wa-input>
|
|
476
|
+
</div>
|
|
477
|
+
`)}
|
|
478
|
+
<div class="parameter-actions">
|
|
479
|
+
<wa-button variant="default" @click=${this.closeParameterPrompt}>
|
|
480
|
+
${t('CANCEL')}
|
|
481
|
+
</wa-button>
|
|
482
|
+
<wa-button variant="primary" @click=${this.executeWithParameters}>
|
|
483
|
+
${t('EXECUTE')}
|
|
484
|
+
</wa-button>
|
|
485
|
+
</div>
|
|
486
|
+
</wa-dialog>
|
|
487
|
+
` : ''}
|
|
488
|
+
`;
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
export default ({ contributionRegistry, commandRegistry, toastInfo, toastError, html, publish }: any) => {
|
|
493
|
+
// Register language bundle
|
|
494
|
+
contributionRegistry.registerContribution(SYSTEM_LANGUAGE_BUNDLES,
|
|
495
|
+
commandpaletteBundle as any);
|
|
496
|
+
|
|
497
|
+
// Register command to open palette using events
|
|
498
|
+
commandRegistry.registerHandler('commandpalette.open', {
|
|
499
|
+
execute: () => {
|
|
500
|
+
// Publish event to open the palette
|
|
501
|
+
publish(TOPIC_OPEN_COMMAND_PALETTE, null);
|
|
502
|
+
}
|
|
503
|
+
});
|
|
504
|
+
|
|
505
|
+
commandRegistry.registerCommand({
|
|
506
|
+
id: 'commandpalette.open',
|
|
507
|
+
name: t('OPEN_COMMAND_PALETTE'),
|
|
508
|
+
description: t('OPEN_COMMAND_PALETTE_DESC'),
|
|
509
|
+
icon: 'terminal',
|
|
510
|
+
keyBinding: 'CTRL+SHIFT+P'
|
|
511
|
+
});
|
|
512
|
+
|
|
513
|
+
// Create the command palette element once and reuse it
|
|
514
|
+
const commandPaletteElement = (() => {
|
|
515
|
+
const element = document.createElement('k-command-palette') as any;
|
|
516
|
+
element.commandRegistry = commandRegistry;
|
|
517
|
+
element.toastInfo = toastInfo;
|
|
518
|
+
element.toastError = toastError;
|
|
519
|
+
return element;
|
|
520
|
+
})();
|
|
521
|
+
|
|
522
|
+
// Register UI component at the top center
|
|
523
|
+
contributionRegistry.registerContribution(TOOLBAR_MAIN_CENTER, {
|
|
524
|
+
label: "Command Palette",
|
|
525
|
+
icon: "terminal",
|
|
526
|
+
html: () => html`${commandPaletteElement}`
|
|
527
|
+
});
|
|
528
|
+
|
|
529
|
+
}
|
|
530
|
+
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"namespace": "commandpalette",
|
|
3
|
+
"en": {
|
|
4
|
+
"PLACEHOLDER": "Type a command name...",
|
|
5
|
+
"NO_COMMANDS_FOUND": "No commands found",
|
|
6
|
+
"PARAMETERS": "Parameters",
|
|
7
|
+
"ENTER_PARAMETERS": "Enter parameters for {commandName}",
|
|
8
|
+
"CANCEL": "Cancel",
|
|
9
|
+
"EXECUTE": "Execute",
|
|
10
|
+
"OPEN_COMMAND_PALETTE": "Open Command Palette",
|
|
11
|
+
"OPEN_COMMAND_PALETTE_DESC": "Opens the command palette to execute commands",
|
|
12
|
+
"MISSING_REQUIRED_PARAMS": "Missing required parameters: {params}",
|
|
13
|
+
"ENTER_PARAM": "Enter {paramName}"
|
|
14
|
+
},
|
|
15
|
+
"de": {
|
|
16
|
+
"PLACEHOLDER": "Befehlsname eingeben...",
|
|
17
|
+
"NO_COMMANDS_FOUND": "Keine Befehle gefunden",
|
|
18
|
+
"PARAMETERS": "Parameter",
|
|
19
|
+
"ENTER_PARAMETERS": "Parameter für {commandName} eingeben",
|
|
20
|
+
"CANCEL": "Abbrechen",
|
|
21
|
+
"EXECUTE": "Ausführen",
|
|
22
|
+
"OPEN_COMMAND_PALETTE": "Befehls-Palette öffnen",
|
|
23
|
+
"OPEN_COMMAND_PALETTE_DESC": "Öffnet die Befehls-Palette zum Ausführen von Befehlen",
|
|
24
|
+
"MISSING_REQUIRED_PARAMS": "Erforderliche Parameter fehlen: {params}",
|
|
25
|
+
"ENTER_PARAM": "{paramName} eingeben"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
package/src/i18n.json
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"namespace": "extensions",
|
|
3
|
+
"en": {
|
|
4
|
+
"EXT_COMMANDPALETTE_NAME": "Command Palette",
|
|
5
|
+
"EXT_COMMANDPALETTE_DESC": "VS Code-style command palette at the top center for quick command execution (Ctrl+Shift+P)"
|
|
6
|
+
},
|
|
7
|
+
"de": {
|
|
8
|
+
"EXT_COMMANDPALETTE_NAME": "Befehls-Palette",
|
|
9
|
+
"EXT_COMMANDPALETTE_DESC": "VS Code-ähnliche Befehls-Palette oben in der Mitte für schnelle Befehlsausführung (Strg+Umschalt+P)"
|
|
10
|
+
}
|
|
11
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { extensionRegistry, i18nLazy, contributionRegistry, SYSTEM_LANGUAGE_BUNDLES } from '@kispace-io/core';
|
|
2
|
+
import bundle from './i18n.json';
|
|
3
|
+
|
|
4
|
+
contributionRegistry.registerContribution(SYSTEM_LANGUAGE_BUNDLES, bundle as any);
|
|
5
|
+
|
|
6
|
+
const t = i18nLazy('extensions');
|
|
7
|
+
|
|
8
|
+
extensionRegistry.registerExtension({
|
|
9
|
+
id: "system.commandpalette",
|
|
10
|
+
name: t('EXT_COMMANDPALETTE_NAME'),
|
|
11
|
+
description: t('EXT_COMMANDPALETTE_DESC'),
|
|
12
|
+
loader: () => import("./command-palette-extension"),
|
|
13
|
+
icon: "terminal",
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
});
|