import {Fragment, useEffect} from 'react'; import type {RouteComponentProps} from 'react-router'; import styled from '@emotion/styled'; import isEqual from 'lodash/isEqual'; import ArchivedBox from 'sentry/components/archivedBox'; import GroupEventDetailsLoadingError from 'sentry/components/errors/groupEventDetailsLoadingError'; import {withMeta} from 'sentry/components/events/meta/metaProxy'; import HookOrDefault from 'sentry/components/hookOrDefault'; import * as Layout from 'sentry/components/layouts/thirds'; import LoadingIndicator from 'sentry/components/loadingIndicator'; import {TransactionProfileIdProvider} from 'sentry/components/profiling/transactionProfileIdProvider'; import ResolutionBox from 'sentry/components/resolutionBox'; import useSentryAppComponentsData from 'sentry/stores/useSentryAppComponentsData'; import {space} from 'sentry/styles/space'; import type { Group, GroupActivityReprocess, GroupReprocessing, Organization, Project, } from 'sentry/types'; import type {Event} from 'sentry/types/event'; import {defined} from 'sentry/utils'; import {browserHistory} from 'sentry/utils/browserHistory'; import {getConfigForIssueType} from 'sentry/utils/issueTypeConfig'; import {VisuallyCompleteWithData} from 'sentry/utils/performanceForSentry'; import usePrevious from 'sentry/utils/usePrevious'; import {normalizeUrl} from 'sentry/utils/withDomainRequired'; import GroupEventDetailsContent from 'sentry/views/issueDetails/groupEventDetails/groupEventDetailsContent'; import GroupEventHeader from 'sentry/views/issueDetails/groupEventHeader'; import GroupSidebar from 'sentry/views/issueDetails/groupSidebar'; import ReprocessingProgress from '../reprocessingProgress'; import { getEventEnvironment, getGroupMostRecentActivity, ReprocessingStatus, useEnvironmentsFromUrl, } from '../utils'; const EscalatingIssuesFeedback = HookOrDefault({ hookName: 'component:escalating-issues-banner-feedback', }); export interface GroupEventDetailsProps extends RouteComponentProps<{groupId: string; eventId?: string}, {}> { eventError: boolean; group: Group; groupReprocessingStatus: ReprocessingStatus; loadingEvent: boolean; onRetry: () => void; organization: Organization; project: Project; event?: Event; } function GroupEventDetails(props: GroupEventDetailsProps) { const { group, project, organization, location, event, groupReprocessingStatus, loadingEvent, onRetry, eventError, params, } = props; const projectId = project.id; const environments = useEnvironmentsFromUrl(); const prevEnvironment = usePrevious(environments); const prevEvent = usePrevious(event); // load the data useSentryAppComponentsData({projectId}); // If environments are being actively changed and will no longer contain the // current event's environment, redirect to latest useEffect(() => { const environmentsHaveChanged = !isEqual(prevEnvironment, environments); // If environments are being actively changed and will no longer contain the // current event's environment, redirect to latest if ( environmentsHaveChanged && prevEvent && params.eventId && !['latest', 'oldest'].includes(params.eventId) ) { const shouldRedirect = environments.length > 0 && !environments.find(env => env === getEventEnvironment(prevEvent as Event)); if (shouldRedirect) { browserHistory.replace( normalizeUrl({ pathname: `/organizations/${organization.slug}/issues/${params.groupId}/`, query: location.query, }) ); return; } } }, [ prevEnvironment, environments, location.query, organization.slug, params, prevEvent, ]); const renderGroupStatusBanner = () => { if (group.status === 'ignored') { return ( ); } if (group.status === 'resolved') { return ( ); } return null; }; const renderContent = () => { if (loadingEvent) { return ; } if (eventError) { return ( ); } return ( ); }; const eventWithMeta = withMeta(event); const issueTypeConfig = getConfigForIssueType(group, project); return ( {groupReprocessingStatus === ReprocessingStatus.REPROCESSING ? ( ) : ( {renderGroupStatusBanner()} {eventWithMeta && issueTypeConfig.stats.enabled && ( )} {renderContent()} )} ); } const StyledLayoutBody = styled(Layout.Body)` /* Makes the borders align correctly */ padding: 0 !important; @media (min-width: ${p => p.theme.breakpoints.large}) { align-content: stretch; } `; const GroupStatusBannerWrapper = styled('div')` margin-bottom: ${space(2)}; `; const StyledLayoutMain = styled(Layout.Main)` padding-top: ${space(2)}; @media (max-width: ${p => p.theme.breakpoints.medium}) { padding-top: ${space(1)}; } @media (min-width: ${p => p.theme.breakpoints.large}) { border-right: 1px solid ${p => p.theme.border}; padding-right: 0; } `; const StyledLayoutSide = styled(Layout.Side)` padding: ${space(3)} ${space(2)} ${space(3)}; @media (min-width: ${p => p.theme.breakpoints.large}) { padding-right: ${space(4)}; padding-left: 0; } `; export default GroupEventDetails;