123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197 |
- import {Fragment, useEffect} from 'react';
- import styled from '@emotion/styled';
- import type {Location} from 'history';
- import {
- getStacktrace,
- StackTracePreviewContent,
- } from 'sentry/components/groupPreviewTooltip/stackTracePreview';
- import {t} from 'sentry/locale';
- import {space} from 'sentry/styles/space';
- import type {Event} from 'sentry/types/event';
- import type {Project} from 'sentry/types/project';
- import {trackAnalytics} from 'sentry/utils/analytics';
- import type EventView from 'sentry/utils/discover/eventView';
- import getDuration from 'sentry/utils/duration/getDuration';
- import {useApiQuery} from 'sentry/utils/queryClient';
- import {
- getStatusBodyText,
- HttpStatus,
- } from 'sentry/views/performance/transactionDetails/eventMetas';
- import ActionDropDown, {ContextValueType} from './actionDropdown';
- import {NoContext} from './quickContextWrapper';
- import {
- ContextBody,
- ContextContainer,
- ContextHeader,
- ContextRow,
- ContextTitle,
- NoContextWrapper,
- Wrapper,
- } from './styles';
- import type {BaseContextProps} from './utils';
- import {ContextType, tenSecondInMs} from './utils';
- interface EventContextProps extends BaseContextProps {
- eventView?: EventView;
- location?: Location;
- projects?: Project[];
- }
- function EventContext(props: EventContextProps) {
- const {organization, dataRow, eventView, location} = props;
- const {isPending, isError, data} = useApiQuery<Event>(
- [
- `/organizations/${organization.slug}/events/${dataRow['project.name']}:${dataRow.id}/`,
- ],
- {
- staleTime: tenSecondInMs,
- }
- );
- useEffect(() => {
- if (data) {
- trackAnalytics('discover_v2.quick_context_hover_contexts', {
- organization,
- contextType: ContextType.EVENT,
- eventType: data.type,
- });
- }
- }, [data, organization]);
- if (isPending || isError) {
- return <NoContext isLoading={isPending} />;
- }
- if (data.type === 'transaction') {
- const transactionDuration = getDuration(
- data.endTimestamp - data.startTimestamp,
- 2,
- true
- );
- const status = getStatusBodyText(data);
- return (
- <Wrapper data-test-id="quick-context-hover-body">
- <EventContextContainer>
- <ContextHeader>
- <ContextTitle>{t('Transaction Duration')}</ContextTitle>
- {location && eventView && (
- <ActionDropDown
- dataRow={dataRow}
- contextValueType={ContextValueType.DURATION}
- location={location}
- eventView={eventView}
- organization={organization}
- queryKey="transaction.duration"
- value={transactionDuration}
- />
- )}
- </ContextHeader>
- <EventContextBody>{transactionDuration}</EventContextBody>
- </EventContextContainer>
- {location && (
- <EventContextContainer>
- <Fragment>
- <ContextHeader>
- <ContextTitle>{t('Status')}</ContextTitle>
- {location && eventView && (
- <ActionDropDown
- dataRow={dataRow}
- contextValueType={ContextValueType.STRING}
- location={location}
- eventView={eventView}
- organization={organization}
- queryKey="transaction.status"
- value={status}
- />
- )}
- </ContextHeader>
- <EventContextBody>
- <ContextRow>
- {status}
- <HttpStatusWrapper>
- (<HttpStatus event={data} />)
- </HttpStatusWrapper>
- </ContextRow>
- </EventContextBody>
- </Fragment>
- </EventContextContainer>
- )}
- </Wrapper>
- );
- }
- const stackTrace = getStacktrace(data);
- return stackTrace ? (
- <Fragment>
- {!dataRow.title && (
- <ErrorTitleContainer>
- <ContextHeader>
- <ContextTitle>{t('Title')}</ContextTitle>
- {location && eventView && (
- <ActionDropDown
- dataRow={dataRow}
- contextValueType={ContextValueType.STRING}
- location={location}
- eventView={eventView}
- organization={organization}
- queryKey="title"
- value={data.title}
- />
- )}
- </ContextHeader>
- <ErrorTitleBody>{data.title}</ErrorTitleBody>
- </ErrorTitleContainer>
- )}
- <StackTraceWrapper>
- <StackTracePreviewContent event={data} stacktrace={stackTrace} />
- </StackTraceWrapper>
- </Fragment>
- ) : (
- <NoContextWrapper>
- {t('There is no stack trace available for this event.')}
- </NoContextWrapper>
- );
- }
- const ErrorTitleContainer = styled(ContextContainer)`
- padding: ${space(1.5)};
- `;
- const ErrorTitleBody = styled(ContextBody)`
- margin: 0;
- max-width: 450px;
- ${p => p.theme.overflowEllipsis}
- `;
- const EventContextBody = styled(ContextBody)`
- font-size: ${p => p.theme.fontSizeExtraLarge};
- margin: 0;
- align-items: flex-start;
- flex-direction: column;
- `;
- const EventContextContainer = styled(ContextContainer)`
- & + & {
- margin-top: ${space(2)};
- }
- `;
- const StackTraceWrapper = styled('div')`
- overflow: hidden;
- max-height: 300px;
- width: 500px;
- overflow-y: auto;
- .traceback {
- margin-bottom: 0;
- border: 0;
- }
- border-radius: ${p => p.theme.borderRadius};
- `;
- const HttpStatusWrapper = styled('span')`
- margin-left: ${space(0.5)};
- `;
- export default EventContext;
|