@workbench-kit/shell-react 0.0.2-prototype.0.2.13 → 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 +15 -0
- 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/view.css +12 -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
|
@@ -92,6 +92,21 @@ const flowActionsRef = useRef<FieldRemapFlowActions | null>(null);
|
|
|
92
92
|
/>;
|
|
93
93
|
```
|
|
94
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
|
+
|
|
95
110
|
## Related docs
|
|
96
111
|
|
|
97
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/field-remap": "0.0.2-prototype.0.2.
|
|
25
|
-
"@workbench-kit/
|
|
26
|
-
"@workbench-kit/
|
|
27
|
-
"@workbench-kit/
|
|
28
|
-
"@workbench-kit/
|
|
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
|
}
|
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
|
|
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,
|