From 9ec3aa861759dc33b8a3a41b9265f724058475ec Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Mon, 25 Sep 2023 10:49:59 +0200 Subject: [PATCH] feat(source-map-debug): Connect source map debug modal to backend (#56257) --- .../crashContent/exception/content.tsx | 14 + .../crashContent/exception/stackTrace.tsx | 4 + .../exception/useSourceMapDebuggerData.tsx | 171 ++++++++++ .../crashContent/stackTrace/content.tsx | 4 + .../interfaces/frame/deprecatedLine.tsx | 48 ++- .../interfaces/sourceMapsDebuggerModal.tsx | 299 ++++++++---------- 6 files changed, 364 insertions(+), 176 deletions(-) create mode 100644 static/app/components/events/interfaces/crashContent/exception/useSourceMapDebuggerData.tsx diff --git a/static/app/components/events/interfaces/crashContent/exception/content.tsx b/static/app/components/events/interfaces/crashContent/exception/content.tsx index b625c44fa73ed1..b3cfa792ba0961 100644 --- a/static/app/components/events/interfaces/crashContent/exception/content.tsx +++ b/static/app/components/events/interfaces/crashContent/exception/content.tsx @@ -2,6 +2,10 @@ import {useState} from 'react'; import styled from '@emotion/styled'; import {Button} from 'sentry/components/button'; +import { + prepareSourceMapDebuggerFrameInformation, + useSourceMapDebuggerData, +} from 'sentry/components/events/interfaces/crashContent/exception/useSourceMapDebuggerData'; import {AnnotatedText} from 'sentry/components/events/meta/annotatedText'; import {Tooltip} from 'sentry/components/tooltip'; import {tct, tn} from 'sentry/locale'; @@ -121,6 +125,7 @@ export function Content({ groupingCurrentLevel, hasHierarchicalGrouping, platform, + projectSlug, values, type, meta, @@ -129,6 +134,8 @@ export function Content({ const {collapsedExceptions, toggleException, expandException} = useCollapsedExceptions(values); + const sourceMapDebuggerData = useSourceMapDebuggerData(event, projectSlug); + // Organization context may be unavailable for the shared event view, so we // avoid using the `useOrganization` hook here and directly useContext // instead. @@ -141,6 +148,12 @@ export function Content({ ? `exception-${exc.mechanism?.exception_id}` : undefined; + const frameSourceMapDebuggerData = sourceMapDebuggerData?.exceptions[ + excIdx + ].frames.map(debuggerFrame => + prepareSourceMapDebuggerFrameInformation(sourceMapDebuggerData, debuggerFrame) + ); + if (exc.mechanism?.parent_id && collapsedExceptions[exc.mechanism.parent_id]) { return null; } @@ -190,6 +203,7 @@ export function Content({ groupingCurrentLevel={groupingCurrentLevel} meta={meta?.[excIdx]?.stacktrace} threadId={threadId} + frameSourceMapDebuggerData={frameSourceMapDebuggerData} /> ); diff --git a/static/app/components/events/interfaces/crashContent/exception/stackTrace.tsx b/static/app/components/events/interfaces/crashContent/exception/stackTrace.tsx index 384931792547f6..5f186f59e85529 100644 --- a/static/app/components/events/interfaces/crashContent/exception/stackTrace.tsx +++ b/static/app/components/events/interfaces/crashContent/exception/stackTrace.tsx @@ -1,4 +1,5 @@ import EmptyMessage from 'sentry/components/emptyMessage'; +import {FrameSourceMapDebuggerData} from 'sentry/components/events/interfaces/sourceMapsDebuggerModal'; import Panel from 'sentry/components/panels/panel'; import {IconWarning} from 'sentry/icons'; import {t} from 'sentry/locale'; @@ -20,6 +21,7 @@ type Props = { platform: PlatformType; stacktrace: ExceptionValue['stacktrace']; expandFirstFrame?: boolean; + frameSourceMapDebuggerData?: FrameSourceMapDebuggerData[]; groupingCurrentLevel?: Group['metadata']['current_level']; meta?: Record; newestFirst?: boolean; @@ -40,6 +42,7 @@ function StackTrace({ event, meta, threadId, + frameSourceMapDebuggerData, }: Props) { if (!defined(stacktrace)) { return null; @@ -121,6 +124,7 @@ function StackTrace({ event={event} meta={meta} threadId={threadId} + frameSourceMapDebuggerData={frameSourceMapDebuggerData} /> ); } diff --git a/static/app/components/events/interfaces/crashContent/exception/useSourceMapDebuggerData.tsx b/static/app/components/events/interfaces/crashContent/exception/useSourceMapDebuggerData.tsx new file mode 100644 index 00000000000000..191805adf815e2 --- /dev/null +++ b/static/app/components/events/interfaces/crashContent/exception/useSourceMapDebuggerData.tsx @@ -0,0 +1,171 @@ +import {FrameSourceMapDebuggerData} from 'sentry/components/events/interfaces/sourceMapsDebuggerModal'; +import {Event} from 'sentry/types/event'; +import {useApiQuery} from 'sentry/utils/queryClient'; +import useOrganization from 'sentry/utils/useOrganization'; + +interface SourceMapDebugBlueThunderResponseFrame { + debug_id_process: { + debug_id: string | null; + uploaded_source_file_with_correct_debug_id: boolean; + uploaded_source_map_with_correct_debug_id: boolean; + }; + release_process: { + abs_path: string; + matching_source_file_names: string[]; + matching_source_map_name: string | null; + source_file_lookup_result: 'found' | 'wrong-dist' | 'unsuccessful'; + source_map_lookup_result: 'found' | 'wrong-dist' | 'unsuccessful'; + source_map_reference: string | null; + } | null; +} + +interface SourceMapDebugBlueThunderResponse { + dist: string | null; + exceptions: { + frames: SourceMapDebugBlueThunderResponseFrame[]; + }[]; + has_debug_ids: boolean; + has_uploaded_some_artifact_with_a_debug_id: boolean; + project_has_some_artifact_bundle: boolean; + release: string | null; + release_has_some_artifact: boolean; + sdk_debug_id_support: 'not-supported' | 'unofficial-sdk' | 'needs-upgrade' | 'full'; + sdk_version: string | null; +} + +export function useSourceMapDebuggerData(event: Event, projectSlug: string) { + const isSdkThatShouldShowSourceMapsDebugger = + !!event.sdk?.name.startsWith('sentry.javascript.'); + const organization = useOrganization({allowNull: true}); + const {data: sourceMapDebuggerData} = useApiQuery( + [ + `/projects/${organization!.slug}/${projectSlug}/events/${ + event.id + }/source-map-debug-blue-thunder-edition/`, + ], + { + enabled: + isSdkThatShouldShowSourceMapsDebugger && + organization !== null && + organization.features.includes('source-maps-debugger-blue-thunder-edition'), + staleTime: Infinity, + retry: false, + refetchOnWindowFocus: false, + } + ); + return sourceMapDebuggerData; +} + +function getDebugIdProgress( + sourceMapDebuggerData: SourceMapDebugBlueThunderResponse, + debuggerFrame: SourceMapDebugBlueThunderResponseFrame +) { + let debugIdProgress = 0; + if (sourceMapDebuggerData.sdk_debug_id_support === 'full') { + debugIdProgress++; + } + if (debuggerFrame.debug_id_process.debug_id !== null) { + debugIdProgress++; + } + if (debuggerFrame.debug_id_process.uploaded_source_file_with_correct_debug_id) { + debugIdProgress++; + } + if (debuggerFrame.debug_id_process.uploaded_source_map_with_correct_debug_id) { + debugIdProgress++; + } + return {debugIdProgress, debugIdProgressPercent: debugIdProgress / 4}; +} + +function getReleaseProgress( + sourceMapDebuggerData: SourceMapDebugBlueThunderResponse, + debuggerFrame: SourceMapDebugBlueThunderResponseFrame +) { + let releaseProgress = 0; + if (sourceMapDebuggerData.release !== null) { + releaseProgress++; + } + if (sourceMapDebuggerData.release_has_some_artifact) { + releaseProgress++; + } + if (debuggerFrame.release_process?.source_file_lookup_result === 'found') { + releaseProgress++; + } + if (debuggerFrame.release_process?.source_map_lookup_result === 'found') { + releaseProgress++; + } + return {releaseProgress, releaseProgressPercent: releaseProgress / 4}; +} + +function getScrapingProgress() { + const scrapingProgress = 0; + + // TODO: Once we have data on scraping uncomment below and add logic to track progress. + + // if (sourceResolutionResults.sourceFileScrapingStatus.status === 'found') { + // scrapingProgress++; + // } + // if (todo === 'found') { + // // We give this step a relative weight of 4/5ths because this is actually way + // // harder than step 1 and we want do deprioritize this tab over the others + // // because the scraping process comes with a few downsides that aren't immediately + // // obvious. + // scrapingProgress += 4; + // } + return {scrapingProgress, scrapingProgressPercent: scrapingProgress / 5}; +} + +export function prepareSourceMapDebuggerFrameInformation( + sourceMapDebuggerData: SourceMapDebugBlueThunderResponse, + debuggerFrame: SourceMapDebugBlueThunderResponseFrame +): FrameSourceMapDebuggerData { + const {debugIdProgressPercent, debugIdProgress} = getDebugIdProgress( + sourceMapDebuggerData, + debuggerFrame + ); + const {releaseProgressPercent, releaseProgress} = getReleaseProgress( + sourceMapDebuggerData, + debuggerFrame + ); + const {scrapingProgressPercent, scrapingProgress} = getScrapingProgress(); + + const frameIsResolved = + debugIdProgressPercent === 1 || + releaseProgressPercent === 1 || + scrapingProgressPercent === 1; + + return { + dist: sourceMapDebuggerData.dist, + eventHasDebugIds: sourceMapDebuggerData.has_debug_ids, + matchingSourceFileNames: + debuggerFrame.release_process?.matching_source_file_names ?? [], + release: sourceMapDebuggerData.release, + releaseHasSomeArtifact: sourceMapDebuggerData.release_has_some_artifact, + releaseSourceMapReference: + debuggerFrame.release_process?.source_map_reference ?? null, + sdkDebugIdSupport: sourceMapDebuggerData.sdk_debug_id_support, + sourceFileReleaseNameFetchingResult: + debuggerFrame.release_process?.source_file_lookup_result ?? 'unsuccessful', + sourceFileScrapingStatus: {status: 'none'}, + sourceMapReleaseNameFetchingResult: + debuggerFrame.release_process?.source_map_lookup_result ?? 'unsuccessful', + sourceMapScrapingStatus: {status: 'none'}, + stackFrameDebugId: debuggerFrame.debug_id_process.debug_id, + stackFramePath: debuggerFrame.release_process?.abs_path ?? null, + uploadedSomeArtifactWithDebugId: + sourceMapDebuggerData.has_uploaded_some_artifact_with_a_debug_id, + uploadedSourceFileWithCorrectDebugId: + debuggerFrame.debug_id_process.uploaded_source_file_with_correct_debug_id, + uploadedSourceMapWithCorrectDebugId: + debuggerFrame.debug_id_process.uploaded_source_map_with_correct_debug_id, + sdkVersion: sourceMapDebuggerData.sdk_version, + matchingSourceMapName: + debuggerFrame.release_process?.matching_source_map_name ?? null, + debugIdProgressPercent, + debugIdProgress, + releaseProgressPercent, + releaseProgress, + scrapingProgressPercent, + scrapingProgress, + frameIsResolved, + } satisfies FrameSourceMapDebuggerData; +} diff --git a/static/app/components/events/interfaces/crashContent/stackTrace/content.tsx b/static/app/components/events/interfaces/crashContent/stackTrace/content.tsx index 6d24721c1aed8e..f869f556d551ca 100644 --- a/static/app/components/events/interfaces/crashContent/stackTrace/content.tsx +++ b/static/app/components/events/interfaces/crashContent/stackTrace/content.tsx @@ -2,6 +2,7 @@ import {cloneElement, Fragment, useState} from 'react'; import styled from '@emotion/styled'; import GuideAnchor from 'sentry/components/assistant/guideAnchor'; +import {FrameSourceMapDebuggerData} from 'sentry/components/events/interfaces/sourceMapsDebuggerModal'; import Panel from 'sentry/components/panels/panel'; import {t} from 'sentry/locale'; import {Frame, Organization, PlatformType} from 'sentry/types'; @@ -32,6 +33,7 @@ type Props = { event: Event; platform: PlatformType; className?: string; + frameSourceMapDebuggerData?: FrameSourceMapDebuggerData[]; hideIcon?: boolean; isHoverPreviewed?: boolean; lockAddress?: string; @@ -58,6 +60,7 @@ function Content({ threadId, lockAddress, organization, + frameSourceMapDebuggerData, }: Props) { const [showingAbsoluteAddresses, setShowingAbsoluteAddresses] = useState(false); const [showCompleteFunctionName, setShowCompleteFunctionName] = useState(false); @@ -244,6 +247,7 @@ function Content({ lockAddress, hiddenFrameCount: frameCountMap[frameIndex], organization, + frameSourceResolutionResults: frameSourceMapDebuggerData?.[frameIndex], }; nRepeats = 0; diff --git a/static/app/components/events/interfaces/frame/deprecatedLine.tsx b/static/app/components/events/interfaces/frame/deprecatedLine.tsx index d642b45afa1fde..2b37f4b623cc95 100644 --- a/static/app/components/events/interfaces/frame/deprecatedLine.tsx +++ b/static/app/components/events/interfaces/frame/deprecatedLine.tsx @@ -3,14 +3,19 @@ import styled from '@emotion/styled'; import classNames from 'classnames'; import scrollToElement from 'scroll-to-element'; +import {openModal} from 'sentry/actionCreators/modal'; import {Button} from 'sentry/components/button'; import {analyzeFrameForRootCause} from 'sentry/components/events/interfaces/analyzeFrames'; import LeadHint from 'sentry/components/events/interfaces/frame/line/leadHint'; +import { + FrameSourceMapDebuggerData, + SourceMapsDebuggerModal, +} from 'sentry/components/events/interfaces/sourceMapsDebuggerModal'; import {getThreadById} from 'sentry/components/events/interfaces/utils'; import StrictClick from 'sentry/components/strictClick'; import Tag from 'sentry/components/tag'; import {SLOW_TOOLTIP_DELAY} from 'sentry/constants'; -import {IconChevron, IconRefresh} from 'sentry/icons'; +import {IconChevron, IconFlag, IconRefresh} from 'sentry/icons'; import {t, tn} from 'sentry/locale'; import DebugMetaStore from 'sentry/stores/debugMetaStore'; import {space} from 'sentry/styles/space'; @@ -50,6 +55,7 @@ export interface DeprecatedLineProps { registers: Record; emptySourceNotation?: boolean; frameMeta?: Record; + frameSourceResolutionResults?: FrameSourceMapDebuggerData; hiddenFrameCount?: number; image?: React.ComponentProps['image']; includeSystemFrames?: boolean; @@ -308,6 +314,12 @@ export class DeprecatedLine extends Component { lockAddress ); + const shouldShowSourceMapDebuggerToggle = + data.inApp && + this.props.frameSourceResolutionResults && + (!this.props.frameSourceResolutionResults.frameIsResolved || + !hasContextSource(data)); + return ( { ) : null} {stacktraceChangesEnabled ? this.renderShowHideToggle() : null} + {shouldShowSourceMapDebuggerToggle ? ( + } + to="" + tooltipText={t( + 'Learn how to show the original source code for this stack frame.' + )} + onClick={e => { + e.stopPropagation(); + openModal(modalProps => ( + + )); + }} + > + {hasContextSource(data) + ? t('Not your source code?') + : t('No source code?')} + + ) : null} {!data.inApp ? ( stacktraceChangesEnabled ? null : ( {t('System')} @@ -611,3 +645,15 @@ const ToggleButton = styled(Button)` color: ${p => p.theme.subText}; } `; + +const SourceMapDebuggerToggle = styled(Tag)` + cursor: pointer; + span { + color: ${p => p.theme.gray300}; + + &:hover { + text-decoration: underline; + text-decoration-color: ${p => p.theme.gray200}; + } + } +`; diff --git a/static/app/components/events/interfaces/sourceMapsDebuggerModal.tsx b/static/app/components/events/interfaces/sourceMapsDebuggerModal.tsx index 1201671e871b80..5fc138f048fd4a 100644 --- a/static/app/components/events/interfaces/sourceMapsDebuggerModal.tsx +++ b/static/app/components/events/interfaces/sourceMapsDebuggerModal.tsx @@ -23,14 +23,23 @@ import { import {t, tct} from 'sentry/locale'; import {space} from 'sentry/styles/space'; -interface SourceResolutionResults { - distName: string | null; +export interface FrameSourceMapDebuggerData { + debugIdProgress: number; + debugIdProgressPercent: number; + dist: string | null; eventHasDebugIds: boolean; - matchingArtifactName: string; - projectHasUploadedArtifacts: boolean; - releaseName: string | null; + frameIsResolved: boolean; + matchingSourceFileNames: string[]; + matchingSourceMapName: string | null; + release: string | null; + releaseHasSomeArtifact: boolean; + releaseProgress: number; + releaseProgressPercent: number; releaseSourceMapReference: string | null; - sdkDebugIdSupport: 'full' | 'needs-upgrade' | 'unofficial-sdk'; + scrapingProgress: number; + scrapingProgressPercent: number; + sdkDebugIdSupport: 'full' | 'needs-upgrade' | 'not-supported' | 'unofficial-sdk'; + sdkVersion: string | null; sourceFileReleaseNameFetchingResult: 'found' | 'wrong-dist' | 'unsuccessful'; sourceFileScrapingStatus: | {status: 'found'} @@ -43,16 +52,13 @@ interface SourceResolutionResults { | {status: 'none'}; stackFrameDebugId: string | null; stackFramePath: string | null; - uploadedSomeArtifact: boolean; - uploadedSomeArtifactToRelease: boolean; uploadedSomeArtifactWithDebugId: boolean; uploadedSourceFileWithCorrectDebugId: boolean; uploadedSourceMapWithCorrectDebugId: boolean; - sdkVersion?: string; } interface SourceMapsDebuggerModalProps extends ModalRenderProps { - sourceResolutionResults: SourceResolutionResults; + sourceResolutionResults: FrameSourceMapDebuggerData; } export function SourceMapsDebuggerModal({ @@ -63,27 +69,17 @@ export function SourceMapsDebuggerModal({ }: SourceMapsDebuggerModalProps) { const theme = useTheme(); - const {debugIdProgress, debugIdProgressPercent} = getDebugIdProgress( - sourceResolutionResults - ); - const {releaseProgress, releaseProgressPercent} = getReleaseProgress( - sourceResolutionResults - ); - const {scrapingProgress, scrapingProgressPercent} = getScrapingProgress( - sourceResolutionResults - ); - const [activeTab, setActiveTab] = useState<'debug-ids' | 'release' | 'fetching'>(() => { const possibleTabs = [ - {tab: 'debug-ids', progress: debugIdProgressPercent}, - {tab: 'release', progress: releaseProgressPercent}, - {tab: 'fetching', progress: scrapingProgressPercent}, + {tab: 'debug-ids', progress: sourceResolutionResults.debugIdProgressPercent}, + {tab: 'release', progress: sourceResolutionResults.releaseProgressPercent}, + {tab: 'fetching', progress: sourceResolutionResults.scrapingProgressPercent}, ] as const; // Get the tab with the most progress return possibleTabs.reduce( (prev, curr) => (curr.progress > prev.progress ? curr : prev), - possibleTabs[0] + possibleTabs[sourceResolutionResults.sdkDebugIdSupport === 'not-supported' ? 1 : 0] ).tab; }); @@ -120,27 +116,35 @@ export function SourceMapsDebuggerModal({ - {t('Debug IDs (recommended)')} + {`${t('Debug IDs')}${ + sourceResolutionResults.sdkDebugIdSupport !== 'not-supported' + ? ' ' + t('(recommended)') + : '' + }`} @@ -148,16 +152,22 @@ export function SourceMapsDebuggerModal({ - {t('Hosting Publicly')} + {/* TODO: Remove "coming soon" when we add data crawling from symbolicator */} + {`${t('Hosting Publicly')} (${t('coming soon')})`} @@ -195,7 +205,11 @@ export function SourceMapsDebuggerModal({ sourceResolutionResults={sourceResolutionResults} /> - {debugIdProgressPercent === 1 ? : } + {sourceResolutionResults.debugIdProgressPercent === 1 ? ( + + ) : ( + + )}

@@ -213,11 +227,11 @@ export function SourceMapsDebuggerModal({ sourceResolutionResults={sourceResolutionResults} /> - {releaseProgressPercent === 1 ? : } + {sourceResolutionResults.releaseProgressPercent === 1 ? ( + + ) : ( + + )}

@@ -252,7 +270,7 @@ export function SourceMapsDebuggerModal({ sourceResolutionResults={sourceResolutionResults} /> - {scrapingProgressPercent === 1 ? ( + {sourceResolutionResults.scrapingProgressPercent === 1 ? ( ) : ( @@ -282,55 +300,6 @@ export function SourceMapsDebuggerModal({ ); } -function getDebugIdProgress(sourceResolutionResults: SourceResolutionResults) { - let debugIdProgress = 0; - if (sourceResolutionResults.sdkDebugIdSupport === 'full') { - debugIdProgress++; - } - if (sourceResolutionResults.stackFrameDebugId !== null) { - debugIdProgress++; - } - if (sourceResolutionResults.uploadedSourceFileWithCorrectDebugId) { - debugIdProgress++; - } - if (sourceResolutionResults.uploadedSourceMapWithCorrectDebugId) { - debugIdProgress++; - } - return {debugIdProgress, debugIdProgressPercent: debugIdProgress / 4}; -} - -function getReleaseProgress(sourceResolutionResults: SourceResolutionResults) { - let releaseProgress = 0; - if (sourceResolutionResults.releaseName !== null) { - releaseProgress++; - } - if (sourceResolutionResults.uploadedSomeArtifactToRelease) { - releaseProgress++; - } - if (sourceResolutionResults.sourceFileReleaseNameFetchingResult === 'found') { - releaseProgress++; - } - if (sourceResolutionResults.sourceMapReleaseNameFetchingResult === 'found') { - releaseProgress++; - } - return {releaseProgress, releaseProgressPercent: releaseProgress / 4}; -} - -function getScrapingProgress(sourceResolutionResults: SourceResolutionResults) { - let scrapingProgress = 0; - if (sourceResolutionResults.sourceFileScrapingStatus.status === 'found') { - scrapingProgress++; - } - if (sourceResolutionResults.sourceMapScrapingStatus.status === 'found') { - // We give this step a relative weight of 4/5ths because this is actually way - // harder than step 1 and we want do deprioritize this tab over the others - // because the scraping process comes with a few downsides that aren't immediately - // obvious. - scrapingProgress += 4; - } - return {scrapingProgress, scrapingProgressPercent: scrapingProgress / 5}; -} - function CheckListItem({children, title, status}: PropsWithChildren) { return ( @@ -362,10 +331,17 @@ function InstalledSdkChecklistItem({ setActiveTab: React.Dispatch< React.SetStateAction<'release' | 'debug-ids' | 'fetching'> >; - sourceResolutionResults: SourceResolutionResults; + sourceResolutionResults: FrameSourceMapDebuggerData; }) { const itemName = t('Installed SDK supports Debug IDs'); + if ( + sourceResolutionResults.eventHasDebugIds || + sourceResolutionResults.sdkDebugIdSupport === 'full' + ) { + return ; + } + if (sourceResolutionResults.sdkDebugIdSupport === 'needs-upgrade') { return ( @@ -391,7 +367,7 @@ function InstalledSdkChecklistItem({

{tct( - 'If upgrading the SDK is not an option for you, you can use the [link:Release Name] process instead.', + 'If upgrading the SDK is not an option for you, you can use the [link:Release] process instead.', { link: setActiveTab('release')} />, } @@ -402,11 +378,22 @@ function InstalledSdkChecklistItem({ ); } - if ( - sourceResolutionResults.stackFrameDebugId !== null || - sourceResolutionResults.sdkDebugIdSupport === 'full' - ) { - return ; + if (sourceResolutionResults.sdkDebugIdSupport === 'not-supported') { + return ( + + +

{t("SDK Doesn't Support Debug IDs")}
+

+ {tct( + 'The SDK you are using does not support debug IDs yet. We recommend using the [link:Release] process instead.', + { + link: setActiveTab('release')} />, + } + )} +

+ + + ); } return ( @@ -436,7 +423,7 @@ function HasDebugIdChecklistItem({ shouldValidate, }: { shouldValidate: boolean; - sourceResolutionResults: SourceResolutionResults; + sourceResolutionResults: FrameSourceMapDebuggerData; }) { const itemName = t('Stack frame has Debug IDs'); @@ -526,7 +513,7 @@ function UploadedSourceFileWithCorrectDebugIdChecklistItem({ shouldValidate, }: { shouldValidate: boolean; - sourceResolutionResults: SourceResolutionResults; + sourceResolutionResults: FrameSourceMapDebuggerData; }) { const itemName = t('Uploaded source file with a matching Debug ID'); @@ -564,39 +551,13 @@ function UploadedSourceFileWithCorrectDebugIdChecklistItem({ ); } - if (sourceResolutionResults.uploadedSomeArtifact) { - return ( - - -
{t('Uploaded Artifacts Without Debug IDs')}
-

- {t( - 'You already uploaded artifacts for this project but none of the artifacts contain Debug IDs. Make sure you inject Debug IDs into your source files before uploading them to Sentry.' - )} -

-

- {tct( - 'Read the [link:Sentry Source Maps Documentation] to learn how to inject Debug IDs into your build artifacts and how to upload them to Sentry.', - { - link: ( - - ), - } - )} -

- {/* TODO: Link to Uploaded Artifacts */} -
-
- ); - } - return ( -
{t('No Artifacts Uploaded')}
+
{t('No Artifacts With Debug IDs Uploaded')}

{tct( - "You didn't upload any artifacts yet. Read the [link:Sentry Source Maps Documentation] to learn how to inject Debug IDs into your build artifacts and how to upload them to Sentry.", + "You didn't upload any artifacts with debug IDs yet. Read the [link:Sentry Source Maps Documentation] to learn how to inject Debug IDs into your build artifacts and how to upload them to Sentry.", { link: ( @@ -615,7 +576,7 @@ function UploadedSourceMapWithCorrectDebugIdChecklistItem({ shouldValidate, }: { shouldValidate: boolean; - sourceResolutionResults: SourceResolutionResults; + sourceResolutionResults: FrameSourceMapDebuggerData; }) { const itemName = t('Uploaded source map with a matching Debug ID'); @@ -654,40 +615,13 @@ function UploadedSourceMapWithCorrectDebugIdChecklistItem({ ); } - if (sourceResolutionResults.uploadedSomeArtifact) { - return ( - - -

{t('Uploaded Artifacts Without Debug IDs')}
-

- {t( - 'You already uploaded artifacts for this project but none of the artifacts contain Debug IDs. Make sure you inject Debug IDs into your source files before uploading them to Sentry.' - )} -

-

- {tct( - 'Read the [link:Sentry Source Maps Documentation] to learn how to inject Debug IDs into your build artifacts and how to upload them to Sentry.', - { - link: ( - - ), - } - )} -

- {/* TODO: Link to Uploaded Artifacts */} -
- -
- ); - } - return (
{t('No Artifacts Uploaded')}

{tct( - "You didn't upload any artifacts yet. Read the [link:Sentry Source Maps Documentation] to learn how to inject Debug IDs into your build artifacts and how to upload them to Sentry.", + "You didn't upload any artifacts with debug IDs yet. Read the [link:Sentry Source Maps Documentation] to learn how to inject Debug IDs into your build artifacts and how to upload them to Sentry.", { link: ( @@ -705,11 +639,11 @@ function UploadedSourceMapWithCorrectDebugIdChecklistItem({ function EventHasReleaseNameChecklistItem({ sourceResolutionResults, }: { - sourceResolutionResults: SourceResolutionResults; + sourceResolutionResults: FrameSourceMapDebuggerData; }) { const itemName = t('Event has release value'); - if (sourceResolutionResults.releaseName !== null) { + if (sourceResolutionResults.release !== null) { return ; } @@ -748,7 +682,7 @@ function ReleaseHasUploadedArtifactsChecklistItem({ shouldValidate, }: { shouldValidate: boolean; - sourceResolutionResults: SourceResolutionResults; + sourceResolutionResults: FrameSourceMapDebuggerData; }) { const itemName = t('Release has uploaded artifacts'); @@ -756,7 +690,7 @@ function ReleaseHasUploadedArtifactsChecklistItem({ return ; } - if (sourceResolutionResults.uploadedSomeArtifactToRelease) { + if (sourceResolutionResults.releaseHasSomeArtifact) { return ; } @@ -768,7 +702,7 @@ function ReleaseHasUploadedArtifactsChecklistItem({ {t( "The release this event belongs to doesn't have any uploaded artifacts. Upload your build artifacts to Sentry using the release:" )}{' '} - {sourceResolutionResults.releaseName} + {sourceResolutionResults.release}

{tct( @@ -790,7 +724,7 @@ function ReleaseSourceFileMatchingChecklistItem({ shouldValidate, }: { shouldValidate: boolean; - sourceResolutionResults: SourceResolutionResults; + sourceResolutionResults: FrameSourceMapDebuggerData; }) { const itemName = t('Stack frame path matches source file artifact'); @@ -812,11 +746,11 @@ function ReleaseSourceFileMatchingChecklistItem({ 'You uploaded a source file artifact with the right name, however the dist value on this event does not match the dist value on the artifact.' )}

- {sourceResolutionResults.distName !== null ? ( + {sourceResolutionResults.dist !== null ? (

{tct( 'Upload your build artifacts to Sentry using the dist [dist] or adjust the dist value in your SDK options.', - {dist: {sourceResolutionResults.distName}} + {dist: {sourceResolutionResults.dist}} )}

) : ( @@ -862,11 +796,20 @@ function ReleaseSourceFileMatchingChecklistItem({ )}

- {t( - 'Upload a source file with exactly the same name or a protocol + hostname prefix:' - )}{' '} - {sourceResolutionResults.matchingArtifactName} + {tct( + 'Upload a source file with exactly one of the following names ([tilde] acts as a wildcard for protocol and hostname):', + { + tilde: ~, + } + )}

+ + {sourceResolutionResults.matchingSourceFileNames.map(mathingSourceFileName => ( +
  • + {mathingSourceFileName} +
  • + ))} +

    {t( "Refer to the documentation of the tool you're using to upload source files to understand how to change artifact names." @@ -892,7 +835,7 @@ function ReleaseSourceMapMatchingChecklistItem({ shouldValidate, }: { shouldValidate: boolean; - sourceResolutionResults: SourceResolutionResults; + sourceResolutionResults: FrameSourceMapDebuggerData; }) { const itemName = t('Source map reference matches source map artifact name'); @@ -937,11 +880,11 @@ function ReleaseSourceMapMatchingChecklistItem({ 'You uploaded a source map artifact with the right name, however the dist value on this event does not match the dist value on the artifact.' )}

    - {sourceResolutionResults.distName !== null ? ( + {sourceResolutionResults.dist !== null ? (

    {tct( 'Upload your build artifacts to Sentry using the dist [dist] or adjust the dist value in your SDK options.', - {dist: {sourceResolutionResults.distName}} + {dist: {sourceResolutionResults.dist}} )}

    ) : ( @@ -965,19 +908,17 @@ function ReleaseSourceMapMatchingChecklistItem({
    {t('Not Found')}

    {tct( - 'The source file had a source map reference [sourceMapReference], but there was no source map artifact uploaded at that location. Make sure to generate and upload all of your source maps!', + 'The source file had a source map reference [sourceMapReference], but there was no source map artifact uploaded at that location. Make sure to generate and upload a source map named [matchingSourceMap] to symbolicate this stack frame!', { sourceMapReference: ( {sourceResolutionResults.releaseSourceMapReference} ), + matchingSourceMap: ( + {sourceResolutionResults.matchingSourceMapName} + ), } )}

    -

    - {t( - 'Note, that if the source map reference is a relative path, Sentry will look for a source map artifact relative to the source file that contains the source map reference.' - )} -

    {/* TODO: Link to Uploaded Artifacts */}
    @@ -988,7 +929,7 @@ function ReleaseSourceMapMatchingChecklistItem({ function ScrapingSourceFileAvailableChecklistItem({ sourceResolutionResults, }: { - sourceResolutionResults: SourceResolutionResults; + sourceResolutionResults: FrameSourceMapDebuggerData; }) { const itemName = t('Source file available to Sentry'); @@ -1034,7 +975,7 @@ function ScrapingSourceMapAvailableChecklistItem({ shouldValidate, }: { shouldValidate: boolean; - sourceResolutionResults: SourceResolutionResults; + sourceResolutionResults: FrameSourceMapDebuggerData; }) { const itemName = t('Source map available to Sentry'); @@ -1227,3 +1168,11 @@ const WizardInstructionParagraph = styled('p')` const InstructionCodeSnippet = styled(CodeSnippet)` margin: ${space(1)} 0 ${space(2)}; `; + +const InstructionList = styled('ul')` + margin-bottom: ${space(1.5)}; + + li { + margin-bottom: ${space(0.5)}; + } +`;