123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156 |
- import {Fragment, useMemo} from 'react';
- import moment from 'moment-timezone';
- import {LinkButton} from 'sentry/components/button';
- import {DateTime} from 'sentry/components/dateTime';
- import {t} from 'sentry/locale';
- import type {Event} from 'sentry/types/event';
- import type {Group} from 'sentry/types/group';
- import type {Organization} from 'sentry/types/organization';
- import type {Project} from 'sentry/types/project';
- import {useApiQuery} from 'sentry/utils/queryClient';
- import {useLocation} from 'sentry/utils/useLocation';
- import type {TimePeriodType} from 'sentry/views/alerts/rules/metric/details/constants';
- import RelatedIssues from 'sentry/views/alerts/rules/metric/details/relatedIssues';
- import RelatedTransactions from 'sentry/views/alerts/rules/metric/details/relatedTransactions';
- import {
- Dataset,
- type MetricRule,
- TimePeriod,
- } from 'sentry/views/alerts/rules/metric/types';
- import {extractEventTypeFilterFromRule} from 'sentry/views/alerts/rules/metric/utils/getEventTypeFilter';
- import {isCrashFreeAlert} from 'sentry/views/alerts/rules/metric/utils/isCrashFreeAlert';
- import {SectionKey} from 'sentry/views/issueDetails/streamline/context';
- import {InterimSection} from 'sentry/views/issueDetails/streamline/interimSection';
- interface MetricIssuesSectionProps {
- event: Event;
- group: Group;
- organization: Organization;
- project: Project;
- }
- export default function MetricIssuesSection({
- organization,
- event,
- group,
- project,
- }: MetricIssuesSectionProps) {
- const location = useLocation();
- const ruleId = event.contexts?.metric_alert?.alert_rule_id;
- const {data: rule} = useApiQuery<MetricRule>(
- [
- `/organizations/${organization.slug}/alert-rules/${ruleId}/`,
- {
- query: {
- expand: 'latestIncident',
- },
- },
- ],
- {
- staleTime: Infinity,
- retry: false,
- }
- );
- const openPeriod = group.openPeriods?.[0];
- const timePeriod = useMemo((): TimePeriodType | null => {
- if (!openPeriod) {
- return null;
- }
- const start = openPeriod.start;
- let end = openPeriod.end;
- if (!end) {
- end = new Date().toISOString();
- }
- return {
- start,
- end,
- period: TimePeriod.SEVEN_DAYS,
- usingPeriod: false,
- label: t('Custom time'),
- display: (
- <Fragment>
- <DateTime date={moment.utc(start)} />
- {' — '}
- <DateTime date={moment.utc(end)} />
- </Fragment>
- ),
- custom: true,
- };
- }, [openPeriod]);
- if (!rule || !timePeriod) {
- return null;
- }
- const {dataset, query} = rule;
- if ([Dataset.METRICS, Dataset.SESSIONS, Dataset.ERRORS].includes(dataset)) {
- const queryParams = {
- start: timePeriod.start,
- end: timePeriod.end,
- groupStatsPeriod: 'auto',
- ...(rule.environment ? {environment: rule.environment} : {}),
- sort: rule.aggregate === 'count_unique(user)' ? 'user' : 'freq',
- query,
- project: [project.id],
- };
- const issueSearch = {
- pathname: `/organizations/${organization.slug}/issues/`,
- query: queryParams,
- };
- const actions = (
- <LinkButton data-test-id="issues-open" size="xs" to={issueSearch}>
- {t('Open in Issues')}
- </LinkButton>
- );
- return (
- <InterimSection
- title={t('Correlated Issues')}
- type={SectionKey.CORRELATED_ISSUES}
- help={t('A list of issues that are correlated with this event')}
- actions={actions}
- >
- <RelatedIssues
- organization={organization}
- rule={rule}
- projects={[project]}
- timePeriod={timePeriod}
- query={
- dataset === Dataset.ERRORS
- ? // Not using (query) AND (event.type:x) because issues doesn't support it yet
- `${extractEventTypeFilterFromRule(rule)} ${query}`.trim()
- : isCrashFreeAlert(dataset)
- ? `${query} error.unhandled:true`.trim()
- : undefined
- }
- skipHeader
- />
- </InterimSection>
- );
- }
- if ([Dataset.TRANSACTIONS, Dataset.GENERIC_METRICS].includes(dataset)) {
- return (
- <InterimSection
- title={t('Correlated Transactions')}
- type={SectionKey.CORRELATED_TRANSACTIONS}
- help={t('A list of transactions that are correlated with this event')}
- >
- <RelatedTransactions
- organization={organization}
- location={location}
- rule={rule}
- projects={[project]}
- timePeriod={timePeriod}
- filter={extractEventTypeFilterFromRule(rule)}
- />
- </InterimSection>
- );
- }
- return null;
- }
|