mirror of
https://github.com/hanzoai/sentinel.git
synced 2026-09-29 22:34:33 +00:00
154 lines
4.7 KiB
TypeScript
154 lines
4.7 KiB
TypeScript
import {Fragment} from 'react';
|
|
import styled from '@emotion/styled';
|
|
|
|
import {addErrorMessage, addSuccessMessage} from 'sentry/actionCreators/indicator';
|
|
import {openModal} from 'sentry/actionCreators/modal';
|
|
import IssueSyncListElement from 'sentry/components/issueSyncListElement';
|
|
import {t} from 'sentry/locale';
|
|
import {space} from 'sentry/styles/space';
|
|
import type {Group, GroupIntegration} from 'sentry/types';
|
|
import {trackAnalytics} from 'sentry/utils/analytics';
|
|
import {getAnalyticsDataForGroup} from 'sentry/utils/events';
|
|
import useApi from 'sentry/utils/useApi';
|
|
import useOrganization from 'sentry/utils/useOrganization';
|
|
import IntegrationItem from 'sentry/views/settings/organizationIntegrations/integrationItem';
|
|
|
|
import ExternalIssueForm from '../externalIssueForm';
|
|
|
|
type Props = {
|
|
configurations: GroupIntegration[];
|
|
group: Group;
|
|
onChange: (onSuccess?: () => void, onError?: () => void) => void;
|
|
};
|
|
|
|
type LinkedIssues = {
|
|
linked: GroupIntegration[];
|
|
unlinked: GroupIntegration[];
|
|
};
|
|
|
|
function ExternalIssueActions({configurations, group, onChange}: Props) {
|
|
const organization = useOrganization();
|
|
const api = useApi();
|
|
const {linked, unlinked} = configurations
|
|
.sort((a, b) => a.name.toLowerCase().localeCompare(b.name.toLowerCase()))
|
|
.reduce(
|
|
(acc: LinkedIssues, curr) => {
|
|
if (curr.externalIssues.length) {
|
|
acc.linked.push(curr);
|
|
} else {
|
|
acc.unlinked.push(curr);
|
|
}
|
|
return acc;
|
|
},
|
|
{linked: [], unlinked: []}
|
|
);
|
|
|
|
const deleteIssue = (integration: GroupIntegration) => {
|
|
const {externalIssues} = integration;
|
|
// Currently we do not support a case where there is multiple external issues.
|
|
// For example, we shouldn't have more than 1 jira ticket created for an issue for each jira configuration.
|
|
const issue = externalIssues[0];
|
|
const {id} = issue;
|
|
const endpoint = `/organizations/${organization.slug}/issues/${group.id}/integrations/${integration.id}/?externalIssue=${id}`;
|
|
|
|
api.request(endpoint, {
|
|
method: 'DELETE',
|
|
success: () => {
|
|
onChange(
|
|
() => addSuccessMessage(t('Successfully unlinked issue.')),
|
|
() => addErrorMessage(t('Unable to unlink issue.'))
|
|
);
|
|
},
|
|
error: () => {
|
|
addErrorMessage(t('Unable to unlink issue.'));
|
|
},
|
|
});
|
|
};
|
|
|
|
const doOpenModal = (integration: GroupIntegration) => {
|
|
trackAnalytics('issue_details.external_issue_modal_opened', {
|
|
organization,
|
|
...getAnalyticsDataForGroup(group),
|
|
external_issue_provider: integration.provider.key,
|
|
external_issue_type: 'first_party',
|
|
});
|
|
|
|
openModal(
|
|
deps => (
|
|
<ExternalIssueForm {...deps} {...{group, onChange, integration, organization}} />
|
|
),
|
|
{closeEvents: 'escape-key'}
|
|
);
|
|
};
|
|
|
|
return (
|
|
<Fragment>
|
|
{linked.map(config => {
|
|
const {provider, externalIssues} = config;
|
|
const issue = externalIssues[0];
|
|
return (
|
|
<IssueSyncListElement
|
|
key={issue.id}
|
|
externalIssueLink={issue.url}
|
|
externalIssueId={issue.id}
|
|
externalIssueKey={issue.key}
|
|
externalIssueDisplayName={issue.displayName}
|
|
onClose={() => deleteIssue(config)}
|
|
integrationType={provider.key}
|
|
hoverCardHeader={t('%s Integration', provider.name)}
|
|
hoverCardBody={
|
|
<div>
|
|
<IssueTitle>{issue.title}</IssueTitle>
|
|
{issue.description && (
|
|
<IssueDescription>{issue.description}</IssueDescription>
|
|
)}
|
|
</div>
|
|
}
|
|
/>
|
|
);
|
|
})}
|
|
|
|
{unlinked.length > 0 && (
|
|
<IssueSyncListElement
|
|
integrationType={unlinked[0].provider.key}
|
|
hoverCardHeader={t('%s Integration', unlinked[0].provider.name)}
|
|
hoverCardBody={
|
|
<Container>
|
|
{unlinked.map(config => (
|
|
<Wrapper onClick={() => doOpenModal(config)} key={config.id}>
|
|
<IntegrationItem integration={config} />
|
|
</Wrapper>
|
|
))}
|
|
</Container>
|
|
}
|
|
onOpen={unlinked.length === 1 ? () => doOpenModal(unlinked[0]) : undefined}
|
|
/>
|
|
)}
|
|
</Fragment>
|
|
);
|
|
}
|
|
|
|
const IssueTitle = styled('div')`
|
|
font-size: 1.1em;
|
|
font-weight: 600;
|
|
${p => p.theme.overflowEllipsis};
|
|
`;
|
|
|
|
const IssueDescription = styled('div')`
|
|
margin-top: ${space(1)};
|
|
${p => p.theme.overflowEllipsis};
|
|
`;
|
|
|
|
const Wrapper = styled('div')`
|
|
margin-bottom: ${space(2)};
|
|
cursor: pointer;
|
|
`;
|
|
|
|
const Container = styled('div')`
|
|
& > div:last-child {
|
|
margin-bottom: ${space(1)};
|
|
}
|
|
`;
|
|
|
|
export default ExternalIssueActions;
|