Updates component explorer

This commit is contained in:
Henning Dieterichs
2026-03-03 12:30:21 +01:00
committed by Henning Dieterichs
parent 51223b6fb5
commit cd41bf1fe1
19 changed files with 122 additions and 37 deletions

View File

@@ -30,7 +30,7 @@ src/vs/workbench/test/browser/componentFixtures/
```typescript
import { ComponentFixtureContext, createEditorServices, defineComponentFixture, defineThemedFixtureGroup } from './fixtureUtils.js';
export default defineThemedFixtureGroup({
export default defineThemedFixtureGroup({ path: 'myFeature/' }, {
Default: defineComponentFixture({ render: renderMyComponent }),
AnotherVariant: defineComponentFixture({ render: renderMyComponent }),
});

View File

@@ -8,8 +8,8 @@
"name": "@vscode/sample-source",
"version": "0.0.0",
"devDependencies": {
"@vscode/component-explorer": "^0.1.1-16",
"@vscode/component-explorer-vite-plugin": "^0.1.1-16",
"@vscode/component-explorer": "^0.1.1-19",
"@vscode/component-explorer-vite-plugin": "^0.1.1-19",
"@vscode/rollup-plugin-esm-url": "^1.0.1-1",
"rollup": "*",
"vite": "npm:rolldown-vite@latest"
@@ -683,9 +683,9 @@
"license": "MIT"
},
"node_modules/@vscode/component-explorer": {
"version": "0.1.1-16",
"resolved": "https://registry.npmjs.org/@vscode/component-explorer/-/component-explorer-0.1.1-16.tgz",
"integrity": "sha512-is1RxdlNO5K1RSqWd5z8BN6gPrqEBZfjgUi3ZJbQj8Z4VqmqoJsNLIzBXOIlQJX+5mWgeNdOq3vxe0u15ZkAlA==",
"version": "0.1.1-19",
"resolved": "https://registry.npmjs.org/@vscode/component-explorer/-/component-explorer-0.1.1-19.tgz",
"integrity": "sha512-wvcjw1A8wSH/oR5q+lZrBSyOQZfvXtLPYkQJBj11FBKu35iHko0FTIPMG25Ee+TpT2/BWLd29dWwiJODDQbC8w==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -694,9 +694,9 @@
}
},
"node_modules/@vscode/component-explorer-vite-plugin": {
"version": "0.1.1-16",
"resolved": "https://registry.npmjs.org/@vscode/component-explorer-vite-plugin/-/component-explorer-vite-plugin-0.1.1-16.tgz",
"integrity": "sha512-z2EqusWl49dUF3vNDgmJJJQXkv4ejeBH9AdFZUWOiGaMvjjFX6UV7oQ733b+vo5YFE8my9WaK7D691i2wZ47Fg==",
"version": "0.1.1-19",
"resolved": "https://registry.npmjs.org/@vscode/component-explorer-vite-plugin/-/component-explorer-vite-plugin-0.1.1-19.tgz",
"integrity": "sha512-V0wMhLvHMbeUHOzwGrBPMwwvcbGhXXaQTCGc9hNfF4fjUutOtQFu5o+9XKDG1hIcKgk5qyvcRoXjVazBcg19lA==",
"dev": true,
"license": "MIT",
"dependencies": {

View File

@@ -9,8 +9,8 @@
"preview": "vite preview"
},
"devDependencies": {
"@vscode/component-explorer": "^0.1.1-16",
"@vscode/component-explorer-vite-plugin": "^0.1.1-16",
"@vscode/component-explorer": "^0.1.1-19",
"@vscode/component-explorer-vite-plugin": "^0.1.1-19",
"@vscode/rollup-plugin-esm-url": "^1.0.1-1",
"rollup": "*",
"vite": "npm:rolldown-vite@latest"

16
package-lock.json generated
View File

@@ -84,8 +84,8 @@
"@types/yazl": "^2.4.2",
"@typescript-eslint/utils": "^8.45.0",
"@typescript/native-preview": "^7.0.0-dev.20260130",
"@vscode/component-explorer": "^0.1.1-16",
"@vscode/component-explorer-cli": "^0.1.1-12",
"@vscode/component-explorer": "^0.1.1-19",
"@vscode/component-explorer-cli": "^0.1.1-15",
"@vscode/gulp-electron": "1.40.1",
"@vscode/l10n-dev": "0.0.35",
"@vscode/telemetry-extractor": "^1.20.2",
@@ -3051,9 +3051,9 @@
"license": "CC-BY-4.0"
},
"node_modules/@vscode/component-explorer": {
"version": "0.1.1-16",
"resolved": "https://registry.npmjs.org/@vscode/component-explorer/-/component-explorer-0.1.1-16.tgz",
"integrity": "sha512-is1RxdlNO5K1RSqWd5z8BN6gPrqEBZfjgUi3ZJbQj8Z4VqmqoJsNLIzBXOIlQJX+5mWgeNdOq3vxe0u15ZkAlA==",
"version": "0.1.1-19",
"resolved": "https://registry.npmjs.org/@vscode/component-explorer/-/component-explorer-0.1.1-19.tgz",
"integrity": "sha512-wvcjw1A8wSH/oR5q+lZrBSyOQZfvXtLPYkQJBj11FBKu35iHko0FTIPMG25Ee+TpT2/BWLd29dWwiJODDQbC8w==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -3062,9 +3062,9 @@
}
},
"node_modules/@vscode/component-explorer-cli": {
"version": "0.1.1-12",
"resolved": "https://registry.npmjs.org/@vscode/component-explorer-cli/-/component-explorer-cli-0.1.1-12.tgz",
"integrity": "sha512-SaChUP94wkf1RaaJ/MnpQsxsr7pUpqQJq5Z9QLbrZuUqRil2TZEHwYLSqpQPqLgybNxZtrlMDivTjcCWXFTttg==",
"version": "0.1.1-15",
"resolved": "https://registry.npmjs.org/@vscode/component-explorer-cli/-/component-explorer-cli-0.1.1-15.tgz",
"integrity": "sha512-5unK3ehSezNAGJqN4Nn1CjIjavLY9Rc17buUOC/4SfqyXSFStWN/0JG7S/ESgwqW1I2WruadZis0X0sS33dlFQ==",
"dev": true,
"license": "MIT",
"dependencies": {

View File

@@ -153,8 +153,8 @@
"@types/yazl": "^2.4.2",
"@typescript-eslint/utils": "^8.45.0",
"@typescript/native-preview": "^7.0.0-dev.20260130",
"@vscode/component-explorer": "^0.1.1-16",
"@vscode/component-explorer-cli": "^0.1.1-12",
"@vscode/component-explorer": "^0.1.1-19",
"@vscode/component-explorer-cli": "^0.1.1-15",
"@vscode/gulp-electron": "1.40.1",
"@vscode/l10n-dev": "0.0.35",
"@vscode/telemetry-extractor": "^1.20.2",

View File

@@ -56,48 +56,59 @@ function renderUpdateWidget(ctx: ComponentFixtureContext, state: State): void {
widget.render(ctx.container);
}
export default defineThemedFixtureGroup({
export default defineThemedFixtureGroup({ path: 'sessions/' }, {
Ready: defineComponentFixture({
labels: { kind: 'screenshot' },
render: (ctx) => renderUpdateWidget(ctx, State.Ready(mockUpdate, true, false)),
}),
CheckingForUpdates: defineComponentFixture({
labels: { kind: 'animated' },
render: (ctx) => renderUpdateWidget(ctx, State.CheckingForUpdates(true)),
}),
AvailableForDownload: defineComponentFixture({
labels: { kind: 'animated' },
render: (ctx) => renderUpdateWidget(ctx, State.AvailableForDownload(mockUpdate)),
}),
Downloading0Percent: defineComponentFixture({
labels: { kind: 'animated' },
render: (ctx) => renderUpdateWidget(ctx, State.Downloading(mockUpdate, true, false, 0, 100_000_000)),
}),
Downloading30Percent: defineComponentFixture({
labels: { kind: 'animated' },
render: (ctx) => renderUpdateWidget(ctx, State.Downloading(mockUpdate, true, false, 30_000_000, 100_000_000)),
}),
Downloading65Percent: defineComponentFixture({
labels: { kind: 'animated' },
render: (ctx) => renderUpdateWidget(ctx, State.Downloading(mockUpdate, true, false, 65_000_000, 100_000_000)),
}),
Downloading100Percent: defineComponentFixture({
labels: { kind: 'animated' },
render: (ctx) => renderUpdateWidget(ctx, State.Downloading(mockUpdate, true, false, 100_000_000, 100_000_000)),
}),
DownloadingIndeterminate: defineComponentFixture({
labels: { kind: 'animated' },
render: (ctx) => renderUpdateWidget(ctx, State.Downloading(mockUpdate, true, false)),
}),
Downloaded: defineComponentFixture({
labels: { kind: 'animated' },
render: (ctx) => renderUpdateWidget(ctx, State.Downloaded(mockUpdate, true, false)),
}),
Updating: defineComponentFixture({
labels: { kind: 'animated' },
render: (ctx) => renderUpdateWidget(ctx, State.Updating(mockUpdate)),
}),
Overwriting: defineComponentFixture({
labels: { kind: 'animated' },
render: (ctx) => renderUpdateWidget(ctx, State.Overwriting(mockUpdate, true)),
}),
});

View File

@@ -9,12 +9,14 @@ import { ISessionData } from '../../../contrib/editTelemetry/browser/editStats/a
import { Random } from '../../../../editor/test/common/core/random.js';
import { ComponentFixtureContext, defineComponentFixture, defineThemedFixtureGroup } from './fixtureUtils.js';
export default defineThemedFixtureGroup({
export default defineThemedFixtureGroup({ path: 'chat/' }, {
AiStatsHover: defineComponentFixture({
labels: { kind: 'screenshot' },
render: (context) => renderAiStatsHover({ ...context, data: createSampleDataWithSessions() }),
}),
AiStatsHoverNoData: defineComponentFixture({
labels: { kind: 'screenshot' },
render: (context) => renderAiStatsHover({ ...context, data: createEmptyData() }),
}),
});

View File

@@ -22,34 +22,42 @@ import { ComponentFixtureContext, defineComponentFixture, defineThemedFixtureGro
export default defineThemedFixtureGroup({
Buttons: defineComponentFixture({
labels: { kind: 'screenshot' },
render: renderButtons,
}),
ButtonBar: defineComponentFixture({
labels: { kind: 'screenshot' },
render: renderButtonBar,
}),
Toggles: defineComponentFixture({
labels: { kind: 'screenshot' },
render: renderToggles,
}),
InputBoxes: defineComponentFixture({
labels: { kind: 'screenshot' },
render: renderInputBoxes,
}),
CountBadges: defineComponentFixture({
labels: { kind: 'screenshot' },
render: renderCountBadges,
}),
ActionBar: defineComponentFixture({
labels: { kind: 'screenshot' },
render: renderActionBar,
}),
ProgressBars: defineComponentFixture({
labels: { kind: 'screenshot' },
render: renderProgressBars,
}),
HighlightedLabels: defineComponentFixture({
labels: { kind: 'screenshot' },
render: renderHighlightedLabels,
}),
});

View File

@@ -101,8 +101,9 @@ function renderProgressPart(
container.appendChild(itemContainer);
}
export default defineThemedFixtureGroup({
export default defineThemedFixtureGroup({ path: 'chat/' }, {
WithSpinner: defineComponentFixture({
labels: { kind: 'animated' },
render: (ctx) => renderProgressPart(
ctx,
createProgressMessage('Searching workspace for relevant files...'),
@@ -112,6 +113,7 @@ export default defineThemedFixtureGroup({
}),
Completed: defineComponentFixture({
labels: { kind: 'screenshot' },
render: (ctx) => renderProgressPart(
ctx,
createProgressMessage('Found 12 relevant files'),
@@ -121,6 +123,7 @@ export default defineThemedFixtureGroup({
}),
WithCustomIcon: defineComponentFixture({
labels: { kind: 'screenshot' },
render: (ctx) => renderProgressPart(
ctx,
createProgressMessage('Running tests...'),
@@ -130,6 +133,7 @@ export default defineThemedFixtureGroup({
}),
WithInlineCode: defineComponentFixture({
labels: { kind: 'animated' },
render: (ctx) => renderProgressPart(
ctx,
createProgressMessage('Reading `src/vs/workbench/contrib/chat/browser/chatWidget.ts`'),
@@ -139,6 +143,7 @@ export default defineThemedFixtureGroup({
}),
LongMessage: defineComponentFixture({
labels: { kind: 'animated' },
render: (ctx) => renderProgressPart(
ctx,
createProgressMessage('Searching across multiple workspace folders for TypeScript files matching the pattern you described, including test files and configuration'),

View File

@@ -124,20 +124,24 @@ const multiSelectQuestion: IChatQuestion = {
// Fixtures
// ============================================================================
export default defineThemedFixtureGroup({
export default defineThemedFixtureGroup({ path: 'chat/' }, {
SingleTextQuestion: defineComponentFixture({
labels: { kind: 'screenshot' },
render: (context) => renderCarousel(context, createCarousel([textQuestion])),
}),
SingleSelectQuestion: defineComponentFixture({
labels: { kind: 'screenshot' },
render: (context) => renderCarousel(context, createCarousel([singleSelectQuestion])),
}),
MultiSelectQuestion: defineComponentFixture({
labels: { kind: 'screenshot' },
render: (context) => renderCarousel(context, createCarousel([multiSelectQuestion])),
}),
MultipleQuestions: defineComponentFixture({
labels: { kind: 'screenshot' },
render: (context) => renderCarousel(context, createCarousel([
textQuestion,
singleSelectQuestion,
@@ -146,10 +150,12 @@ export default defineThemedFixtureGroup({
}),
NoSkip: defineComponentFixture({
labels: { kind: 'screenshot' },
render: (context) => renderCarousel(context, createCarousel([singleSelectQuestion], false)),
}),
SubmittedSummary: defineComponentFixture({
labels: { kind: 'screenshot' },
render: (context) => {
const carousel = createCarousel([textQuestion, singleSelectQuestion, multiSelectQuestion]);
carousel.isUsed = true;
@@ -163,6 +169,7 @@ export default defineThemedFixtureGroup({
}),
SkippedSummary: defineComponentFixture({
labels: { kind: 'screenshot' },
render: (context) => {
const carousel = createCarousel([textQuestion, singleSelectQuestion]);
carousel.isUsed = true;

View File

@@ -92,11 +92,13 @@ const simpleFixes: IActionListItem<string>[] = [
{ kind: ActionListItemKind.Action, item: 'fix-3', label: 'Add \'await\' to async call', group: { title: 'Quick Fix', icon: Codicon.lightBulb } },
];
export default defineThemedFixtureGroup({
export default defineThemedFixtureGroup({ path: 'editor/' }, {
GroupedCodeActions: defineComponentFixture({
labels: { kind: 'animated' },
render: (context) => renderCodeActionList({ ...context, items: quickFixItems }),
}),
SimpleQuickFixes: defineComponentFixture({
labels: { kind: 'screenshot' },
render: (context) => renderCodeActionList({ ...context, items: simpleFixes }),
}),
});

View File

@@ -68,8 +68,9 @@ function renderCodeEditor({ container, disposableStore, theme }: ComponentFixtur
editor.setModel(model);
}
export default defineThemedFixtureGroup({
export default defineThemedFixtureGroup({ path: 'editor/' }, {
CodeEditor: defineComponentFixture({
labels: { kind: 'screenshot' },
render: (context) => renderCodeEditor(context),
}),
});

View File

@@ -119,11 +119,13 @@ async function renderFindWidget(options: FindFixtureOptions): Promise<void> {
await new Promise(resolve => setTimeout(resolve, 300));
}
export default defineThemedFixtureGroup({
export default defineThemedFixtureGroup({ path: 'editor/' }, {
Find: defineComponentFixture({
labels: { kind: 'animated' },
render: (context) => renderFindWidget({ ...context, searchString: 'count' }),
}),
FindAndReplace: defineComponentFixture({
labels: { kind: 'animated' },
render: (context) => renderFindWidget({ ...context, searchString: 'count', replaceString: 'value', showReplace: true }),
}),
});

View File

@@ -474,6 +474,24 @@ export function createTextModel(
// Fixture Adapters
// ============================================================================
export interface ThemedFixtureGroupLabels {
readonly kind?: 'screenshot' | 'animated';
readonly blocksCi?: true;
}
function resolveLabels(labels: ThemedFixtureGroupLabels | undefined): string[] {
const result: string[] = [];
if (labels?.kind === 'screenshot') {
result.push('.screenshot');
} else if (labels?.kind === 'animated') {
result.push('animated');
}
if (labels?.blocksCi) {
result.push('blocks-ci');
}
return result;
}
export interface ComponentFixtureContext {
container: HTMLElement;
disposableStore: DisposableStore;
@@ -482,6 +500,7 @@ export interface ComponentFixtureContext {
export interface ComponentFixtureOptions {
render: (context: ComponentFixtureContext) => void | Promise<void>;
labels?: ThemedFixtureGroupLabels;
}
type ThemedFixtures = ReturnType<typeof defineFixtureVariants>;
@@ -509,18 +528,33 @@ export function defineComponentFixture(options: ComponentFixtureOptions): Themed
},
});
return defineFixtureVariants({
const labels = resolveLabels(options.labels);
return defineFixtureVariants(labels.length > 0 ? { labels } : {}, {
Dark: createFixture(darkTheme),
Light: createFixture(lightTheme),
});
}
type ThemedFixtureGroupInput = Record<string, ThemedFixtures>;
interface ThemedFixtureGroupOptions {
readonly path?: string;
readonly labels?: ThemedFixtureGroupLabels;
}
type ThemedFixtureGroupFixtures = Record<string, ThemedFixtures>;
/**
* Creates a nested fixture group from themed fixtures.
* E.g., { MergeEditor: { Dark: ..., Light: ... } } becomes a nested group: MergeEditor > Dark/Light
*/
export function defineThemedFixtureGroup(group: ThemedFixtureGroupInput): ReturnType<typeof defineFixtureGroup> {
return defineFixtureGroup(group);
export function defineThemedFixtureGroup(options: ThemedFixtureGroupOptions, fixtures: ThemedFixtureGroupFixtures): ReturnType<typeof defineFixtureGroup>;
export function defineThemedFixtureGroup(fixtures: ThemedFixtureGroupFixtures): ReturnType<typeof defineFixtureGroup>;
export function defineThemedFixtureGroup(optionsOrFixtures: ThemedFixtureGroupOptions | ThemedFixtureGroupFixtures, fixtures?: ThemedFixtureGroupFixtures): ReturnType<typeof defineFixtureGroup> {
if (fixtures) {
const options = optionsOrFixtures as ThemedFixtureGroupOptions;
return defineFixtureGroup({
labels: resolveLabels(options.labels),
path: options.path,
}, fixtures as ThemedFixtureGroupFixtures);
}
return defineFixtureGroup(optionsOrFixtures as ThemedFixtureGroupFixtures);
}

View File

@@ -107,9 +107,10 @@ function renderInlineEdit(options: InlineEditOptions): void {
// Fixtures
// ============================================================================
export default defineThemedFixtureGroup({
export default defineThemedFixtureGroup({ path: 'editor/' }, {
// Side-by-side view: Multi-line replacement
SideBySideView: defineComponentFixture({
labels: { kind: 'screenshot' },
render: (context) => renderInlineEdit({
...context,
code: `function greet(name) {
@@ -123,6 +124,7 @@ export default defineThemedFixtureGroup({
// Word replacement view: Single word change
WordReplacementView: defineComponentFixture({
labels: { kind: 'screenshot' },
render: (context) => renderInlineEdit({
...context,
code: `class BufferData {
@@ -139,6 +141,7 @@ export default defineThemedFixtureGroup({
// Insertion view: Insert new content
InsertionView: defineComponentFixture({
labels: { kind: 'screenshot' },
render: (context) => renderInlineEdit({
...context,
code: `class BufferData {

View File

@@ -276,17 +276,21 @@ function createLongDistanceEditor(options: {
controller?.model?.get();
}
export default defineThemedFixtureGroup({
export default defineThemedFixtureGroup({ path: 'editor/' }, {
HintsToolbar: defineComponentFixture({
labels: { kind: 'screenshot' },
render: (context) => renderHintsToolbar(context),
}),
HintsToolbarHovered: defineComponentFixture({
labels: { kind: 'screenshot' },
render: (context) => renderHintsToolbar({ ...context, simulateHover: true }),
}),
JumpToHint: defineComponentFixture({
labels: { kind: 'screenshot' },
render: renderJumpToHint,
}),
LongDistanceHint: defineComponentFixture({
labels: { kind: 'animated' },
render: (context) => createLongDistanceEditor({
...context,
code: LONG_DISTANCE_CODE,

View File

@@ -50,8 +50,9 @@ class FixtureQuickInputService extends QuickInputService {
}
}
export default defineThemedFixtureGroup({
export default defineThemedFixtureGroup({ path: 'chat/' }, {
PromptFiles: defineComponentFixture({
labels: { kind: 'screenshot' },
render: context => renderPromptFilePickerFixture({
...context,
type: PromptsType.prompt,
@@ -69,6 +70,7 @@ export default defineThemedFixtureGroup({
}),
InstructionFilesWithAgentInstructions: defineComponentFixture({
labels: { kind: 'screenshot' },
render: context => renderPromptFilePickerFixture({
...context,
type: PromptsType.instructions,

View File

@@ -93,8 +93,9 @@ function renderRenameWidget(options: RenameFixtureOptions): void {
);
}
export default defineThemedFixtureGroup({
export default defineThemedFixtureGroup({ path: 'editor/' }, {
RenameVariable: defineComponentFixture({
labels: { kind: 'animated' },
render: (context) => renderRenameWidget({
...context,
cursorLine: 4,
@@ -105,6 +106,7 @@ export default defineThemedFixtureGroup({
}),
}),
RenameClass: defineComponentFixture({
labels: { kind: 'animated' },
render: (context) => renderRenameWidget({
...context,
cursorLine: 1,

View File

@@ -144,8 +144,9 @@ const mixedKindCompletions: CompletionList = {
],
};
export default defineThemedFixtureGroup({
export default defineThemedFixtureGroup({ path: 'editor/' }, {
MethodCompletions: defineComponentFixture({
labels: { kind: 'screenshot' },
render: (context) => renderSuggestWidget({
...context,
code: `const element = document.getElementById('app');
@@ -159,6 +160,7 @@ if (element) {
}),
MixedKinds: defineComponentFixture({
labels: { kind: 'screenshot' },
render: (context) => renderSuggestWidget({
...context,
code: '',