Browse Source

ref(onboarding): Convert platform android to new structure (#58160)

- relates to https://github.com/getsentry/sentry/issues/56549
ArthurKnaus 1 year ago
parent
commit
ac703d16d6

+ 55 - 33
static/app/gettingStartedDocs/android/android.spec.tsx

@@ -1,42 +1,64 @@
-import {render, screen} from 'sentry-test/reactTestingLibrary';
+import {renderWithOnboardingLayout} from 'sentry-test/onboarding/renderWithOnboardingLayout';
+import {screen} from 'sentry-test/reactTestingLibrary';
+import {textWithMarkupMatcher} from 'sentry-test/utils';
 
-import {StepTitle} from 'sentry/components/onboarding/gettingStartedDoc/step';
+import docs, {InstallationMode} from './android';
 
-import {GettingStartedWithAndroid, InstallationMode, steps} from './android';
+describe('java-spring-boot onboarding docs', function () {
+  it('renders gradle docs correctly', async function () {
+    renderWithOnboardingLayout(docs, {
+      releaseRegistry: {
+        'sentry.java.android.gradle-plugin': {
+          version: '1.99.9',
+        },
+      },
+      selectedOptions: {
+        installationMode: InstallationMode.MANUAL,
+      },
+    });
 
-describe('GettingStartedWithAndroid', function () {
-  it('renders doc correctly', function () {
-    render(<GettingStartedWithAndroid dsn="test-dsn" projectSlug="test-project" />);
+    // Renders main headings
+    expect(screen.getByRole('heading', {name: 'Install'})).toBeInTheDocument();
+    expect(screen.getByRole('heading', {name: 'Configure SDK'})).toBeInTheDocument();
+    expect(screen.getByRole('heading', {name: 'Verify'})).toBeInTheDocument();
 
-    // Steps
-    for (const step of steps({
-      dsn: 'test-dsn',
-      hasPerformance: true,
-      hasProfiling: true,
-      installationMode: InstallationMode.AUTO,
-    })) {
-      expect(
-        screen.getByRole('heading', {name: step.title ?? StepTitle[step.type]})
-      ).toBeInTheDocument();
-    }
+    // Renders SDK version from registry
+    expect(
+      await screen.findByText(
+        textWithMarkupMatcher(/id "io\.sentry\.android\.gradle" version "1\.99\.9"/)
+      )
+    ).toBeInTheDocument();
   });
-  it('renders Manual mode for Windows by default', function () {
-    Object.defineProperty(window.navigator, 'userAgent', {
-      value:
-        'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.12) Gecko/20050915 Firefox/1.0.7',
+
+  it('renders wizard docs', async function () {
+    renderWithOnboardingLayout(docs, {
+      releaseRegistry: {
+        'sentry.java.spring-boot.jakarta': {
+          version: '2.99.9',
+        },
+        'sentry.java.mavenplugin': {
+          version: '3.99.9',
+        },
+      },
+      selectedOptions: {
+        installationMode: InstallationMode.AUTO,
+      },
     });
-    render(<GettingStartedWithAndroid dsn="test-dsn" projectSlug="test-project" />);
 
-    // Steps
-    for (const step of steps({
-      dsn: 'test-dsn',
-      hasPerformance: true,
-      hasProfiling: true,
-      installationMode: InstallationMode.MANUAL,
-    })) {
-      expect(
-        screen.getByRole('heading', {name: step.title ?? StepTitle[step.type]})
-      ).toBeInTheDocument();
-    }
+    // Renders main headings
+    expect(screen.getByRole('heading', {name: 'Install'})).toBeInTheDocument();
+    expect(
+      screen.queryByRole('heading', {name: 'Configure SDK'})
+    ).not.toBeInTheDocument();
+    expect(screen.queryByRole('heading', {name: 'Verify'})).not.toBeInTheDocument();
+
+    // Renders SDK version from registry
+    expect(
+      await screen.findByText(
+        textWithMarkupMatcher(
+          /Add Sentry automatically to your app with the Sentry wizard/m
+        )
+      )
+    ).toBeInTheDocument();
   });
 });

+ 233 - 262
static/app/gettingStartedDocs/android/android.tsx

@@ -3,12 +3,13 @@ import {Fragment} from 'react';
 import ExternalLink from 'sentry/components/links/externalLink';
 import List from 'sentry/components/list/';
 import ListItem from 'sentry/components/list/listItem';
-import {Layout, LayoutProps} from 'sentry/components/onboarding/gettingStartedDoc/layout';
-import {ModuleProps} from 'sentry/components/onboarding/gettingStartedDoc/sdkDocumentation';
 import {StepType} from 'sentry/components/onboarding/gettingStartedDoc/step';
-import {PlatformOption} from 'sentry/components/onboarding/gettingStartedDoc/types';
-import {useUrlPlatformOptions} from 'sentry/components/onboarding/platformOptionsControl';
-import {ProductSolution} from 'sentry/components/onboarding/productSelection';
+import {
+  BasePlatformOptions,
+  Docs,
+  DocsParams,
+  OnboardingConfig,
+} from 'sentry/components/onboarding/gettingStartedDoc/types';
 import {t, tct} from 'sentry/locale';
 
 export enum InstallationMode {
@@ -16,156 +17,47 @@ export enum InstallationMode {
   MANUAL = 'manual',
 }
 
-type PlaformOptionKey = 'installationMode';
-
-interface StepsParams {
-  dsn: string;
-  hasPerformance: boolean;
-  hasProfiling: boolean;
-  installationMode?: InstallationMode;
-  sourcePackageRegistries?: ModuleProps['sourcePackageRegistries'];
-}
-
-// Configuration Start
-const autoInstallSteps = [
-  {
-    type: StepType.INSTALL,
-    description: (
-      <p>
-        {tct(
-          'Add Sentry automatically to your app with the [wizardLink:Sentry wizard] (call this inside your project directory).',
-          {
-            wizardLink: (
-              <ExternalLink href="https://docs.sentry.io/platforms/android/#install" />
-            ),
-          }
-        )}
-      </p>
-    ),
-    configurations: [
+const platformOptions = {
+  installationMode: {
+    label: t('Installation Mode'),
+    items: [
       {
-        language: 'bash',
-        code: `brew install getsentry/tools/sentry-wizard && sentry-wizard -i android`,
+        label: t('Auto'),
+        value: InstallationMode.AUTO,
       },
       {
-        description: (
-          <Fragment>
-            {t('The Sentry wizard will automatically patch your application:')}
-            <List symbol="bullet">
-              <ListItem>
-                {tct(
-                  "Update your app's [buildGradle:build.gradle] file with the Sentry Gradle plugin and configure it.",
-                  {
-                    buildGradle: <code />,
-                  }
-                )}
-              </ListItem>
-              <ListItem>
-                {tct(
-                  'Update your [manifest: AndroidManifest.xml] with the default Sentry configuration',
-                  {
-                    manifest: <code />,
-                  }
-                )}
-              </ListItem>
-              <ListItem>
-                {tct(
-                  'Create [sentryProperties: sentry.properties] with an auth token to upload proguard mappings (this file is automatically added to [gitignore: .gitignore])',
-                  {
-                    sentryProperties: <code />,
-                    gitignore: <code />,
-                  }
-                )}
-              </ListItem>
-              <ListItem>
-                {t(
-                  "Add an example error to your app's Main Activity to verify your Sentry setup"
-                )}
-              </ListItem>
-            </List>
-            <p>
-              {tct(
-                'Alternatively, you can also [manualSetupLink:set up the SDK manually].',
-                {
-                  manualSetupLink: (
-                    <ExternalLink href="https://docs.sentry.io/platforms/android/manual-setup/" />
-                  ),
-                }
-              )}
-            </p>
-          </Fragment>
-        ),
+        label: t('Manual'),
+        value: InstallationMode.MANUAL,
       },
     ],
+    defaultValue:
+      navigator.userAgent.indexOf('Win') !== -1
+        ? InstallationMode.MANUAL
+        : InstallationMode.AUTO,
   },
-];
+} satisfies BasePlatformOptions;
 
-export const steps = ({
-  dsn,
-  sourcePackageRegistries,
-  hasPerformance,
-  hasProfiling,
-  installationMode,
-}: StepsParams): LayoutProps['steps'] =>
-  installationMode === InstallationMode.AUTO
-    ? autoInstallSteps
-    : [
-        {
-          type: StepType.INSTALL,
-          description: (
-            <p>
-              {tct(
-                'Add the [sagpLink:Sentry Android Gradle plugin] to your [app:app] module:',
-                {
-                  sagpLink: (
-                    <ExternalLink href="https://docs.sentry.io/platforms/android/configuration/gradle/" />
-                  ),
-                  app: <code />,
-                }
-              )}
-            </p>
-          ),
-          configurations: [
-            {
-              language: 'groovy',
-              partialLoading: sourcePackageRegistries?.isLoading,
-              code: `
+type PlatformOptions = typeof platformOptions;
+type Params = DocsParams<PlatformOptions>;
+
+const isAutoInstall = (params: Params) =>
+  params.platformOptions.installationMode === InstallationMode.AUTO;
+
+const getManualInstallSnippet = (params: Params) => `
 plugins {
   id "com.android.application" // should be in the same module
   id "io.sentry.android.gradle" version "${
-    sourcePackageRegistries?.isLoading
+    params.sourcePackageRegistries?.isLoading
       ? t('\u2026loading')
-      : sourcePackageRegistries?.data?.['sentry.java.android.gradle-plugin']?.version ??
-        '3.12.0'
+      : params.sourcePackageRegistries?.data?.['sentry.java.android.gradle-plugin']
+          ?.version ?? '3.12.0'
   }"
-}
-        `,
-            },
-          ],
-        },
-        {
-          type: StepType.CONFIGURE,
-          description: (
-            <Fragment>
-              <p>
-                {tct(
-                  'Configuration is done via the application [manifest: AndroidManifest.xml]. Under the hood Sentry uses a [provider:ContentProvider] to initialize the SDK based on the values provided below. This way the SDK can capture important crashes and metrics right from the app start.',
-                  {
-                    manifest: <code />,
-                    provider: <code />,
-                  }
-                )}
-              </p>
-              <p>{t("Here's an example config which should get you started:")}</p>
-            </Fragment>
-          ),
-          configurations: [
-            {
-              language: 'xml',
-              code: `
+}`;
+
+const getConfigurationSnippet = (params: Params) => `
 <application>
   <!-- Required: set your sentry.io project identifier (DSN) -->
-  <meta-data android:name="io.sentry.dsn" android:value="${dsn}" />
+  <meta-data android:name="io.sentry.dsn" android:value="${params.dsn}" />
 
   <!-- enable automatic breadcrumbs for user interactions (clicks, swipes, scrolls) -->
   <meta-data android:name="io.sentry.traces.user-interaction.enable" android:value="true" />
@@ -173,40 +65,22 @@ plugins {
   <meta-data android:name="io.sentry.attach-screenshot" android:value="true" />
   <!-- enable view hierarchy for crashes -->
   <meta-data android:name="io.sentry.attach-view-hierarchy" android:value="true" />${
-    hasPerformance
+    params.isPerformanceSelected
       ? `
 
   <!-- enable the performance API by setting a sample-rate, adjust in production env -->
   <meta-data android:name="io.sentry.traces.sample-rate" android:value="1.0" />`
       : ''
   }${
-    hasProfiling
+    params.isProfilingSelected
       ? `
   <!-- enable profiling when starting transactions, adjust in production env -->
   <meta-data android:name="io.sentry.traces.profiling.sample-rate" android:value="1.0" />`
       : ''
   }
-</application>
-        `,
-            },
-          ],
-        },
-        {
-          type: StepType.VERIFY,
-          description: (
-            <p>
-              {tct(
-                "This snippet contains an intentional error and can be used as a test to make sure that everything's working as expected. You can add it to your app's [mainActivity: MainActivity].",
-                {
-                  mainActivity: <code />,
-                }
-              )}
-            </p>
-          ),
-          configurations: [
-            {
-              language: 'kotlin',
-              code: `
+</application>`;
+
+const getVerifySnippet = () => `
 val breakWorld = Button(this).apply {
   text = "Break the world"
   setOnClickListener {
@@ -215,104 +89,201 @@ val breakWorld = Button(this).apply {
 }
 
 addContentView(breakWorld, ViewGroup.LayoutParams(
-  ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT))
-        `,
-            },
-          ],
-        },
-      ];
-
-export const nextStepsManual = [
-  {
-    id: 'advanced-configuration',
-    name: t('Advanced Configuration'),
-    description: t('Customize the SDK initialization behavior.'),
-    link: 'https://docs.sentry.io/platforms/android/configuration/manual-init/#manual-initialization',
-  },
-  {
-    id: 'proguard-r8',
-    name: t('ProGuard/R8'),
-    description: t('Deobfuscate and get readable stacktraces in your Sentry errors.'),
-    link: 'https://docs.sentry.io/platforms/android/configuration/gradle/#proguardr8--dexguard',
-  },
-  {
-    id: 'jetpack-compose',
-    name: t('Jetpack Compose'),
-    description: t('Learn about our first class integration with Jetpack Compose.'),
-    link: 'https://docs.sentry.io/platforms/android/configuration/integrations/jetpack-compose/',
-  },
-  {
-    id: 'source-context',
-    name: t('Source Context'),
-    description: t('See your source code as part of your stacktraces in Sentry.'),
-    link: 'https://docs.sentry.io/platforms/android/enhance-errors/source-context/',
-  },
-];
-
-export const nextStepsAuto = [
-  {
-    id: 'advanced-configuration',
-    name: t('Advanced Configuration'),
-    description: t('Customize the SDK initialization behavior.'),
-    link: 'https://docs.sentry.io/platforms/android/configuration/manual-init/#manual-initialization',
-  },
-  {
-    id: 'jetpack-compose',
-    name: t('Jetpack Compose'),
-    description: t('Learn about our first class integration with Jetpack Compose.'),
-    link: 'https://docs.sentry.io/platforms/android/configuration/integrations/jetpack-compose/',
-  },
-];
-// Configuration End
+  ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT))`;
 
-export function GettingStartedWithAndroid({
-  dsn,
-  sourcePackageRegistries,
-  activeProductSelection = [],
-  ...props
-}: ModuleProps) {
-  const platformOptions: Record<PlaformOptionKey, PlatformOption> = {
-    installationMode: {
-      label: t('Installation Mode'),
-      items: [
-        {
-          label: t('Auto'),
-          value: InstallationMode.AUTO,
-        },
-        {
-          label: t('Manual'),
-          value: InstallationMode.MANUAL,
-        },
-      ],
-      defaultValue:
-        navigator.userAgent.indexOf('Win') !== -1
-          ? InstallationMode.MANUAL
-          : InstallationMode.AUTO,
-    },
-  };
-  const optionValues = useUrlPlatformOptions(platformOptions);
+const onboarding: OnboardingConfig<PlatformOptions> = {
+  install: params =>
+    isAutoInstall(params)
+      ? [
+          {
+            type: StepType.INSTALL,
+            description: tct(
+              'Add Sentry automatically to your app with the [wizardLink:Sentry wizard] (call this inside your project directory).',
+              {
+                wizardLink: (
+                  <ExternalLink href="https://docs.sentry.io/platforms/android/#install" />
+                ),
+              }
+            ),
+            configurations: [
+              {
+                language: 'bash',
+                code: `brew install getsentry/tools/sentry-wizard && sentry-wizard -i android`,
+              },
+              {
+                description: (
+                  <Fragment>
+                    {t('The Sentry wizard will automatically patch your application:')}
+                    <List symbol="bullet">
+                      <ListItem>
+                        {tct(
+                          "Update your app's [buildGradle:build.gradle] file with the Sentry Gradle plugin and configure it.",
+                          {
+                            buildGradle: <code />,
+                          }
+                        )}
+                      </ListItem>
+                      <ListItem>
+                        {tct(
+                          'Update your [manifest: AndroidManifest.xml] with the default Sentry configuration',
+                          {
+                            manifest: <code />,
+                          }
+                        )}
+                      </ListItem>
+                      <ListItem>
+                        {tct(
+                          'Create [sentryProperties: sentry.properties] with an auth token to upload proguard mappings (this file is automatically added to [gitignore: .gitignore])',
+                          {
+                            sentryProperties: <code />,
+                            gitignore: <code />,
+                          }
+                        )}
+                      </ListItem>
+                      <ListItem>
+                        {t(
+                          "Add an example error to your app's Main Activity to verify your Sentry setup"
+                        )}
+                      </ListItem>
+                    </List>
+                    <p>
+                      {tct(
+                        'Alternatively, you can also [manualSetupLink:set up the SDK manually].',
+                        {
+                          manualSetupLink: (
+                            <ExternalLink href="https://docs.sentry.io/platforms/android/manual-setup/" />
+                          ),
+                        }
+                      )}
+                    </p>
+                  </Fragment>
+                ),
+              },
+            ],
+          },
+        ]
+      : [
+          {
+            type: StepType.INSTALL,
+            description: tct(
+              'Add the [sagpLink:Sentry Android Gradle plugin] to your [app:app] module:',
+              {
+                sagpLink: (
+                  <ExternalLink href="https://docs.sentry.io/platforms/android/configuration/gradle/" />
+                ),
+                app: <code />,
+              }
+            ),
+            configurations: [
+              {
+                language: 'groovy',
+                partialLoading: params.sourcePackageRegistries?.isLoading,
+                code: getManualInstallSnippet(params),
+              },
+            ],
+          },
+        ],
+  configure: params =>
+    isAutoInstall(params)
+      ? []
+      : [
+          {
+            type: StepType.CONFIGURE,
+            description: (
+              <Fragment>
+                <p>
+                  {tct(
+                    'Configuration is done via the application [manifest: AndroidManifest.xml]. Under the hood Sentry uses a [provider:ContentProvider] to initialize the SDK based on the values provided below. This way the SDK can capture important crashes and metrics right from the app start.',
+                    {
+                      manifest: <code />,
+                      provider: <code />,
+                    }
+                  )}
+                </p>
+                <p>{t("Here's an example config which should get you started:")}</p>
+              </Fragment>
+            ),
+            configurations: [
+              {
+                language: 'xml',
+                code: getConfigurationSnippet(params),
+              },
+            ],
+          },
+        ],
+  verify: params =>
+    isAutoInstall(params)
+      ? []
+      : [
+          {
+            type: StepType.VERIFY,
+            description: tct(
+              "This snippet contains an intentional error and can be used as a test to make sure that everything's working as expected. You can add it to your app's [mainActivity: MainActivity].",
+              {
+                mainActivity: <code />,
+              }
+            ),
+            configurations: [
+              {
+                language: 'kotlin',
+                code: getVerifySnippet(),
+              },
+            ],
+          },
+        ],
+  nextSteps: params =>
+    isAutoInstall(params)
+      ? [
+          {
+            id: 'advanced-configuration',
+            name: t('Advanced Configuration'),
+            description: t('Customize the SDK initialization behavior.'),
+            link: 'https://docs.sentry.io/platforms/android/configuration/manual-init/#manual-initialization',
+          },
+          {
+            id: 'jetpack-compose',
+            name: t('Jetpack Compose'),
+            description: t(
+              'Learn about our first class integration with Jetpack Compose.'
+            ),
+            link: 'https://docs.sentry.io/platforms/android/configuration/integrations/jetpack-compose/',
+          },
+        ]
+      : [
+          {
+            id: 'advanced-configuration',
+            name: t('Advanced Configuration'),
+            description: t('Customize the SDK initialization behavior.'),
+            link: 'https://docs.sentry.io/platforms/android/configuration/manual-init/#manual-initialization',
+          },
+          {
+            id: 'proguard-r8',
+            name: t('ProGuard/R8'),
+            description: t(
+              'Deobfuscate and get readable stacktraces in your Sentry errors.'
+            ),
+            link: 'https://docs.sentry.io/platforms/android/configuration/gradle/#proguardr8--dexguard',
+          },
+          {
+            id: 'jetpack-compose',
+            name: t('Jetpack Compose'),
+            description: t(
+              'Learn about our first class integration with Jetpack Compose.'
+            ),
+            link: 'https://docs.sentry.io/platforms/android/configuration/integrations/jetpack-compose/',
+          },
+          {
+            id: 'source-context',
+            name: t('Source Context'),
+            description: t('See your source code as part of your stacktraces in Sentry.'),
+            link: 'https://docs.sentry.io/platforms/android/enhance-errors/source-context/',
+          },
+        ],
+};
 
-  const installationMode = optionValues.installationMode as InstallationMode;
-  const hasPerformance = activeProductSelection.includes(
-    ProductSolution.PERFORMANCE_MONITORING
-  );
-  const hasProfiling = activeProductSelection.includes(ProductSolution.PROFILING);
-  return (
-    <Layout
-      steps={steps({
-        dsn,
-        sourcePackageRegistries,
-        hasPerformance,
-        hasProfiling,
-        installationMode,
-      })}
-      platformOptions={platformOptions}
-      nextSteps={
-        installationMode === InstallationMode.AUTO ? nextStepsAuto : nextStepsManual
-      }
-      {...props}
-    />
-  );
-}
+const docs: Docs<PlatformOptions> = {
+  onboarding,
+  platformOptions,
+};
 
-export default GettingStartedWithAndroid;
+export default docs;