diff --git a/static/app/gettingStartedDocs/node/awslambda.tsx b/static/app/gettingStartedDocs/node/awslambda.tsx index 3ef59b3e02fcb1..a4a2ca6d52fa96 100644 --- a/static/app/gettingStartedDocs/node/awslambda.tsx +++ b/static/app/gettingStartedDocs/node/awslambda.tsx @@ -1,5 +1,6 @@ import {StepType} from 'sentry/components/onboarding/gettingStartedDoc/step'; import type { + BasePlatformOptions, Docs, DocsParams, OnboardingConfig, @@ -12,9 +13,33 @@ import { } from 'sentry/components/onboarding/gettingStartedDoc/utils/feedbackOnboarding'; import {getJSServerMetricsOnboarding} from 'sentry/components/onboarding/gettingStartedDoc/utils/metricsOnboarding'; import {t, tct} from 'sentry/locale'; +import {trackAnalytics} from 'sentry/utils/analytics'; import {getInstallConfig, getSdkInitSnippet} from 'sentry/utils/gettingStartedDocs/node'; -type Params = DocsParams; +export enum InstallationMode { + AUTO = 'auto', + MANUAL = 'manual', +} + +const platformOptions = { + installationMode: { + label: t('Installation Mode'), + items: [ + { + label: t('Auto'), + value: InstallationMode.AUTO, + }, + { + label: t('Manual'), + value: InstallationMode.MANUAL, + }, + ], + defaultValue: InstallationMode.AUTO, + }, +} satisfies BasePlatformOptions; + +type PlatformOptions = typeof platformOptions; +type Params = DocsParams; const getSdkSetupSnippet = (params: Params) => ` // IMPORTANT: Make sure to import and initialize Sentry at the top of your file. @@ -39,7 +64,7 @@ Sentry.init({ // }, });`; -const onboarding: OnboardingConfig = { +const onboarding: OnboardingConfig = { install: params => [ { type: StepType.INSTALL, @@ -87,9 +112,21 @@ const onboarding: OnboardingConfig = { ], }, ], + onPlatformOptionsChange(params) { + return option => { + if (option.installationMode === InstallationMode.MANUAL) { + trackAnalytics('integrations.switch_manual_sdk_setup', { + integration_type: 'first_party', + integration: 'aws_lambda', + view: 'onboarding', + organization: params.organization, + }); + } + }; + }, }; -const customMetricsOnboarding: OnboardingConfig = { +const customMetricsOnboarding: OnboardingConfig = { install: params => [ { type: StepType.INSTALL, @@ -122,7 +159,7 @@ const customMetricsOnboarding: OnboardingConfig = { verify: getJSServerMetricsOnboarding().verify, }; -const crashReportOnboarding: OnboardingConfig = { +const crashReportOnboarding: OnboardingConfig = { introduction: () => getCrashReportModalIntroduction(), install: (params: Params) => getCrashReportJavaScriptInstallStep(params), configure: () => [ @@ -137,10 +174,11 @@ const crashReportOnboarding: OnboardingConfig = { nextSteps: () => [], }; -const docs: Docs = { +const docs: Docs = { onboarding, customMetricsOnboarding, crashReportOnboarding, + platformOptions, }; export default docs; diff --git a/static/app/gettingStartedDocs/python/awslambda.tsx b/static/app/gettingStartedDocs/python/awslambda.tsx index 7bcd9bd85e77b8..4c83cf2337af15 100644 --- a/static/app/gettingStartedDocs/python/awslambda.tsx +++ b/static/app/gettingStartedDocs/python/awslambda.tsx @@ -4,6 +4,7 @@ import Alert from 'sentry/components/alert'; import ExternalLink from 'sentry/components/links/externalLink'; import {StepType} from 'sentry/components/onboarding/gettingStartedDoc/step'; import { + type BasePlatformOptions, type Docs, DocsPageLocation, type DocsParams, @@ -13,8 +14,32 @@ import {getPythonMetricsOnboarding} from 'sentry/components/onboarding/gettingSt import {crashReportOnboardingPython} from 'sentry/gettingStartedDocs/python/python'; import {t, tct} from 'sentry/locale'; import {space} from 'sentry/styles/space'; +import {trackAnalytics} from 'sentry/utils/analytics'; -type Params = DocsParams; +export enum InstallationMode { + AUTO = 'auto', + MANUAL = 'manual', +} + +const platformOptions = { + installationMode: { + label: t('Installation Mode'), + items: [ + { + label: t('Auto'), + value: InstallationMode.AUTO, + }, + { + label: t('Manual'), + value: InstallationMode.MANUAL, + }, + ], + defaultValue: InstallationMode.AUTO, + }, +} satisfies BasePlatformOptions; + +type PlatformOptions = typeof platformOptions; +type Params = DocsParams; const getInstallSnippet = () => `pip install --upgrade sentry-sdk`; @@ -53,7 +78,7 @@ sentry_sdk.init( ], )`; -const onboarding: OnboardingConfig = { +const onboarding: OnboardingConfig = { introduction: () => tct( 'Create a deployment package on your local machine and install the required dependencies in the deployment package. For more information, see [link:AWS Lambda deployment package in Python].', @@ -146,14 +171,27 @@ const onboarding: OnboardingConfig = { }, ], verify: () => [], + onPlatformOptionsChange(params) { + return option => { + if (option.installationMode === InstallationMode.MANUAL) { + trackAnalytics('integrations.switch_manual_sdk_setup', { + integration_type: 'first_party', + integration: 'aws_lambda', + view: 'onboarding', + organization: params.organization, + }); + } + }; + }, }; -const docs: Docs = { +const docs: Docs = { onboarding, customMetricsOnboarding: getPythonMetricsOnboarding({ installSnippet: getInstallSnippet(), }), crashReportOnboarding: crashReportOnboardingPython, + platformOptions, }; export default docs; diff --git a/static/app/views/onboarding/components/integrations/addInstallationInstructions.tsx b/static/app/views/onboarding/components/integrations/addInstallationInstructions.tsx index 7cf13fe9aa5420..d237cff5db4503 100644 --- a/static/app/views/onboarding/components/integrations/addInstallationInstructions.tsx +++ b/static/app/views/onboarding/components/integrations/addInstallationInstructions.tsx @@ -27,8 +27,8 @@ export default function AddInstallationInstructions() {

{tct( - 'If you don’t want to add CloudFormation stack to your AWS environment, press the [manualSetup] button instead.', - {manualSetup: {t('Manual Setup')}} + 'If you don’t want to add CloudFormation stack to your AWS environment, press the [manual] button above instead.', + {manual: {t('Manual')}} )}

diff --git a/static/app/views/onboarding/components/useOnboardingQueryParams.tsx b/static/app/views/onboarding/components/useOnboardingQueryParams.tsx index 628fe7f85f6c1d..bc298311fb8cfd 100644 --- a/static/app/views/onboarding/components/useOnboardingQueryParams.tsx +++ b/static/app/views/onboarding/components/useOnboardingQueryParams.tsx @@ -1,11 +1,16 @@ import {useCallback} from 'react'; -import {decodeBoolean, decodeList} from 'sentry/utils/queryString'; +import {decodeBoolean, decodeList, decodeScalar} from 'sentry/utils/queryString'; import useLocationQuery from 'sentry/utils/url/useLocationQuery'; import {useLocation} from 'sentry/utils/useLocation'; import {useNavigate} from 'sentry/utils/useNavigate'; type QueryValues = { + /** + * Used to show the installation mode for certain platforms, e.g. manual or auto. + * This is defined inside of a platform file + */ + installationMode: string; /** * Used to show product selection (error monitoring, tracing, profiling and session replay) for certain platforms, e.g. javascript-react */ @@ -31,6 +36,7 @@ export function useOnboardingQueryParams(): [ product: decodeList, showLoader: decodeBoolean, showManualSetup: decodeBoolean, + installationMode: decodeScalar, }, }); diff --git a/static/app/views/onboarding/integrationSetup.tsx b/static/app/views/onboarding/integrationSetup.tsx index 6d92cdf0676f03..ac97c02271d24a 100644 --- a/static/app/views/onboarding/integrationSetup.tsx +++ b/static/app/views/onboarding/integrationSetup.tsx @@ -5,39 +5,58 @@ import {motion} from 'framer-motion'; import {openInviteMembersModal} from 'sentry/actionCreators/modal'; import {Alert} from 'sentry/components/alert'; import {Button} from 'sentry/components/button'; -import ButtonBar from 'sentry/components/buttonBar'; import ExternalLink from 'sentry/components/links/externalLink'; import LoadingError from 'sentry/components/loadingError'; -import platforms from 'sentry/data/platforms'; +import LoadingIndicator from 'sentry/components/loadingIndicator'; +import type {DocsParams} from 'sentry/components/onboarding/gettingStartedDoc/types'; +import {useLoadGettingStarted} from 'sentry/components/onboarding/gettingStartedDoc/utils/useLoadGettingStarted'; +import { + PlatformOptionsControl, + useUrlPlatformOptions, +} from 'sentry/components/onboarding/platformOptionsControl'; import {t, tct} from 'sentry/locale'; +import ConfigStore from 'sentry/stores/configStore'; +import {useLegacyStore} from 'sentry/stores/useLegacyStore'; import {space} from 'sentry/styles/space'; import type {IntegrationProvider} from 'sentry/types/integrations'; -import type {Project} from 'sentry/types/project'; +import type {PlatformIntegration, Project} from 'sentry/types/project'; import {trackAnalytics} from 'sentry/utils/analytics'; import getDynamicText from 'sentry/utils/getDynamicText'; -import {trackIntegrationAnalytics} from 'sentry/utils/integrationUtil'; import useApi from 'sentry/utils/useApi'; import useOrganization from 'sentry/utils/useOrganization'; +import SetupIntroduction from 'sentry/views/onboarding/components/setupIntroduction'; import {AddIntegrationButton} from 'sentry/views/settings/organizationIntegrations/addIntegrationButton'; import AddInstallationInstructions from './components/integrations/addInstallationInstructions'; import PostInstallCodeSnippet from './components/integrations/postInstallCodeSnippet'; -import SetupIntroduction from './components/setupIntroduction'; type Props = { integrationSlug: string; - project: Project | null; - onClickManualSetup?: () => void; + platform: PlatformIntegration; + project: Project; }; -function IntegrationSetup(props: Props) { +function IntegrationSetup({project, integrationSlug, platform}: Props) { const [hasError, setHasError] = useState(false); const [installed, setInstalled] = useState(false); const [provider, setProvider] = useState(null); const organization = useOrganization(); - - const {project, integrationSlug} = props; + const {isSelfHosted, urlPrefix} = useLegacyStore(ConfigStore); + + const { + isLoading, + docs: docsConfig, + dsn, + projectKeyId, + refetch, + } = useLoadGettingStarted({ + orgSlug: organization.slug, + projSlug: project.slug, + platform, + }); + + const platformOptions = useUrlPlatformOptions(docsConfig?.platformOptions); const api = useApi(); const fetchData = useCallback(() => { @@ -64,10 +83,7 @@ function IntegrationSetup(props: Props) { const loadingError = ( ); @@ -78,26 +94,13 @@ function IntegrationSetup(props: Props) { ); - const renderSetupInstructions = () => { - const currentPlatform = project?.platform ?? 'other'; - return ( - p.id === currentPlatform)?.name ?? '' - )} - platform={currentPlatform} - /> - ); - }; const renderIntegrationInstructions = () => { - if (!provider || !project) { + if (!provider) { return null; } return ( - {renderSetupInstructions()} - - setInstalled(true)} - organization={organization} - priority="primary" - size="sm" - analyticsParams={{view: 'onboarding', already_installed: false}} - modalParams={{projectId: project.id}} - /> - - + setInstalled(true)} + organization={organization} + priority="primary" + size="sm" + analyticsParams={{view: 'onboarding', already_installed: false}} + modalParams={{projectId: project.id}} + /> ); }; const renderPostInstallInstructions = () => { - if (!project || !provider) { + if (!provider) { return null; } return ( - {renderSetupInstructions()} ; + } + + if (!docsConfig || !dsn || !projectKeyId) { + return ( + + ); + } + + const docParams: DocsParams = { + api, + projectKeyId, + dsn, + organization, + platformKey: platform.id, + projectId: project.id, + projectSlug: project.slug, + isFeedbackSelected: false, + isPerformanceSelected: false, + isProfilingSelected: false, + isReplaySelected: false, + isSelfHosted, + platformOptions, + sourcePackageRegistries: { + isLoading: false, + data: undefined, + }, + urlPrefix, + }; + return ( + + {docsConfig.platformOptions && ( + + )} + {installed ? renderPostInstallInstructions() : renderIntegrationInstructions()} {getDynamicText({ value: !hasError ? null : loadingError, @@ -206,15 +239,12 @@ DocsWrapper.defaultProps = { exit: {opacity: 0}, }; -const StyledButtonBar = styled(ButtonBar)` - margin-top: ${space(3)}; - width: max-content; - - @media (max-width: ${p => p.theme.breakpoints.small}) { - width: auto; - grid-row-gap: ${space(1)}; - grid-auto-flow: row; - } +const Divider = styled('hr')` + height: 1px; + width: 100%; + background: ${p => p.theme.border}; + border: none; + margin-bottom: ${space(3)}; `; export default IntegrationSetup; diff --git a/static/app/views/onboarding/setupDocs.tsx b/static/app/views/onboarding/setupDocs.tsx index 1d62bf03f0b14d..7ab2404cb24cbf 100644 --- a/static/app/views/onboarding/setupDocs.tsx +++ b/static/app/views/onboarding/setupDocs.tsx @@ -33,7 +33,7 @@ function SetupDocs({location, recentCreatedProject: project}: StepProps) { const currentPlatform = platforms.find(p => p.id === currentPlatformKey) ?? otherPlatform; - const [params, setParams] = useOnboardingQueryParams(); + const [params] = useOnboardingQueryParams(); if (!project || !currentPlatform) { return null; @@ -41,7 +41,8 @@ function SetupDocs({location, recentCreatedProject: project}: StepProps) { const platformName = currentPlatform.name; const integrationSlug = project.platform && platformToIntegrationMap[project.platform]; - const showIntegrationOnboarding = integrationSlug && !params.showManualSetup; + const showIntegrationOnboarding = + integrationSlug && params.installationMode !== 'manual'; return ( @@ -51,9 +52,7 @@ function SetupDocs({location, recentCreatedProject: project}: StepProps) { { - setParams({showManualSetup: true}); - }} + platform={currentPlatform} /> ) : (