@workbench-kit/shell-react 0.0.2-prototype.0.2.11 → 0.0.2-prototype.0.2.14
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 +24 -7
- package/package.json +8 -8
- package/src/chat/command-error-message.ts +7 -0
- package/src/chat/command-surface.tsx +1 -8
- package/src/chat/use-chat-command-proposals.ts +1 -8
- package/src/field-remap/chrome-labels.ts +16 -0
- package/src/field-remap/demo.tsx +1 -8
- package/src/field-remap/flow.tsx +108 -1
- package/src/field-remap/panel.tsx +6 -8
- package/src/field-remap/view.css +29 -1
- package/src/index.ts +8 -0
- package/src/shell/chrome-labels.ts +98 -0
- package/src/shell/model.tsx +63 -1
- package/src/shell/secondary-actions.tsx +10 -3
- package/src/shell/shell.tsx +106 -12
- package/src/shell/view-host.tsx +73 -0
- package/src/workbench/command-host.tsx +145 -8
- package/src/workbench/layout-storage.ts +6 -0
package/README.md
CHANGED
|
@@ -63,13 +63,15 @@ for Flow-only embeds and custom bundler setups. The full barrel
|
|
|
63
63
|
`FieldRemapFlowMapper` (and `FieldRemapPanel` pass-through) accept optional chrome
|
|
64
64
|
hooks so hosts avoid CSS/DOM workarounds:
|
|
65
65
|
|
|
66
|
-
| Prop | Behavior
|
|
67
|
-
| --------------------------------------------------------------- |
|
|
68
|
-
| `showMinimap` | Default `true`. When `false`, MiniMap is not mounted.
|
|
69
|
-
| `
|
|
70
|
-
| `
|
|
71
|
-
| `
|
|
72
|
-
| `
|
|
66
|
+
| Prop | Behavior |
|
|
67
|
+
| --------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- |
|
|
68
|
+
| `showMinimap` | Default `true`. When `false`, MiniMap is not mounted. |
|
|
69
|
+
| `onShowMinimapChange` | When set, adds a MiniMap toggle inside Flow Controls (+/−/fit). |
|
|
70
|
+
| `includeHidden` / `onIncludeHiddenChange` | When callback set, adds a hidden-fields toggle in the same Controls. Host/Panel still project shapes. |
|
|
71
|
+
| `onPaneContextMenu` / `onNodeContextMenu` / `onEdgeContextMenu` | Native event + selection payload; host owns menu UI. |
|
|
72
|
+
| `flowActionsRef` | `{ fitView(options?) }` using the same defaults as Controls fit-view. |
|
|
73
|
+
| `labels` / `t` | Override edge-list / Convert palette chrome (e.g. “Field maps”). |
|
|
74
|
+
| `ioChrome` (Panel) | `'browse' \| 'edit' \| 'none'` — prefer browse for inspect-only I/O. |
|
|
73
75
|
|
|
74
76
|
```tsx
|
|
75
77
|
const flowActionsRef = useRef<FieldRemapFlowActions | null>(null);
|
|
@@ -90,6 +92,21 @@ const flowActionsRef = useRef<FieldRemapFlowActions | null>(null);
|
|
|
90
92
|
/>;
|
|
91
93
|
```
|
|
92
94
|
|
|
95
|
+
## Shell chrome labels / `t()`
|
|
96
|
+
|
|
97
|
+
`WorkbenchShell` accepts optional `labels` and `t(key, fallback)` for high-visibility chrome
|
|
98
|
+
(ActivityBar / StatusBar aria names, Profile/Settings secondary items, command palette).
|
|
99
|
+
English defaults apply when neither is set. See
|
|
100
|
+
`resolveWorkbenchShellChromeLabels` / `workbenchShellChromeLabelKeys` and
|
|
101
|
+
[Consumer Capabilities — Shell chrome label injection](../../docs/workbench/consumer-capabilities.md#shell-chrome-label--t-injection-126).
|
|
102
|
+
|
|
103
|
+
```tsx
|
|
104
|
+
<WorkbenchShell
|
|
105
|
+
t={(key, fallback) => hostTranslate(key, fallback)}
|
|
106
|
+
labels={{ settingsLabel: 'Settings' }}
|
|
107
|
+
/>
|
|
108
|
+
```
|
|
109
|
+
|
|
93
110
|
## Related docs
|
|
94
111
|
|
|
95
112
|
- [Component Map](../../docs/guides/component-map.md)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@workbench-kit/shell-react",
|
|
3
|
-
"version": "0.0.2-prototype.0.2.
|
|
3
|
+
"version": "0.0.2-prototype.0.2.14",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -21,13 +21,13 @@
|
|
|
21
21
|
"@xyflow/react": "^12.11.2",
|
|
22
22
|
"jsonata": "^2.2.0",
|
|
23
23
|
"react-table-mapping": "^1.0.3",
|
|
24
|
-
"@workbench-kit/
|
|
25
|
-
"@workbench-kit/
|
|
26
|
-
"@workbench-kit/
|
|
27
|
-
"@workbench-kit/workbench-
|
|
28
|
-
"@workbench-kit/workspace": "0.0.2-prototype.0.2.
|
|
29
|
-
"@workbench-kit/
|
|
30
|
-
"@workbench-kit/
|
|
24
|
+
"@workbench-kit/field-remap": "0.0.2-prototype.0.2.14",
|
|
25
|
+
"@workbench-kit/tokens": "0.0.2-prototype.0.2.14",
|
|
26
|
+
"@workbench-kit/workbench-config": "0.0.2-prototype.0.2.14",
|
|
27
|
+
"@workbench-kit/workbench-core": "0.0.2-prototype.0.2.14",
|
|
28
|
+
"@workbench-kit/workspace": "0.0.2-prototype.0.2.14",
|
|
29
|
+
"@workbench-kit/react": "0.0.2-prototype.0.2.14",
|
|
30
|
+
"@workbench-kit/platform": "0.0.2-prototype.0.2.14"
|
|
31
31
|
},
|
|
32
32
|
"peerDependencies": {
|
|
33
33
|
"react": "^19.0.0",
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
type WorkbenchCommandDescriptor,
|
|
7
7
|
} from '@workbench-kit/react/workbench';
|
|
8
8
|
|
|
9
|
+
import { getCommandErrorMessage } from './command-error-message.js';
|
|
9
10
|
import { parseWorkbenchChatCommandInput } from './command-input.js';
|
|
10
11
|
import { useWorkbench } from '../shell/provider.js';
|
|
11
12
|
import { useWorkbenchCommandDescriptors } from '../commands/use-command-descriptors.js';
|
|
@@ -145,11 +146,3 @@ export function useWorkbenchChatCommandSurface({
|
|
|
145
146
|
runInputAsCommand,
|
|
146
147
|
};
|
|
147
148
|
}
|
|
148
|
-
|
|
149
|
-
function getCommandErrorMessage(error: unknown) {
|
|
150
|
-
if (error instanceof Error) {
|
|
151
|
-
return error.message;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
return String(error);
|
|
155
|
-
}
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
} from '@workbench-kit/react/workbench';
|
|
8
8
|
import type { ChatCommandProposal, ChatMessage } from '@workbench-kit/react/workbench/chat';
|
|
9
9
|
|
|
10
|
+
import { getCommandErrorMessage } from './command-error-message.js';
|
|
10
11
|
import { type WorkbenchChatCommandRunResult } from './command-surface.js';
|
|
11
12
|
import { useWorkbench } from '../shell/provider.js';
|
|
12
13
|
|
|
@@ -24,14 +25,6 @@ export interface UseWorkbenchChatCommandProposalsOptions {
|
|
|
24
25
|
policyInput?: ResolveWorkbenchCommandExecutionPolicyInput | undefined;
|
|
25
26
|
}
|
|
26
27
|
|
|
27
|
-
function getCommandErrorMessage(error: unknown) {
|
|
28
|
-
if (error instanceof Error) {
|
|
29
|
-
return error.message;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
return String(error);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
28
|
function createProposalId(commandId: string) {
|
|
36
29
|
return `proposal-${commandId}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
37
30
|
}
|
|
@@ -21,6 +21,10 @@ export interface FieldRemapChromeLabels {
|
|
|
21
21
|
readonly placeConvert: string;
|
|
22
22
|
readonly operatorsTitle: string;
|
|
23
23
|
readonly operatorsDescription: string;
|
|
24
|
+
readonly showMinimap: string;
|
|
25
|
+
readonly hideMinimap: string;
|
|
26
|
+
readonly showHiddenFields: string;
|
|
27
|
+
readonly hideHiddenFields: string;
|
|
24
28
|
}
|
|
25
29
|
|
|
26
30
|
export const defaultFieldRemapChromeLabels: FieldRemapChromeLabels = {
|
|
@@ -34,6 +38,10 @@ export const defaultFieldRemapChromeLabels: FieldRemapChromeLabels = {
|
|
|
34
38
|
operatorsTitle: 'n→m operators',
|
|
35
39
|
operatorsDescription:
|
|
36
40
|
'Create combine (n→1) or split (1→n), then wire ports or edit in the side rail.',
|
|
41
|
+
showMinimap: 'Show minimap',
|
|
42
|
+
hideMinimap: 'Hide minimap',
|
|
43
|
+
showHiddenFields: 'Show hidden fields',
|
|
44
|
+
hideHiddenFields: 'Hide hidden fields',
|
|
37
45
|
};
|
|
38
46
|
|
|
39
47
|
/** Stable capability ids for optional `t()` injection (not free prose). */
|
|
@@ -46,6 +54,10 @@ export const fieldRemapChromeLabelKeys = {
|
|
|
46
54
|
placeConvert: 'fieldRemap.placeConvert',
|
|
47
55
|
operatorsTitle: 'fieldRemap.operatorsTitle',
|
|
48
56
|
operatorsDescription: 'fieldRemap.operatorsDescription',
|
|
57
|
+
showMinimap: 'fieldRemap.showMinimap',
|
|
58
|
+
hideMinimap: 'fieldRemap.hideMinimap',
|
|
59
|
+
showHiddenFields: 'fieldRemap.showHiddenFields',
|
|
60
|
+
hideHiddenFields: 'fieldRemap.hideHiddenFields',
|
|
49
61
|
} as const satisfies Record<keyof FieldRemapChromeLabels, string>;
|
|
50
62
|
|
|
51
63
|
export function resolveFieldRemapChromeLabels(
|
|
@@ -70,5 +82,9 @@ export function resolveFieldRemapChromeLabels(
|
|
|
70
82
|
placeConvert: resolve('placeConvert'),
|
|
71
83
|
operatorsTitle: resolve('operatorsTitle'),
|
|
72
84
|
operatorsDescription: resolve('operatorsDescription'),
|
|
85
|
+
showMinimap: resolve('showMinimap'),
|
|
86
|
+
hideMinimap: resolve('hideMinimap'),
|
|
87
|
+
showHiddenFields: resolve('showHiddenFields'),
|
|
88
|
+
hideHiddenFields: resolve('hideHiddenFields'),
|
|
73
89
|
};
|
|
74
90
|
}
|
package/src/field-remap/demo.tsx
CHANGED
|
@@ -57,14 +57,6 @@ export function SampleFieldRemapDemo({
|
|
|
57
57
|
data-testid="field-remap-host-chrome"
|
|
58
58
|
style={{ display: 'flex', gap: '0.5rem', marginBottom: '0.75rem', flexWrap: 'wrap' }}
|
|
59
59
|
>
|
|
60
|
-
<Button
|
|
61
|
-
compact
|
|
62
|
-
type="button"
|
|
63
|
-
data-testid="field-remap-toggle-minimap"
|
|
64
|
-
onClick={() => setShowMinimap((current) => !current)}
|
|
65
|
-
>
|
|
66
|
-
{showMinimap ? 'Hide MiniMap' : 'Show MiniMap'}
|
|
67
|
-
</Button>
|
|
68
60
|
<Button
|
|
69
61
|
compact
|
|
70
62
|
type="button"
|
|
@@ -84,6 +76,7 @@ export function SampleFieldRemapDemo({
|
|
|
84
76
|
key={`${sample.id}:${ioChrome ?? 'default'}:${browseSeedShapes ? 'seed' : 'plain'}`}
|
|
85
77
|
sample={sample}
|
|
86
78
|
showMinimap={showMinimap}
|
|
79
|
+
onShowMinimapChange={setShowMinimap}
|
|
87
80
|
ioChrome={ioChrome}
|
|
88
81
|
editableShapes={ioChrome === 'browse' ? false : undefined}
|
|
89
82
|
sources={browseShapes?.sources}
|
package/src/field-remap/flow.tsx
CHANGED
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
} from 'react';
|
|
13
13
|
import {
|
|
14
14
|
Background,
|
|
15
|
+
ControlButton,
|
|
15
16
|
Controls,
|
|
16
17
|
Handle,
|
|
17
18
|
MiniMap,
|
|
@@ -333,6 +334,22 @@ export interface FieldRemapFlowMapperProps {
|
|
|
333
334
|
* backward compatibility with existing samples.
|
|
334
335
|
*/
|
|
335
336
|
readonly showMinimap?: boolean | undefined;
|
|
337
|
+
/**
|
|
338
|
+
* When set, Flow Controls (+/−/fit) include a MiniMap toggle button in the same
|
|
339
|
+
* panel. Hosts should prefer this over a separate toolbar control.
|
|
340
|
+
*/
|
|
341
|
+
readonly onShowMinimapChange?: ((show: boolean) => void) | undefined;
|
|
342
|
+
/**
|
|
343
|
+
* When false (default), hosts should project shapes with hidden fields omitted
|
|
344
|
+
* before passing `sources` / `targets`. Flow itself does not filter — this flag
|
|
345
|
+
* drives the Controls toggle pressed state only.
|
|
346
|
+
*/
|
|
347
|
+
readonly includeHidden?: boolean | undefined;
|
|
348
|
+
/**
|
|
349
|
+
* When set, Flow Controls include a hidden-fields toggle next to zoom / MiniMap.
|
|
350
|
+
* Pair with host (or Panel) shape projection on `includeHidden`.
|
|
351
|
+
*/
|
|
352
|
+
readonly onIncludeHiddenChange?: ((includeHidden: boolean) => void) | undefined;
|
|
336
353
|
/** Pane context menu; host owns menu UI. Receives current Field Remap selection. */
|
|
337
354
|
readonly onPaneContextMenu?:
|
|
338
355
|
| ((event: MouseEvent | globalThis.MouseEvent, ctx: { selection: FieldRemapSelection }) => void)
|
|
@@ -375,6 +392,9 @@ function FieldRemapFlowCanvas({
|
|
|
375
392
|
selection: selectionProp,
|
|
376
393
|
onSelectionChange: onSelectionChangeProp,
|
|
377
394
|
showMinimap = true,
|
|
395
|
+
onShowMinimapChange,
|
|
396
|
+
includeHidden = false,
|
|
397
|
+
onIncludeHiddenChange,
|
|
378
398
|
onPaneContextMenu,
|
|
379
399
|
onNodeContextMenu,
|
|
380
400
|
onEdgeContextMenu,
|
|
@@ -713,6 +733,7 @@ function FieldRemapFlowCanvas({
|
|
|
713
733
|
className="workbench-field-remap-flow"
|
|
714
734
|
data-testid="field-remap-mapper"
|
|
715
735
|
data-minimap={showMinimap ? 'on' : 'off'}
|
|
736
|
+
data-hidden-fields={includeHidden ? 'on' : 'off'}
|
|
716
737
|
onKeyDown={onKeyDown}
|
|
717
738
|
>
|
|
718
739
|
<p className="workbench-field-remap-mapper__hint" data-testid="field-remap-hint">
|
|
@@ -784,7 +805,93 @@ function FieldRemapFlowCanvas({
|
|
|
784
805
|
>
|
|
785
806
|
<FieldRemapFlowActionsBridge flowActionsRef={flowActionsRef} />
|
|
786
807
|
<Background gap={16} color="var(--xy-background-pattern-color)" />
|
|
787
|
-
<Controls showInteractive={false} fitViewOptions={DEFAULT_FIT_VIEW_OPTIONS}
|
|
808
|
+
<Controls showInteractive={false} fitViewOptions={DEFAULT_FIT_VIEW_OPTIONS}>
|
|
809
|
+
{onShowMinimapChange ? (
|
|
810
|
+
<ControlButton
|
|
811
|
+
aria-label={showMinimap ? chromeLabels.hideMinimap : chromeLabels.showMinimap}
|
|
812
|
+
className={
|
|
813
|
+
showMinimap
|
|
814
|
+
? 'workbench-field-remap-flow__minimap-toggle is-active'
|
|
815
|
+
: 'workbench-field-remap-flow__minimap-toggle'
|
|
816
|
+
}
|
|
817
|
+
data-testid="field-remap-toggle-minimap"
|
|
818
|
+
title={showMinimap ? chromeLabels.hideMinimap : chromeLabels.showMinimap}
|
|
819
|
+
onClick={() => {
|
|
820
|
+
onShowMinimapChange(!showMinimap);
|
|
821
|
+
}}
|
|
822
|
+
>
|
|
823
|
+
<svg
|
|
824
|
+
aria-hidden="true"
|
|
825
|
+
fill="none"
|
|
826
|
+
height="16"
|
|
827
|
+
stroke="currentColor"
|
|
828
|
+
strokeLinecap="round"
|
|
829
|
+
strokeLinejoin="round"
|
|
830
|
+
strokeWidth="1.75"
|
|
831
|
+
viewBox="0 0 24 24"
|
|
832
|
+
width="16"
|
|
833
|
+
>
|
|
834
|
+
<path d="M3 6.5 9 4l6 2.5L21 4v13.5L15 20l-6-2.5L3 20z" />
|
|
835
|
+
<path d="M9 4v13.5" />
|
|
836
|
+
<path d="M15 6.5V20" />
|
|
837
|
+
</svg>
|
|
838
|
+
</ControlButton>
|
|
839
|
+
) : null}
|
|
840
|
+
{onIncludeHiddenChange ? (
|
|
841
|
+
<ControlButton
|
|
842
|
+
aria-label={
|
|
843
|
+
includeHidden ? chromeLabels.hideHiddenFields : chromeLabels.showHiddenFields
|
|
844
|
+
}
|
|
845
|
+
aria-pressed={includeHidden}
|
|
846
|
+
className={
|
|
847
|
+
includeHidden
|
|
848
|
+
? 'workbench-field-remap-flow__hidden-toggle is-active'
|
|
849
|
+
: 'workbench-field-remap-flow__hidden-toggle'
|
|
850
|
+
}
|
|
851
|
+
data-testid="field-remap-toggle-hidden-fields"
|
|
852
|
+
title={
|
|
853
|
+
includeHidden ? chromeLabels.hideHiddenFields : chromeLabels.showHiddenFields
|
|
854
|
+
}
|
|
855
|
+
onClick={() => {
|
|
856
|
+
onIncludeHiddenChange(!includeHidden);
|
|
857
|
+
}}
|
|
858
|
+
>
|
|
859
|
+
{includeHidden ? (
|
|
860
|
+
<svg
|
|
861
|
+
aria-hidden="true"
|
|
862
|
+
fill="none"
|
|
863
|
+
height="16"
|
|
864
|
+
stroke="currentColor"
|
|
865
|
+
strokeLinecap="round"
|
|
866
|
+
strokeLinejoin="round"
|
|
867
|
+
strokeWidth="1.75"
|
|
868
|
+
viewBox="0 0 24 24"
|
|
869
|
+
width="16"
|
|
870
|
+
>
|
|
871
|
+
<path d="M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7-10-7-10-7z" />
|
|
872
|
+
<circle cx="12" cy="12" r="3" />
|
|
873
|
+
</svg>
|
|
874
|
+
) : (
|
|
875
|
+
<svg
|
|
876
|
+
aria-hidden="true"
|
|
877
|
+
fill="none"
|
|
878
|
+
height="16"
|
|
879
|
+
stroke="currentColor"
|
|
880
|
+
strokeLinecap="round"
|
|
881
|
+
strokeLinejoin="round"
|
|
882
|
+
strokeWidth="1.75"
|
|
883
|
+
viewBox="0 0 24 24"
|
|
884
|
+
width="16"
|
|
885
|
+
>
|
|
886
|
+
<path d="M3 3l18 18" />
|
|
887
|
+
<path d="M10.6 10.6a3 3 0 0 0 4.2 4.2" />
|
|
888
|
+
<path d="M9.9 5.1A10.6 10.6 0 0 1 12 5c6.5 0 10 7 10 7a17.4 17.4 0 0 1-3.2 4.4" />
|
|
889
|
+
<path d="M6.1 6.1C3.9 7.7 2 12 2 12s3.5 7 10 7a10.4 10.4 0 0 0 4.2-.9" />
|
|
890
|
+
</svg>
|
|
891
|
+
)}
|
|
892
|
+
</ControlButton>
|
|
893
|
+
) : null}
|
|
894
|
+
</Controls>
|
|
788
895
|
{showMinimap ? (
|
|
789
896
|
<MiniMap
|
|
790
897
|
pannable
|
|
@@ -83,6 +83,8 @@ export interface FieldRemapPanelProps {
|
|
|
83
83
|
readonly targetShape?: unknown;
|
|
84
84
|
/** Forwarded to {@link FieldRemapFlowMapper} (default true). */
|
|
85
85
|
readonly showMinimap?: boolean | undefined;
|
|
86
|
+
/** Forwarded to {@link FieldRemapFlowMapper} Controls MiniMap toggle. */
|
|
87
|
+
readonly onShowMinimapChange?: FieldRemapFlowMapperProps['onShowMinimapChange'];
|
|
86
88
|
readonly onPaneContextMenu?: FieldRemapFlowMapperProps['onPaneContextMenu'];
|
|
87
89
|
readonly onNodeContextMenu?: FieldRemapFlowMapperProps['onNodeContextMenu'];
|
|
88
90
|
readonly onEdgeContextMenu?: FieldRemapFlowMapperProps['onEdgeContextMenu'];
|
|
@@ -136,6 +138,7 @@ export function FieldRemapPanel({
|
|
|
136
138
|
sourceSample: sourceSampleProp,
|
|
137
139
|
targetShape: targetShapeProp,
|
|
138
140
|
showMinimap,
|
|
141
|
+
onShowMinimapChange,
|
|
139
142
|
onPaneContextMenu,
|
|
140
143
|
onNodeContextMenu,
|
|
141
144
|
onEdgeContextMenu,
|
|
@@ -396,14 +399,6 @@ export function FieldRemapPanel({
|
|
|
396
399
|
className="workbench-field-remap-demo__shapes"
|
|
397
400
|
data-testid="field-remap-io-browse-wrap"
|
|
398
401
|
>
|
|
399
|
-
<label className="workbench-field-remap-io-browse__toggle">
|
|
400
|
-
<input
|
|
401
|
-
checked={includeHidden}
|
|
402
|
-
onChange={(event) => setIncludeHidden(event.target.checked)}
|
|
403
|
-
type="checkbox"
|
|
404
|
-
/>
|
|
405
|
-
Show hidden fields
|
|
406
|
-
</label>
|
|
407
402
|
<FieldRemapIoClassBrowse
|
|
408
403
|
includeHidden={includeHidden}
|
|
409
404
|
sources={sourceFields}
|
|
@@ -425,6 +420,9 @@ export function FieldRemapPanel({
|
|
|
425
420
|
sourceTitle={sample.sourceLabel}
|
|
426
421
|
targetTitle={sample.targetLabel}
|
|
427
422
|
showMinimap={showMinimap}
|
|
423
|
+
onShowMinimapChange={onShowMinimapChange}
|
|
424
|
+
includeHidden={includeHidden}
|
|
425
|
+
onIncludeHiddenChange={setIncludeHidden}
|
|
428
426
|
onPaneContextMenu={onPaneContextMenu}
|
|
429
427
|
onNodeContextMenu={onNodeContextMenu}
|
|
430
428
|
onEdgeContextMenu={onEdgeContextMenu}
|
package/src/field-remap/view.css
CHANGED
|
@@ -331,7 +331,11 @@
|
|
|
331
331
|
display: flex;
|
|
332
332
|
flex-direction: column;
|
|
333
333
|
gap: 0.65rem;
|
|
334
|
+
box-sizing: border-box;
|
|
334
335
|
min-width: 0;
|
|
336
|
+
min-height: 0;
|
|
337
|
+
height: 100%;
|
|
338
|
+
overflow: hidden;
|
|
335
339
|
padding: 0.75rem;
|
|
336
340
|
border: 1px solid var(--vscode-panel-border, var(--color-border));
|
|
337
341
|
border-radius: 0.375rem;
|
|
@@ -354,14 +358,21 @@
|
|
|
354
358
|
color: var(--vscode-descriptionForeground, var(--color-text-muted));
|
|
355
359
|
}
|
|
356
360
|
|
|
361
|
+
.workbench-field-remap-convert-palette__header,
|
|
362
|
+
.workbench-field-remap-convert-palette__place,
|
|
363
|
+
.workbench-field-remap-convert-palette__operators {
|
|
364
|
+
flex: 0 0 auto;
|
|
365
|
+
}
|
|
366
|
+
|
|
357
367
|
.workbench-field-remap-convert-palette__list {
|
|
358
368
|
list-style: none;
|
|
359
369
|
margin: 0;
|
|
360
370
|
padding: 0;
|
|
361
371
|
display: flex;
|
|
372
|
+
flex: 1 1 auto;
|
|
362
373
|
flex-direction: column;
|
|
363
374
|
gap: 0.35rem;
|
|
364
|
-
|
|
375
|
+
min-height: 0;
|
|
365
376
|
overflow: auto;
|
|
366
377
|
}
|
|
367
378
|
|
|
@@ -483,6 +494,23 @@
|
|
|
483
494
|
max-height: 12px;
|
|
484
495
|
}
|
|
485
496
|
|
|
497
|
+
.workbench-field-remap-flow__canvas
|
|
498
|
+
.react-flow__controls-button.workbench-field-remap-flow__minimap-toggle
|
|
499
|
+
svg,
|
|
500
|
+
.workbench-field-remap-flow__canvas
|
|
501
|
+
.react-flow__controls-button.workbench-field-remap-flow__hidden-toggle
|
|
502
|
+
svg {
|
|
503
|
+
fill: none;
|
|
504
|
+
stroke: currentColor;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
.workbench-field-remap-flow__canvas
|
|
508
|
+
.react-flow__controls-button.workbench-field-remap-flow__minimap-toggle.is-active,
|
|
509
|
+
.workbench-field-remap-flow__canvas
|
|
510
|
+
.react-flow__controls-button.workbench-field-remap-flow__hidden-toggle.is-active {
|
|
511
|
+
color: var(--vscode-focusBorder, var(--color-accent, #3794ff));
|
|
512
|
+
}
|
|
513
|
+
|
|
486
514
|
.workbench-field-remap-flow__canvas .react-flow__minimap {
|
|
487
515
|
margin: 0.5rem;
|
|
488
516
|
border: 1px solid var(--vscode-panel-border, var(--color-border));
|
package/src/index.ts
CHANGED
|
@@ -286,6 +286,14 @@ export {
|
|
|
286
286
|
type WorkbenchSecondaryActivityItemsInput,
|
|
287
287
|
type WorkbenchSecondaryActivityRoute,
|
|
288
288
|
} from './shell/secondary-actions.js';
|
|
289
|
+
export {
|
|
290
|
+
defaultWorkbenchShellChromeLabels,
|
|
291
|
+
resolveWorkbenchShellChromeLabels,
|
|
292
|
+
workbenchShellChromeLabelKeys,
|
|
293
|
+
type WorkbenchI18n,
|
|
294
|
+
type WorkbenchShellChromeLabels,
|
|
295
|
+
type WorkbenchTranslate,
|
|
296
|
+
} from './shell/chrome-labels.js';
|
|
289
297
|
export {
|
|
290
298
|
WorkbenchProfileModal,
|
|
291
299
|
type WorkbenchProfileDetail,
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Host-overridable chrome strings for WorkbenchShell surfaces
|
|
3
|
+
* (ActivityBar / StatusBar aria, secondary Profile/Settings, command palette,
|
|
4
|
+
* Quick Open).
|
|
5
|
+
*
|
|
6
|
+
* Resolution order per string: `labels[key]` → `t(capabilityId, default)` → English default.
|
|
7
|
+
* Kit does not ship locale packs — hosts inject `t` or partial `labels`.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export type WorkbenchTranslate = (
|
|
11
|
+
key: string,
|
|
12
|
+
fallback: string,
|
|
13
|
+
params?: Readonly<Record<string, string | number>>,
|
|
14
|
+
) => string;
|
|
15
|
+
|
|
16
|
+
/** Optional host i18n bag (same `t` signature as Field Remap chrome). */
|
|
17
|
+
export interface WorkbenchI18n {
|
|
18
|
+
readonly t: WorkbenchTranslate;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface WorkbenchShellChromeLabels {
|
|
22
|
+
readonly activityBarAriaLabel: string;
|
|
23
|
+
readonly statusBarAriaLabel: string;
|
|
24
|
+
readonly profileLabel: string;
|
|
25
|
+
readonly profileTitle: string;
|
|
26
|
+
readonly settingsLabel: string;
|
|
27
|
+
readonly commandPaletteTitle: string;
|
|
28
|
+
readonly commandPalettePlaceholder: string;
|
|
29
|
+
readonly commandPaletteCloseLabel: string;
|
|
30
|
+
readonly commandPaletteEmptyLabel: string;
|
|
31
|
+
readonly quickOpenTitle: string;
|
|
32
|
+
readonly quickOpenPlaceholder: string;
|
|
33
|
+
readonly quickOpenCloseLabel: string;
|
|
34
|
+
readonly quickOpenEmptyLabel: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export const defaultWorkbenchShellChromeLabels: WorkbenchShellChromeLabels = {
|
|
38
|
+
activityBarAriaLabel: 'Activity bar',
|
|
39
|
+
statusBarAriaLabel: 'Status bar',
|
|
40
|
+
profileLabel: 'Profile',
|
|
41
|
+
profileTitle: 'Open profile',
|
|
42
|
+
settingsLabel: 'Settings',
|
|
43
|
+
commandPaletteTitle: 'Command Palette',
|
|
44
|
+
commandPalettePlaceholder: 'Search commands',
|
|
45
|
+
commandPaletteCloseLabel: 'Close command palette',
|
|
46
|
+
commandPaletteEmptyLabel: 'No commands match your search',
|
|
47
|
+
quickOpenTitle: 'Quick Open',
|
|
48
|
+
quickOpenPlaceholder: 'Search files by name',
|
|
49
|
+
quickOpenCloseLabel: 'Close Quick Open',
|
|
50
|
+
quickOpenEmptyLabel: 'No matching files',
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
/** Stable capability ids for optional `t()` injection (not free prose). */
|
|
54
|
+
export const workbenchShellChromeLabelKeys = {
|
|
55
|
+
activityBarAriaLabel: 'shell.activityBar',
|
|
56
|
+
statusBarAriaLabel: 'shell.statusBar',
|
|
57
|
+
profileLabel: 'shell.profile',
|
|
58
|
+
profileTitle: 'shell.profileTitle',
|
|
59
|
+
settingsLabel: 'shell.settings',
|
|
60
|
+
commandPaletteTitle: 'commandPalette.title',
|
|
61
|
+
commandPalettePlaceholder: 'commandPalette.placeholder',
|
|
62
|
+
commandPaletteCloseLabel: 'commandPalette.close',
|
|
63
|
+
commandPaletteEmptyLabel: 'commandPalette.empty',
|
|
64
|
+
quickOpenTitle: 'quickOpen.title',
|
|
65
|
+
quickOpenPlaceholder: 'quickOpen.placeholder',
|
|
66
|
+
quickOpenCloseLabel: 'quickOpen.close',
|
|
67
|
+
quickOpenEmptyLabel: 'quickOpen.empty',
|
|
68
|
+
} as const satisfies Record<keyof WorkbenchShellChromeLabels, string>;
|
|
69
|
+
|
|
70
|
+
export function resolveWorkbenchShellChromeLabels(
|
|
71
|
+
labels?: Partial<WorkbenchShellChromeLabels> | undefined,
|
|
72
|
+
t?: WorkbenchTranslate | undefined,
|
|
73
|
+
): WorkbenchShellChromeLabels {
|
|
74
|
+
const resolve = <K extends keyof WorkbenchShellChromeLabels>(key: K): string => {
|
|
75
|
+
const override = labels?.[key];
|
|
76
|
+
if (override !== undefined) {
|
|
77
|
+
return override;
|
|
78
|
+
}
|
|
79
|
+
const fallback = defaultWorkbenchShellChromeLabels[key];
|
|
80
|
+
return t?.(workbenchShellChromeLabelKeys[key], fallback) ?? fallback;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
return {
|
|
84
|
+
activityBarAriaLabel: resolve('activityBarAriaLabel'),
|
|
85
|
+
statusBarAriaLabel: resolve('statusBarAriaLabel'),
|
|
86
|
+
profileLabel: resolve('profileLabel'),
|
|
87
|
+
profileTitle: resolve('profileTitle'),
|
|
88
|
+
settingsLabel: resolve('settingsLabel'),
|
|
89
|
+
commandPaletteTitle: resolve('commandPaletteTitle'),
|
|
90
|
+
commandPalettePlaceholder: resolve('commandPalettePlaceholder'),
|
|
91
|
+
commandPaletteCloseLabel: resolve('commandPaletteCloseLabel'),
|
|
92
|
+
commandPaletteEmptyLabel: resolve('commandPaletteEmptyLabel'),
|
|
93
|
+
quickOpenTitle: resolve('quickOpenTitle'),
|
|
94
|
+
quickOpenPlaceholder: resolve('quickOpenPlaceholder'),
|
|
95
|
+
quickOpenCloseLabel: resolve('quickOpenCloseLabel'),
|
|
96
|
+
quickOpenEmptyLabel: resolve('quickOpenEmptyLabel'),
|
|
97
|
+
};
|
|
98
|
+
}
|
package/src/shell/model.tsx
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
import type { ReactNode } from 'react';
|
|
2
|
-
import type {
|
|
2
|
+
import type {
|
|
3
|
+
ActivityBarItem,
|
|
4
|
+
StatusBarItemModel,
|
|
5
|
+
StatusBarSectionModel,
|
|
6
|
+
} from '@workbench-kit/react/workbench/shell';
|
|
3
7
|
import type {
|
|
4
8
|
ExtensionDependencyDiagnosticSeverity,
|
|
5
9
|
WorkbenchActivityContribution,
|
|
10
|
+
WorkbenchStatusBarContribution,
|
|
6
11
|
WorkbenchViewContainerContribution,
|
|
7
12
|
WorkbenchViewContribution,
|
|
8
13
|
} from '@workbench-kit/workbench-core';
|
|
@@ -65,6 +70,63 @@ export function createWorkbenchShellActivityItems({
|
|
|
65
70
|
});
|
|
66
71
|
}
|
|
67
72
|
|
|
73
|
+
function compareStatusBarPriority(
|
|
74
|
+
left: WorkbenchStatusBarContribution,
|
|
75
|
+
right: WorkbenchStatusBarContribution,
|
|
76
|
+
): number {
|
|
77
|
+
const leftPriority = left.priority ?? 0;
|
|
78
|
+
const rightPriority = right.priority ?? 0;
|
|
79
|
+
if (leftPriority !== rightPriority) {
|
|
80
|
+
return rightPriority - leftPriority;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return left.id.localeCompare(right.id);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function toStatusBarItemModel(item: WorkbenchStatusBarContribution): StatusBarItemModel {
|
|
87
|
+
return {
|
|
88
|
+
id: item.id,
|
|
89
|
+
label: item.text,
|
|
90
|
+
order: item.priority,
|
|
91
|
+
title: item.text,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/** Map extension `contributes.statusBar` items into shell status sections. */
|
|
96
|
+
export function createContributedWorkbenchStatusSections(
|
|
97
|
+
items: readonly WorkbenchStatusBarContribution[],
|
|
98
|
+
): StatusBarSectionModel[] {
|
|
99
|
+
const leftItems = items
|
|
100
|
+
.filter((item) => item.alignment === 'left')
|
|
101
|
+
.sort(compareStatusBarPriority)
|
|
102
|
+
.map(toStatusBarItemModel);
|
|
103
|
+
const rightItems = items
|
|
104
|
+
.filter((item) => item.alignment === 'right')
|
|
105
|
+
.sort(compareStatusBarPriority)
|
|
106
|
+
.map(toStatusBarItemModel);
|
|
107
|
+
|
|
108
|
+
return [
|
|
109
|
+
...(leftItems.length > 0
|
|
110
|
+
? [
|
|
111
|
+
{
|
|
112
|
+
align: 'start' as const,
|
|
113
|
+
id: 'extension-status-left',
|
|
114
|
+
items: leftItems,
|
|
115
|
+
},
|
|
116
|
+
]
|
|
117
|
+
: []),
|
|
118
|
+
...(rightItems.length > 0
|
|
119
|
+
? [
|
|
120
|
+
{
|
|
121
|
+
align: 'end' as const,
|
|
122
|
+
id: 'extension-status-right',
|
|
123
|
+
items: rightItems,
|
|
124
|
+
},
|
|
125
|
+
]
|
|
126
|
+
: []),
|
|
127
|
+
];
|
|
128
|
+
}
|
|
129
|
+
|
|
68
130
|
export function createDefaultWorkbenchStatusSections({
|
|
69
131
|
dependencyDiagnostics,
|
|
70
132
|
extensionCount,
|
|
@@ -11,6 +11,10 @@ export interface WorkbenchSecondaryActivityItemsInput {
|
|
|
11
11
|
isProfileOpen: boolean;
|
|
12
12
|
isSettingsOpen: boolean;
|
|
13
13
|
showSettings?: boolean | undefined;
|
|
14
|
+
/** Resolved chrome labels (defaults match English kit copy). */
|
|
15
|
+
profileLabel?: string | undefined;
|
|
16
|
+
profileTitle?: string | undefined;
|
|
17
|
+
settingsLabel?: string | undefined;
|
|
14
18
|
}
|
|
15
19
|
|
|
16
20
|
export function createWorkbenchSecondaryActivityItems({
|
|
@@ -18,6 +22,9 @@ export function createWorkbenchSecondaryActivityItems({
|
|
|
18
22
|
isProfileOpen,
|
|
19
23
|
isSettingsOpen,
|
|
20
24
|
showSettings = true,
|
|
25
|
+
profileLabel = 'Profile',
|
|
26
|
+
profileTitle = 'Open profile',
|
|
27
|
+
settingsLabel = 'Settings',
|
|
21
28
|
}: WorkbenchSecondaryActivityItemsInput): ActivityBarItem[] {
|
|
22
29
|
return [
|
|
23
30
|
...(hasProfile
|
|
@@ -26,8 +33,8 @@ export function createWorkbenchSecondaryActivityItems({
|
|
|
26
33
|
active: isProfileOpen,
|
|
27
34
|
icon: <i aria-hidden="true" className="codicon codicon-account" />,
|
|
28
35
|
id: WORKBENCH_PROFILE_ACTIVITY_ITEM_ID,
|
|
29
|
-
label:
|
|
30
|
-
title:
|
|
36
|
+
label: profileLabel,
|
|
37
|
+
title: profileTitle,
|
|
31
38
|
},
|
|
32
39
|
]
|
|
33
40
|
: []),
|
|
@@ -37,7 +44,7 @@ export function createWorkbenchSecondaryActivityItems({
|
|
|
37
44
|
active: isSettingsOpen,
|
|
38
45
|
icon: <i aria-hidden="true" className="codicon codicon-settings-gear" />,
|
|
39
46
|
id: WORKBENCH_SETTINGS_ACTIVITY_ITEM_ID,
|
|
40
|
-
label:
|
|
47
|
+
label: settingsLabel,
|
|
41
48
|
},
|
|
42
49
|
]
|
|
43
50
|
: []),
|
package/src/shell/shell.tsx
CHANGED
|
@@ -35,6 +35,11 @@ import {
|
|
|
35
35
|
sortActivityBarItems,
|
|
36
36
|
} from '@workbench-kit/react/workbench/activityBarOrder';
|
|
37
37
|
import { useWorkbench } from './provider.js';
|
|
38
|
+
import {
|
|
39
|
+
resolveWorkbenchShellChromeLabels,
|
|
40
|
+
type WorkbenchShellChromeLabels,
|
|
41
|
+
type WorkbenchTranslate,
|
|
42
|
+
} from './chrome-labels.js';
|
|
38
43
|
import { WorkbenchCommandHost, type WorkbenchCommandHostProps } from '../workbench/command-host.js';
|
|
39
44
|
import {
|
|
40
45
|
MANAGE_ACCOUNTS_COMMAND_ID,
|
|
@@ -60,10 +65,12 @@ import {
|
|
|
60
65
|
import { SETTINGS_EXTENSION_ID, WORKBENCH_PREFERENCE_SCOPES } from './settings-constants.js';
|
|
61
66
|
import { createSettingsCategories, type WorkbenchThemeOption } from './settings.js';
|
|
62
67
|
import {
|
|
68
|
+
createContributedWorkbenchStatusSections,
|
|
63
69
|
createDefaultWorkbenchStatusSections,
|
|
64
70
|
createWorkbenchShellActivityItems,
|
|
65
71
|
} from './model.js';
|
|
66
|
-
import {
|
|
72
|
+
import { mergeWorkbenchStatusSections } from '../workbench/status-sections.js';
|
|
73
|
+
import { renderDefaultBottomPanel, renderDefaultPrimarySidebar } from './view-host.js';
|
|
67
74
|
import { WorkbenchShellTitleBarLayoutControls } from './titlebar-layout-controls.js';
|
|
68
75
|
import { WorkbenchProfileModal, type WorkbenchProfileInput } from '../workbench/profile-modal.js';
|
|
69
76
|
import { useContextKeyRevision } from '../commands/use-context-key-revision.js';
|
|
@@ -102,6 +109,11 @@ export interface WorkbenchShellProps {
|
|
|
102
109
|
editorArea?: ReactNode;
|
|
103
110
|
helpContent?: ReactNode;
|
|
104
111
|
helpTitle?: ReactNode;
|
|
112
|
+
/**
|
|
113
|
+
* Partial chrome label overrides for ActivityBar / StatusBar / secondary items /
|
|
114
|
+
* command palette. Wins over `t` when both are set for the same key.
|
|
115
|
+
*/
|
|
116
|
+
labels?: Partial<WorkbenchShellChromeLabels> | undefined;
|
|
105
117
|
lightPreset?: string | undefined;
|
|
106
118
|
onDarkPresetChange?: ((preset: string) => void) | undefined;
|
|
107
119
|
onLightPresetChange?: ((preset: string) => void) | undefined;
|
|
@@ -116,6 +128,11 @@ export interface WorkbenchShellProps {
|
|
|
116
128
|
rootClassName?: string;
|
|
117
129
|
shellPreset?: string | undefined;
|
|
118
130
|
statusSections?: StatusBarSectionModel[];
|
|
131
|
+
/**
|
|
132
|
+
* Optional `t(key, fallback)` injection for shell chrome strings.
|
|
133
|
+
* Missing `t` keeps English defaults from `resolveWorkbenchShellChromeLabels`.
|
|
134
|
+
*/
|
|
135
|
+
t?: WorkbenchTranslate | undefined;
|
|
119
136
|
theme?: string;
|
|
120
137
|
themeOptions?: readonly WorkbenchThemeOption[] | undefined;
|
|
121
138
|
title?: ReactNode;
|
|
@@ -148,6 +165,7 @@ export function WorkbenchShell({
|
|
|
148
165
|
editorArea,
|
|
149
166
|
helpContent,
|
|
150
167
|
helpTitle = 'Workbench Help',
|
|
168
|
+
labels: labelOverrides,
|
|
151
169
|
lightPreset,
|
|
152
170
|
locale = 'en',
|
|
153
171
|
onDarkPresetChange,
|
|
@@ -162,6 +180,7 @@ export function WorkbenchShell({
|
|
|
162
180
|
rootClassName,
|
|
163
181
|
shellPreset = DEFAULT_SHELL_PRESET,
|
|
164
182
|
statusSections,
|
|
183
|
+
t,
|
|
165
184
|
theme,
|
|
166
185
|
themeOptions,
|
|
167
186
|
title = 'Workbench',
|
|
@@ -210,15 +229,20 @@ export function WorkbenchShell({
|
|
|
210
229
|
const resolvedStatusSections = useMemo(
|
|
211
230
|
() =>
|
|
212
231
|
statusSections ??
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
232
|
+
mergeWorkbenchStatusSections(
|
|
233
|
+
createDefaultWorkbenchStatusSections({
|
|
234
|
+
dependencyDiagnostics: extensionRegistry.getDependencyDiagnostics(),
|
|
235
|
+
extensionCount: extensionRegistry.getExtensions().length,
|
|
236
|
+
missingExtensionIds,
|
|
237
|
+
profile,
|
|
238
|
+
}),
|
|
239
|
+
createContributedWorkbenchStatusSections(extensionRegistry.statusBar.getStatusBarItems()),
|
|
240
|
+
),
|
|
219
241
|
[extensionRegistry, missingExtensionIds, profile, statusSections],
|
|
220
242
|
);
|
|
221
243
|
const activeViewContainerId = layout.sideBar.activeViewContainer;
|
|
244
|
+
const activePanelViewContainerId = layout.panel.activeViewContainer;
|
|
245
|
+
const panelViewContainers = extensionRegistry.views.getViewContainers('panel');
|
|
222
246
|
const visibleActivities = useMemo(
|
|
223
247
|
() =>
|
|
224
248
|
filterActivitiesByWhenClause(
|
|
@@ -231,7 +255,7 @@ export function WorkbenchShell({
|
|
|
231
255
|
createWorkbenchShellActivityItems({
|
|
232
256
|
activeViewContainerId,
|
|
233
257
|
activities: visibleActivities,
|
|
234
|
-
viewContainers: extensionRegistry.views.getViewContainers(),
|
|
258
|
+
viewContainers: extensionRegistry.views.getViewContainers('activitybar'),
|
|
235
259
|
views: extensionRegistry.views.getViews(),
|
|
236
260
|
}),
|
|
237
261
|
layout.activityBar.itemOrder,
|
|
@@ -243,11 +267,18 @@ export function WorkbenchShell({
|
|
|
243
267
|
const canOpenSettingsValue = contextKeyService.get(
|
|
244
268
|
WORKBENCH_PERMISSION_CONTEXT_KEY_CAN_OPEN_SETTINGS,
|
|
245
269
|
);
|
|
270
|
+
const chromeLabels = useMemo(
|
|
271
|
+
() => resolveWorkbenchShellChromeLabels(labelOverrides, t),
|
|
272
|
+
[labelOverrides, t],
|
|
273
|
+
);
|
|
246
274
|
const secondaryActivityItems = createWorkbenchSecondaryActivityItems({
|
|
247
275
|
hasProfile: profile !== undefined,
|
|
248
276
|
isProfileOpen,
|
|
249
277
|
isSettingsOpen,
|
|
250
278
|
showSettings: canOpenSettingsValue !== false,
|
|
279
|
+
profileLabel: chromeLabels.profileLabel,
|
|
280
|
+
profileTitle: chromeLabels.profileTitle,
|
|
281
|
+
settingsLabel: chromeLabels.settingsLabel,
|
|
251
282
|
});
|
|
252
283
|
|
|
253
284
|
useEffect(() => {
|
|
@@ -260,6 +291,20 @@ export function WorkbenchShell({
|
|
|
260
291
|
layoutService.setActiveViewContainer(visibleActivityItems[0]?.id);
|
|
261
292
|
}
|
|
262
293
|
}, [activeViewContainerId, layoutService, visibleActivityItems]);
|
|
294
|
+
|
|
295
|
+
useEffect(() => {
|
|
296
|
+
if (panelViewContainers.length === 0) {
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
const panelContainerIds = new Set(panelViewContainers.map((container) => container.id));
|
|
301
|
+
if (
|
|
302
|
+
activePanelViewContainerId === undefined ||
|
|
303
|
+
!panelContainerIds.has(activePanelViewContainerId)
|
|
304
|
+
) {
|
|
305
|
+
layoutService.setActivePanelViewContainer(panelViewContainers[0]?.id);
|
|
306
|
+
}
|
|
307
|
+
}, [activePanelViewContainerId, layoutService, panelViewContainers]);
|
|
263
308
|
const settingsCategories = useMemo(() => {
|
|
264
309
|
const managementCategories: WorkbenchSettingsCategory[] = [];
|
|
265
310
|
|
|
@@ -389,6 +434,16 @@ export function WorkbenchShell({
|
|
|
389
434
|
}
|
|
390
435
|
}, [activeViewContainerId, extensionRegistry, forceRender]);
|
|
391
436
|
|
|
437
|
+
useEffect(() => {
|
|
438
|
+
if (!activePanelViewContainerId) {
|
|
439
|
+
return;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
for (const view of extensionRegistry.views.getViews(activePanelViewContainerId)) {
|
|
443
|
+
void extensionRegistry.activateView(view.id).then(forceRender);
|
|
444
|
+
}
|
|
445
|
+
}, [activePanelViewContainerId, extensionRegistry, forceRender]);
|
|
446
|
+
|
|
392
447
|
useEffect(() => {
|
|
393
448
|
if (extensionRegistry.capabilityRegistry.has(WORKBENCH_SETTINGS_CAPABILITY_ID)) {
|
|
394
449
|
return undefined;
|
|
@@ -429,6 +484,17 @@ export function WorkbenchShell({
|
|
|
429
484
|
return {
|
|
430
485
|
...hostProps,
|
|
431
486
|
additionalCommands,
|
|
487
|
+
commandPaletteCloseLabel:
|
|
488
|
+
hostProps.commandPaletteCloseLabel ?? chromeLabels.commandPaletteCloseLabel,
|
|
489
|
+
commandPaletteEmptyLabel:
|
|
490
|
+
hostProps.commandPaletteEmptyLabel ?? chromeLabels.commandPaletteEmptyLabel,
|
|
491
|
+
commandPalettePlaceholder:
|
|
492
|
+
hostProps.commandPalettePlaceholder ?? chromeLabels.commandPalettePlaceholder,
|
|
493
|
+
commandPaletteTitle: hostProps.commandPaletteTitle ?? chromeLabels.commandPaletteTitle,
|
|
494
|
+
quickOpenCloseLabel: hostProps.quickOpenCloseLabel ?? chromeLabels.quickOpenCloseLabel,
|
|
495
|
+
quickOpenEmptyLabel: hostProps.quickOpenEmptyLabel ?? chromeLabels.quickOpenEmptyLabel,
|
|
496
|
+
quickOpenPlaceholder: hostProps.quickOpenPlaceholder ?? chromeLabels.quickOpenPlaceholder,
|
|
497
|
+
quickOpenTitle: hostProps.quickOpenTitle ?? chromeLabels.quickOpenTitle,
|
|
432
498
|
onRunCommand: (command, context) => {
|
|
433
499
|
if (command.id === MANAGE_COMMANDS_COMMAND_ID) {
|
|
434
500
|
layoutService.setActiveViewContainer(BUILTIN_COMMANDS_VIEW_CONTAINER_ID);
|
|
@@ -455,7 +521,7 @@ export function WorkbenchShell({
|
|
|
455
521
|
return hostProps.onRunCommand?.(command, context) ?? false;
|
|
456
522
|
},
|
|
457
523
|
};
|
|
458
|
-
}, [commandHost, layoutService]);
|
|
524
|
+
}, [chromeLabels, commandHost, layoutService]);
|
|
459
525
|
|
|
460
526
|
const handleStatusItemActivate = useCallback(
|
|
461
527
|
(item: StatusBarItemModel) => {
|
|
@@ -473,14 +539,28 @@ export function WorkbenchShell({
|
|
|
473
539
|
return;
|
|
474
540
|
}
|
|
475
541
|
|
|
542
|
+
const contributed = extensionRegistry.statusBar.getStatusBarItem(item.id);
|
|
543
|
+
if (contributed?.command) {
|
|
544
|
+
void executeCommand(contributed.command).catch(() => undefined);
|
|
545
|
+
return;
|
|
546
|
+
}
|
|
547
|
+
|
|
476
548
|
onStatusItemActivate?.(item);
|
|
477
549
|
},
|
|
478
|
-
[
|
|
550
|
+
[
|
|
551
|
+
accountManagement,
|
|
552
|
+
executeCommand,
|
|
553
|
+
extensionRegistry,
|
|
554
|
+
onStatusItemActivate,
|
|
555
|
+
profile,
|
|
556
|
+
showProfileModal,
|
|
557
|
+
],
|
|
479
558
|
);
|
|
480
559
|
|
|
481
560
|
return (
|
|
482
561
|
<ReactWorkbenchShell
|
|
483
562
|
activityBar={{
|
|
563
|
+
'aria-label': chromeLabels.activityBarAriaLabel,
|
|
484
564
|
visible: layout.activityBar.visible,
|
|
485
565
|
items: visibleActivityItems,
|
|
486
566
|
reorderable: true,
|
|
@@ -506,6 +586,7 @@ export function WorkbenchShell({
|
|
|
506
586
|
},
|
|
507
587
|
}}
|
|
508
588
|
compactStatus={compactStatus}
|
|
589
|
+
statusBarAriaLabel={chromeLabels.statusBarAriaLabel}
|
|
509
590
|
onStatusItemActivate={handleStatusItemActivate}
|
|
510
591
|
primarySidebar={{
|
|
511
592
|
isVisible: layout.sideBar.visible,
|
|
@@ -536,7 +617,20 @@ export function WorkbenchShell({
|
|
|
536
617
|
}}
|
|
537
618
|
bottomPanel={{
|
|
538
619
|
isVisible: layout.panel.visible,
|
|
539
|
-
node:
|
|
620
|
+
node: renderDefaultBottomPanel(extensionRegistry, activePanelViewContainerId, {
|
|
621
|
+
catalogTrustPolicy,
|
|
622
|
+
catalogUrl,
|
|
623
|
+
onActiveViewContainerChange: (viewContainerId) => {
|
|
624
|
+
layoutService.setActivePanelViewContainer(viewContainerId);
|
|
625
|
+
if (!layout.panel.visible) {
|
|
626
|
+
layoutService.setPanelVisible(true);
|
|
627
|
+
}
|
|
628
|
+
},
|
|
629
|
+
}),
|
|
630
|
+
onSizePercentChange: (sizePercent) => {
|
|
631
|
+
layoutService.setPanelSizePercent(sizePercent);
|
|
632
|
+
},
|
|
633
|
+
sizePercent: layout.panel.sizePercent,
|
|
540
634
|
}}
|
|
541
635
|
rootClassName={rootClassName}
|
|
542
636
|
secondaryArea={resolvedEditorArea}
|
|
@@ -563,7 +657,7 @@ export function WorkbenchShell({
|
|
|
563
657
|
footer={<Button onClick={() => setSettingsOpen(false)}>Close</Button>}
|
|
564
658
|
scopes={[...WORKBENCH_PREFERENCE_SCOPES]}
|
|
565
659
|
searchValue={settingsSearchValue}
|
|
566
|
-
title=
|
|
660
|
+
title={chromeLabels.settingsLabel}
|
|
567
661
|
titleSuffix={
|
|
568
662
|
<Badge variant="muted">
|
|
569
663
|
{settingsContributionCount === 1
|
package/src/shell/view-host.tsx
CHANGED
|
@@ -56,6 +56,79 @@ export function renderDefaultPrimarySidebar(
|
|
|
56
56
|
);
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
+
export function renderDefaultBottomPanel(
|
|
60
|
+
extensionRegistry: Pick<ExtensionRegistry, 'viewHostFactories' | 'views'>,
|
|
61
|
+
activeViewContainerId: string | undefined,
|
|
62
|
+
options: {
|
|
63
|
+
catalogTrustPolicy?: ExtensionCatalogTrustPolicy | undefined;
|
|
64
|
+
catalogUrl?: string | undefined;
|
|
65
|
+
onActiveViewContainerChange?: ((viewContainerId: string) => void) | undefined;
|
|
66
|
+
} = {},
|
|
67
|
+
) {
|
|
68
|
+
const containers = extensionRegistry.views.getViewContainers('panel');
|
|
69
|
+
if (containers.length === 0) {
|
|
70
|
+
return (
|
|
71
|
+
<section aria-label="Panel" className="workbench-bottom-panel">
|
|
72
|
+
<div className="workbench-bottom-panel__empty">No panel views contributed.</div>
|
|
73
|
+
</section>
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const resolvedActiveViewContainerId =
|
|
78
|
+
activeViewContainerId !== undefined &&
|
|
79
|
+
containers.some((container) => container.id === activeViewContainerId)
|
|
80
|
+
? activeViewContainerId
|
|
81
|
+
: containers[0]?.id;
|
|
82
|
+
const views = resolvedActiveViewContainerId
|
|
83
|
+
? extensionRegistry.views.getViews(resolvedActiveViewContainerId)
|
|
84
|
+
: [];
|
|
85
|
+
|
|
86
|
+
return (
|
|
87
|
+
<section aria-label="Panel" className="workbench-bottom-panel">
|
|
88
|
+
<div className="workbench-bottom-panel__header" role="tablist" aria-label="Panel views">
|
|
89
|
+
{containers.map((container) => {
|
|
90
|
+
const isActive = container.id === resolvedActiveViewContainerId;
|
|
91
|
+
return (
|
|
92
|
+
<button
|
|
93
|
+
key={container.id}
|
|
94
|
+
type="button"
|
|
95
|
+
role="tab"
|
|
96
|
+
aria-selected={isActive}
|
|
97
|
+
className={
|
|
98
|
+
isActive
|
|
99
|
+
? 'workbench-bottom-panel__tab workbench-bottom-panel__tab--active'
|
|
100
|
+
: 'workbench-bottom-panel__tab'
|
|
101
|
+
}
|
|
102
|
+
data-panel-view-container-id={container.id}
|
|
103
|
+
onClick={() => options.onActiveViewContainerChange?.(container.id)}
|
|
104
|
+
>
|
|
105
|
+
{container.title}
|
|
106
|
+
</button>
|
|
107
|
+
);
|
|
108
|
+
})}
|
|
109
|
+
</div>
|
|
110
|
+
<div className="workbench-bottom-panel__body">
|
|
111
|
+
{views.length === 0 ? (
|
|
112
|
+
<div className="workbench-bottom-panel__empty">No views in this panel container.</div>
|
|
113
|
+
) : (
|
|
114
|
+
views.map((view) => (
|
|
115
|
+
<section key={view.id} data-view-id={view.id} className="workbench-bottom-panel__view">
|
|
116
|
+
<WorkbenchViewHost
|
|
117
|
+
catalogTrustPolicy={options.catalogTrustPolicy}
|
|
118
|
+
catalogUrl={options.catalogUrl}
|
|
119
|
+
fallback={view.name}
|
|
120
|
+
provider={extensionRegistry.views.getViewProvider(view.id)}
|
|
121
|
+
viewHostFactories={extensionRegistry.viewHostFactories}
|
|
122
|
+
viewId={view.id}
|
|
123
|
+
/>
|
|
124
|
+
</section>
|
|
125
|
+
))
|
|
126
|
+
)}
|
|
127
|
+
</div>
|
|
128
|
+
</section>
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
|
|
59
132
|
export function WorkbenchViewHost({
|
|
60
133
|
catalogTrustPolicy,
|
|
61
134
|
catalogUrl,
|
|
@@ -4,8 +4,14 @@ import {
|
|
|
4
4
|
} from '@workbench-kit/platform';
|
|
5
5
|
import {
|
|
6
6
|
WorkbenchCommandPalette,
|
|
7
|
+
WorkbenchQuickOpen,
|
|
7
8
|
WorkbenchShortcutCommandBridge,
|
|
8
9
|
createWorkbenchShellCommands,
|
|
10
|
+
createWorkspaceFilesQuickOpenProvider,
|
|
11
|
+
resolveQuickOpenItemPath,
|
|
12
|
+
type QuickOpenItem,
|
|
13
|
+
type QuickOpenProvider,
|
|
14
|
+
type QuickOpenSelectContext,
|
|
9
15
|
type WorkbenchCommandDescriptor,
|
|
10
16
|
type WorkbenchCommandRunContext,
|
|
11
17
|
type WorkbenchShellCommandContext,
|
|
@@ -22,33 +28,94 @@ import {
|
|
|
22
28
|
resolveShellCommandActivities,
|
|
23
29
|
} from './command-palette.js';
|
|
24
30
|
import { resolveExtensionKeybindingCommand } from './keybinding-bridge.js';
|
|
31
|
+
import { isWorkspaceResourceService, useWorkspaceResourceState } from './workspace-view-state.js';
|
|
32
|
+
|
|
33
|
+
const WORKSPACE_OPEN_COMMAND_ID = 'workspace.open' as const;
|
|
25
34
|
|
|
26
35
|
export interface WorkbenchCommandHostProps {
|
|
27
36
|
additionalCommands?: readonly WorkbenchCommandDescriptor[];
|
|
37
|
+
/** Override command palette close control label (default English). */
|
|
38
|
+
commandPaletteCloseLabel?: string | undefined;
|
|
39
|
+
/** Override command palette empty-state copy (default English). */
|
|
40
|
+
commandPaletteEmptyLabel?: string | undefined;
|
|
41
|
+
/** Override command palette search placeholder (default English). */
|
|
42
|
+
commandPalettePlaceholder?: string | undefined;
|
|
43
|
+
/** Override command palette dialog title (default English). */
|
|
44
|
+
commandPaletteTitle?: string | undefined;
|
|
28
45
|
enableCommandPalette?: boolean;
|
|
29
46
|
enableExtensionKeybindings?: boolean;
|
|
47
|
+
/**
|
|
48
|
+
* When true (default), Ctrl/Cmd+P opens Quick Open instead of the command palette.
|
|
49
|
+
* Ctrl/Cmd+Shift+P still opens the command palette.
|
|
50
|
+
*/
|
|
51
|
+
enableQuickOpen?: boolean;
|
|
30
52
|
enableShortcutBridge?: boolean;
|
|
31
53
|
onOpenSettings: () => void;
|
|
54
|
+
/**
|
|
55
|
+
* Called when a Quick Open item is selected. Return `true` to skip the default
|
|
56
|
+
* `workspace.open` path for file items.
|
|
57
|
+
*/
|
|
58
|
+
onOpenQuickOpenItem?: (item: QuickOpenItem, context: QuickOpenSelectContext) => boolean | void;
|
|
32
59
|
onRunCommand?: (
|
|
33
60
|
command: WorkbenchCommandDescriptor,
|
|
34
61
|
context: WorkbenchCommandRunContext,
|
|
35
62
|
) => boolean | void;
|
|
63
|
+
/** Override Quick Open close control label (default English). */
|
|
64
|
+
quickOpenCloseLabel?: string | undefined;
|
|
65
|
+
/** Override Quick Open empty-state copy (default English). */
|
|
66
|
+
quickOpenEmptyLabel?: string | undefined;
|
|
67
|
+
/** Override Quick Open search placeholder (default English). */
|
|
68
|
+
quickOpenPlaceholder?: string | undefined;
|
|
69
|
+
/**
|
|
70
|
+
* Extra / replacement Quick Open providers. When omitted, the host wires a
|
|
71
|
+
* workspace-files provider from the registered workspace host port.
|
|
72
|
+
*/
|
|
73
|
+
quickOpenProviders?: readonly QuickOpenProvider[];
|
|
74
|
+
/** Override Quick Open dialog title (default English). */
|
|
75
|
+
quickOpenTitle?: string | undefined;
|
|
76
|
+
/** Optional recent paths elevated when the Quick Open query is empty. */
|
|
77
|
+
quickOpenRecentPaths?: readonly string[] | undefined;
|
|
36
78
|
}
|
|
37
79
|
|
|
38
80
|
export function WorkbenchCommandHost({
|
|
39
81
|
additionalCommands = [],
|
|
82
|
+
commandPaletteCloseLabel = 'Close command palette',
|
|
83
|
+
commandPaletteEmptyLabel = 'No commands match your search',
|
|
84
|
+
commandPalettePlaceholder = 'Search commands',
|
|
85
|
+
commandPaletteTitle = 'Command Palette',
|
|
40
86
|
enableCommandPalette = true,
|
|
41
87
|
enableExtensionKeybindings = true,
|
|
88
|
+
enableQuickOpen = true,
|
|
42
89
|
enableShortcutBridge = true,
|
|
43
90
|
onOpenSettings,
|
|
91
|
+
onOpenQuickOpenItem,
|
|
44
92
|
onRunCommand,
|
|
93
|
+
quickOpenCloseLabel = 'Close Quick Open',
|
|
94
|
+
quickOpenEmptyLabel = 'No matching files',
|
|
95
|
+
quickOpenPlaceholder = 'Search files by name',
|
|
96
|
+
quickOpenProviders,
|
|
97
|
+
quickOpenRecentPaths,
|
|
98
|
+
quickOpenTitle = 'Quick Open',
|
|
45
99
|
}: WorkbenchCommandHostProps) {
|
|
46
|
-
const {
|
|
100
|
+
const {
|
|
101
|
+
executeCommand,
|
|
102
|
+
extensionRegistry,
|
|
103
|
+
keybindingOverrides,
|
|
104
|
+
layoutService,
|
|
105
|
+
workspaceHostPort,
|
|
106
|
+
} = useWorkbench();
|
|
47
107
|
const [paletteOpen, setPaletteOpen] = useState(false);
|
|
48
108
|
const [paletteQuery, setPaletteQuery] = useState('');
|
|
109
|
+
const [quickOpenOpen, setQuickOpenOpen] = useState(false);
|
|
110
|
+
const [quickOpenQuery, setQuickOpenQuery] = useState('');
|
|
49
111
|
const [layout, setLayout] = useState(() => layoutService.getState());
|
|
50
112
|
const shellContextRef = useRef<WorkbenchShellCommandContext | undefined>(undefined);
|
|
51
113
|
|
|
114
|
+
const workspaceService = isWorkspaceResourceService(workspaceHostPort?.service)
|
|
115
|
+
? workspaceHostPort.service
|
|
116
|
+
: undefined;
|
|
117
|
+
const workspaceState = useWorkspaceResourceState(workspaceService);
|
|
118
|
+
|
|
52
119
|
useEffect(() => {
|
|
53
120
|
const disposable = layoutService.onDidChangeLayout(({ state }) => {
|
|
54
121
|
setLayout(state);
|
|
@@ -127,18 +194,43 @@ export function WorkbenchCommandHost({
|
|
|
127
194
|
shellCommands: shellCommandDefinitions,
|
|
128
195
|
shellContext,
|
|
129
196
|
}),
|
|
130
|
-
[additionalCommands, extensionRegistry, shellContext],
|
|
197
|
+
[additionalCommands, extensionRegistry, shellContext, shellCommandDefinitions],
|
|
131
198
|
);
|
|
132
199
|
|
|
200
|
+
const resolvedQuickOpenProviders = useMemo(() => {
|
|
201
|
+
if (quickOpenProviders) {
|
|
202
|
+
return quickOpenProviders;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const files = workspaceState?.files ?? workspaceService?.getState().files ?? [];
|
|
206
|
+
return [
|
|
207
|
+
createWorkspaceFilesQuickOpenProvider({
|
|
208
|
+
files: () => workspaceService?.getState().files ?? files,
|
|
209
|
+
recentPaths: quickOpenRecentPaths,
|
|
210
|
+
}),
|
|
211
|
+
];
|
|
212
|
+
}, [quickOpenProviders, quickOpenRecentPaths, workspaceService, workspaceState?.files]);
|
|
213
|
+
|
|
133
214
|
const closePalette = useCallback(() => {
|
|
134
215
|
setPaletteOpen(false);
|
|
135
216
|
}, []);
|
|
136
217
|
|
|
137
218
|
const openPalette = useCallback((query = '') => {
|
|
219
|
+
setQuickOpenOpen(false);
|
|
138
220
|
setPaletteQuery(query);
|
|
139
221
|
setPaletteOpen(true);
|
|
140
222
|
}, []);
|
|
141
223
|
|
|
224
|
+
const closeQuickOpen = useCallback(() => {
|
|
225
|
+
setQuickOpenOpen(false);
|
|
226
|
+
}, []);
|
|
227
|
+
|
|
228
|
+
const openQuickOpen = useCallback((query = '') => {
|
|
229
|
+
setPaletteOpen(false);
|
|
230
|
+
setQuickOpenQuery(query);
|
|
231
|
+
setQuickOpenOpen(true);
|
|
232
|
+
}, []);
|
|
233
|
+
|
|
142
234
|
const runPaletteCommand = useCallback(
|
|
143
235
|
(command: WorkbenchCommandDescriptor, context: WorkbenchCommandRunContext) => {
|
|
144
236
|
const finish = () => {
|
|
@@ -155,13 +247,35 @@ export function WorkbenchCommandHost({
|
|
|
155
247
|
[closePalette, executeCommand, onRunCommand],
|
|
156
248
|
);
|
|
157
249
|
|
|
250
|
+
const runQuickOpenItem = useCallback(
|
|
251
|
+
(item: QuickOpenItem, context: QuickOpenSelectContext) => {
|
|
252
|
+
const finish = () => {
|
|
253
|
+
closeQuickOpen();
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
if (onOpenQuickOpenItem?.(item, context)) {
|
|
257
|
+
finish();
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
const path = resolveQuickOpenItemPath(item);
|
|
262
|
+
if (!path) {
|
|
263
|
+
finish();
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
void executeCommand(WORKSPACE_OPEN_COMMAND_ID, { path }).finally(finish);
|
|
268
|
+
},
|
|
269
|
+
[closeQuickOpen, executeCommand, onOpenQuickOpenItem],
|
|
270
|
+
);
|
|
271
|
+
|
|
158
272
|
useEffect(() => {
|
|
159
|
-
if (!enableCommandPalette) {
|
|
273
|
+
if (!enableCommandPalette && !enableQuickOpen) {
|
|
160
274
|
return undefined;
|
|
161
275
|
}
|
|
162
276
|
|
|
163
277
|
const onKeyDown = (event: KeyboardEvent) => {
|
|
164
|
-
if (matchesWorkbenchCommandPaletteShortcut(event)) {
|
|
278
|
+
if (enableCommandPalette && matchesWorkbenchCommandPaletteShortcut(event)) {
|
|
165
279
|
event.preventDefault();
|
|
166
280
|
openPalette('>');
|
|
167
281
|
return;
|
|
@@ -169,7 +283,14 @@ export function WorkbenchCommandHost({
|
|
|
169
283
|
|
|
170
284
|
if (matchesWorkbenchQuickAccessShortcut(event)) {
|
|
171
285
|
event.preventDefault();
|
|
172
|
-
|
|
286
|
+
if (enableQuickOpen) {
|
|
287
|
+
openQuickOpen();
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
if (enableCommandPalette) {
|
|
292
|
+
openPalette();
|
|
293
|
+
}
|
|
173
294
|
}
|
|
174
295
|
};
|
|
175
296
|
|
|
@@ -177,7 +298,7 @@ export function WorkbenchCommandHost({
|
|
|
177
298
|
return () => {
|
|
178
299
|
window.removeEventListener('keydown', onKeyDown);
|
|
179
300
|
};
|
|
180
|
-
}, [enableCommandPalette, openPalette]);
|
|
301
|
+
}, [enableCommandPalette, enableQuickOpen, openPalette, openQuickOpen]);
|
|
181
302
|
|
|
182
303
|
useEffect(() => {
|
|
183
304
|
if (!enableExtensionKeybindings) {
|
|
@@ -228,16 +349,32 @@ export function WorkbenchCommandHost({
|
|
|
228
349
|
) : null}
|
|
229
350
|
{enableCommandPalette ? (
|
|
230
351
|
<WorkbenchCommandPalette
|
|
352
|
+
closeLabel={commandPaletteCloseLabel}
|
|
231
353
|
commands={paletteCommands}
|
|
354
|
+
emptyLabel={commandPaletteEmptyLabel}
|
|
232
355
|
open={paletteOpen}
|
|
233
|
-
placeholder=
|
|
356
|
+
placeholder={commandPalettePlaceholder}
|
|
234
357
|
query={paletteQuery}
|
|
235
|
-
title=
|
|
358
|
+
title={commandPaletteTitle}
|
|
236
359
|
onClose={closePalette}
|
|
237
360
|
onQueryChange={setPaletteQuery}
|
|
238
361
|
onRunCommand={runPaletteCommand}
|
|
239
362
|
/>
|
|
240
363
|
) : null}
|
|
364
|
+
{enableQuickOpen ? (
|
|
365
|
+
<WorkbenchQuickOpen
|
|
366
|
+
closeLabel={quickOpenCloseLabel}
|
|
367
|
+
emptyLabel={quickOpenEmptyLabel}
|
|
368
|
+
open={quickOpenOpen}
|
|
369
|
+
placeholder={quickOpenPlaceholder}
|
|
370
|
+
providers={resolvedQuickOpenProviders}
|
|
371
|
+
query={quickOpenQuery}
|
|
372
|
+
title={quickOpenTitle}
|
|
373
|
+
onClose={closeQuickOpen}
|
|
374
|
+
onQueryChange={setQuickOpenQuery}
|
|
375
|
+
onSelectItem={runQuickOpenItem}
|
|
376
|
+
/>
|
|
377
|
+
) : null}
|
|
241
378
|
</>
|
|
242
379
|
);
|
|
243
380
|
}
|
|
@@ -30,6 +30,8 @@ export function workbenchLayoutConfigToInput(
|
|
|
30
30
|
visible: config.auxiliaryBar.visible,
|
|
31
31
|
},
|
|
32
32
|
panel: {
|
|
33
|
+
activeViewContainer: config.panel.activeViewContainer,
|
|
34
|
+
sizePercent: config.panel.sizePercent,
|
|
33
35
|
visible: config.panel.visible,
|
|
34
36
|
},
|
|
35
37
|
sideBar: {
|
|
@@ -58,6 +60,10 @@ export function workbenchLayoutStateToStorageValue(
|
|
|
58
60
|
},
|
|
59
61
|
panel: {
|
|
60
62
|
visible: state.panel.visible,
|
|
63
|
+
...(state.panel.activeViewContainer
|
|
64
|
+
? { activeViewContainer: state.panel.activeViewContainer }
|
|
65
|
+
: {}),
|
|
66
|
+
...(state.panel.sizePercent !== undefined ? { sizePercent: state.panel.sizePercent } : {}),
|
|
61
67
|
},
|
|
62
68
|
sideBar: {
|
|
63
69
|
visible: state.sideBar.visible,
|