Просмотр исходного кода

ref(onboarding): wizard onboarding layout (#78466)

Ogi 5 месяцев назад
Родитель
Сommit
86d47d7253

+ 22 - 19
static/app/components/onboarding/gettingStartedDoc/step.tsx

@@ -126,15 +126,18 @@ interface BaseStepProps {
    * Content that goes directly above the code snippet
    */
   codeHeader?: React.ReactNode;
+  /**
+   * Whether the step instructions are collapsible
+   */
+  collapsible?: boolean;
+  /**
+   * An array of configurations to be displayed
+   */
   configurations?: Configuration[];
   /**
    * A brief description of the step
    */
   description?: React.ReactNode | React.ReactNode[];
-  /**
-   * Whether the step is optional
-   */
-  isOptional?: boolean;
   /**
    * Fired when the optional toggle is clicked.
    * Useful for when we want to fire analytics events.
@@ -205,7 +208,7 @@ export function Step({
   additionalInfo,
   description,
   onOptionalToggleClick,
-  isOptional = false,
+  collapsible = false,
   codeHeader,
 }: StepProps) {
   const [showOptionalConfig, setShowOptionalConfig] = useState(false);
@@ -248,25 +251,23 @@ export function Step({
     </Fragment>
   );
 
-  return isOptional ? (
+  return collapsible ? (
     <div>
-      <OptionalConfigWrapper>
+      <OptionalConfigWrapper
+        expanded={showOptionalConfig}
+        onClick={() => {
+          onOptionalToggleClick?.(!showOptionalConfig);
+          setShowOptionalConfig(!showOptionalConfig);
+        }}
+      >
+        <h4 style={{marginBottom: 0}}>{title ?? StepTitle[type]}</h4>
         <ToggleButton
           priority="link"
           borderless
           size="zero"
           icon={<IconChevron direction={showOptionalConfig ? 'down' : 'right'} />}
           aria-label={t('Toggle optional configuration')}
-          onClick={() => {
-            onOptionalToggleClick?.(!showOptionalConfig);
-            setShowOptionalConfig(!showOptionalConfig);
-          }}
-        >
-          <h4 style={{marginBottom: 0}}>
-            {title ?? StepTitle[type]}
-            {t(' (Optional)')}
-          </h4>
-        </ToggleButton>
+        />
       </OptionalConfigWrapper>
       {showOptionalConfig ? config : null}
     </div>
@@ -307,13 +308,15 @@ const GeneralAdditionalInfo = styled(Description)`
   margin-top: ${space(2)};
 `;
 
-const OptionalConfigWrapper = styled('div')`
+const OptionalConfigWrapper = styled('div')<{expanded: boolean}>`
   display: flex;
+  gap: ${space(1)};
+  margin-bottom: ${p => (p.expanded ? space(2) : 0)};
   cursor: pointer;
-  margin-bottom: 0.5em;
 `;
 
 const ToggleButton = styled(Button)`
+  padding: 0;
   &,
   :hover {
     color: ${p => p.theme.gray500};

+ 2 - 2
static/app/gettingStartedDocs/javascript/astro.tsx

@@ -218,7 +218,7 @@ const replayOnboarding: OnboardingConfig = {
   ],
   configure: (params: Params) => [
     {
-      type: StepType.CONFIGURE,
+      title: 'Configure Session Replay (Optional)',
       description: tct(
         'There are several privacy and sampling options available. Learn more about configuring Session Replay by reading the [link:configuration docs].',
         {
@@ -297,7 +297,7 @@ import * as Sentry from "@sentry/astro";`,
         },
       ],
       additionalInfo: <TracePropagationMessage />,
-      isOptional: true,
+      collapsible: true,
     },
   ],
   verify: getReplayVerifyStep(),

+ 2 - 2
static/app/gettingStartedDocs/javascript/javascript.tsx

@@ -197,11 +197,11 @@ const loaderScriptOnboarding: OnboardingConfig<PlatformOptions> = {
   ],
   configure: params => [
     {
-      type: StepType.CONFIGURE,
+      title: t('Configure SDK (Optional)'),
       description: t(
         "Initialize Sentry as early as possible in your application's lifecycle."
       ),
-      isOptional: true,
+      collapsible: true,
       configurations: [
         {
           language: 'html',

+ 2 - 2
static/app/gettingStartedDocs/javascript/jsLoader/jsLoader.tsx

@@ -64,7 +64,7 @@ const replayOnboardingJsLoader: OnboardingConfig = {
   install: (params: Params) => getInstallConfig(params),
   configure: (params: Params) => [
     {
-      type: StepType.CONFIGURE,
+      title: t('Configure Session Replay (Optional)'),
       description: getReplayConfigureDescription({
         link: 'https://docs.sentry.io/platforms/javascript/session-replay/',
       }),
@@ -74,7 +74,7 @@ const replayOnboardingJsLoader: OnboardingConfig = {
           code: getReplayJsLoaderSdkSetupSnippet(params),
         },
       ],
-      isOptional: true,
+      collapsible: true,
       additionalInfo: <TracePropagationMessage />,
     },
   ],

+ 5 - 10
static/app/gettingStartedDocs/javascript/nextjs.spec.tsx

@@ -11,7 +11,9 @@ describe('javascript-nextjs onboarding docs', function () {
     renderWithOnboardingLayout(docs);
 
     // Renders main headings
-    expect(screen.getByRole('heading', {name: 'Install'})).toBeInTheDocument();
+    expect(
+      screen.getByRole('heading', {name: 'Automatic Configuration (Recommended)'})
+    ).toBeInTheDocument();
 
     // Includes configure statement
     expect(
@@ -19,7 +21,7 @@ describe('javascript-nextjs onboarding docs', function () {
     ).toBeInTheDocument();
   });
 
-  it('displays the configure instructions', () => {
+  it('displays the verify instructions', () => {
     renderWithOnboardingLayout(docs, {
       selectedProducts: [
         ProductSolution.ERROR_MONITORING,
@@ -29,14 +31,7 @@ describe('javascript-nextjs onboarding docs', function () {
     });
 
     expect(
-      screen.queryByText(textWithMarkupMatcher(/sentry.client.config.js/))
-    ).toBeInTheDocument();
-    expect(screen.queryByText(textWithMarkupMatcher(/Sentry.init/))).toBeInTheDocument();
-    expect(
-      screen.queryByText(textWithMarkupMatcher(/.env.sentry-build-plugin/))
-    ).toBeInTheDocument();
-    expect(
-      screen.queryByText(textWithMarkupMatcher(/instrumentation.ts/))
+      screen.queryByText(textWithMarkupMatcher(/sentry-example-page/))
     ).toBeInTheDocument();
   });
 });

+ 106 - 58
static/app/gettingStartedDocs/javascript/nextjs.tsx

@@ -42,7 +42,7 @@ const getInstallConfig = (params: Params) => {
   return [
     {
       description: tct(
-        'Configure your app automatically with the [wizardLink:Sentry wizard].',
+        'Configure your app automatically by running the [wizardLink:Sentry wizard] in the root of your project.',
         {
           wizardLink: (
             <ExternalLink href="https://docs.sentry.io/platforms/javascript/guides/nextjs/#install" />
@@ -78,65 +78,111 @@ const getManualInstallConfig = () => [
 const onboarding: OnboardingConfig = {
   install: (params: Params) => [
     {
-      type: StepType.INSTALL,
+      title: t('Automatic Configuration (Recommended)'),
       configurations: getInstallConfig(params),
-      additionalInfo: (
+    },
+  ],
+  configure: () => [
+    {
+      title: t('Manual Configuration'),
+      collapsible: true,
+      configurations: [
+        {
+          description: (
+            <Fragment>
+              <p>
+                {tct(
+                  'Alternatively, you can also [manualSetupLink:set up the SDK manually], by following these steps:',
+                  {
+                    manualSetupLink: (
+                      <ExternalLink href="https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/" />
+                    ),
+                  }
+                )}
+              </p>
+              <List symbol="bullet">
+                <ListItem>
+                  {tct(
+                    'Create [code:sentry.server.config.js], [code:sentry.client.config.js] and [code:sentry.edge.config.js] with the default [code:Sentry.init].',
+                    {
+                      code: <code />,
+                    }
+                  )}
+                </ListItem>
+                <ListItem>
+                  {tct(
+                    'Create or update the Next.js instrumentation file [instrumentationCode:instrumentation.ts] to initialize the SDK with the configuration files added in the previous step.',
+                    {
+                      instrumentationCode: <code />,
+                    }
+                  )}
+                </ListItem>
+                <ListItem>
+                  {tct(
+                    'Create or update your Next.js config [nextConfig:next.config.js] with the default Sentry configuration.',
+                    {
+                      nextConfig: <code />,
+                    }
+                  )}
+                </ListItem>
+                <ListItem>
+                  {tct(
+                    'Create a [bundlerPluginsEnv:.env.sentry-build-plugin] with an auth token (which is used to upload source maps when building the application).',
+                    {
+                      bundlerPluginsEnv: <code />,
+                    }
+                  )}
+                </ListItem>
+                <ListItem>
+                  {t('Add an example page to your app to verify your Sentry setup.')}
+                </ListItem>
+              </List>
+            </Fragment>
+          ),
+        },
+      ],
+    },
+  ],
+  verify: (params: Params) => [
+    {
+      type: StepType.VERIFY,
+      description: (
         <Fragment>
+          <p>
+            {tct(
+              'Start your development server and visit [code:/sentry-example-page] if you have set it up. Click the button to trigger a test error.',
+              {
+                code: <code />,
+              }
+            )}
+          </p>
           <p>
             {t(
-              'The Sentry wizard will automatically patch your application to configure the Sentry SDK:'
+              'Or, trigger a sample error by calling a function that does not exist somewhere in your application.'
             )}
           </p>
-          <List symbol="bullet">
-            <ListItem>
-              {tct(
-                'Create [code:sentry.server.config.js], [code:sentry.client.config.js] and [code:sentry.edge.config.js] with the default [code:Sentry.init].',
-                {
-                  code: <code />,
-                }
-              )}
-            </ListItem>
-            <ListItem>
-              {tct(
-                'Create or update the Next.js instrumentation file [instrumentationCode:instrumentation.ts] to initialize the SDK with the configuration files added in the previous step.',
-                {
-                  instrumentationCode: <code />,
-                }
-              )}
-            </ListItem>
-            <ListItem>
-              {tct(
-                'Create or update your Next.js config [nextConfig:next.config.js] with the default Sentry configuration.',
-                {
-                  nextConfig: <code />,
-                }
-              )}
-            </ListItem>
-            <ListItem>
-              {tct(
-                'Create a [bundlerPluginsEnv:.env.sentry-build-plugin] with an auth token (which is used to upload source maps when building the application).',
-                {
-                  bundlerPluginsEnv: <code />,
-                }
-              )}
-            </ListItem>
-            <ListItem>
-              {t('Add an example page to your app to verify your Sentry setup.')}
-            </ListItem>
-          </List>
-          <br />
-          <ManualSetupTitle>{t('Manual Setup')}</ManualSetupTitle>
+        </Fragment>
+      ),
+      configurations: [
+        {
+          code: [
+            {
+              label: 'Javascript',
+              value: 'javascript',
+              language: 'javascript',
+              code: `myUndefinedFunction();`,
+            },
+          ],
+        },
+      ],
+      additionalInfo: (
+        <Fragment>
           <p>
-            {tct(
-              'Alternatively, you can also [manualSetupLink:set up the SDK manually].',
-              {
-                manualSetupLink: (
-                  <ExternalLink href="https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/" />
-                ),
-              }
+            {t(
+              'If you see an issue in your Sentry dashboard, you have successfully set up Sentry with Next.js.'
             )}
           </p>
-          <br />
+          <Divider />
           <DSNText>
             <p>
               {tct(
@@ -162,8 +208,6 @@ const onboarding: OnboardingConfig = {
       ),
     },
   ],
-  configure: () => [],
-  verify: () => [],
 };
 
 const replayOnboarding: OnboardingConfig = {
@@ -388,13 +432,17 @@ const DSNText = styled('div')`
   margin-bottom: ${space(0.5)};
 `;
 
-const ManualSetupTitle = styled('p')`
-  font-size: ${p => p.theme.fontSizeLarge};
-  font-weight: ${p => p.theme.fontWeightBold};
-`;
-
 const AdditionalInfoWrapper = styled('div')`
   display: flex;
   flex-direction: column;
   gap: ${space(2)};
 `;
+
+const Divider = styled('hr')`
+  height: 1px;
+  width: 100%;
+  background: ${p => p.theme.border};
+  border: none;
+  margin-top: ${space(1)};
+  margin-bottom: ${space(2)};
+`;

+ 4 - 6
static/app/gettingStartedDocs/javascript/remix.spec.tsx

@@ -9,13 +9,11 @@ describe('javascript-remix onboarding docs', function () {
     renderWithOnboardingLayout(docs);
 
     // Renders main headings
-    expect(screen.getByRole('heading', {name: 'Install'})).toBeInTheDocument();
-    expect(screen.getByRole('heading', {name: 'Configure SDK'})).toBeInTheDocument();
-
-    // Includes minimum required Astro version
-    expect(screen.getByText(textWithMarkupMatcher(/Remix 1.0.0/))).toBeInTheDocument();
+    expect(
+      screen.getByRole('heading', {name: 'Automatic Configuration (Recommended)'})
+    ).toBeInTheDocument();
 
-    // Includes wizard command statement
+    // Includes configure statement
     expect(
       screen.getByText(textWithMarkupMatcher(/npx @sentry\/wizard@latest -i remix/))
     ).toBeInTheDocument();

+ 51 - 16
static/app/gettingStartedDocs/javascript/remix.tsx

@@ -31,10 +31,11 @@ type Params = DocsParams;
 
 const getConfigStep = ({isSelfHosted, organization, projectSlug}: Params) => {
   const urlParam = isSelfHosted ? '' : '--saas';
+
   return [
     {
       description: tct(
-        'Configure your app automatically with the [wizardLink:Sentry wizard].',
+        'Configure your app automatically by running the [wizardLink:Sentry wizard] in the root of your project.',
         {
           wizardLink: (
             <ExternalLink href="https://docs.sentry.io/platforms/javascript/guides/remix/#install" />
@@ -59,12 +60,23 @@ const onboarding: OnboardingConfig = {
     tct("Sentry's integration with [remixLink:Remix] supports Remix 1.0.0 and above.", {
       remixLink: <ExternalLink href="https://remix.run/" />,
     }),
-  install: (params: Params) => getInstallConfig(params),
+  install: (params: Params) => [
+    {
+      title: t('Automatic Configuration (Recommended)'),
+      configurations: getConfigStep(params),
+    },
+  ],
   configure: () => [
     {
-      type: StepType.CONFIGURE,
-      description: t(
-        'The Sentry wizard will automatically add code to your project to inialize and configure the Sentry SDK:'
+      collapsible: true,
+      title: t('Manual Configuration'),
+      description: tct(
+        'Alternatively, you can also [manualSetupLink:set up the SDK manually], by following these steps:',
+        {
+          manualSetupLink: (
+            <ExternalLink href="https://docs.sentry.io/platforms/javascript/guides/remix/manual-setup/" />
+          ),
+        }
       ),
       configurations: [
         {
@@ -105,23 +117,46 @@ const onboarding: OnboardingConfig = {
             </List>
           ),
         },
+      ],
+    },
+  ],
+  verify: () => [
+    {
+      type: StepType.VERIFY,
+      description: (
+        <Fragment>
+          <p>
+            {tct(
+              'Start your development server and visit [code:/sentry-example-page] if you have set it up. Click the button to trigger a test error.',
+              {
+                code: <code />,
+              }
+            )}
+          </p>
+          <p>
+            {t(
+              'Or, trigger a sample error by calling a function that does not exist somewhere in your application.'
+            )}
+          </p>
+        </Fragment>
+      ),
+      configurations: [
         {
-          description: tct(
-            'You can also further [manualConfigure:configure your SDK] or [manualSetupLink:set it up manually], without the wizard.',
+          code: [
             {
-              manualConfigure: (
-                <ExternalLink href="https://docs.sentry.io/platforms/javascript/guides/remix/manual-setup/#configuration" />
-              ),
-              manualSetupLink: (
-                <ExternalLink href="https://docs.sentry.io/platforms/javascript/guides/remix/manual-setup/" />
-              ),
-            }
-          ),
+              label: 'Javascript',
+              value: 'javascript',
+              language: 'javascript',
+              code: `myUndefinedFunction();`,
+            },
+          ],
         },
       ],
+      additionalInfo: t(
+        'If you see an issue in your Sentry dashboard, you have successfully set up Sentry.'
+      ),
     },
   ],
-  verify: () => [],
   nextSteps: () => [],
 };
 

+ 5 - 8
static/app/gettingStartedDocs/javascript/sveltekit.spec.tsx

@@ -11,8 +11,9 @@ describe('javascript-sveltekit onboarding docs', function () {
     renderWithOnboardingLayout(docs);
 
     // Renders main headings
-    expect(screen.getByRole('heading', {name: 'Install'})).toBeInTheDocument();
-    expect(screen.getByRole('heading', {name: 'Configure SDK'})).toBeInTheDocument();
+    expect(
+      screen.getByRole('heading', {name: 'Automatic Configuration (Recommended)'})
+    ).toBeInTheDocument();
 
     // Includes configure statement
     expect(
@@ -20,7 +21,7 @@ describe('javascript-sveltekit onboarding docs', function () {
     ).toBeInTheDocument();
   });
 
-  it('displays the configure instructions', () => {
+  it('displays the verify instructions', () => {
     renderWithOnboardingLayout(docs, {
       selectedProducts: [
         ProductSolution.ERROR_MONITORING,
@@ -30,11 +31,7 @@ describe('javascript-sveltekit onboarding docs', function () {
     });
 
     expect(
-      screen.queryByText(textWithMarkupMatcher(/vite.config.js/))
-    ).toBeInTheDocument();
-    expect(
-      screen.queryByText(textWithMarkupMatcher(/src\/hooks.server.js/))
+      screen.queryByText(textWithMarkupMatcher(/sentry-example-page/))
     ).toBeInTheDocument();
-    expect(screen.queryByText(textWithMarkupMatcher(/.sentryclirc/))).toBeInTheDocument();
   });
 });

+ 62 - 14
static/app/gettingStartedDocs/javascript/sveltekit.tsx

@@ -1,3 +1,5 @@
+import {Fragment} from 'react';
+
 import ExternalLink from 'sentry/components/links/externalLink';
 import List from 'sentry/components/list/';
 import ListItem from 'sentry/components/list/listItem';
@@ -27,14 +29,14 @@ import {t, tct} from 'sentry/locale';
 
 type Params = DocsParams;
 
-const getInstallConfig = ({isSelfHosted, organization, projectSlug}: Params) => {
+const getConfigStep = ({isSelfHosted, organization, projectSlug}: Params) => {
   const urlParam = isSelfHosted ? '' : '--saas';
 
   return [
     {
       type: StepType.INSTALL,
       description: tct(
-        'Configure your app automatically with the [wizardLink:Sentry wizard].',
+        'Configure your app automatically by running the [wizardLink:Sentry wizard] in the root of your project.',
         {
           wizardLink: (
             <ExternalLink href="https://docs.sentry.io/platforms/javascript/guides/sveltekit/#install" />
@@ -51,13 +53,31 @@ const getInstallConfig = ({isSelfHosted, organization, projectSlug}: Params) =>
   ];
 };
 
+const getInstallConfig = (params: Params) => [
+  {
+    type: StepType.INSTALL,
+    configurations: getConfigStep(params),
+  },
+];
+
 const onboarding: OnboardingConfig = {
-  install: (params: Params) => getInstallConfig(params),
+  install: (params: Params) => [
+    {
+      title: t('Automatic Configuration (Recommended)'),
+      configurations: getConfigStep(params),
+    },
+  ],
   configure: () => [
     {
-      type: StepType.CONFIGURE,
-      description: t(
-        'The Sentry wizard will automatically patch your application to configure the Sentry SDK:'
+      title: t('Manual Configuration'),
+      collapsible: true,
+      description: tct(
+        'Alternatively, you can also [manualSetupLink:set up the SDK manually], by following these steps:',
+        {
+          manualSetupLink: (
+            <ExternalLink href="https://docs.sentry.io/platforms/javascript/guides/sveltekit/manual-setup/" />
+          ),
+        }
       ),
       configurations: [
         {
@@ -89,19 +109,47 @@ const onboarding: OnboardingConfig = {
               </ListItem>
             </List>
           ),
-          additionalInfo: tct(
-            'Alternatively, you can also [manualSetupLink:set up the SDK manually].',
+        },
+      ],
+    },
+  ],
+  verify: () => [
+    {
+      type: StepType.VERIFY,
+      description: (
+        <Fragment>
+          <p>
+            {tct(
+              'Start your development server and visit [code:/sentry-example-page] if you have set it up. Click the button to trigger a test error.',
+              {
+                code: <code />,
+              }
+            )}
+          </p>
+          <p>
+            {t(
+              'Or, trigger a sample error by calling a function that does not exist somewhere in your application.'
+            )}
+          </p>
+        </Fragment>
+      ),
+      configurations: [
+        {
+          code: [
             {
-              manualSetupLink: (
-                <ExternalLink href="https://docs.sentry.io/platforms/javascript/guides/sveltekit/manual-setup/" />
-              ),
-            }
-          ),
+              label: 'Javascript',
+              value: 'javascript',
+              language: 'javascript',
+              code: `myUndefinedFunction();`,
+            },
+          ],
         },
       ],
+      additionalInfo: t(
+        'If you see an issue in your Sentry dashboard, you have successfully set up Sentry.'
+      ),
     },
   ],
-  verify: () => [],
 };
 
 const replayOnboarding: OnboardingConfig = {