import {Fragment} from 'react';
import styled from '@emotion/styled';
import {LinkButton} from 'sentry/components/button';
import GroupList from 'sentry/components/issues/groupList';
import Link from 'sentry/components/links/link';
import LoadingError from 'sentry/components/loadingError';
import LoadingIndicator from 'sentry/components/loadingIndicator';
import {t} from 'sentry/locale';
import {space} from 'sentry/styles/space';
import {useApiQuery} from 'sentry/utils/queryClient';
import useOrganization from 'sentry/utils/useOrganization';
import {useParams} from 'sentry/utils/useParams';
type RelatedIssuesResponse = {
data: number[];
meta: {
event_id: string;
trace_id: string;
};
type: string;
};
interface RelatedIssuesSectionProps {
groupId: string;
orgSlug: string;
relationType: string;
}
function GroupRelatedIssues() {
const params = useParams<{groupId: string}>();
const organization = useOrganization();
const orgSlug = organization.slug;
return (
);
}
function RelatedIssuesSection({
groupId,
orgSlug,
relationType,
}: RelatedIssuesSectionProps) {
// Fetch the list of related issues
const {
isPending,
isError,
data: relatedIssues,
refetch,
} = useApiQuery(
[`/issues/${groupId}/related-issues/?type=${relationType}`],
{
staleTime: 0,
}
);
const traceMeta = relationType === 'trace_connected' ? relatedIssues?.meta : undefined;
const issues = relatedIssues?.data ?? [];
const query = `issue.id:[${issues}]`;
// project=-1 allows ensuring that the query will show issues from any projects for the org
// This is important for traces since issues can be for any project in the org
const baseUrl = `/organizations/${orgSlug}/issues/?project=-1`;
let title: React.ReactNode = null;
let extraInfo: React.ReactNode = null;
let openIssuesButton: React.ReactNode = null;
if (relationType === 'trace_connected' && traceMeta) {
({title, extraInfo, openIssuesButton} = getTraceConnectedContent(
traceMeta,
baseUrl,
orgSlug
));
} else {
title = t('Issues with similar titles');
extraInfo = t(
'These issues have the same title and may have been caused by the same root cause.'
);
openIssuesButton = getLinkButton(
`${baseUrl}&query=issue.id:[${groupId},${issues}]`,
'Clicked Open Issues from same-root related issues',
'similar_issues.same_root_cause_clicked_open_issues'
);
}
return (
{isPending ? (
) : isError ? (
) : issues.length > 0 ? (
{title}
{extraInfo}
{openIssuesButton}
) : null}
);
}
const getTraceConnectedContent = (
traceMeta: RelatedIssuesResponse['meta'],
baseUrl: string,
orgSlug: string
) => {
const title = t('Issues in the same trace');
const url = `/organizations/${orgSlug}/performance/trace/${traceMeta.trace_id}/?node=error-${traceMeta.event_id}`;
const extraInfo = (
{t('These issues were all found within')}
{t('this trace')}.
);
const openIssuesButton = getLinkButton(
`${baseUrl}&query=trace:${traceMeta.trace_id}`,
'Clicked Open Issues from trace-connected related issues',
'similar_issues.trace_connected_issues_clicked_open_issues'
);
return {title, extraInfo, openIssuesButton};
};
const getLinkButton = (to: string, eventName: string, eventKey: string) => {
return (
{t('Open in Issues')}
);
};
// Export the component without feature flag controls
export {GroupRelatedIssues};
const Title = styled('h4')`
font-size: ${p => p.theme.fontSizeLarge};
margin-bottom: ${space(0.75)};
`;
const HeaderWrapper = styled('div')`
margin-bottom: ${space(2)};
small {
color: ${p => p.theme.subText};
}
`;
const TextButtonWrapper = styled('div')`
align-items: center;
display: flex;
justify-content: space-between;
margin-bottom: ${space(1)};
width: 100%;
`;