diff --git a/static/app/components/agentHandoff/agentHandoffPrompt.tsx b/static/app/components/agentHandoff/agentHandoffPrompt.tsx index a03cc1c48577..b625578185e6 100644 --- a/static/app/components/agentHandoff/agentHandoffPrompt.tsx +++ b/static/app/components/agentHandoff/agentHandoffPrompt.tsx @@ -1,7 +1,8 @@ import {useState, type PointerEventHandler} from 'react'; -import {ThemeProvider} from '@emotion/react'; +import {css, ThemeProvider, type Theme} from '@emotion/react'; import styled from '@emotion/styled'; import {IconCopy} from '@sentry/icons/copy'; +import {IconOpen} from '@sentry/icons/open'; import {IconSettings} from '@sentry/icons/settings'; import {useStore} from 'zustand'; @@ -84,55 +85,64 @@ export function AgentHandoffPrompt({ - - {tct( - 'Follow the instructions verbatim at [guideUrl]. Your handoff code is [token].', - { - guideUrl, - token: ( - - sntryh_**** - - ), - } - )} - - - + )} + ); diff --git a/static/app/components/onboarding/agenticProgress/setupCardFrame.tsx b/static/app/components/onboarding/agenticProgress/setupCardFrame.tsx new file mode 100644 index 000000000000..cf6f43b4663d --- /dev/null +++ b/static/app/components/onboarding/agenticProgress/setupCardFrame.tsx @@ -0,0 +1,66 @@ +import type {ReactNode} from 'react'; +import {css, useTheme, type Theme} from '@emotion/react'; +import styled from '@emotion/styled'; + +import {Container} from '@sentry/scraps/layout'; +// eslint-disable-next-line @sentry/scraps/no-token-import -- the brand stack uses named categorical colors the theme does not expose +import {color} from '@sentry/scraps/tokens'; + +interface SetupCardFrameProps { + children: ReactNode; + /** Tilts the card and adds the stacked brand border and shadows. */ + layered: boolean; +} + +export function SetupCardFrame({children, layered}: SetupCardFrameProps) { + const theme = useTheme(); + + return ( + + {surfaceProps => ( + + {children} + + )} + + ); +} + +function getLayerColors(theme: Theme) { + if (theme.type === 'dark') { + return { + accent: color.categorical.dark.blurple, + middle: color.categorical.dark.magenta, + bottom: color.categorical.dark.salmon, + }; + } + + return { + accent: color.blue.light.opaque1100, + middle: color.categorical.light.magenta, + bottom: color.categorical.light.salmon, + }; +} + +function layeredStyles(theme: Theme) { + const layers = getLayerColors(theme); + return css` + transform: rotate(-1deg); + border: 1px solid ${layers.accent}; + box-shadow: + 0 2px 0 ${layers.accent}, + 0 6px 0 ${layers.middle}, + 0 10px 0 ${layers.bottom}; + `; +} + +const LayeredSurface = styled('div')<{layered: boolean}>` + ${p => p.layered && layeredStyles(p.theme)} +`; diff --git a/static/app/components/onboarding/consts.ts b/static/app/components/onboarding/consts.ts index ae19c21c1af2..959ac52c267a 100644 --- a/static/app/components/onboarding/consts.ts +++ b/static/app/components/onboarding/consts.ts @@ -1,10 +1,5 @@ -import type {IconSize} from '@sentry/scraps/theme'; - /** * Shared layout constants for SCM onboarding steps. * Matches the Figma main content area width. */ export const SCM_STEP_CONTENT_WIDTH = '520px'; - -export const SETUP_CARD_ICON_SIZE: IconSize = 'md'; -export const SETUP_CARD_MARKER_PX = '24px'; diff --git a/static/app/views/onboarding/components/newWelcome.tsx b/static/app/views/onboarding/components/newWelcome.tsx index 89993fe01ba6..b19c221df9f0 100644 --- a/static/app/views/onboarding/components/newWelcome.tsx +++ b/static/app/views/onboarding/components/newWelcome.tsx @@ -145,8 +145,8 @@ export function NewWelcomeUI(props: StepProps) { const scmHeading = showAgentHeading ? getAgentHeading({hasRunFailed, isSetupComplete}) : { - title: t("Code breaks.\nWe'll help you fix it faster"), - description: t('Monitor, debug, and fix your code, all in one place.'), + title: t('Code breaks. Fix it faster'), + description: t('Detect, diagnose, and debug, all in one place'), }; useWelcomeAnalyticsEffect({showAgentSetup}); @@ -182,14 +182,14 @@ export function NewWelcomeUI(props: StepProps) { - + {scmHeading.title} - + {scmHeading.description} diff --git a/static/app/views/onboarding/components/welcomeAgentSetup.tsx b/static/app/views/onboarding/components/welcomeAgentSetup.tsx index 6dcf327dc6f6..4f7b3e2423a2 100644 --- a/static/app/views/onboarding/components/welcomeAgentSetup.tsx +++ b/static/app/views/onboarding/components/welcomeAgentSetup.tsx @@ -19,6 +19,7 @@ export function WelcomeAgentSetup({onSetupInBrowser, ...props}: WelcomeAgentSetu return ( { expect( screen.getByRole('heading', {name: 'Let your agent set up Sentry'}) ).toBeInTheDocument(); - expect(screen.getByText('Detects your stack')).toBeInTheDocument(); + expect( + screen.getByText('Detects your stack and installs the Sentry CLI') + ).toBeInTheDocument(); expect(screen.getByRole('button', {name: 'Advanced options'})).toBeInTheDocument(); expect( screen.getByRole('link', {name: 'See the full instructions'}) @@ -636,13 +638,15 @@ describe('Onboarding', () => { }); renderOnboarding('welcome'); - expect(screen.getByRole('heading', {name: /Code breaks/})).toBeInTheDocument(); + expect( + screen.getByRole('heading', {name: 'Code breaks. Fix it faster'}) + ).toBeInTheDocument(); act(resolveAgenticRunRequest); expect(await screen.findByRole('heading', {name: heading})).toBeInTheDocument(); expect( - screen.queryByRole('heading', {name: /Code breaks/}) + screen.queryByRole('heading', {name: 'Code breaks. Fix it faster'}) ).not.toBeInTheDocument(); expect(screen.queryByText('sntryh_****')).not.toBeInTheDocument(); } diff --git a/static/app/views/projectInstall/scmCreateProject.spec.tsx b/static/app/views/projectInstall/scmCreateProject.spec.tsx index e7f4b90bdda2..36cd79a73766 100644 --- a/static/app/views/projectInstall/scmCreateProject.spec.tsx +++ b/static/app/views/projectInstall/scmCreateProject.spec.tsx @@ -1299,7 +1299,9 @@ describe('ScmCreateProject', () => { const session = request.mock.calls[0]?.[1]?.data; expect(session.clientRunId).not.toBe(onboardingSession.agenticProgressClientRunId); expect(session.onboardingCode).toBeUndefined(); - expect(screen.getByText('Detects your stack')).toBeInTheDocument(); + expect( + screen.getByText('Detects your stack and installs the Sentry CLI') + ).toBeInTheDocument(); expect(JSON.parse(sessionStorage.getItem('onboarding') ?? '{}')).toEqual( onboardingSession );