From 23dde17ce8ee4f9c97079b23988a4d79ef4a8d47 Mon Sep 17 00:00:00 2001
From: Ogi <86684834+obostjancic@users.noreply.github.com>
Date: Fri, 18 Jul 2025 12:57:37 +0200
Subject: [PATCH 1/3] ref(getting-started): svelte content blocks
---
.../gettingStartedDocs/javascript/svelte.tsx | 75 ++++++++++++++-----
1 file changed, 56 insertions(+), 19 deletions(-)
diff --git a/static/app/gettingStartedDocs/javascript/svelte.tsx b/static/app/gettingStartedDocs/javascript/svelte.tsx
index edd7574f578582..fd6050cfa65152 100644
--- a/static/app/gettingStartedDocs/javascript/svelte.tsx
+++ b/static/app/gettingStartedDocs/javascript/svelte.tsx
@@ -5,6 +5,7 @@ import crashReportCallout from 'sentry/components/onboarding/gettingStartedDoc/f
import widgetCallout from 'sentry/components/onboarding/gettingStartedDoc/feedback/widgetCallout';
import TracePropagationMessage from 'sentry/components/onboarding/gettingStartedDoc/replay/tracePropagationMessage';
import type {
+ ContentBlock,
Docs,
DocsParams,
OnboardingConfig,
@@ -160,6 +161,27 @@ const getInstallConfig = () => [
},
];
+const installSnippetBlock: ContentBlock = {
+ type: 'code',
+ tabs: [
+ {
+ label: 'npm',
+ language: 'bash',
+ code: 'npm install --save @sentry/svelte',
+ },
+ {
+ label: 'yarn',
+ language: 'bash',
+ code: 'yarn add @sentry/svelte',
+ },
+ {
+ label: 'pnpm',
+ language: 'bash',
+ code: 'pnpm add @sentry/svelte',
+ },
+ ],
+};
+
const onboarding: OnboardingConfig = {
introduction: params => (
}
- ),
- configurations: getInstallConfig(),
+ content: [
+ {
+ type: 'text',
+ text: tct(
+ 'Add the Sentry SDK as a dependency using [code:npm], [code:yarn], or [code:pnpm]:',
+ {code:
}
+ ),
+ },
+ installSnippetBlock,
+ ],
},
],
configure: (params: Params) => [
{
type: StepType.CONFIGURE,
- description: tct(
- "Initialize Sentry as early as possible in your application's lifecycle, usually your Svelte app's entry point ([code:main.ts/js]):",
- {code:
}
- ),
- configurations: [
+ content: [
{
- code: [
+ type: 'text',
+ text: tct(
+ "Initialize Sentry as early as possible in your application's lifecycle, usually your Svelte app's entry point ([code:main.ts/js]):",
+ {code:
}
+ ),
+ },
+ {
+ type: 'code',
+ tabs: [
{
label: 'Svelte v5',
value: 'svelte v5',
@@ -208,9 +239,11 @@ const onboarding: OnboardingConfig = {
},
],
},
- ...(params.isProfilingSelected
- ? [getProfilingDocumentHeaderConfigurationStep()]
- : []),
+ {
+ type: 'conditional',
+ condition: params.isProfilingSelected,
+ content: getProfilingDocumentHeaderConfigurationStep().content!,
+ },
],
},
getUploadSourceMapsStep({
@@ -221,12 +254,16 @@ const onboarding: OnboardingConfig = {
verify: () => [
{
type: StepType.VERIFY,
- description: t(
- "This snippet contains an intentional error and can be used as a test to make sure that everything's working as expected."
- ),
- configurations: [
+ content: [
{
- code: [
+ type: 'text',
+ text: t(
+ "This snippet contains an intentional error and can be used as a test to make sure that everything's working as expected."
+ ),
+ },
+ {
+ type: 'code',
+ tabs: [
{
label: 'Svelte v5',
value: 'svelte v5',
From f292b64a6b11e266c53ab14edfa4d4239003ae00 Mon Sep 17 00:00:00 2001
From: Ogi <86684834+obostjancic@users.noreply.github.com>
Date: Fri, 18 Jul 2025 13:36:24 +0200
Subject: [PATCH 2/3] remove profiling
---
static/app/gettingStartedDocs/javascript/svelte.tsx | 10 +---------
1 file changed, 1 insertion(+), 9 deletions(-)
diff --git a/static/app/gettingStartedDocs/javascript/svelte.tsx b/static/app/gettingStartedDocs/javascript/svelte.tsx
index fd6050cfa65152..899be1e7e31cf7 100644
--- a/static/app/gettingStartedDocs/javascript/svelte.tsx
+++ b/static/app/gettingStartedDocs/javascript/svelte.tsx
@@ -19,10 +19,7 @@ import {
getFeedbackConfigOptions,
getFeedbackConfigureDescription,
} from 'sentry/components/onboarding/gettingStartedDoc/utils/feedbackOnboarding';
-import {
- getProfilingDocumentHeaderConfigurationStep,
- MaybeBrowserProfilingBetaWarning,
-} from 'sentry/components/onboarding/gettingStartedDoc/utils/profilingOnboarding';
+import {MaybeBrowserProfilingBetaWarning} from 'sentry/components/onboarding/gettingStartedDoc/utils/profilingOnboarding';
import {
getReplayConfigOptions,
getReplayConfigureDescription,
@@ -239,11 +236,6 @@ const onboarding: OnboardingConfig = {
},
],
},
- {
- type: 'conditional',
- condition: params.isProfilingSelected,
- content: getProfilingDocumentHeaderConfigurationStep().content!,
- },
],
},
getUploadSourceMapsStep({
From df0ac78a4b9e168048ecc370b88c90b873bc258e Mon Sep 17 00:00:00 2001
From: Ogi <86684834+obostjancic@users.noreply.github.com>
Date: Fri, 18 Jul 2025 14:45:21 +0200
Subject: [PATCH 3/3] other platforms
---
.../gettingStartedDocs/javascript/angular.tsx | 165 ++++++++------
.../gettingStartedDocs/javascript/astro.tsx | 81 +++++--
.../gettingStartedDocs/javascript/ember.tsx | 64 +++++-
.../gettingStartedDocs/javascript/gatsby.tsx | 75 +++++--
.../javascript/javascript.tsx | 80 +++++--
.../gettingStartedDocs/javascript/nuxt.tsx | 73 +++++--
.../javascript/react-router.spec.tsx | 168 ++++++++++++++
.../gettingStartedDocs/javascript/remix.tsx | 58 ++---
.../gettingStartedDocs/javascript/solid.tsx | 70 ++++--
.../javascript/solidstart.spec.tsx | 116 ++++++++++
.../javascript/tanstackstart-react.spec.tsx | 127 +++++++++++
.../javascript/tanstackstart-react.tsx | 206 +++++++++++-------
.../app/gettingStartedDocs/javascript/vue.tsx | 83 +++++--
13 files changed, 1072 insertions(+), 294 deletions(-)
create mode 100644 static/app/gettingStartedDocs/javascript/react-router.spec.tsx
create mode 100644 static/app/gettingStartedDocs/javascript/solidstart.spec.tsx
create mode 100644 static/app/gettingStartedDocs/javascript/tanstackstart-react.spec.tsx
diff --git a/static/app/gettingStartedDocs/javascript/angular.tsx b/static/app/gettingStartedDocs/javascript/angular.tsx
index 1f6c028fc1a4ff..b8405c0420d77c 100644
--- a/static/app/gettingStartedDocs/javascript/angular.tsx
+++ b/static/app/gettingStartedDocs/javascript/angular.tsx
@@ -4,7 +4,7 @@ import widgetCallout from 'sentry/components/onboarding/gettingStartedDoc/feedba
import TracePropagationMessage from 'sentry/components/onboarding/gettingStartedDoc/replay/tracePropagationMessage';
import {
type BasePlatformOptions,
- type Configuration,
+ type ContentBlock,
type Docs,
type DocsParams,
type OnboardingConfig,
@@ -214,54 +214,11 @@ export const appConfig: ApplicationConfig = {
};
`;
-const getVerifySnippetTemplate = () => `
-
-`;
-
const getVerifySnippetComponent = () => `
public throwTestError(): void {
throw new Error("Sentry Test Error");
}`;
-function getVerifyConfiguration(): Configuration {
- return {
- description: t(
- 'To verify that everything is working as expected, you can trigger a test error in your app. As an example we will add a button that throws an error when being clicked to your main app component.'
- ),
- configurations: [
- {
- description: tct(
- 'First add the button element to your [code:app.component.html]:',
- {code:
}
- ),
- code: [
- {
- label: 'HTML',
- value: 'html',
- language: 'html',
- filename: 'app.component.html',
- code: getVerifySnippetTemplate(),
- },
- ],
- },
- {
- description: tct('Then, in your [code:app.component.ts] add the event handler:', {
- code:
,
- }),
- code: [
- {
- label: 'TypeScript',
- value: 'typescript',
- language: 'typescript',
- filename: 'app.component.ts',
- code: getVerifySnippetComponent(),
- },
- ],
- },
- ],
- };
-}
-
const getInstallConfig = () => [
{
language: 'bash',
@@ -288,6 +245,27 @@ const getInstallConfig = () => [
},
];
+const installSnippetBlock: ContentBlock = {
+ type: 'code',
+ tabs: [
+ {
+ label: 'npm',
+ language: 'bash',
+ code: 'npm install --save @sentry/angular',
+ },
+ {
+ label: 'yarn',
+ language: 'bash',
+ code: 'yarn add @sentry/angular',
+ },
+ {
+ label: 'pnpm',
+ language: 'bash',
+ code: 'pnpm install @sentry/angular',
+ },
+ ],
+};
+
const onboarding: OnboardingConfig
}
- ),
- configurations: getInstallConfig(),
+ content: [
+ {
+ type: 'text',
+ text: tct(
+ 'Add the Sentry SDK as a dependency using [code:npm], [code:yarn] or [code:pnpm]:',
+ {code:
}
+ ),
+ },
+ installSnippetBlock,
+ ],
},
],
configure: (params: Params) => [
{
type: StepType.CONFIGURE,
- configurations: [
+ content: [
{
- description: tct(
+ type: 'text',
+ text: tct(
`Initialize the Sentry Angular SDK in your [code:main.ts] file as early as possible, before initializing Angular:`,
{
code:
,
}
),
- language: 'javascript',
- code: getSdkSetupSnippet(params),
},
{
- description: isModuleConfig(params)
+ type: 'code',
+ tabs: [
+ {
+ label: 'JavaScript',
+ language: 'javascript',
+ code: getSdkSetupSnippet(params),
+ },
+ ],
+ },
+ {
+ type: 'text',
+ text: isModuleConfig(params)
? tct(
"Register the Sentry Angular SDK's ErrorHandler and Tracing providers in your [code:app.module.ts] file:",
{code:
}
@@ -330,10 +323,18 @@ const onboarding: OnboardingConfig
}
),
- language: 'javascript',
- code: isModuleConfig(params)
- ? getConfigureAppModuleSnippet()
- : getConfigureAppConfigSnippet(),
+ },
+ {
+ type: 'code',
+ tabs: [
+ {
+ label: 'JavaScript',
+ language: 'javascript',
+ code: isModuleConfig(params)
+ ? getConfigureAppModuleSnippet()
+ : getConfigureAppConfigSnippet(),
+ },
+ ],
},
],
},
@@ -345,10 +346,52 @@ const onboarding: OnboardingConfig
,
+ }),
+ },
+ {
+ type: 'code',
+ tabs: [
+ {
+ label: 'HTML',
+ value: 'html',
+ language: 'html',
+ filename: 'app.component.html',
+ code: '',
+ },
+ ],
+ },
+ {
+ type: 'text',
+ text: tct('Then, in your [code:app.component.ts] add the event handler:', {
+ code:
,
+ }),
+ },
+ {
+ type: 'code',
+ tabs: [
+ {
+ label: 'TypeScript',
+ value: 'typescript',
+ language: 'typescript',
+ filename: 'app.component.ts',
+ code: getVerifySnippetComponent(),
+ },
+ ],
+ },
{
- description: t(
+ type: 'text',
+ text: t(
"After clicking the button, you should see the error on Sentry's Issues page."
),
},
diff --git a/static/app/gettingStartedDocs/javascript/astro.tsx b/static/app/gettingStartedDocs/javascript/astro.tsx
index 19271002c2f6f9..7388d6b1a50672 100644
--- a/static/app/gettingStartedDocs/javascript/astro.tsx
+++ b/static/app/gettingStartedDocs/javascript/astro.tsx
@@ -5,6 +5,7 @@ import crashReportCallout from 'sentry/components/onboarding/gettingStartedDoc/f
import widgetCallout from 'sentry/components/onboarding/gettingStartedDoc/feedback/widgetCallout';
import TracePropagationMessage from 'sentry/components/onboarding/gettingStartedDoc/replay/tracePropagationMessage';
import type {
+ ContentBlock,
Docs,
DocsParams,
OnboardingConfig,
@@ -70,7 +71,7 @@ const getVerifySnippet = () => `
document.querySelector("#error-button").addEventListener("click", handleClick);
`;
-
+// TODO: Remove once the other product areas support content blocks
const getInstallConfig = () => [
{
type: StepType.INSTALL,
@@ -96,6 +97,17 @@ const getInstallConfig = () => [
},
];
+const installSnippetBlock: ContentBlock = {
+ type: 'code',
+ tabs: [
+ {
+ label: 'bash',
+ language: 'bash',
+ code: 'npx astro add @sentry/astro',
+ },
+ ],
+};
+
const onboarding: OnboardingConfig = {
introduction: () => (
,
+ }
+ ),
+ },
+ installSnippetBlock,
+ ],
+ },
+ ],
configure: (params: Params) => [
{
type: StepType.CONFIGURE,
- description: tct(
- 'Open up your [astroConfig:astro.config.mjs] file and configure the DSN, and any other settings you need:',
+ content: [
{
- astroConfig:
,
- }
- ),
- configurations: [
+ type: 'text',
+ text: tct(
+ 'Open up your [astroConfig:astro.config.mjs] file and configure the DSN, and any other settings you need:',
+ {
+ astroConfig:
,
+ }
+ ),
+ },
{
- code: [
+ type: 'code',
+ tabs: [
{
label: 'JavaScript',
value: 'javascript',
@@ -136,24 +168,27 @@ const onboarding: OnboardingConfig = {
],
},
{
- description: tct(
+ type: 'text',
+ text: tct(
'Add your Sentry auth token to the [authTokenEnvVar:SENTRY_AUTH_TOKEN] environment variable:',
{
authTokenEnvVar:
,
}
),
- language: 'bash',
- code: [
+ },
+ {
+ type: 'code',
+ tabs: [
{
- value: 'bash',
- language: 'bash',
label: 'bash',
- code: `SENTRY_AUTH_TOKEN=___ORG_AUTH_TOKEN___`,
+ language: 'bash',
+ code: 'SENTRY_AUTH_TOKEN=___ORG_AUTH_TOKEN___',
},
],
},
{
- description: tct(
+ type: 'text',
+ text: tct(
'You can further customize your SDK by [manualSetupLink:manually initializing the SDK].',
{
manualSetupLink: (
@@ -168,12 +203,16 @@ const onboarding: OnboardingConfig = {
verify: () => [
{
type: StepType.VERIFY,
- description: t(
- 'Then throw a test error anywhere in your app, so you can test that everything is working:'
- ),
- configurations: [
+ content: [
{
- code: [
+ type: 'text',
+ text: t(
+ 'Then throw a test error anywhere in your app, so you can test that everything is working:'
+ ),
+ },
+ {
+ type: 'code',
+ tabs: [
{
label: 'Astro',
value: 'html',
diff --git a/static/app/gettingStartedDocs/javascript/ember.tsx b/static/app/gettingStartedDocs/javascript/ember.tsx
index fea25e1c794ea3..a2fc266fd563ff 100644
--- a/static/app/gettingStartedDocs/javascript/ember.tsx
+++ b/static/app/gettingStartedDocs/javascript/ember.tsx
@@ -3,6 +3,7 @@ import crashReportCallout from 'sentry/components/onboarding/gettingStartedDoc/f
import widgetCallout from 'sentry/components/onboarding/gettingStartedDoc/feedback/widgetCallout';
import TracePropagationMessage from 'sentry/components/onboarding/gettingStartedDoc/replay/tracePropagationMessage';
import type {
+ ContentBlock,
Docs,
DocsParams,
OnboardingConfig,
@@ -115,6 +116,7 @@ export default class App extends Application {
`;
};
+// TODO: Remove once the other product areas support content blocks
const getInstallConfig = () => [
{
language: 'bash',
@@ -125,6 +127,17 @@ ember install @sentry/ember
},
];
+const installSnippetBlock: ContentBlock = {
+ type: 'code',
+ tabs: [
+ {
+ label: 'ember-cli',
+ language: 'bash',
+ code: 'ember install @sentry/ember',
+ },
+ ],
+};
+
const getVerifyEmberSnippet = () => `
myUndefinedFunction();`;
@@ -139,21 +152,33 @@ const onboarding: OnboardingConfig = {
description: t(
'Sentry captures data by using an SDK within your application’s runtime.'
),
- configurations: getInstallConfig(),
+ content: [
+ {
+ type: 'text',
+ text: t(
+ 'Sentry captures data by using an SDK within your application’s runtime.'
+ ),
+ },
+ installSnippetBlock,
+ ],
},
],
configure: (params: Params) => [
{
type: StepType.CONFIGURE,
- description: tct(
- 'You should [code:init] the Sentry SDK as soon as possible during your application load up in [code:app.js], before initializing Ember:',
+ content: [
{
- code:
,
- }
- ),
- configurations: [
+ type: 'text',
+ text: tct(
+ 'You should [code:init] the Sentry SDK as soon as possible during your application load up in [code:app.js], before initializing Ember:',
+ {
+ code:
,
+ }
+ ),
+ },
{
- code: [
+ type: 'code',
+ tabs: [
{
label: 'JavaScript',
value: 'javascript',
@@ -172,9 +197,26 @@ const onboarding: OnboardingConfig = {
verify: () => [
{
type: StepType.VERIFY,
- description: t(
- "This snippet contains an intentional error and can be used as a test to make sure that everything's working as expected."
- ),
+ content: [
+ {
+ type: 'text',
+ text: t(
+ "This snippet contains an intentional error and can be used as a test to make sure that everything's working as expected."
+ ),
+ },
+ {
+ type: 'code',
+ tabs: [
+ {
+ label: 'JavaScript',
+ value: 'javascript',
+ language: 'javascript',
+ code: getVerifyEmberSnippet(),
+ },
+ ],
+ },
+ ],
+
configurations: [
{
code: [
diff --git a/static/app/gettingStartedDocs/javascript/gatsby.tsx b/static/app/gettingStartedDocs/javascript/gatsby.tsx
index 36d23d60d3f2c4..91844dd3bbf91d 100644
--- a/static/app/gettingStartedDocs/javascript/gatsby.tsx
+++ b/static/app/gettingStartedDocs/javascript/gatsby.tsx
@@ -5,9 +5,11 @@ import crashReportCallout from 'sentry/components/onboarding/gettingStartedDoc/f
import widgetCallout from 'sentry/components/onboarding/gettingStartedDoc/feedback/widgetCallout';
import TracePropagationMessage from 'sentry/components/onboarding/gettingStartedDoc/replay/tracePropagationMessage';
import type {
+ ContentBlock,
Docs,
DocsParams,
OnboardingConfig,
+ OnboardingStep,
} from 'sentry/components/onboarding/gettingStartedDoc/types';
import {StepType} from 'sentry/components/onboarding/gettingStartedDoc/types';
import {getUploadSourceMapsStep} from 'sentry/components/onboarding/gettingStartedDoc/utils';
@@ -116,19 +118,22 @@ root.render(
}
),
- code: [
+ },
+ {
+ type: 'code',
+ tabs: [
{
label: 'JavaScript',
- value: 'javascript',
language: 'javascript',
code: `module.exports = {
plugins: [{
@@ -139,14 +144,17 @@ const getConfigureStep = (params: Params) => {
],
},
{
- description: tct(
+ type: 'text',
+ text: tct(
'Then, configure your [codeSentry:Sentry.init:]. For this, create a new file called [codeSentry:sentry.config.js] in the root of your project and add the following code:',
{codeSentry:
}
),
- code: [
+ },
+ {
+ type: 'code',
+ tabs: [
{
label: 'JavaScript',
- value: 'javascript',
language: 'javascript',
filename: 'sentry.config.js',
code: getSdkSetupSnippet(params),
@@ -157,6 +165,7 @@ const getConfigureStep = (params: Params) => {
};
};
+// TODO: Remove once the other product areas support content blocks
const getInstallConfig = () => [
{
language: 'bash',
@@ -173,6 +182,27 @@ const getInstallConfig = () => [
},
];
+const installSnippetBlock: ContentBlock = {
+ type: 'code',
+ tabs: [
+ {
+ label: 'npm',
+ language: 'bash',
+ code: 'npm install --save @sentry/gatsby',
+ },
+ {
+ label: 'yarn',
+ language: 'bash',
+ code: 'yarn add @sentry/gatsby',
+ },
+ {
+ label: 'pnpm',
+ language: 'bash',
+ code: 'pnpm add @sentry/gatsby',
+ },
+ ],
+};
+
const onboarding: OnboardingConfig = {
introduction: () =>
tct(
@@ -184,11 +214,16 @@ const onboarding: OnboardingConfig = {
install: () => [
{
type: StepType.INSTALL,
- description: tct(
- 'Add the Sentry SDK as a dependency using [code:npm], [code:yarn], or [code:pnpm]:',
- {code:
}
- ),
- configurations: getInstallConfig(),
+ content: [
+ {
+ type: 'text',
+ text: tct(
+ 'Add the Sentry SDK as a dependency using [code:npm], [code:yarn], or [code:pnpm]:',
+ {code:
}
+ ),
+ },
+ installSnippetBlock,
+ ],
},
],
configure: (params: Params) => [
@@ -201,12 +236,16 @@ const onboarding: OnboardingConfig = {
verify: () => [
{
type: StepType.VERIFY,
- description: t(
- "This snippet contains an intentional error and can be used as a test to make sure that everything's working as expected."
- ),
- configurations: [
+ content: [
{
- code: [
+ type: 'text',
+ text: t(
+ "This snippet contains an intentional error and can be used as a test to make sure that everything's working as expected."
+ ),
+ },
+ {
+ type: 'code',
+ tabs: [
{
label: 'JavaScript',
value: 'javascript',
diff --git a/static/app/gettingStartedDocs/javascript/javascript.tsx b/static/app/gettingStartedDocs/javascript/javascript.tsx
index 0a3f641714aba6..39aa2ab56cec7c 100644
--- a/static/app/gettingStartedDocs/javascript/javascript.tsx
+++ b/static/app/gettingStartedDocs/javascript/javascript.tsx
@@ -9,6 +9,7 @@ import widgetCallout from 'sentry/components/onboarding/gettingStartedDoc/feedba
import TracePropagationMessage from 'sentry/components/onboarding/gettingStartedDoc/replay/tracePropagationMessage';
import type {
BasePlatformOptions,
+ ContentBlock,
Docs,
DocsParams,
OnboardingConfig,
@@ -275,6 +276,7 @@ Sentry.init({
const getVerifyJSSnippet = () => `
myUndefinedFunction();`;
+// TODO: Remove once the other product areas support content blocks
const getInstallConfig = () => [
{
language: 'bash',
@@ -301,27 +303,53 @@ const getInstallConfig = () => [
},
];
-const getVerifyConfig = () => [
+const installSnippetBlock: ContentBlock = {
+ type: 'code',
+ tabs: [
+ {
+ label: 'npm',
+ language: 'bash',
+ code: 'npm install --save @sentry/browser',
+ },
+ {
+ label: 'yarn',
+ language: 'bash',
+ code: 'yarn add @sentry/browser',
+ },
+ {
+ label: 'pnpm',
+ language: 'bash',
+ code: 'pnpm add @sentry/browser',
+ },
+ ],
+};
+
+const verifySnippetBlock: ContentBlock[] = [
{
- type: StepType.VERIFY,
- description: t(
+ type: 'text',
+ text: t(
"This snippet contains an intentional error and can be used as a test to make sure that everything's working as expected."
),
- configurations: [
+ },
+ {
+ type: 'code',
+ tabs: [
{
- code: [
- {
- label: 'Javascript',
- value: 'javascript',
- language: 'javascript',
- code: getVerifyJSSnippet(),
- },
- ],
+ label: 'Javascript',
+ language: 'javascript',
+ code: getVerifyJSSnippet(),
},
],
},
];
+const getVerifyConfig = () => [
+ {
+ type: StepType.VERIFY,
+ content: verifySnippetBlock,
+ },
+];
+
const getAiRulesConfig = (params: Params) =>
getAIRulesForCodeEditorStep({
rules: `
@@ -639,24 +667,32 @@ const packageManagerOnboarding: OnboardingConfig- {tctCode( - 'Build and run your application and visit [code:/sentry-example-page] if you have set it up. Click the button to trigger a test error.' - )} -
-{t('Or, throw an error in a simple vue component.')}
-
- {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: ,
- }
- )}
-
- {t( - 'Or, trigger a sample error by calling a function that does not exist somewhere in your application.' - )} -
-
,
+ }
+ ),
+ },
+ {
+ type: 'text',
+ text: t(
+ 'Or, trigger a sample error by calling a function that does not exist somewhere in your application.'
+ ),
+ },
+ {
+ type: 'code',
+ tabs: [
{
label: 'Javascript',
value: 'javascript',
diff --git a/static/app/gettingStartedDocs/javascript/solid.tsx b/static/app/gettingStartedDocs/javascript/solid.tsx
index 4e6285607e6e79..62888db8006af1 100644
--- a/static/app/gettingStartedDocs/javascript/solid.tsx
+++ b/static/app/gettingStartedDocs/javascript/solid.tsx
@@ -5,6 +5,7 @@ import crashReportCallout from 'sentry/components/onboarding/gettingStartedDoc/f
import widgetCallout from 'sentry/components/onboarding/gettingStartedDoc/feedback/widgetCallout';
import TracePropagationMessage from 'sentry/components/onboarding/gettingStartedDoc/replay/tracePropagationMessage';
import type {
+ ContentBlock,
Docs,
DocsParams,
OnboardingConfig,
@@ -134,6 +135,7 @@ const getVerifySnippet = () => `
Throw error
`;
+// TODO: Remove once the other product areas support content blocks
const getInstallConfig = () => [
{
language: 'bash',
@@ -160,6 +162,27 @@ const getInstallConfig = () => [
},
];
+const installSnippetBlock: ContentBlock = {
+ type: 'code',
+ tabs: [
+ {
+ label: 'npm',
+ language: 'bash',
+ code: 'npm install --save @sentry/solid',
+ },
+ {
+ label: 'yarn',
+ language: 'bash',
+ code: 'yarn add @sentry/solid',
+ },
+ {
+ label: 'pnpm',
+ language: 'bash',
+ code: 'pnpm add @sentry/solid',
+ },
+ ],
+};
+
const onboarding: OnboardingConfig = {
introduction: () => (
,
- }
- ),
- configurations: getInstallConfig(),
+ type: 'text',
+ text: tct(
+ 'Add the Sentry SDK as a dependency using [code:npm], [code:yarn], or [code:pnpm]:',
+ {
+ code:
,
+ }
+ ),
+ },
+ installSnippetBlock,
+ ],
},
],
configure: (params: Params) => [
{
type: StepType.CONFIGURE,
- description: tct(
- "Initialize Sentry as early as possible in your application's lifecycle, usually your solid app's entry point ([code:main.ts/js]):",
- {code:
}
- ),
- configurations: [
+ content: [
{
- code: [
+ type: 'text',
+ text: tct(
+ "Initialize Sentry as early as possible in your application's lifecycle, usually your solid app's entry point ([code:main.ts/js]):",
+ {code:
}
+ ),
+ },
+ {
+ type: 'code',
+ tabs: [
{
label: 'JavaScript',
value: 'javascript',
@@ -214,12 +246,16 @@ const onboarding: OnboardingConfig = {
verify: () => [
{
type: StepType.VERIFY,
- description: t(
- "This snippet contains an intentional error and can be used as a test to make sure that everything's working as expected."
- ),
- configurations: [
+ content: [
{
- code: [
+ type: 'text',
+ text: t(
+ "This snippet contains an intentional error and can be used as a test to make sure that everything's working as expected."
+ ),
+ },
+ {
+ type: 'code',
+ tabs: [
{
label: 'JavaScript',
value: 'javascript',
diff --git a/static/app/gettingStartedDocs/javascript/solidstart.spec.tsx b/static/app/gettingStartedDocs/javascript/solidstart.spec.tsx
new file mode 100644
index 00000000000000..c78cfc56af0a98
--- /dev/null
+++ b/static/app/gettingStartedDocs/javascript/solidstart.spec.tsx
@@ -0,0 +1,116 @@
+import {renderWithOnboardingLayout} from 'sentry-test/onboarding/renderWithOnboardingLayout';
+import {screen} from 'sentry-test/reactTestingLibrary';
+import {textWithMarkupMatcher} from 'sentry-test/utils';
+
+import {ProductSolution} from 'sentry/components/onboarding/gettingStartedDoc/types';
+
+import docs from './solidstart';
+
+describe('javascript-solidstart onboarding docs', function () {
+ it('renders onboarding docs correctly', () => {
+ renderWithOnboardingLayout(docs);
+
+ // Renders main headings
+ expect(screen.getByRole('heading', {name: 'Install'})).toBeInTheDocument();
+ expect(screen.getByRole('heading', {name: 'Configure'})).toBeInTheDocument();
+ expect(screen.getByRole('heading', {name: 'Verify'})).toBeInTheDocument();
+
+ // Includes import statement
+ expect(
+ screen.getByText(
+ textWithMarkupMatcher(/import \* as Sentry from "@sentry\/solidstart"/)
+ )
+ ).toBeInTheDocument();
+ });
+
+ it('enables performance setting the tracesSampleRate to 1', () => {
+ renderWithOnboardingLayout(docs, {
+ selectedProducts: [
+ ProductSolution.ERROR_MONITORING,
+ ProductSolution.PERFORMANCE_MONITORING,
+ ],
+ });
+
+ expect(
+ screen.getByText(textWithMarkupMatcher(/tracesSampleRate: 1\.0/))
+ ).toBeInTheDocument();
+ expect(
+ screen.getByText(textWithMarkupMatcher(/solidRouterBrowserTracingIntegration\(\)/))
+ ).toBeInTheDocument();
+ });
+
+ it('enables replay by setting replay samplerates', () => {
+ renderWithOnboardingLayout(docs, {
+ selectedProducts: [
+ ProductSolution.ERROR_MONITORING,
+ ProductSolution.SESSION_REPLAY,
+ ],
+ });
+
+ expect(
+ screen.getByText(textWithMarkupMatcher(/replaysSessionSampleRate: 0\.1/))
+ ).toBeInTheDocument();
+ expect(
+ screen.getByText(textWithMarkupMatcher(/replaysOnErrorSampleRate: 1\.0/))
+ ).toBeInTheDocument();
+ expect(
+ screen.getByText(textWithMarkupMatcher(/replayIntegration\(/))
+ ).toBeInTheDocument();
+ });
+
+ it('enables profiling by setting profiling sample rates', () => {
+ renderWithOnboardingLayout(docs, {
+ selectedProducts: [ProductSolution.ERROR_MONITORING, ProductSolution.PROFILING],
+ });
+
+ expect(
+ screen.getByText(textWithMarkupMatcher(/Sentry.browserProfilingIntegration\(\)/))
+ ).toBeInTheDocument();
+ expect(
+ screen.getByText(textWithMarkupMatcher(/profilesSampleRate: 1\.0/))
+ ).toBeInTheDocument();
+ });
+
+ it('includes SolidStart specific configurations', () => {
+ renderWithOnboardingLayout(docs, {
+ selectedProducts: [
+ ProductSolution.ERROR_MONITORING,
+ ProductSolution.PERFORMANCE_MONITORING,
+ ],
+ });
+
+ // Check for SolidStart specific setup
+ expect(
+ screen.getByText(textWithMarkupMatcher(/sentryBeforeResponseMiddleware/))
+ ).toBeInTheDocument();
+ expect(
+ screen.getByText(textWithMarkupMatcher(/withSentryRouterRouting/))
+ ).toBeInTheDocument();
+ expect(
+ screen.getByText(textWithMarkupMatcher(/instrument\.server\.mjs/))
+ ).toBeInTheDocument();
+ });
+
+ it('includes server instrumentation setup', () => {
+ renderWithOnboardingLayout(docs);
+
+ expect(
+ screen.getByText(
+ textWithMarkupMatcher(/NODE_OPTIONS.*--import.*instrument\.server\.mjs/)
+ )
+ ).toBeInTheDocument();
+ expect(
+ screen.getByText(textWithMarkupMatcher(/entry-client\.tsx/))
+ ).toBeInTheDocument();
+ expect(screen.getByText(textWithMarkupMatcher(/middleware\.ts/))).toBeInTheDocument();
+ });
+
+ it('displays test error button in verify section', () => {
+ renderWithOnboardingLayout(docs);
+
+ expect(screen.getByText(textWithMarkupMatcher(/Throw error/))).toBeInTheDocument();
+ expect(
+ screen.getByText(textWithMarkupMatcher(/Sentry Frontend Error/))
+ ).toBeInTheDocument();
+ });
+});
diff --git a/static/app/gettingStartedDocs/javascript/tanstackstart-react.spec.tsx b/static/app/gettingStartedDocs/javascript/tanstackstart-react.spec.tsx
new file mode 100644
index 00000000000000..93aef3025adb24
--- /dev/null
+++ b/static/app/gettingStartedDocs/javascript/tanstackstart-react.spec.tsx
@@ -0,0 +1,127 @@
+import {renderWithOnboardingLayout} from 'sentry-test/onboarding/renderWithOnboardingLayout';
+import {screen} from 'sentry-test/reactTestingLibrary';
+import {textWithMarkupMatcher} from 'sentry-test/utils';
+
+import {ProductSolution} from 'sentry/components/onboarding/gettingStartedDoc/types';
+
+import docs from './tanstackstart-react';
+
+describe('javascript-tanstackstart-react onboarding docs', function () {
+ it('renders onboarding docs correctly', () => {
+ renderWithOnboardingLayout(docs);
+
+ // Renders main headings
+ expect(screen.getByRole('heading', {name: 'Install'})).toBeInTheDocument();
+ expect(screen.getByRole('heading', {name: 'Set up the SDK'})).toBeInTheDocument();
+ expect(screen.getByRole('heading', {name: 'Verify'})).toBeInTheDocument();
+
+ // Includes import statement
+ expect(
+ screen.getByText(
+ textWithMarkupMatcher(/import \* as Sentry from "@sentry\/tanstackstart-react"/)
+ )
+ ).toBeInTheDocument();
+
+ // Includes configuration wrapper
+ expect(
+ screen.getByText(textWithMarkupMatcher(/wrapVinxiConfigWithSentry/))
+ ).toBeInTheDocument();
+ });
+
+ it('displays sample rates by default', () => {
+ renderWithOnboardingLayout(docs, {
+ selectedProducts: [
+ ProductSolution.ERROR_MONITORING,
+ ProductSolution.PERFORMANCE_MONITORING,
+ ProductSolution.SESSION_REPLAY,
+ ],
+ });
+
+ expect(
+ screen.getByText(textWithMarkupMatcher(/tracesSampleRate/))
+ ).toBeInTheDocument();
+ expect(
+ screen.getByText(textWithMarkupMatcher(/replaysSessionSampleRate/))
+ ).toBeInTheDocument();
+ expect(
+ screen.getByText(textWithMarkupMatcher(/replaysOnErrorSampleRate/))
+ ).toBeInTheDocument();
+ });
+
+ it('enables performance setting the tracesSampleRate to 1', () => {
+ renderWithOnboardingLayout(docs, {
+ selectedProducts: [
+ ProductSolution.ERROR_MONITORING,
+ ProductSolution.PERFORMANCE_MONITORING,
+ ],
+ });
+
+ expect(
+ screen.getByText(textWithMarkupMatcher(/tracesSampleRate: 1\.0/))
+ ).toBeInTheDocument();
+ expect(
+ screen.getByText(
+ textWithMarkupMatcher(/tanstackRouterBrowserTracingIntegration\(router\)/)
+ )
+ ).toBeInTheDocument();
+ });
+
+ it('enables replay by setting replay samplerates', () => {
+ renderWithOnboardingLayout(docs, {
+ selectedProducts: [
+ ProductSolution.ERROR_MONITORING,
+ ProductSolution.SESSION_REPLAY,
+ ],
+ });
+
+ expect(
+ screen.getByText(textWithMarkupMatcher(/replaysSessionSampleRate: 0\.1/))
+ ).toBeInTheDocument();
+ expect(
+ screen.getByText(textWithMarkupMatcher(/replaysOnErrorSampleRate: 1\.0/))
+ ).toBeInTheDocument();
+ expect(
+ screen.getByText(textWithMarkupMatcher(/replayIntegration\(\)/))
+ ).toBeInTheDocument();
+ });
+
+ it('includes TanStack Start specific configurations', () => {
+ renderWithOnboardingLayout(docs);
+
+ // Check for TanStack Start specific setup
+ expect(
+ screen.getByText(textWithMarkupMatcher(/wrapCreateRootRouteWithSentry/))
+ ).toBeInTheDocument();
+ expect(
+ screen.getByText(textWithMarkupMatcher(/wrapStreamHandlerWithSentry/))
+ ).toBeInTheDocument();
+ expect(
+ screen.getByText(textWithMarkupMatcher(/sentryGlobalServerMiddlewareHandler/))
+ ).toBeInTheDocument();
+ });
+
+ it('includes error boundary configuration', () => {
+ renderWithOnboardingLayout(docs);
+
+ expect(
+ screen.getByText(textWithMarkupMatcher(/withErrorBoundary/))
+ ).toBeInTheDocument();
+ expect(
+ screen.getByText(textWithMarkupMatcher(/captureException/))
+ ).toBeInTheDocument();
+ });
+
+ it('displays test error button in verify section', () => {
+ renderWithOnboardingLayout(docs);
+
+ expect(
+ screen.getByText(textWithMarkupMatcher(/Break the world/))
+ ).toBeInTheDocument();
+ expect(
+ screen.getByText(textWithMarkupMatcher(/Sentry Test Error/))
+ ).toBeInTheDocument();
+ expect(
+ screen.getByText(textWithMarkupMatcher(/sentry-example-api/))
+ ).toBeInTheDocument();
+ });
+});
diff --git a/static/app/gettingStartedDocs/javascript/tanstackstart-react.tsx b/static/app/gettingStartedDocs/javascript/tanstackstart-react.tsx
index 799c76a9365d46..996b73b6331635 100644
--- a/static/app/gettingStartedDocs/javascript/tanstackstart-react.tsx
+++ b/static/app/gettingStartedDocs/javascript/tanstackstart-react.tsx
@@ -12,61 +12,65 @@ import {getNodeAgentMonitoringOnboarding} from 'sentry/utils/gettingStartedDocs/
type Params = DocsParams;
-const getInstallConfig = () => [
- {
- language: 'bash',
- code: [
- {
- label: 'npm',
- value: 'npm',
- language: 'bash',
- code: 'npm install --save @sentry/tanstackstart-react',
- },
- {
- label: 'yarn',
- value: 'yarn',
- language: 'bash',
- code: 'yarn add @sentry/tanstackstart-react',
- },
- {
- label: 'pnpm',
- value: 'pnpm',
- language: 'bash',
- code: 'pnpm add @sentry/tanstackstart-react',
- },
- ],
- },
-];
-
const onboarding: OnboardingConfig = {
introduction: () =>
t("In this guide you'll set up the Sentry TanStack Start React SDK"),
install: () => [
{
type: StepType.INSTALL,
- description: tct(
- 'Add the Sentry TanStack Start SDK as a dependency using [code:npm], [code:yarn] or [code:pnpm]:',
- {code:
}
- ),
- configurations: getInstallConfig(),
+ content: [
+ {
+ type: 'text',
+ text: tct(
+ 'Add the Sentry TanStack Start SDK as a dependency using [code:npm], [code:yarn] or [code:pnpm]:',
+ {code:
}
+ ),
+ },
+ {
+ type: 'code',
+ tabs: [
+ {
+ label: 'npm',
+ language: 'bash',
+ code: 'npm install --save @sentry/tanstackstart-react',
+ },
+ {
+ label: 'yarn',
+ language: 'bash',
+ code: 'yarn add @sentry/tanstackstart-react',
+ },
+ {
+ label: 'pnpm',
+ language: 'bash',
+ code: 'pnpm add @sentry/tanstackstart-react',
+ },
+ ],
+ },
+ ],
},
],
configure: (params: Params) => [
{
title: t('Set up the SDK'),
- description: t(
- 'In the following steps we will set up the SDK and instrument various parts of your application.'
- ),
- configurations: [
+ content: [
{
- description: tct(
+ type: 'text',
+ text: t(
+ 'In the following steps we will set up the SDK and instrument various parts of your application.'
+ ),
+ },
+ {
+ type: 'text',
+ text: tct(
"First, extend your app's default TanStack Start configuration by adding [code:wrapVinxiConfigWithSentry] to your [code:app.config.ts] file:",
{code:
}
),
- code: [
+ },
+ {
+ type: 'code',
+ tabs: [
{
label: 'TypeScript',
- value: 'typescript',
language: 'typescript',
filename: 'app.config.ts',
code: `import { defineConfig } from "@tanstack/react-start/config";
@@ -90,11 +94,15 @@ export default wrapVinxiConfigWithSentry(config, {
],
},
{
- description: tct(
+ type: 'text',
+ text: tct(
'In future versions of this SDK, setting the [code:SENTRY_AUTH_TOKEN] environment variable during your build will upload sourcemaps for you to see unminified errors in Sentry.',
{code:
}
),
- code: [
+ },
+ {
+ type: 'code',
+ tabs: [
{
value: 'bash',
language: 'bash',
@@ -104,13 +112,17 @@ export default wrapVinxiConfigWithSentry(config, {
],
},
{
- description: tct(
+ type: 'text',
+ text: tct(
'Add the following initialization code to your [code:app/client.tsx] file to initialize Sentry on the client:',
{code:
}
),
- code: [
+ },
+ {
+ type: 'code',
+ tabs: [
{
- label: 'tsx',
+ label: 'TypeScript',
value: 'tsx',
language: 'tsx',
filename: 'app/client.tsx',
@@ -168,13 +180,17 @@ hydrateRoot(document,
}
),
- code: [
+ },
+ {
+ type: 'code',
+ tabs: [
{
- label: 'tsx',
+ label: 'TypeScript',
value: 'tsx',
language: 'tsx',
filename: 'app/ssr.tsx',
@@ -202,13 +218,17 @@ Sentry.init({
],
},
{
- description: tct(
+ type: 'text',
+ text: tct(
"Wrap TanStack Start's [code:createRootRoute] function using [code:wrapCreateRootRouteWithSentry] to apply tracing to Server-Side Rendering (SSR):",
{code:
}
),
- code: [
+ },
+ {
+ type: 'code',
+ tabs: [
{
- label: 'tsx',
+ label: 'TypeScript',
value: 'tsx',
language: 'tsx',
filename: 'app/routes/__root.tsx',
@@ -223,13 +243,17 @@ export const Route = wrapCreateRootRouteWithSentry(createRootRoute)({
],
},
{
- description: tct(
+ type: 'text',
+ text: tct(
"Wrap TanStack Start's [code:defaultStreamHandler] function using [code:wrapStreamHandlerWithSentry] to instrument requests to your server:",
{code:
}
),
- code: [
+ },
+ {
+ type: 'code',
+ tabs: [
{
- label: 'tsx',
+ label: 'TypeScript',
value: 'tsx',
language: 'tsx',
filename: 'app/ssr.tsx',
@@ -249,11 +273,15 @@ export default createStartHandler({
],
},
{
- description: tct(
+ type: 'text',
+ text: tct(
"Add the [code:sentryGlobalServerMiddlewareHandler] to your global middlewares to instrument your server function invocations. If you haven't done so, create a [code:app/global-middleware.ts] file.",
{code:
}
),
- code: [
+ },
+ {
+ type: 'code',
+ tabs: [
{
label: 'TypeScript',
value: 'typescript',
@@ -274,18 +302,23 @@ registerGlobalMiddleware({
],
},
{
- description: t(
+ type: 'text',
+ text: t(
'The Sentry SDK cannot capture errors that you manually caught yourself with error boundaries.'
),
},
{
- description: tct(
+ type: 'text',
+ text: tct(
'If you have React error boundaries in your app and you want to report errors that these boundaries catch to Sentry, apply the [code:withErrorBoundary] wrapper to your [code:ErrorBoundary]:',
{code:
}
),
- code: [
+ },
+ {
+ type: 'code',
+ tabs: [
{
- label: 'tsx',
+ label: 'TypeScript',
value: 'tsx',
language: 'tsx',
code: `import React from "react";
@@ -305,13 +338,17 @@ export const MySentryWrappedErrorBoundary = withErrorBoundary(
],
},
{
- description: tct(
+ type: 'text',
+ text: tct(
'If you defined [code:errorComponents] in your Code-Based TanStack Router routes, capture the [code:error] argument with [code:captureException] inside a [code:useEffect] hook:',
{code:
}
),
- code: [
+ },
+ {
+ type: 'code',
+ tabs: [
{
- label: 'tsx',
+ label: 'TypeScript',
value: 'tsx',
language: 'tsx',
code: `import { createRoute } from "@tanstack/react-router";
@@ -337,18 +374,24 @@ const route = createRoute({
verify: () => [
{
type: StepType.VERIFY,
- description: t(
- "Let's test your setup and confirm that Sentry is working correctly and sending data to your Sentry project."
- ),
- configurations: [
+ content: [
{
- description: t(
+ type: 'text',
+ text: t(
+ "Let's test your setup and confirm that Sentry is working correctly and sending data to your Sentry project."
+ ),
+ },
+ {
+ type: 'text',
+ text: t(
'To verify that Sentry captures errors and creates issues in your Sentry project, add a test button to an existing page or create a new one:'
),
- code: [
+ },
+ {
+ type: 'code',
+ tabs: [
{
- label: 'tsx',
- value: 'tsx',
+ label: 'TypeScript',
language: 'tsx',
code: `}
),
- code: [
+ },
+ {
+ type: 'code',
+ tabs: [
{
label: 'TypeScript',
- value: 'typescript',
language: 'typescript',
filename: 'app/routes/api/sentry-example-api.ts',
code: `import { json } from "@tanstack/react-start";
@@ -387,14 +433,17 @@ export const APIRoute = createAPIFileRoute("/api/sentry-example-api")({
],
},
{
- description: tct(
+ type: 'text',
+ text: tct(
"Next, update your test button to call this route and throw an error if the response isn't [code:ok]:",
{code:
}
),
- code: [
+ },
+ {
+ type: 'code',
+ tabs: [
{
- label: 'tsx',
- value: 'tsx',
+ label: 'TypeScript',
language: 'tsx',
code: `