Add in-editor survey pane#322192
Merged
Merged
Conversation
Moves in-product surveys from notification-based flows into an editor pane, following the same pattern as the issue reporter editor. - EditorInput + EditorPane architecture (singleton, readonly) - Segmented control (Q1) styled with --vscode-radio-* tokens - List-row selection (Q2/Q3) with native radios visually hidden inside full-width label elements, styled via :has(:checked) - Responsive container query (collapses 2-col to 1-col at 600px) - HC/focus-visible support for both segment and list-row patterns - Success animation with auto-close after 3s - Telemetry event for survey submission (survey/submit) - Works in both workbench and sessions/agent window - Testable via Developer: Open Survey command Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Contributor
There was a problem hiding this comment.
Pull request overview
Adds a proof-of-concept “in-editor” survey experience to the VS Code workbench (and Sessions window) by introducing a dedicated EditorInput + EditorPane pair, plus a developer command to open the survey and basic submission telemetry.
Changes:
- Registers a new survey editor (
SurveyEditorInput/SurveyEditorPane) and wires it into the workbench + sessions entrypoints. - Defines an initial Copilot PMF survey model (3 questions) and renders it with a segmented control + list-row radio selection.
- Logs a
survey/submittelemetry event and shows a success state with auto-close.
Show a summary per file
| File | Description |
|---|---|
| src/vs/workbench/workbench.web.main.ts | Imports the surveys contribution for web workbench startup. |
| src/vs/workbench/workbench.desktop.main.ts | Imports the surveys contribution for desktop workbench startup. |
| src/vs/workbench/contrib/surveys/browser/surveyQuestions.ts | Adds the initial Copilot PMF survey definition + question types. |
| src/vs/workbench/contrib/surveys/browser/surveyEditorPane.ts | Implements the editor pane UI, interaction handling, submit flow, and success state. |
| src/vs/workbench/contrib/surveys/browser/surveyEditorInput.ts | Adds the singleton/readonly editor input and icon for survey editor. |
| src/vs/workbench/contrib/surveys/browser/survey.contribution.ts | Registers the editor pane and a Developer command to open the survey. |
| src/vs/workbench/contrib/surveys/browser/media/surveyEditorPane.css | Adds styles for the survey layout, segmented control, list rows, and success state. |
| src/vs/sessions/sessions.web.main.ts | Imports the surveys contribution for sessions web startup. |
| src/vs/sessions/sessions.desktop.main.ts | Imports the surveys contribution for sessions desktop startup. |
Copilot's findings
- Files reviewed: 9/9 changed files
- Comments generated: 10
- Gate 'Open Survey' command behind IsDevelopmentContext (dev builds only) - Localize all user-facing strings (title, description, questions, options) - Use stable option IDs for telemetry instead of locale-dependent labels - Replace custom submit button CSS with shared Button widget - Add aria-hidden on decorative icons (sparkle, checkAll) - Add role=status + aria-live=polite on success container - Announce 'Response sent' via status() for screen readers - Move focus to success container after submit - Use --vscode-strokeThickness token for border widths - Snap padding to spacing ramp (7px → 8px) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Responsive: - Remove broken flex-wrap on segment control (caused 2x2+1 orphan grid) - At narrow widths, segment stacks vertically (flex-direction: column) with full-width items and proper border-radius per edge - Segment labels get min-width: 0 + text-overflow: ellipsis so they shrink gracefully in horizontal mode without wrapping - Remove overflow: hidden from segment group (was clipping focus rings) Accessibility: - Add role=form + aria-label on the editor pane container - Increase auto-close timeout to 5s (gives screen readers time to read) - Add position: relative on focus-visible segments for z-index stacking - Segment labels get explicit border-radius on first/last (no overflow hidden needed) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Engineering:
- Override focus() to move focus to first radio when survey opens
- Make resource URI dynamic (vscode-survey:/{surveyId}) to prevent
collisions across multiple survey definitions
- Guard closeEditor in auto-close timeout with .catch(onUnexpectedError)
Accessibility:
- Add aria-required=true on all radio groups
- Fix HC focus-visible vs checked outline conflict: checked uses 1px
solid contrastActiveBorder, focus-visible uses 2px dashed focusBorder
- Add completion hint ('Answer all questions to submit') with
aria-describedby on the submit button; hides once all answered
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add position: relative to contain absolutely-positioned radio inputs, and flex-wrap: nowrap to ensure 5 segment items always stay in a single row at widths above the 600px container-query breakpoint. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Remove one-sided border-radius + left-accent on selected list rows; use full rectangular border matching VS Code's native list selection - Reduce row padding (8px→6px), gap (4px→2px), question margin (24→20px) and submit margin (28→20px) for a more compact layout - Add 60px bottom padding to ensure the Submit button is always reachable when scrolling - Split container queries: segment stacks at 560px, list grid collapses to single-column at 480px (was 600px for both — too aggressive) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add SurveyAccessibilityHelp with AccessibleViewProviderId.Survey and AccessibilityVerbositySettingId.Survey for screen reader discovery - Use var(--vscode-strokeThickness) for list-option border - Use var(--vscode-codiconFontSize) + transform: scale(2) for success icon - Reduce list-option padding to 6px 10px (on spacing ramp) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add 'source' field to SurveyEditorInput so the triggering feature (completions, panel.agent, agent.codeEdit) is captured with the response - Register '_workbench.action.openCopilotSurvey' command for the Copilot extension to open the in-editor survey instead of external URL - Restructure telemetry: extract pmfScore, primaryBenefit, primaryFriction as top-level fields for direct Kusto querying (keep JSON blob for forward-compat) - Rename question IDs: main-benefit→primary-benefit, blockers→primary-friction - Add pmfQuestionId to ISurveyDefinition schema Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- pmfScore is now a number (0=not at all, 4=extremely) with isMeasurement:true for direct Kusto aggregation - no JSON blob - Update Copilot SurveyService.promptSurvey() to call '_workbench.action.openCopilotSurvey' command instead of opening external URL - works in both main workbench and agent window - Remove unused IAuthenticationService, IEnvService, SURVEY_URI from SurveyService (no longer needed without external URL) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Validate command source against allowlist (telemetry safety) - Add runtime guard for dev command in stable builds - Make SurveyEditorInput.source mutable via updateSource() - Update existing input's source when singleton is re-opened - Restore focus to survey pane when closing a11y help - Await command execution in extension with error handling Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Questions now declare their own telemetry field via telemetryKey and asMeasurement properties. The pane iterates these at submit time instead of hardcoding field names. Telemetry fields: - score (number): primary measure, option index - primaryBenefit (string): value driver option ID - primaryFriction (string): friction point option ID - programmingExperience (number): experience bracket index Added Q4: programming experience (5 brackets, 0-4 numeric measure). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Source allowlist now uses prefix matching (inline.*, panel.*, agent.*) to accept real Copilot sources like inline.codeEdit, panel.agent - Extension resets cooldown to DAYS_LATER on command failure so users get re-prompted instead of losing 90 days silently - Added 'Something else' escape hatch to Q2 (benefit) and Q3 (friction) so users are not forced into inaccurate answers Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Programming experience now renders as a segment band with compressed labels (<3 yr, 3-5 yr, 6-9 yr, 10-19 yr, 20+ yr) — saves vertical space and matches the PMF score visual pattern - Increased container bottom padding from 60px to 80px to prevent submit button from being clipped when scrolled Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
roblourens
approved these changes
Jun 22, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Moves in-product Copilot PMF surveys from a notification → external-URL flow into a native editor pane, following the same pattern as the Issue Reporter editor.
Architecture
vscode-survey:/{surveyId}URI schemeworkbench.action.openSurvey— Developer-only (F1 visible,IsDevelopmentContextprecondition + stable-build runtime guard)_workbench.action.openCopilotSurvey— Internal programmatic command for extension use; acceptssourceargument validated against an allowlistSurveyService.promptSurvey()notification now calls_workbench.action.openCopilotSurveyinstead ofvscode.env.openExternaleditorGroupsService.mainPart.activeGroup(same as Issue Reporter)UI
--vscode-radio-*tokens<label>rows with hidden native radios, selected via:has(:checked)with full rectangular borderhc-black/hc-lightsupport with dashed focus indicators andcontrastActiveBorderrole="status"+aria-live="polite", auto-close after 5s (longer for screen reader readout)Telemetry
Single
survey/submitevent with flat fields:surveyIdcopilot-pmf)sourcecompletions,panel.agent)pmfScoreprimaryBenefitprimaryFrictionAccessibility
AccessibleViewProviderId.Survey+AccessibilityVerbositySettingId.SurveySecurity
sourceargument is validated against a known-sources allowlist; unknown values map to"unknown"How to test
Developer: Open SurveyFiles changed
src/vs/workbench/contrib/surveys/browser/survey.contribution.tssrc/vs/workbench/contrib/surveys/browser/surveyEditorPane.tssrc/vs/workbench/contrib/surveys/browser/surveyEditorInput.tssrc/vs/workbench/contrib/surveys/browser/surveyQuestions.tssrc/vs/workbench/contrib/surveys/browser/media/surveyEditorPane.csssrc/vs/workbench/workbench.desktop.main.tssrc/vs/workbench/workbench.web.main.tssrc/vs/sessions/sessions.desktop.main.tssrc/vs/sessions/sessions.web.main.tssrc/vs/platform/accessibility/browser/accessibleView.tssrc/vs/workbench/contrib/accessibility/browser/accessibilityConfiguration.tsextensions/copilot/src/platform/survey/vscode/surveyServiceImpl.ts