import {Fragment} from 'react';
import styled from '@emotion/styled';
import AlertLink from 'sentry/components/alertLink';
import {Button, type ButtonProps, LinkButton} from 'sentry/components/button';
import DropdownButton from 'sentry/components/dropdownButton';
import {DropdownMenu} from 'sentry/components/dropdownMenu';
import ErrorBoundary from 'sentry/components/errorBoundary';
import type {ExternalIssueAction} from 'sentry/components/group/externalIssuesList/hooks/types';
import useGroupExternalIssues from 'sentry/components/group/externalIssuesList/hooks/useGroupExternalIssues';
import Placeholder from 'sentry/components/placeholder';
import * as SidebarSection from 'sentry/components/sidebarSection';
import {Tooltip} from 'sentry/components/tooltip';
import {t} from 'sentry/locale';
import {space} from 'sentry/styles/space';
import type {Event} from 'sentry/types/event';
import type {Group} from 'sentry/types/group';
import type {Project} from 'sentry/types/project';
import useOrganization from 'sentry/utils/useOrganization';
import {SidebarSectionTitle} from 'sentry/views/issueDetails/streamline/sidebar/sidebar';
function getActionLabelAndTextValue({
action,
integrationDisplayName,
}: {
action: ExternalIssueAction;
integrationDisplayName: string;
}): {label: string | JSX.Element; textValue: string} {
// If there's no subtext or subtext matches name, just show name
if (!action.nameSubText || action.nameSubText === action.name) {
return {
label: action.name,
textValue: action.name,
};
}
// If action name matches integration name, just show subtext
if (action.name === integrationDisplayName) {
return {
label: action.nameSubText,
textValue: `${action.name} ${action.nameSubText}`,
};
}
// Otherwise show both name and subtext
return {
label: (
{action.name}
{action.nameSubText}
),
textValue: `${action.name} ${action.nameSubText}`,
};
}
interface ExternalIssueListProps {
event: Event;
group: Group;
project: Project;
}
export function ExternalIssueList({group, event, project}: ExternalIssueListProps) {
const organization = useOrganization();
const {isLoading, integrations, linkedIssues} = useGroupExternalIssues({
group,
event,
project,
});
if (isLoading) {
return (
);
}
return (
{t('Issue Tracking')}
{integrations.length || linkedIssues.length ? (
{linkedIssues.map(linkedIssue => (
{linkedIssue.title}
{t('Unlink issue')}
}
isHoverable
>
{linkedIssue.displayName}
))}
{integrations.map(integration => {
const sharedButtonProps: ButtonProps = {
size: 'zero',
icon: integration.displayIcon,
children: {integration.displayName},
};
if (integration.actions.length === 1) {
return (
);
}
return (
(
)}
items={integration.actions.map(action => ({
key: action.id,
...getActionLabelAndTextValue({
action,
integrationDisplayName: integration.displayName,
}),
onAction: action.onClick,
disabled: integration.disabled,
}))}
/>
);
})}
) : (
{t('Track this issue in Jira, GitHub, etc.')}
)}
);
}
const IssueActionWrapper = styled('div')`
display: flex;
flex-wrap: wrap;
gap: ${space(1)};
line-height: 1.2;
&:not(:last-child) {
margin-bottom: ${space(1)};
}
`;
const LinkedIssue = styled(LinkButton)`
display: flex;
align-items: center;
padding: ${space(0.5)} ${space(0.75)};
border: 1px solid ${p => p.theme.border};
border-radius: ${p => p.theme.borderRadius};
font-weight: normal;
`;
const IssueActionButton = styled(Button)`
display: flex;
align-items: center;
padding: ${space(0.5)} ${space(0.75)};
border: 1px dashed ${p => p.theme.border};
border-radius: ${p => p.theme.borderRadius};
font-weight: normal;
`;
const IssueActionDropdownMenu = styled(DropdownButton)`
display: flex;
align-items: center;
padding: ${space(0.5)} ${space(0.75)};
border: 1px dashed ${p => p.theme.border};
border-radius: ${p => p.theme.borderRadius};
font-weight: normal;
&[aria-expanded='true'] {
border: 1px solid ${p => p.theme.border};
}
`;
const IssueActionName = styled('div')`
${p => p.theme.overflowEllipsis}
max-width: 200px;
`;
const LinkedIssueTooltipWrapper = styled('div')`
display: flex;
align-items: center;
gap: ${space(0.5)};
white-space: nowrap;
`;
const LinkedIssueName = styled('div')`
${p => p.theme.overflowEllipsis}
margin-right: ${space(0.25)};
`;
const HorizontalSeparator = styled('div')`
width: 1px;
height: 14px;
background: ${p => p.theme.border};
`;
const UnlinkButton = styled(Button)`
color: ${p => p.theme.subText};
`;