@workbench-kit/shell-react 0.0.2-prototype.0.2.26 → 0.0.2-prototype.0.2.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -2
- package/package.json +10 -10
- package/src/chat/command-policy.ts +3 -17
- package/src/commands/use-command-descriptors.ts +2 -30
- package/src/commands/use-context-key-revision.ts +12 -12
- package/src/commands/use-extension-registry-command-descriptors.ts +46 -0
- package/src/devtools/use-workbench-devtools-snapshot.ts +1 -1
- package/src/editor/pane-visibility.ts +0 -23
- package/src/editor/view-providers.tsx +0 -7
- package/src/explorer/reveal.ts +1 -12
- package/src/extensions/builtin/commands/src/command-inspector-editor-host.ts +1 -19
- package/src/extensions/builtin/commands/src/index.ts +2 -2
- package/src/field-remap/convert-note-editor.tsx +2 -4
- package/src/field-remap/convert-palette.tsx +17 -20
- package/src/field-remap/flow-adapter.ts +21 -57
- package/src/field-remap/flow-ops.ts +0 -24
- package/src/field-remap/index.ts +0 -1
- package/src/field-remap/io-class-browse.tsx +29 -6
- package/src/field-remap/jsonata-transform.ts +9 -39
- package/src/field-remap/shape-io-editor.tsx +1 -1
- package/src/field-remap/transform-options-editor.tsx +1 -2
- package/src/field-remap/view.css +4 -29
- package/src/index.ts +1 -10
- package/src/jdw/widget-form-view.tsx +3 -20
- package/src/jdw/widget-preview-view.tsx +2 -20
- package/src/management/use-command-management.ts +22 -7
- package/src/management/use-keybinding-management.ts +1 -10
- package/src/shell/provider.tsx +19 -9
- package/src/shell/shell.tsx +11 -4
- package/src/workbench/command-host.tsx +46 -7
- package/src/workbench/command-palette.ts +12 -45
- package/src/workbench/workspace-view-state.ts +18 -1
- package/src/field-remap/graph.tsx +0 -559
- package/src/field-remap/table-mapping-adapter.ts +0 -59
- package/src/field-remap/tree.tsx +0 -404
|
@@ -20,6 +20,10 @@ export interface FieldRemapIoClassBrowseProps {
|
|
|
20
20
|
readonly targetsTitle?: string;
|
|
21
21
|
readonly className?: string;
|
|
22
22
|
readonly emptyLabel?: string;
|
|
23
|
+
readonly labels?: {
|
|
24
|
+
readonly hiddenBadge?: string;
|
|
25
|
+
readonly classRefTitle?: string;
|
|
26
|
+
};
|
|
23
27
|
}
|
|
24
28
|
|
|
25
29
|
export function resolveFieldRemapIoChrome(
|
|
@@ -39,9 +43,11 @@ function formatClassRef(classRef: { readonly id: string; readonly version: numbe
|
|
|
39
43
|
function FieldTree({
|
|
40
44
|
nodes,
|
|
41
45
|
emptyLabel,
|
|
46
|
+
labels,
|
|
42
47
|
}: {
|
|
43
48
|
readonly nodes: readonly (SourceField | TargetSlot)[];
|
|
44
49
|
readonly emptyLabel: string;
|
|
50
|
+
readonly labels: FieldRemapIoClassBrowseProps['labels'];
|
|
45
51
|
}): JSX.Element {
|
|
46
52
|
if (nodes.length === 0) {
|
|
47
53
|
return <p className="workbench-field-remap-io-browse__empty">{emptyLabel}</p>;
|
|
@@ -55,19 +61,22 @@ function FieldTree({
|
|
|
55
61
|
<span className="workbench-field-remap-io-browse__meta">
|
|
56
62
|
{node.dataType ? <span>{node.dataType}</span> : null}
|
|
57
63
|
{node.classRef ? (
|
|
58
|
-
<span
|
|
64
|
+
<span
|
|
65
|
+
className="workbench-field-remap-io-browse__badge"
|
|
66
|
+
title={labels?.classRefTitle ?? 'classRef'}
|
|
67
|
+
>
|
|
59
68
|
{formatClassRef(node.classRef)}
|
|
60
69
|
</span>
|
|
61
70
|
) : null}
|
|
62
71
|
{node.hidden === true ? (
|
|
63
72
|
<span className="workbench-field-remap-io-browse__badge" title="hidden">
|
|
64
|
-
Hidden
|
|
73
|
+
{labels?.hiddenBadge ?? 'Hidden'}
|
|
65
74
|
</span>
|
|
66
75
|
) : null}
|
|
67
76
|
</span>
|
|
68
77
|
</div>
|
|
69
78
|
{node.children?.length ? (
|
|
70
|
-
<FieldTree emptyLabel={emptyLabel} nodes={node.children} />
|
|
79
|
+
<FieldTree emptyLabel={emptyLabel} labels={labels} nodes={node.children} />
|
|
71
80
|
) : null}
|
|
72
81
|
</li>
|
|
73
82
|
))}
|
|
@@ -79,10 +88,12 @@ function PortSection({
|
|
|
79
88
|
title,
|
|
80
89
|
nodes,
|
|
81
90
|
emptyLabel,
|
|
91
|
+
labels,
|
|
82
92
|
}: {
|
|
83
93
|
readonly title: string;
|
|
84
94
|
readonly nodes: readonly (SourceField | TargetSlot)[];
|
|
85
95
|
readonly emptyLabel: string;
|
|
96
|
+
readonly labels: FieldRemapIoClassBrowseProps['labels'];
|
|
86
97
|
}): JSX.Element {
|
|
87
98
|
return (
|
|
88
99
|
<section aria-label={title} className="workbench-field-remap-io-browse__section">
|
|
@@ -96,11 +107,12 @@ function PortSection({
|
|
|
96
107
|
<span className="workbench-field-remap-io-browse__port-id">{node.label}</span>
|
|
97
108
|
<span className="workbench-field-remap-io-browse__port-meta">
|
|
98
109
|
{node.classRef ? formatClassRef(node.classRef) : node.id}
|
|
99
|
-
{node.hidden === true ?
|
|
110
|
+
{node.hidden === true ? ` · ${labels?.hiddenBadge ?? 'Hidden'}` : ''}
|
|
100
111
|
</span>
|
|
101
112
|
</p>
|
|
102
113
|
<FieldTree
|
|
103
114
|
emptyLabel={emptyLabel}
|
|
115
|
+
labels={labels}
|
|
104
116
|
nodes={node.children?.length ? node.children : [node]}
|
|
105
117
|
/>
|
|
106
118
|
</div>
|
|
@@ -123,6 +135,7 @@ export function FieldRemapIoClassBrowse({
|
|
|
123
135
|
targetsTitle = 'Outputs',
|
|
124
136
|
className,
|
|
125
137
|
emptyLabel = 'No fields',
|
|
138
|
+
labels,
|
|
126
139
|
}: FieldRemapIoClassBrowseProps): JSX.Element {
|
|
127
140
|
const projectedSources = useMemo(
|
|
128
141
|
() => projectSourceFields(sources, { includeHidden }),
|
|
@@ -138,8 +151,18 @@ export function FieldRemapIoClassBrowse({
|
|
|
138
151
|
className={['workbench-field-remap-io-browse', className].filter(Boolean).join(' ')}
|
|
139
152
|
data-testid="field-remap-io-browse"
|
|
140
153
|
>
|
|
141
|
-
<PortSection
|
|
142
|
-
|
|
154
|
+
<PortSection
|
|
155
|
+
emptyLabel={emptyLabel}
|
|
156
|
+
labels={labels}
|
|
157
|
+
nodes={projectedSources}
|
|
158
|
+
title={sourcesTitle}
|
|
159
|
+
/>
|
|
160
|
+
<PortSection
|
|
161
|
+
emptyLabel={emptyLabel}
|
|
162
|
+
labels={labels}
|
|
163
|
+
nodes={projectedTargets}
|
|
164
|
+
title={targetsTitle}
|
|
165
|
+
/>
|
|
143
166
|
</div>
|
|
144
167
|
);
|
|
145
168
|
}
|
|
@@ -10,8 +10,6 @@ export const DEFAULT_JSONATA_TIMEOUT_MS = 2_000;
|
|
|
10
10
|
/** Default maximum expression source length (characters). */
|
|
11
11
|
export const DEFAULT_JSONATA_MAX_EXPRESSION_LENGTH = 4_096;
|
|
12
12
|
|
|
13
|
-
export type JsonataTransformErrorPolicy = 'passthrough' | 'throw';
|
|
14
|
-
|
|
15
13
|
export interface CreateJsonataValueTransformOptions {
|
|
16
14
|
/** Wall-clock timeout for `evaluate` (default {@link DEFAULT_JSONATA_TIMEOUT_MS}). */
|
|
17
15
|
readonly timeoutMs?: number;
|
|
@@ -20,11 +18,6 @@ export interface CreateJsonataValueTransformOptions {
|
|
|
20
18
|
* (default {@link DEFAULT_JSONATA_MAX_EXPRESSION_LENGTH}).
|
|
21
19
|
*/
|
|
22
20
|
readonly maxExpressionLength?: number;
|
|
23
|
-
/**
|
|
24
|
-
* - `throw` (default): surface timeout / compile / evaluate failures to the host
|
|
25
|
-
* - `passthrough`: return the original value (legacy silent identity)
|
|
26
|
-
*/
|
|
27
|
-
readonly onError?: JsonataTransformErrorPolicy;
|
|
28
21
|
}
|
|
29
22
|
|
|
30
23
|
export function createJsonataValueTransform(
|
|
@@ -32,7 +25,6 @@ export function createJsonataValueTransform(
|
|
|
32
25
|
): ValueTransformDefinition {
|
|
33
26
|
const timeoutMs = options.timeoutMs ?? DEFAULT_JSONATA_TIMEOUT_MS;
|
|
34
27
|
const maxExpressionLength = options.maxExpressionLength ?? DEFAULT_JSONATA_MAX_EXPRESSION_LENGTH;
|
|
35
|
-
const onError = options.onError ?? 'throw';
|
|
36
28
|
|
|
37
29
|
return {
|
|
38
30
|
id: JSONATA_TRANSFORM_ID,
|
|
@@ -57,30 +49,22 @@ export function createJsonataValueTransform(
|
|
|
57
49
|
}
|
|
58
50
|
|
|
59
51
|
if (expression.length > maxExpressionLength) {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
`JSONata expression exceeds max length (${expression.length} > ${maxExpressionLength}).`,
|
|
63
|
-
),
|
|
64
|
-
value,
|
|
65
|
-
onError,
|
|
52
|
+
throw new Error(
|
|
53
|
+
`JSONata expression exceeds max length (${expression.length} > ${maxExpressionLength}).`,
|
|
66
54
|
);
|
|
67
55
|
}
|
|
68
56
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
});
|
|
76
|
-
} catch (error) {
|
|
77
|
-
return handleJsonataError(error, value, onError);
|
|
78
|
-
}
|
|
57
|
+
const compiled = jsonata(expression);
|
|
58
|
+
// jsonata@2.x evaluate returns a Promise (1.x was synchronous).
|
|
59
|
+
return await raceJsonataEvaluation(compiled.evaluate(value), {
|
|
60
|
+
timeoutMs,
|
|
61
|
+
signal: context.signal,
|
|
62
|
+
});
|
|
79
63
|
},
|
|
80
64
|
};
|
|
81
65
|
}
|
|
82
66
|
|
|
83
|
-
/** Default bounded transform (
|
|
67
|
+
/** Default bounded transform (2s timeout, 4k expression cap). */
|
|
84
68
|
export const jsonataValueTransform: ValueTransformDefinition = createJsonataValueTransform();
|
|
85
69
|
|
|
86
70
|
export class JsonataTransformTimeoutError extends Error {
|
|
@@ -150,17 +134,3 @@ export async function raceJsonataEvaluation<T>(
|
|
|
150
134
|
);
|
|
151
135
|
});
|
|
152
136
|
}
|
|
153
|
-
|
|
154
|
-
function handleJsonataError(
|
|
155
|
-
error: unknown,
|
|
156
|
-
value: unknown,
|
|
157
|
-
onError: JsonataTransformErrorPolicy,
|
|
158
|
-
): unknown {
|
|
159
|
-
if (onError === 'passthrough') {
|
|
160
|
-
return value;
|
|
161
|
-
}
|
|
162
|
-
if (error instanceof Error) {
|
|
163
|
-
throw error;
|
|
164
|
-
}
|
|
165
|
-
throw new Error(String(error));
|
|
166
|
-
}
|
|
@@ -34,7 +34,7 @@ function formatJson(value: unknown): string {
|
|
|
34
34
|
|
|
35
35
|
/**
|
|
36
36
|
* Host-owned shape IO surface: paste JSON → ingest fields/slots, edit FieldDataType.
|
|
37
|
-
* Persistence stays host-owned (`FieldRemapDocument`
|
|
37
|
+
* Persistence stays host-owned (`FieldRemapDocument` stores mappings, not shapes).
|
|
38
38
|
*/
|
|
39
39
|
export function FieldRemapShapeIoEditor({
|
|
40
40
|
role,
|
|
@@ -195,8 +195,7 @@ function JsonOptionEditor({
|
|
|
195
195
|
|
|
196
196
|
/**
|
|
197
197
|
* Presentational editor for `TransformOptionField` kinds (string / number / boolean /
|
|
198
|
-
* stringMap / json). Emits
|
|
199
|
-
* `patchOptionStep` / `sanitizeOptionRecord`.
|
|
198
|
+
* stringMap / json). Emits the full options record for one transform step.
|
|
200
199
|
*/
|
|
201
200
|
export function TransformOptionsEditor({
|
|
202
201
|
fields,
|
package/src/field-remap/view.css
CHANGED
|
@@ -365,41 +365,16 @@
|
|
|
365
365
|
}
|
|
366
366
|
|
|
367
367
|
.workbench-field-remap-convert-palette__list {
|
|
368
|
-
list-style: none;
|
|
369
|
-
margin: 0;
|
|
370
|
-
padding: 0;
|
|
371
|
-
display: flex;
|
|
372
368
|
flex: 1 1 auto;
|
|
373
|
-
flex-direction: column;
|
|
374
|
-
gap: 0.35rem;
|
|
375
369
|
min-height: 0;
|
|
376
370
|
overflow: auto;
|
|
377
371
|
}
|
|
378
372
|
|
|
379
|
-
.workbench-field-remap-convert-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
gap: 0.15rem;
|
|
384
|
-
width: 100%;
|
|
385
|
-
margin: 0;
|
|
386
|
-
padding: 0.45rem 0.5rem;
|
|
387
|
-
border: 1px solid var(--vscode-panel-border, var(--color-border));
|
|
388
|
-
border-radius: 0.25rem;
|
|
389
|
-
background: var(--vscode-editor-background, var(--color-bg));
|
|
390
|
-
color: inherit;
|
|
391
|
-
text-align: left;
|
|
392
|
-
cursor: pointer;
|
|
393
|
-
font: inherit;
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
.workbench-field-remap-convert-palette__item.is-selected {
|
|
397
|
-
border-color: var(--vscode-focusBorder, var(--color-accent, #3794ff));
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
.workbench-field-remap-convert-palette__item code {
|
|
373
|
+
.workbench-field-remap-convert-palette__list code {
|
|
374
|
+
overflow: hidden;
|
|
375
|
+
text-overflow: ellipsis;
|
|
376
|
+
white-space: nowrap;
|
|
401
377
|
font-size: 0.7rem;
|
|
402
|
-
word-break: break-all;
|
|
403
378
|
}
|
|
404
379
|
|
|
405
380
|
.workbench-field-remap-convert-palette__operators {
|
package/src/index.ts
CHANGED
|
@@ -63,11 +63,8 @@ export { EditorArea, type EditorAreaProps, type EditorViewMode } from './editor/
|
|
|
63
63
|
export {
|
|
64
64
|
DEFAULT_EDITOR_DOCUMENT_VIEW_PROVIDERS,
|
|
65
65
|
EditorDocumentViewProviderRegistry,
|
|
66
|
-
JDW_PREVIEW_PROVIDER_ID,
|
|
67
|
-
JDW_WIDGET_FORM_PROVIDER_ID,
|
|
68
66
|
JSON_FORM_PROVIDER,
|
|
69
67
|
JSON_FORM_PROVIDER_ID,
|
|
70
|
-
MARKDOWN_PREVIEW_PROVIDER_ID,
|
|
71
68
|
createEditorDocumentViewProviderRegistry,
|
|
72
69
|
resolveEditorDocumentViewProvider,
|
|
73
70
|
resolveEditorDocumentViews,
|
|
@@ -182,7 +179,6 @@ export {
|
|
|
182
179
|
createJsonataValueTransform,
|
|
183
180
|
jsonataValueTransform,
|
|
184
181
|
type CreateJsonataValueTransformOptions,
|
|
185
|
-
type JsonataTransformErrorPolicy,
|
|
186
182
|
} from './field-remap/jsonata-transform.js';
|
|
187
183
|
export {
|
|
188
184
|
FIELD_REMAP_SAMPLES,
|
|
@@ -216,13 +212,7 @@ export {
|
|
|
216
212
|
type WorkbenchThemeOption,
|
|
217
213
|
} from './shell/shell.js';
|
|
218
214
|
export {
|
|
219
|
-
getWorkbenchCommandPaletteShortcutLabel,
|
|
220
|
-
getWorkbenchQuickAccessShortcutLabel,
|
|
221
|
-
WORKBENCH_COMMAND_PALETTE_SHORTCUT,
|
|
222
|
-
WORKBENCH_QUICK_ACCESS_SHORTCUT,
|
|
223
215
|
buildWorkbenchPaletteCommands,
|
|
224
|
-
matchesWorkbenchCommandPaletteShortcut,
|
|
225
|
-
matchesWorkbenchQuickAccessShortcut,
|
|
226
216
|
mergeWorkbenchCommandDescriptors,
|
|
227
217
|
resolveShellCommandActivities,
|
|
228
218
|
} from './workbench/command-palette.js';
|
|
@@ -242,6 +232,7 @@ export {
|
|
|
242
232
|
type WorkbenchChatCommandSurfaceOptions,
|
|
243
233
|
} from './chat/command-surface.js';
|
|
244
234
|
export { useWorkbenchCommandDescriptors } from './commands/use-command-descriptors.js';
|
|
235
|
+
export { useExtensionRegistryCommandDescriptors } from './commands/use-extension-registry-command-descriptors.js';
|
|
245
236
|
export {
|
|
246
237
|
executeWorkbenchUserCommandAction,
|
|
247
238
|
registerWorkbenchUserCommands,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useMemo } from 'react';
|
|
2
2
|
import { resolveWidgetStudioAssetCatalog } from '@workbench-kit/react/widget-studio';
|
|
3
3
|
import { WidgetTreeLab } from '@workbench-kit/react/widget-tree';
|
|
4
4
|
import { BUILTIN_JDW_REGISTRY } from '@workbench-kit/react/jdw';
|
|
@@ -6,7 +6,7 @@ import { BUILTIN_JDW_REGISTRY } from '@workbench-kit/react/jdw';
|
|
|
6
6
|
import { useWorkbench } from '../shell/provider.js';
|
|
7
7
|
import {
|
|
8
8
|
isWorkspaceResourceService,
|
|
9
|
-
|
|
9
|
+
useWorkspaceTextDocuments,
|
|
10
10
|
} from '../workbench/workspace-view-state.js';
|
|
11
11
|
|
|
12
12
|
export interface JdwWidgetFormViewProps {
|
|
@@ -15,8 +15,6 @@ export interface JdwWidgetFormViewProps {
|
|
|
15
15
|
readonly onContentChange: (content: string) => void;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
const EMPTY_WORKSPACE_FILES: readonly { readonly path: string; readonly content: string }[] = [];
|
|
19
|
-
|
|
20
18
|
/**
|
|
21
19
|
* Form authoring surface for JDW widgets. Builds the Assets palette from built-in
|
|
22
20
|
* assets, workspace asset packages, and other workspace `*.jdw.json` documents.
|
|
@@ -28,22 +26,7 @@ export function JdwWidgetFormView({ path, content, onContentChange }: JdwWidgetF
|
|
|
28
26
|
const workspaceService = isWorkspaceResourceService(workspaceHostPort?.service)
|
|
29
27
|
? workspaceHostPort.service
|
|
30
28
|
: undefined;
|
|
31
|
-
const
|
|
32
|
-
const files =
|
|
33
|
-
workspaceState?.files ?? workspaceService?.getState().files ?? EMPTY_WORKSPACE_FILES;
|
|
34
|
-
|
|
35
|
-
const filesByPath = useMemo(() => {
|
|
36
|
-
const map = new Map<string, string>();
|
|
37
|
-
for (const file of files) {
|
|
38
|
-
map.set(file.path.replace(/\\/g, '/'), file.content);
|
|
39
|
-
}
|
|
40
|
-
return map;
|
|
41
|
-
}, [files]);
|
|
42
|
-
|
|
43
|
-
const loadDocument = useCallback(
|
|
44
|
-
(documentPath: string) => filesByPath.get(documentPath.replace(/\\/g, '/')) ?? null,
|
|
45
|
-
[filesByPath],
|
|
46
|
-
);
|
|
29
|
+
const { files, loadDocument } = useWorkspaceTextDocuments(workspaceService);
|
|
47
30
|
|
|
48
31
|
const assetCatalog = useMemo(
|
|
49
32
|
() =>
|
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import { useCallback, useMemo } from 'react';
|
|
2
1
|
import { JdwPreviewViewport } from '@workbench-kit/react/jdw/preview-viewport';
|
|
3
2
|
import { BUILTIN_JDW_REGISTRY } from '@workbench-kit/react/jdw';
|
|
4
3
|
|
|
5
4
|
import { useWorkbench } from '../shell/provider.js';
|
|
6
5
|
import {
|
|
7
6
|
isWorkspaceResourceService,
|
|
8
|
-
|
|
7
|
+
useWorkspaceTextDocuments,
|
|
9
8
|
} from '../workbench/workspace-view-state.js';
|
|
10
9
|
|
|
11
10
|
export interface JdwWidgetPreviewViewProps {
|
|
@@ -14,8 +13,6 @@ export interface JdwWidgetPreviewViewProps {
|
|
|
14
13
|
readonly className?: string | undefined;
|
|
15
14
|
}
|
|
16
15
|
|
|
17
|
-
const EMPTY_WORKSPACE_FILES: readonly { readonly path: string; readonly content: string }[] = [];
|
|
18
|
-
|
|
19
16
|
/**
|
|
20
17
|
* Preview viewport for JDW documents. Expands workspace `type: "ref"` imports
|
|
21
18
|
* before layout/draw without rewriting the source buffer.
|
|
@@ -25,22 +22,7 @@ export function JdwWidgetPreviewView({ path, content, className }: JdwWidgetPrev
|
|
|
25
22
|
const workspaceService = isWorkspaceResourceService(workspaceHostPort?.service)
|
|
26
23
|
? workspaceHostPort.service
|
|
27
24
|
: undefined;
|
|
28
|
-
const
|
|
29
|
-
const files =
|
|
30
|
-
workspaceState?.files ?? workspaceService?.getState().files ?? EMPTY_WORKSPACE_FILES;
|
|
31
|
-
|
|
32
|
-
const filesByPath = useMemo(() => {
|
|
33
|
-
const map = new Map<string, string>();
|
|
34
|
-
for (const file of files) {
|
|
35
|
-
map.set(file.path.replace(/\\/g, '/'), file.content);
|
|
36
|
-
}
|
|
37
|
-
return map;
|
|
38
|
-
}, [files]);
|
|
39
|
-
|
|
40
|
-
const loadDocument = useCallback(
|
|
41
|
-
(documentPath: string) => filesByPath.get(documentPath.replace(/\\/g, '/')) ?? null,
|
|
42
|
-
[filesByPath],
|
|
43
|
-
);
|
|
25
|
+
const { loadDocument } = useWorkspaceTextDocuments(workspaceService);
|
|
44
26
|
|
|
45
27
|
return (
|
|
46
28
|
<JdwPreviewViewport
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
} from '@workbench-kit/react/workbench/management';
|
|
8
8
|
import { createWorkbenchShellCommands } from '@workbench-kit/react/workbench';
|
|
9
9
|
|
|
10
|
+
import { useContextKeyRevision } from '../commands/use-context-key-revision.js';
|
|
10
11
|
import { useWorkbench } from '../shell/provider.js';
|
|
11
12
|
import {
|
|
12
13
|
collectExtensionCommandFeaturesById,
|
|
@@ -14,12 +15,17 @@ import {
|
|
|
14
15
|
} from '../workbench/command-palette.js';
|
|
15
16
|
|
|
16
17
|
export function useCommandManagementModel() {
|
|
17
|
-
const { executeCommand, extensionRegistry } = useWorkbench();
|
|
18
|
+
const { contextKeyService, executeCommand, extensionRegistry } = useWorkbench();
|
|
19
|
+
const contextKeyRevision = useContextKeyRevision(contextKeyService);
|
|
20
|
+
const contextKeySnapshot = useMemo(
|
|
21
|
+
() => contextKeyService.createSnapshot(),
|
|
22
|
+
[contextKeyRevision, contextKeyService],
|
|
23
|
+
);
|
|
18
24
|
const [lastRun, setLastRun] = useState<CommandManagementRunState | undefined>();
|
|
19
25
|
const [refreshToken, refreshRegistry] = useReducer((count: number) => count + 1, 0);
|
|
20
26
|
|
|
21
27
|
useEffect(() => {
|
|
22
|
-
const commandDisposable = extensionRegistry.commands.
|
|
28
|
+
const commandDisposable = extensionRegistry.commands.onDidChangeCommands(() => {
|
|
23
29
|
refreshRegistry();
|
|
24
30
|
});
|
|
25
31
|
|
|
@@ -29,8 +35,8 @@ export function useCommandManagementModel() {
|
|
|
29
35
|
}, [extensionRegistry]);
|
|
30
36
|
|
|
31
37
|
const groups = useMemo(
|
|
32
|
-
() => buildCommandManagementModelGroups(extensionRegistry, refreshToken),
|
|
33
|
-
[extensionRegistry, refreshToken],
|
|
38
|
+
() => buildCommandManagementModelGroups(extensionRegistry, refreshToken, contextKeySnapshot),
|
|
39
|
+
[contextKeySnapshot, extensionRegistry, refreshToken],
|
|
34
40
|
);
|
|
35
41
|
|
|
36
42
|
const totalCount = countCommandManagementEntries(groups);
|
|
@@ -71,19 +77,28 @@ export function useCommandManagementModel() {
|
|
|
71
77
|
export function buildCommandManagementModelGroups(
|
|
72
78
|
extensionRegistry: ExtensionRegistry,
|
|
73
79
|
_refreshToken = 0,
|
|
80
|
+
contextKeys?: object | undefined,
|
|
74
81
|
) {
|
|
75
|
-
const
|
|
82
|
+
const managedShellCommands = createWorkbenchShellCommands({
|
|
76
83
|
activities: resolveShellCommandActivities(extensionRegistry),
|
|
77
84
|
includeSettings: true,
|
|
78
85
|
includeSidebarToggle: true,
|
|
79
86
|
});
|
|
80
|
-
const
|
|
87
|
+
const managedShellCommandIds = new Set(managedShellCommands.map((command) => command.id));
|
|
88
|
+
const shellCommands =
|
|
89
|
+
contextKeys === undefined
|
|
90
|
+
? managedShellCommands
|
|
91
|
+
: createWorkbenchShellCommands({
|
|
92
|
+
activities: resolveShellCommandActivities(extensionRegistry, contextKeys),
|
|
93
|
+
includeSettings: true,
|
|
94
|
+
includeSidebarToggle: true,
|
|
95
|
+
});
|
|
81
96
|
const commandFeaturesById = collectExtensionCommandFeaturesById(extensionRegistry);
|
|
82
97
|
|
|
83
98
|
return buildCommandManagementGroups({
|
|
84
99
|
extensionCommands: collectExtensionCommandEntries(
|
|
85
100
|
extensionRegistry,
|
|
86
|
-
|
|
101
|
+
managedShellCommandIds,
|
|
87
102
|
commandFeaturesById,
|
|
88
103
|
),
|
|
89
104
|
keybindingsByCommandId: collectKeybindingsByCommandId(extensionRegistry),
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
import { useMemo } from 'react';
|
|
2
|
-
import {
|
|
3
|
-
buildKeybindingManagementEntries,
|
|
4
|
-
type KeybindingDefinition,
|
|
5
|
-
} from '@workbench-kit/platform';
|
|
2
|
+
import { buildKeybindingManagementEntries } from '@workbench-kit/platform';
|
|
6
3
|
import { createWorkbenchShellCommands } from '@workbench-kit/react/workbench';
|
|
7
4
|
import type { ExtensionRegistry } from '@workbench-kit/workbench-core';
|
|
8
5
|
|
|
@@ -122,9 +119,3 @@ function collectKeybindingManagementCommands(extensionRegistry: ExtensionRegistr
|
|
|
122
119
|
|
|
123
120
|
return commands;
|
|
124
121
|
}
|
|
125
|
-
|
|
126
|
-
export function toKeybindingOverrideDefinitions(
|
|
127
|
-
overrides: readonly KeybindingDefinition[],
|
|
128
|
-
): KeybindingDefinition[] {
|
|
129
|
-
return overrides.map((binding) => ({ ...binding }));
|
|
130
|
-
}
|
package/src/shell/provider.tsx
CHANGED
|
@@ -185,6 +185,24 @@ interface DeferredProviderDispose {
|
|
|
185
185
|
|
|
186
186
|
const WorkbenchContext = createContext<WorkbenchContextValue | undefined>(undefined);
|
|
187
187
|
|
|
188
|
+
function createInitialContextKeyService(
|
|
189
|
+
contextKeyValues: Readonly<Record<string, ContextKeyValue>> | undefined,
|
|
190
|
+
): ContextKeyService {
|
|
191
|
+
const service = new ContextKeyService();
|
|
192
|
+
|
|
193
|
+
for (const [key, value] of Object.entries(
|
|
194
|
+
createWorkbenchPermissionContextKeys({ role: 'owner' }),
|
|
195
|
+
)) {
|
|
196
|
+
service.set(key, value);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
for (const [key, value] of Object.entries(contextKeyValues ?? {})) {
|
|
200
|
+
service.set(key, value);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
return service;
|
|
204
|
+
}
|
|
205
|
+
|
|
188
206
|
export function WorkbenchProvider({
|
|
189
207
|
availableExtensions,
|
|
190
208
|
children,
|
|
@@ -267,15 +285,7 @@ export function WorkbenchProvider({
|
|
|
267
285
|
const [keybindingOverrides, setKeybindingOverridesState] = useState(
|
|
268
286
|
resolvedInitialKeybindingOverrides,
|
|
269
287
|
);
|
|
270
|
-
const contextKeyService =
|
|
271
|
-
const service = new ContextKeyService();
|
|
272
|
-
for (const [key, value] of Object.entries(
|
|
273
|
-
createWorkbenchPermissionContextKeys({ role: 'owner' }),
|
|
274
|
-
)) {
|
|
275
|
-
service.set(key, value);
|
|
276
|
-
}
|
|
277
|
-
return service;
|
|
278
|
-
}, []);
|
|
288
|
+
const [contextKeyService] = useState(() => createInitialContextKeyService(contextKeyValues));
|
|
279
289
|
|
|
280
290
|
useEffect(() => {
|
|
281
291
|
return () => {
|
package/src/shell/shell.tsx
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { useCallback, useEffect, useMemo, useReducer, useState, type ReactNode } from 'react';
|
|
2
2
|
import { Modal } from '@workbench-kit/react/modal';
|
|
3
|
-
import { TilepaperAppIcon } from '@workbench-kit/react';
|
|
4
3
|
import { Badge, Button, IconButton } from '@workbench-kit/react/primitives';
|
|
5
4
|
import {
|
|
6
5
|
WorkbenchSettingsModal,
|
|
@@ -89,6 +88,8 @@ export type { WorkbenchLocaleOption, WorkbenchThemeOption } from './settings.js'
|
|
|
89
88
|
export interface WorkbenchShellProps {
|
|
90
89
|
accountManagement?: WorkbenchAccountManagementInput | undefined;
|
|
91
90
|
additionalSettingsCategories?: readonly WorkbenchSettingsCategory[] | undefined;
|
|
91
|
+
/** Host-owned product mark shown by the default title bar. */
|
|
92
|
+
appIcon?: ReactNode;
|
|
92
93
|
catalogTrustPolicy?: ExtensionCatalogTrustPolicy | undefined;
|
|
93
94
|
catalogUrl?: string | undefined;
|
|
94
95
|
commandHost?: false | Omit<WorkbenchCommandHostProps, 'onOpenSettings'>;
|
|
@@ -147,6 +148,7 @@ const OPEN_SETTINGS_COMMAND_ID = 'workbench-kit.builtin.settings.open';
|
|
|
147
148
|
export function WorkbenchShell({
|
|
148
149
|
accountManagement,
|
|
149
150
|
additionalSettingsCategories,
|
|
151
|
+
appIcon,
|
|
150
152
|
catalogTrustPolicy,
|
|
151
153
|
catalogUrl = '/extension-catalog.json',
|
|
152
154
|
commandHost,
|
|
@@ -383,6 +385,7 @@ export function WorkbenchShell({
|
|
|
383
385
|
const resolvedTitleBar =
|
|
384
386
|
titleBar === undefined ? (
|
|
385
387
|
<WorkbenchShellTitleBar
|
|
388
|
+
appIcon={appIcon}
|
|
386
389
|
helpContent={helpContent}
|
|
387
390
|
isAuxiliarySidebarVisible={layout.auxiliaryBar.visible}
|
|
388
391
|
isPanelVisible={layout.panel.visible}
|
|
@@ -725,6 +728,7 @@ export function WorkbenchShell({
|
|
|
725
728
|
}
|
|
726
729
|
|
|
727
730
|
function WorkbenchShellTitleBar({
|
|
731
|
+
appIcon,
|
|
728
732
|
helpContent,
|
|
729
733
|
isAuxiliarySidebarVisible,
|
|
730
734
|
isPanelVisible,
|
|
@@ -739,6 +743,7 @@ function WorkbenchShellTitleBar({
|
|
|
739
743
|
onTogglePanel,
|
|
740
744
|
onTogglePrimarySidebar,
|
|
741
745
|
}: {
|
|
746
|
+
appIcon: ReactNode | undefined;
|
|
742
747
|
helpContent: ReactNode | undefined;
|
|
743
748
|
isAuxiliarySidebarVisible: boolean;
|
|
744
749
|
isPanelVisible: boolean;
|
|
@@ -756,9 +761,11 @@ function WorkbenchShellTitleBar({
|
|
|
756
761
|
return (
|
|
757
762
|
<>
|
|
758
763
|
<div className="workbench-shell-titlebar__identity">
|
|
759
|
-
|
|
760
|
-
<
|
|
761
|
-
|
|
764
|
+
{appIcon ? (
|
|
765
|
+
<span aria-hidden className="workbench-shell-titlebar__app-icon">
|
|
766
|
+
{appIcon}
|
|
767
|
+
</span>
|
|
768
|
+
) : null}
|
|
762
769
|
<span className="workbench-shell-titlebar__title">{title}</span>
|
|
763
770
|
{titleMeta ? <span className="workbench-shell-titlebar__meta">{titleMeta}</span> : null}
|
|
764
771
|
</div>
|