diff --git a/build/gulpfile.vscode.ts b/build/gulpfile.vscode.ts index 080d97f3197cf..1e216b7f5ad92 100644 --- a/build/gulpfile.vscode.ts +++ b/build/gulpfile.vscode.ts @@ -97,6 +97,7 @@ const vscodeResourceIncludes = [ // Welcome 'out-build/vs/workbench/contrib/welcomeGettingStarted/common/media/**/*.{svg,png}', + 'out-build/vs/workbench/contrib/welcomeOnboarding/browser/media/*.svg', // Sessions 'out-build/vs/sessions/contrib/chat/browser/media/*.svg', diff --git a/build/gulpfile.vscode.web.ts b/build/gulpfile.vscode.web.ts index 3e6b29adfe9fa..9af2afecb38ba 100644 --- a/build/gulpfile.vscode.web.ts +++ b/build/gulpfile.vscode.web.ts @@ -74,6 +74,7 @@ export const vscodeWebResourceIncludes = [ // Welcome 'out-build/vs/workbench/contrib/welcomeGettingStarted/common/media/**/*.{svg,png}', + 'out-build/vs/workbench/contrib/welcomeOnboarding/browser/media/*.svg', // Extensions 'out-build/vs/workbench/contrib/extensions/browser/media/{theme-icon.png,language-icon.svg}', diff --git a/build/next/index.ts b/build/next/index.ts index 93c7a035c0635..3b530ea1e5184 100644 --- a/build/next/index.ts +++ b/build/next/index.ts @@ -278,6 +278,7 @@ const desktopResourcePatterns = [ // Media - images 'vs/workbench/contrib/welcomeGettingStarted/common/media/**/*.svg', 'vs/workbench/contrib/welcomeGettingStarted/common/media/**/*.png', + 'vs/workbench/contrib/welcomeOnboarding/browser/media/*.svg', 'vs/workbench/contrib/extensions/browser/media/{theme-icon.png,language-icon.svg}', 'vs/workbench/services/extensionManagement/common/media/*.svg', 'vs/workbench/services/extensionManagement/common/media/*.png', @@ -337,6 +338,7 @@ const serverWebResourcePatterns = [ // Media - images 'vs/workbench/contrib/welcomeGettingStarted/common/media/**/*.svg', 'vs/workbench/contrib/welcomeGettingStarted/common/media/**/*.png', + 'vs/workbench/contrib/welcomeOnboarding/browser/media/*.svg', 'vs/workbench/contrib/extensions/browser/media/*.svg', 'vs/workbench/contrib/extensions/browser/media/*.png', 'vs/workbench/services/extensionManagement/common/media/*.svg', @@ -363,6 +365,7 @@ const webResourcePatterns = [ // Media - images 'vs/workbench/contrib/welcomeGettingStarted/common/media/**/*.svg', 'vs/workbench/contrib/welcomeGettingStarted/common/media/**/*.png', + 'vs/workbench/contrib/welcomeOnboarding/browser/media/*.svg', 'vs/workbench/contrib/extensions/browser/media/*.svg', 'vs/workbench/contrib/extensions/browser/media/*.png', 'vs/workbench/services/extensionManagement/common/media/*.svg', diff --git a/src/vs/workbench/contrib/welcomeOnboarding/browser/onboardingVariationA.ts b/src/vs/workbench/contrib/welcomeOnboarding/browser/onboardingVariationA.ts index c9d06f401f7f5..9c2dcb921ed4a 100644 --- a/src/vs/workbench/contrib/welcomeOnboarding/browser/onboardingVariationA.ts +++ b/src/vs/workbench/contrib/welcomeOnboarding/browser/onboardingVariationA.ts @@ -30,7 +30,9 @@ import { IQuickInputService } from '../../../../platform/quickinput/common/quick import { IFileService } from '../../../../platform/files/common/files.js'; import { IPathService } from '../../../services/path/common/pathService.js'; import { ITelemetryService } from '../../../../platform/telemetry/common/telemetry.js'; -import { InstallChatEvent, InstallChatClassification } from '../../chat/browser/chatSetup/chatSetup.js'; +import { InstallChatEvent, InstallChatClassification, ChatSetupStrategy } from '../../chat/browser/chatSetup/chatSetup.js'; +import { ICommandService } from '../../../../platform/commands/common/commands.js'; +import { IAccessibilityService } from '../../../../platform/accessibility/common/accessibility.js'; import { OnboardingStepId, ONBOARDING_STEPS, @@ -135,6 +137,8 @@ export class OnboardingVariationA extends Disposable implements IOnboardingServi @IFileService private readonly fileService: IFileService, @IPathService private readonly pathService: IPathService, @ITelemetryService private readonly telemetryService: ITelemetryService, + @ICommandService private readonly commandService: ICommandService, + @IAccessibilityService private readonly accessibilityService: IAccessibilityService, ) { super(); @@ -365,6 +369,8 @@ export class OnboardingVariationA extends Disposable implements IOnboardingServi this._renderAgentSessionsSubtitle(this.subtitleEl); } else if (stepId === OnboardingStepId.Personalize) { this._renderPersonalizeSubtitle(this.subtitleEl); + } else if (stepId === OnboardingStepId.Extensions) { + this._renderExtensionsSubtitle(this.subtitleEl); } else { this.subtitleEl.textContent = getOnboardingStepSubtitle(stepId); } @@ -561,6 +567,11 @@ export class OnboardingVariationA extends Disposable implements IOnboardingServi if (account) { this._userSignedIn = true; this.telemetryService.publicLog2('commandCenter.chatInstall', { installResult: 'installed', installDuration: watch.elapsed(), signUpErrorCode: undefined, provider }); + // Run chat setup in the background (sign-up, extension install, entitlement resolution) + this.commandService.executeCommand('workbench.action.chat.triggerSetup', undefined, { + disableChatViewReveal: true, + setupStrategy: ChatSetupStrategy.DefaultSetup, + }); this._nextStep(); } } catch (error) { @@ -592,6 +603,10 @@ export class OnboardingVariationA extends Disposable implements IOnboardingServi if (account) { this._userSignedIn = true; this.telemetryService.publicLog2('commandCenter.chatInstall', { installResult: 'installed', installDuration: watch.elapsed(), signUpErrorCode: undefined, provider }); + this.commandService.executeCommand('workbench.action.chat.triggerSetup', undefined, { + disableChatViewReveal: true, + setupStrategy: ChatSetupStrategy.DefaultSetup, + }); this._nextStep(); } } catch (error) { @@ -743,6 +758,7 @@ export class OnboardingVariationA extends Disposable implements IOnboardingServi } pill.classList.add('selected'); pill.setAttribute('aria-checked', 'true'); + this.accessibilityService.alert(localize('onboarding.keymap.selected.alert', "{0} keyboard mapping selected", keymap.label)); })); } const selectedKeymapIndex = keymapOptions.findIndex(k => k.id === this.selectedKeymapId); @@ -765,6 +781,20 @@ export class OnboardingVariationA extends Disposable implements IOnboardingServi ); } + private _renderExtensionsSubtitle(container: HTMLElement): void { + clearNode(container); + const modifier = isMacintosh ? 'Cmd' : 'Ctrl'; + container.append( + localize('onboarding.extensions.subtitle.prefix', "Install extensions to enhance your workflow. Press "), + this._createKbd(localize({ key: 'onboarding.extensions.subtitle.modifier', comment: ['Keyboard modifier key'] }, "{0}", modifier)), + '+', + this._createKbd(localize('onboarding.extensions.subtitle.shift', "Shift")), + '+', + this._createKbd(localize('onboarding.extensions.subtitle.x', "X")), + localize('onboarding.extensions.subtitle.suffix', " to browse the Extension Marketplace."), + ); + } + private _createThemeCard(parent: HTMLElement, theme: IOnboardingThemeOption, allCards: HTMLElement[]): void { const card = this._registerStepFocusable(append(parent, $('div.onboarding-a-theme-card'))); allCards.push(card); @@ -795,6 +825,7 @@ export class OnboardingVariationA extends Disposable implements IOnboardingServi } card.classList.add('selected'); card.setAttribute('aria-checked', 'true'); + this.accessibilityService.alert(localize('onboarding.theme.selected.alert', "{0} theme selected", theme.label)); })); this.stepDisposables.add(addDisposableListener(card, EventType.KEY_DOWN, (e: KeyboardEvent) => { @@ -841,6 +872,7 @@ export class OnboardingVariationA extends Disposable implements IOnboardingServi const installBtn = this._registerStepFocusable(append(row, $('button.onboarding-a-ext-install'))); installBtn.type = 'button'; installBtn.textContent = localize('onboarding.ext.install', "Install"); + installBtn.setAttribute('aria-label', localize('onboarding.ext.install.aria', "Install {0}", ext.name)); this.stepDisposables.add(addDisposableListener(installBtn, EventType.CLICK, () => { this._logAction('installExtension', undefined, ext.id); @@ -850,6 +882,8 @@ export class OnboardingVariationA extends Disposable implements IOnboardingServi () => { installBtn.textContent = localize('onboarding.ext.installed', "Installed"); installBtn.classList.add('installed'); + installBtn.setAttribute('aria-label', localize('onboarding.ext.installed.aria', "{0} installed", ext.name)); + this.accessibilityService.alert(localize('onboarding.ext.installed.alert', "{0} has been installed", ext.name)); }, () => { installBtn.textContent = localize('onboarding.ext.install', "Install"); @@ -1068,6 +1102,7 @@ export class OnboardingVariationA extends Disposable implements IOnboardingServi c.setAttribute('aria-checked', c.dataset.id === option.id ? 'true' : 'false'); } this._applyAiPreference(option.id); + this.accessibilityService.alert(localize('onboarding.aiPref.selected.alert', "{0} selected", option.label)); })); } const selectedAiIndex = ONBOARDING_AI_PREFERENCE_OPTIONS.findIndex(o => o.id === this.selectedAiMode); @@ -1148,7 +1183,10 @@ export class OnboardingVariationA extends Disposable implements IOnboardingServi } private _createFeatureCard(parent: HTMLElement, icon: ThemeIcon, title: string, description?: string): HTMLElement { - const card = append(parent, $('div.onboarding-a-feature-card')); + const card = this._registerStepFocusable(append(parent, $('div.onboarding-a-feature-card'))); + card.setAttribute('tabindex', '0'); + card.setAttribute('role', 'group'); + card.setAttribute('aria-label', title); const iconCol = append(card, $('div.onboarding-a-feature-icon')); iconCol.appendChild(renderIcon(icon)); const textCol = append(card, $('div.onboarding-a-feature-text'));