feat(onboarding): SCM connect step UI polish and analytics#111478
feat(onboarding): SCM connect step UI polish and analytics#111478
Conversation
2210996 to
8df46bf
Compare
4899b24 to
a01d40f
Compare
| )} | ||
| {BENEFITS.map(({icon: Icon, title, description}) => ( | ||
| <Flex key={title} gap="lg" align="start"> | ||
| <Icon legacySize="20px" variant="muted" /> |
There was a problem hiding this comment.
possible to avoid legacy size here?
There was a problem hiding this comment.
Unfortunately not really unless the design itself changes, available non-legacy icon sizes are
const ICON_SIZES: Record<IconSize, string> = {
xs: '12px',
sm: '14px',
md: '16px',
lg: '24px',
xl: '32px',
'2xl': '72px',
} as const;There was a problem hiding this comment.
Feels like lg isn't a huge difference here. Can we see a comparison?
There was a problem hiding this comment.
This is a design system problem if the design is specifying icons like this. cc @natemoo-re @itsdangold
There was a problem hiding this comment.
Good callout. Legacy sizing is a known issue (hence "legacy") but we shouldn't have new designs using it. We'll be normalizing on 12px, 16px, 24px moving forward. The in-betweens aren't significantly different enough to provide value.
size="lg" would be the design systems recc here.
| <selectComponents.Control {...props}> | ||
| <IconSearch size="sm" variant="muted" style={{marginLeft: 12, flexShrink: 0}} /> | ||
| {children} | ||
| </selectComponents.Control> |
There was a problem hiding this comment.
We can't use a leadingItems type thign for this can we?
There was a problem hiding this comment.
Looks to me like leadingItems is only possible to add for Select option items, not the Control component. There is an inFieldLabel prop, but that is is just a text prefix for the selected value.
| { | ||
| value: selectedSlug, | ||
| label: selectedRepository.name, | ||
| textValue: selectedRepository.name, |
There was a problem hiding this comment.
I don't think we actually need this since label isn't a react node
| ); | ||
| } | ||
|
|
||
| const MotionStack = motion.create(Stack); |
There was a problem hiding this comment.
Oh damn I didn't know about motion.create very nice
| <motion.div | ||
| exit={{opacity: 0}} | ||
| initial={{opacity: 0}} | ||
| animate={{opacity: 1}} | ||
| key="benefits" | ||
| > | ||
| <ScmBenefitsCard /> | ||
| </motion.div> |
There was a problem hiding this comment.
can we also use motion.create on ScmBenifitsCard?
There was a problem hiding this comment.
It is possible but it would require altering ScmBenefitsCard to accept a ref and forward it to the Container that it renders.
There was a problem hiding this comment.
that doesn't sound too bad I think
65c2555 to
4703c93
Compare
7579eda to
a9522c5
Compare
When the POST to register a repo fails (e.g., 400 because repo already exists as hidden, or any other error), keep the optimistic selection rather than reverting to undefined. The user selected a valid repo and clearing their choice is disruptive. The missing Sentry ID only matters for cleanup on repo switch, which is best-effort anyway. Refs VDY-22
The Continue button checked selectedRepository.id, but the optimistic repo has id='' (falsy) until the POST resolves. Since we now keep the optimistic value on POST failure, just check for the existence of selectedRepository instead.
Remove debug console.log from useScmRepoSelection. Re-apply the Continue button fix: check for selectedRepository existence instead of selectedRepository.id, since the optimistic repo has an empty id until the POST resolves.
The Continue button must require a real Sentry repo ID before proceeding. Downstream steps need the ID to associate the project with the repo. The optimistic repo with empty id should not allow continuation — the POST needs to succeed first. Refs VDY-22
All Text elements in the SCM connect step need density="comfortable" for line-height 1.4 to match the Figma specs. Without it, they inherit the browser default (~1.2). Also re-enables wrap on provider pills so they flow to a second row when there are more providers than fit in one line. Refs VDY-22
- Extract SCM_STEP_CONTENT_WIDTH constant for the 506px content width used by ScmStepContent and ScmStepFooter - Extract SCM_STEP_FADE_IN and scmStepFadeIn() for repeated motion props in scmConnect.tsx - Revert useScmRepoSelection error handling back to original behavior (revert on POST failure) — the 400 errors were caused by stale local dev state, not a production scenario Refs VDY-22
Remove unnecessary useMemo for static components object in ScmRepoSelector per PR review comment. Update onboarding test to remove assertion for 'Manage in Settings' link which was removed from the connected state in V1. Refs VDY-22
Restore error message in error state, remove dead has_repo analytics param from Skip button, consolidate duplicate import, fix any type on SearchControl, remove unnecessary Flex wrappers and useCallback usage, move SCM_STEP_CONTENT_WIDTH to consts.ts, and update stale comment.
Restore useMemo for the custom components object passed to Select to prevent react-select from remounting on every render. Revert the ComponentProps type annotation back to any since react-select generics are contravariant and produce type errors with the narrowed option type.
Remove memoization wrapper and pass the components object inline, matching the established pattern across the codebase.
Collapse two early returns in the options memo into a single guard, document the any type on SearchControl props (react-select generic contravariance), and note why client-side filtering is disabled.
Change "Connected to github.com/jaydgoss" to "Connected to GitHub org jaydgoss" to match the Figma design.
Move trackAnalytics call from onSelect callback (which fires twice per selection due to optimistic + resolved updates) to handleChange where it represents a single user action. Also fix stale test assertion for connected tag format.
…tion Restructure scmConnect to make the content sections direct motion siblings of the footer within a LayoutGroup. Split the connected state into two keyed MotionStacks (with/without repo selected) so the footer with layout="position" can animate when the section above swaps. VDY-24
The LayoutGroup refactor made SCM_STEP_FADE_IN, scmStepFadeIn, and scmStepContent.tsx dead code. Remove them to fix knip. VDY-24
…ates Move loading and error early returns into the main render so the step header and footer remain visible in all states. Extract the content branch into a variable to replace the nested ternary chain. VDY-24
textValue is only needed when label is a React node so the Select can filter on a plain string. Here label is already a string, making textValue redundant.
a9522c5 to
a1ace12
Compare
The exit props on MotionStack are ineffective because they are children of LayoutGroup, not AnimatePresence. MotionStack is still needed for LayoutGroup coordination.
Replace the motion.div wrapper with motion.create(ScmBenefitsCard) to avoid an extra DOM node. ScmBenefitsCard now accepts ref and spreads extra props onto its root Container.
Replace legacySize="20px" with size="lg" (24px) per design system guidance to avoid legacy sizing.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
| </Flex> | ||
| )} | ||
| </Stack> | ||
| }} |
There was a problem hiding this comment.
Search state not reset when clearing selected repo
Low Severity
The onInputChange handler only calls setSearch for input-change actions. When the user clears the selected value via the clear button, react-select fires onInputChange('', {action: 'set-value'}), which is ignored. This leaves the internal search state (and debouncedSearch) at the old value, so the query remains enabled with the stale search term. As a result, when the dropdown reopens after clearing, the user sees old search results despite the input being visually empty. The set-value action needs to also reset the search state to avoid this inconsistency.
) When a user navigates back to repo selection and picks a different repo, the previously selected platform, features, and created project slug are stale. Adds `clearDerivedState` to the onboarding context that clears these fields in a single session storage update without wiping the entire session -- which `setSelectedPlatform(undefined)` would do due to the `removeOnboarding()` call in its undefined branch. The repo selector's `onSelect` callback now calls `clearDerivedState()` whenever the repository changes. **Stacked on [PR #111478](#111478 (VDY-22: UI polish and analytics). Refs VDY-22


Add analytics instrumentation, UI polish, and state management improvements for the SCM connect onboarding step.
Addresses VDY-22. The SCM connect step was implemented in PR #110883 with analytics and UI polish explicitly deferred.
Stacked on PR #111160 (VDY-30: sync feature selections from context).
Analytics
All 6 events from the ticket are tracked:
trackAnalyticson mountintegrations.installation_startwithview: 'onboarding'integrations.installation_completewithview: 'onboarding'trackAnalyticsin Select onChangeanalyticsEventKeypropanalyticsEventKeypropUI polish
<Tag variant="success">with checkmarkRepo selector overhaul
Replaced
CompactSelectwithSelectfrom scraps to get a full-width combo box input matching the Figma design. Added a customSearchControlcomponent that prepends a search icon inside the select input.Downstream state reset
When a user goes back to repo selection and picks a different repo,
clearDerivedState()on the onboarding context now resets selectedPlatform, selectedFeatures, and createdProjectSlug without wiping the entire session (whichsetSelectedPlatform(undefined)would do).Shared components extracted
ScmStepHeader-- step indicator + heading + subtitle (reusable across SCM steps)ScmStepContent-- 506px max-width content wrapperScmStepFooter-- right-aligned 506px footer with top paddingRefs VDY-22