Conversation
148c21f to
188989b
Compare
|
🚨 Warning: This pull request contains Frontend and Backend changes! It's discouraged to make changes to Sentry's Frontend and Backend in a single pull request. The Frontend and Backend are not atomically deployed. If the changes are interdependent of each other, they must be separated into two pull requests and be made forward or backwards compatible, such that the Backend or Frontend can be safely deployed independently. Have questions? Please ask in the |
static/app/views/onboarding/components/scmFeatureSelectionCards.tsx
Outdated
Show resolved
Hide resolved
Remove redundant id in gaming platform check (platformInfo already has id). When clicking "Back to recommended", also select the first detected platform so the view switches correctly when the current selection is not in the detected list. Refs VDY-23
…ng check isDisabledGamingPlatform expects Platform which requires category. PlatformIntegration doesn't have it. Refs VDY-23
…m, 'id' | 'type'> The function only uses id and type, so requiring the full Platform type (including category) was unnecessarily restrictive. This avoids needing to synthesize a category when calling with PlatformIntegration data. Refs VDY-23
Inline isSelected variable in platform card map and convert to concise arrow function. Add alwaysEnabled field to FeatureMeta so the always-on behavior of error monitoring is data-driven instead of hardcoded ProductSolution checks.
…ards The button's text content already provides the accessible name via the label and description inside it. Also simplifies the "renders only passed features" test to check checkbox count per review feedback.
…e cards Replace Flex wrapper with Container composition pattern to eliminate an extra div around the icon. Container is the correct primitive since only padding is applied, not flex layout.
Move card presentation logic out of the map bodies and into dedicated components. ScmCardButton remains the shared unstyled button base, while each card component owns its own layout and visual treatment.
…ling-tracing dependency Previously the SCM onboarding step let users toggle features their plan does not support and allowed enabling profiling without tracing. Reuse getDisabledProducts from productSelection to gate features by plan, and mirror the profiling-requires-tracing constraint from the legacy ProductSelection component.
…llowed cursor Show tooltip with reason on disabled feature cards: plan-gated features display the restriction reason, error monitoring explains it is always enabled. Change disabled cursor from default to not-allowed to match ProductSelection behavior.
… no platforms When SCM is connected but platform detection errors or returns no resolvable platforms, the component showed an empty "Recommended SDK" section. Now fall through to the manual picker automatically when detection finishes with no results.
…state Derive currentPlatformKey from selectedPlatform ?? detectedPlatformKey instead of writing to context via useEffect. Persist the detected platform to context in the onComplete handler when the user accepts the default without making an explicit selection.
When the user accepts the default feature selection without toggling, selectedFeatures in context remained undefined. Now persist the derived currentFeatures to context alongside the platform default.
…ount The selected count could overcount if context carried stale features from a previously selected platform. Filter against availableFeatures so only relevant selections are counted.
Extract toSelectedSdk to eliminate 3 duplicate PlatformIntegration to OnboardingSelectedSDK conversions in setPlatform, openConsoleModal, and the framework suggestion modal.
Platform cards act as a single-select group but lacked accessibility attributes. Add role="radio" and aria-checked to ScmPlatformCard, and role="radiogroup" to the parent container.
Inline getAvailableFeaturesForPlatform one-liner, use neutral 'all' category in toSelectedSdk since PlatformIntegration lacks category, add tests for framework suggestion modal and gaming platform blocking, and use RepositoryFixture instead of manual mock object. Refs VDY-23
765c01c to
fc7d5a5
Compare
…re card icons SVGIconProps is the base type for all icon components, making it the correct shared type for the icon prop in feature cards. IconGraphProps was unnecessarily specific since all icons accept SVGIconProps.
Implement the `SCM_PROJECT_DETAILS` onboarding step -- the third step in the SCM-first onboarding flow where users configure and create a project after selecting a platform and features. **Project name:** Defaults from platform key, slugified and editable. **Team selection:** Uses the existing `TeamSelector` component, defaulting to the first team with admin access. **Alert frequency:** Reuses the `IssueAlertOptions` component from the project creation page with three radio options -- high priority issues (default), custom threshold/metric/interval, and create alerts later. **Project creation:** Uses `useCreateProjectAndRules` for atomic project + alert rule creation. After creation, stores the project slug in a separate `createdProjectSlug` context field so `useRecentCreatedProject` in SetupDocs can find it without corrupting `selectedPlatform.key` (which the platform features step still needs). ## PR stack This PR is stacked on [#111160](#111160) (SCM platform & features step). - [PR 1: SCM platform & features step](#111160) - **PR 2 (this): SCM project details step** - [PR 3: Sync feature selections to SetupDocs URL params](#111334) Refs VDY-27
…RL params (#111334) When a user selects features in the SCM_PLATFORM_FEATURES step, those choices are stored in OnboardingContext. The SetupDocs step reads product selections from URL params (used by the inline ProductSelection component). This PR passes feature selections as query params through the `onComplete` -> `goNextStep` -> `navigate` chain so they arrive in the URL when navigating to setup-docs. No mount-time sync effect needed. The `onComplete` callback and `goNextStep` accept an optional `query` parameter that is forwarded to `navigate()` via `normalizeUrl`. scmProjectDetails passes `{product: selectedFeatures}` when calling `onComplete`, so the URL already contains the correct product selections when SetupDocs mounts. Legacy flow is unaffected since query is only passed when provided. ## PR stack - [PR 1: SCM platform & features step](#111160) - [PR 2: SCM project details step](#111306) - **PR 3 (this): Sync feature selections to SetupDocs** Refs VDY-30
Add analytics instrumentation, UI polish, and state management improvements for the SCM connect onboarding step. Addresses [VDY-22](https://linear.app/getsentry/issue/VDY-22). The SCM connect step was implemented in PR #110883 with analytics and UI polish explicitly deferred. **Stacked on [PR #111160](#111160 (VDY-30: sync feature selections from context). ## Analytics All 6 events from the ticket are tracked: | Event | Mechanism | |-------|-----------| | Step viewed | `trackAnalytics` on mount | | Provider selected | Existing `integrations.installation_start` with `view: 'onboarding'` | | Integration connected | Existing `integrations.installation_complete` with `view: 'onboarding'` | | Repo selected | `trackAnalytics` in Select onChange | | Skip clicked | Button `analyticsEventKey` prop | | Continue clicked | Button `analyticsEventKey` prop | ## UI polish - Step indicator ("Step 1 of 3" + Optional tag) with audited font size/weight/spacing - "Why connect your repository?" benefits card with 4 items (icons, titles, descriptions) - Connected state uses `<Tag variant="success">` with checkmark - Benefits card visibility: shown with title in initial state, without title when repo selected, hidden when searching - "Skip for now" hidden when a repo is selected - Repo search dropdown shows error message on API failure - Provider pills filtered to design-specified 4 (GitHub, GitLab, Bitbucket, Azure DevOps), ordered per Figma ## Repo selector overhaul Replaced `CompactSelect` with `Select` from scraps to get a full-width combo box input matching the Figma design. Added a custom `SearchControl` component 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 (which `setSelectedPlatform(undefined)` would do). ## Shared components extracted - `ScmStepHeader` -- step indicator + heading + subtitle (reusable across SCM steps) - `ScmStepContent` -- 506px max-width content wrapper - `ScmStepFooter` -- right-aligned 506px footer with top padding Refs VDY-22
TkDodo
left a comment
There was a problem hiding this comment.
just leaving some low importance post-merge cleanup points if you get to it.
| [currentPlatformKey] | ||
| ); | ||
|
|
||
| const disabledProducts = useMemo( |
There was a problem hiding this comment.
as far as I can see, none of the useMemo or useCallbacks in this file are necessary. All we do at the end is pass those to another component, which isn’t memoized. None of the operations seem expensive either:
const disabledProducts = getDisabledProducts(organization);
is perfectly fine 🤷 . It would remove a bunch of cognitive load and about 30 loc.
| const resolvedPlatforms = useMemo( | ||
| () => | ||
| detectedPlatforms.reduce<ResolvedPlatform[]>((acc, detected) => { | ||
| const info = getPlatformInfo(detected.platform); | ||
| if (info) { | ||
| acc.push({...detected, info}); | ||
| } | ||
| return acc; | ||
| }, []), | ||
| [detectedPlatforms] | ||
| ); |
There was a problem hiding this comment.
reducing from an array into an array can usually be represented with a simpler alternative, in this case, a flatMap:
const resolvedPlatforms = detectedPlatforms.flatMap(detected => {
const info = getPlatformInfo(detected.platform);
return info ? [{...detected, info}] : [];
});
| const query = useQuery({ | ||
| queryKey: [ | ||
| getApiUrl(`/organizations/$organizationIdOrSlug/repos/$repoId/platforms/`, { | ||
| path: { | ||
| organizationIdOrSlug: organization.slug, | ||
| repoId: repoId!, | ||
| }, | ||
| }), | ||
| {method: 'GET'}, | ||
| ] as const, | ||
| queryFn: async context => { | ||
| return fetchDataQuery<PlatformDetectionResponse>(context); | ||
| }, | ||
| staleTime: 30_000, | ||
| enabled: !!repoId, | ||
| }); |
There was a problem hiding this comment.
@JonasBa I think we need better skills for how to do this in new code. The recommended approach would be apiOptions with skipToken:
const query = useQuery(
apiOptions.as<PlatformDetectionResponse>()(
'/organizations/$organizationIdOrSlug/repos/$repoId/platforms/',
{
path: repoId
? {organizationIdOrSlug: organization.slug, repoId}
: skipToken,
staleTime: 30_000,
}
)
);
I just told claude “rewrite this to apiOptions” and it did a good job, so we have to nudge it in that direction per default.
The advantage of using skipToken also means we don’t need a no-null assertion when building the path.
Implement the
SCM_PLATFORM_FEATURESonboarding step -- the second step in the SCM-first onboarding flow where users select a platform and features after connecting their SCM.What it does
Two variants depending on whether the user connected their SCM in the previous step:
SCM connected: Calls the platform detection API to identify platforms from the repository. Detected platforms are rendered as selectable cards with the first auto-selected. Falls through to manual selection if detection returns no results.
Skipped SCM: Shows a searchable dropdown for manually picking from 100+ platforms. Base languages (JavaScript, Python, etc.) trigger a framework suggestion modal.
Both variants share a feature selection card grid. Error Monitoring is always on. Available features are filtered by
platformProductAvailabilityand gated by the user's plan viagetDisabledProducts(disabled features show a tooltip with the reason). Profiling requires tracing -- enabling profiling auto-enables tracing, disabling tracing auto-removes profiling. Gaming/console platforms are blocked when not enabled for the org.How state flows
Platform and feature selections use derived state locally (e.g.
selectedPlatform?.key ?? detectedPlatformKey) and are persisted toOnboardingContextin the Continue handler. Platform detection is pre-warmed inSCM_CONNECTvia React Query cache sharing.New files
useScmPlatformDetection.ts-- hook wrapping the platform detection APIscmFeatureSelectionCards.tsx-- 2-column feature card grid with heading and countscmFeatureCard.tsx-- individual feature card with icon, checkbox, and tooltipscmPlatformCard.tsx-- detected platform card with platform icon and namescmCardButton.tsx-- shared unstyled button primitive for card click semanticsdetectedPlatform.ts(fixture) -- test fixture for detected platform dataFollow-up
VDY-30 -- sync feature selections from context into SetupDocs URL params.
Refs VDY-23