mirror of
https://github.com/hanzoai/sentinel.git
synced 2026-10-30 14:49:14 +00:00
297 lines
11 KiB
TypeScript
297 lines
11 KiB
TypeScript
import {Fragment} from 'react';
|
|
import styled from '@emotion/styled';
|
|
|
|
import {CommitRow} from 'sentry/components/commitRow';
|
|
import ErrorBoundary from 'sentry/components/errorBoundary';
|
|
import {EventContexts} from 'sentry/components/events/contexts';
|
|
import {EventDevice} from 'sentry/components/events/device';
|
|
import {EventAttachments} from 'sentry/components/events/eventAttachments';
|
|
import {EventDataSection} from 'sentry/components/events/eventDataSection';
|
|
import {EventEntry} from 'sentry/components/events/eventEntry';
|
|
import {EventEvidence} from 'sentry/components/events/eventEvidence';
|
|
import {EventExtraData} from 'sentry/components/events/eventExtraData';
|
|
import EventReplay from 'sentry/components/events/eventReplay';
|
|
import {EventSdk} from 'sentry/components/events/eventSdk';
|
|
import AggregateSpanDiff from 'sentry/components/events/eventStatisticalDetector/aggregateSpanDiff';
|
|
import EventBreakpointChart from 'sentry/components/events/eventStatisticalDetector/breakpointChart';
|
|
import {EventAffectedTransactions} from 'sentry/components/events/eventStatisticalDetector/eventAffectedTransactions';
|
|
import EventComparison from 'sentry/components/events/eventStatisticalDetector/eventComparison';
|
|
import {EventDifferentialFlamegraph} from 'sentry/components/events/eventStatisticalDetector/eventDifferentialFlamegraph';
|
|
import {EventFunctionComparisonList} from 'sentry/components/events/eventStatisticalDetector/eventFunctionComparisonList';
|
|
import {EventRegressionSummary} from 'sentry/components/events/eventStatisticalDetector/eventRegressionSummary';
|
|
import {EventFunctionBreakpointChart} from 'sentry/components/events/eventStatisticalDetector/functionBreakpointChart';
|
|
import {TransactionsDeltaProvider} from 'sentry/components/events/eventStatisticalDetector/transactionsDeltaProvider';
|
|
import {EventTagsAndScreenshot} from 'sentry/components/events/eventTagsAndScreenshot';
|
|
import {EventViewHierarchy} from 'sentry/components/events/eventViewHierarchy';
|
|
import {EventGroupingInfo} from 'sentry/components/events/groupingInfo';
|
|
import {ActionableItems} from 'sentry/components/events/interfaces/crashContent/exception/actionableItems';
|
|
import {actionableItemsEnabled} from 'sentry/components/events/interfaces/crashContent/exception/useActionableItems';
|
|
import {CronTimelineSection} from 'sentry/components/events/interfaces/crons/cronTimelineSection';
|
|
import {AnrRootCause} from 'sentry/components/events/interfaces/performance/anrRootCause';
|
|
import {SpanEvidenceSection} from 'sentry/components/events/interfaces/performance/spanEvidence';
|
|
import {EventPackageData} from 'sentry/components/events/packageData';
|
|
import {EventRRWebIntegration} from 'sentry/components/events/rrwebIntegration';
|
|
import {DataSection} from 'sentry/components/events/styles';
|
|
import {SuspectCommits} from 'sentry/components/events/suspectCommits';
|
|
import {EventUserFeedback} from 'sentry/components/events/userFeedback';
|
|
import {t} from 'sentry/locale';
|
|
import {space} from 'sentry/styles/space';
|
|
import type {Event, Group, Project} from 'sentry/types';
|
|
import {IssueCategory, IssueType} from 'sentry/types';
|
|
import type {EventTransaction} from 'sentry/types/event';
|
|
import {EntryType} from 'sentry/types/event';
|
|
import {shouldShowCustomErrorResourceConfig} from 'sentry/utils/issueTypeConfig';
|
|
import {useLocation} from 'sentry/utils/useLocation';
|
|
import useOrganization from 'sentry/utils/useOrganization';
|
|
import {ResourcesAndMaybeSolutions} from 'sentry/views/issueDetails/resourcesAndMaybeSolutions';
|
|
|
|
type GroupEventDetailsContentProps = {
|
|
group: Group;
|
|
project: Project;
|
|
event?: Event;
|
|
};
|
|
|
|
type GroupEventEntryProps = {
|
|
entryType: EntryType;
|
|
event: Event;
|
|
group: Group;
|
|
project: Project;
|
|
};
|
|
|
|
function GroupEventEntry({event, entryType, group, project}: GroupEventEntryProps) {
|
|
const organization = useOrganization();
|
|
const matchingEntry = event.entries.find(entry => entry.type === entryType);
|
|
|
|
if (!matchingEntry) {
|
|
return null;
|
|
}
|
|
|
|
return (
|
|
<EventEntry
|
|
projectSlug={project.slug}
|
|
group={group}
|
|
entry={matchingEntry}
|
|
{...{organization, event}}
|
|
/>
|
|
);
|
|
}
|
|
|
|
function DefaultGroupEventDetailsContent({
|
|
group,
|
|
event,
|
|
project,
|
|
}: Required<GroupEventDetailsContentProps>) {
|
|
const organization = useOrganization();
|
|
const location = useLocation();
|
|
const projectSlug = project.slug;
|
|
const hasReplay = Boolean(event.tags?.find(({key}) => key === 'replayId')?.value);
|
|
const mechanism = event.tags?.find(({key}) => key === 'mechanism')?.value;
|
|
const isANR = mechanism === 'ANR' || mechanism === 'AppExitInfo';
|
|
const hasAnrImprovementsFeature = organization.features.includes('anr-improvements');
|
|
const showMaybeSolutionsHigher = shouldShowCustomErrorResourceConfig(group, project);
|
|
|
|
const eventEntryProps = {group, event, project};
|
|
|
|
const hasActionableItems = actionableItemsEnabled({
|
|
eventId: event.id,
|
|
organization,
|
|
projectSlug,
|
|
});
|
|
|
|
return (
|
|
<Fragment>
|
|
{hasActionableItems && (
|
|
<ActionableItems event={event} project={project} isShare={false} />
|
|
)}
|
|
<SuspectCommits
|
|
project={project}
|
|
eventId={event.id}
|
|
group={group}
|
|
commitRow={CommitRow}
|
|
/>
|
|
{event.userReport && (
|
|
<EventDataSection title="User Feedback" type="user-feedback">
|
|
<EventUserFeedback
|
|
report={event.userReport}
|
|
orgSlug={organization.slug}
|
|
issueId={group.id}
|
|
/>
|
|
</EventDataSection>
|
|
)}
|
|
{group.issueCategory === IssueCategory.CRON && (
|
|
<CronTimelineSection event={event} organization={organization} />
|
|
)}
|
|
<EventTagsAndScreenshot
|
|
event={event}
|
|
organization={organization}
|
|
projectSlug={project.slug}
|
|
location={location}
|
|
/>
|
|
{showMaybeSolutionsHigher && (
|
|
<ResourcesAndMaybeSolutions event={event} project={project} group={group} />
|
|
)}
|
|
<EventEvidence event={event} group={group} project={project} />
|
|
<GroupEventEntry entryType={EntryType.MESSAGE} {...eventEntryProps} />
|
|
<GroupEventEntry entryType={EntryType.EXCEPTION} {...eventEntryProps} />
|
|
<GroupEventEntry entryType={EntryType.STACKTRACE} {...eventEntryProps} />
|
|
<GroupEventEntry entryType={EntryType.THREADS} {...eventEntryProps} />
|
|
{hasAnrImprovementsFeature && isANR && (
|
|
<AnrRootCause event={event} organization={organization} />
|
|
)}
|
|
{group.issueCategory === IssueCategory.PERFORMANCE && (
|
|
<SpanEvidenceSection
|
|
event={event as EventTransaction}
|
|
organization={organization}
|
|
projectSlug={project.slug}
|
|
/>
|
|
)}
|
|
<EventReplay event={event} group={group} projectSlug={project.slug} />
|
|
<GroupEventEntry entryType={EntryType.HPKP} {...eventEntryProps} />
|
|
<GroupEventEntry entryType={EntryType.CSP} {...eventEntryProps} />
|
|
<GroupEventEntry entryType={EntryType.EXPECTCT} {...eventEntryProps} />
|
|
<GroupEventEntry entryType={EntryType.EXPECTSTAPLE} {...eventEntryProps} />
|
|
<GroupEventEntry entryType={EntryType.TEMPLATE} {...eventEntryProps} />
|
|
<GroupEventEntry entryType={EntryType.BREADCRUMBS} {...eventEntryProps} />
|
|
{!showMaybeSolutionsHigher && (
|
|
<ResourcesAndMaybeSolutions event={event} project={project} group={group} />
|
|
)}
|
|
<GroupEventEntry entryType={EntryType.DEBUGMETA} {...eventEntryProps} />
|
|
<GroupEventEntry entryType={EntryType.REQUEST} {...eventEntryProps} />
|
|
<EventContexts group={group} event={event} />
|
|
<EventExtraData event={event} />
|
|
<EventPackageData event={event} />
|
|
<EventDevice event={event} />
|
|
<EventViewHierarchy event={event} project={project} />
|
|
<EventAttachments event={event} projectSlug={project.slug} />
|
|
<EventSdk sdk={event.sdk} meta={event._meta?.sdk} />
|
|
{event.groupID && (
|
|
<EventGroupingInfo
|
|
projectSlug={project.slug}
|
|
event={event}
|
|
showGroupingConfig={
|
|
organization.features.includes('set-grouping-config') &&
|
|
'groupingConfig' in event
|
|
}
|
|
group={group}
|
|
/>
|
|
)}
|
|
|
|
{!hasReplay && (
|
|
<EventRRWebIntegration
|
|
event={event}
|
|
orgId={organization.slug}
|
|
projectSlug={project.slug}
|
|
/>
|
|
)}
|
|
</Fragment>
|
|
);
|
|
}
|
|
|
|
function PerformanceDurationRegressionIssueDetailsContent({
|
|
group,
|
|
event,
|
|
project,
|
|
}: Required<GroupEventDetailsContentProps>) {
|
|
return (
|
|
<Fragment>
|
|
<ErrorBoundary mini>
|
|
<EventRegressionSummary event={event} group={group} />
|
|
</ErrorBoundary>
|
|
<ErrorBoundary mini>
|
|
<EventBreakpointChart event={event} />
|
|
</ErrorBoundary>
|
|
<ErrorBoundary mini>
|
|
<AggregateSpanDiff event={event} project={project} />
|
|
</ErrorBoundary>
|
|
<ErrorBoundary mini>
|
|
<EventComparison event={event} project={project} />
|
|
</ErrorBoundary>
|
|
</Fragment>
|
|
);
|
|
}
|
|
|
|
function ProfilingDurationRegressionIssueDetailsContent({
|
|
group,
|
|
event,
|
|
project,
|
|
}: Required<GroupEventDetailsContentProps>) {
|
|
return (
|
|
<TransactionsDeltaProvider event={event} project={project}>
|
|
<Fragment>
|
|
<ErrorBoundary mini>
|
|
<EventRegressionSummary event={event} group={group} />
|
|
</ErrorBoundary>
|
|
<ErrorBoundary mini>
|
|
<EventFunctionBreakpointChart event={event} />
|
|
</ErrorBoundary>
|
|
<ErrorBoundary mini>
|
|
<EventAffectedTransactions event={event} group={group} project={project} />
|
|
</ErrorBoundary>
|
|
<ErrorBoundary mini>
|
|
<DataSection>
|
|
<b>{t('Largest Changes in Call Stack Frequency')}</b>
|
|
<p>
|
|
{t(`See which functions changed the most before and after the regression. The
|
|
frame with the largest increase in call stack population likely
|
|
contributed to the cause for the duration regression.`)}
|
|
</p>
|
|
|
|
<EventDifferentialFlamegraph event={event} />
|
|
</DataSection>
|
|
</ErrorBoundary>
|
|
<ErrorBoundary mini>
|
|
<EventFunctionComparisonList event={event} group={group} project={project} />
|
|
</ErrorBoundary>
|
|
</Fragment>
|
|
</TransactionsDeltaProvider>
|
|
);
|
|
}
|
|
|
|
function GroupEventDetailsContent({
|
|
group,
|
|
event,
|
|
project,
|
|
}: GroupEventDetailsContentProps) {
|
|
if (!event) {
|
|
return (
|
|
<NotFoundMessage>
|
|
<h3>{t('Latest event not available')}</h3>
|
|
</NotFoundMessage>
|
|
);
|
|
}
|
|
|
|
switch (group.issueType) {
|
|
case IssueType.PERFORMANCE_DURATION_REGRESSION:
|
|
case IssueType.PERFORMANCE_ENDPOINT_REGRESSION: {
|
|
return (
|
|
<PerformanceDurationRegressionIssueDetailsContent
|
|
group={group}
|
|
event={event}
|
|
project={project}
|
|
/>
|
|
);
|
|
}
|
|
case IssueType.PROFILE_FUNCTION_REGRESSION_EXPERIMENTAL:
|
|
case IssueType.PROFILE_FUNCTION_REGRESSION: {
|
|
return (
|
|
<ProfilingDurationRegressionIssueDetailsContent
|
|
group={group}
|
|
event={event}
|
|
project={project}
|
|
/>
|
|
);
|
|
}
|
|
default: {
|
|
return (
|
|
<DefaultGroupEventDetailsContent group={group} event={event} project={project} />
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
const NotFoundMessage = styled('div')`
|
|
padding: ${space(2)} ${space(4)};
|
|
`;
|
|
|
|
export default GroupEventDetailsContent;
|