Files
2024-02-15 17:01:50 +00:00

121 lines
3.4 KiB
TypeScript

import {Fragment, useMemo} from 'react';
import styled from '@emotion/styled';
import moment from 'moment';
import ActorAvatar from 'sentry/components/avatar/actorAvatar';
import Duration from 'sentry/components/duration';
import ErrorBoundary from 'sentry/components/errorBoundary';
import IdBadge from 'sentry/components/idBadge';
import Link from 'sentry/components/links/link';
import Tag from 'sentry/components/tag';
import TimeSince from 'sentry/components/timeSince';
import {t} from 'sentry/locale';
import TeamStore from 'sentry/stores/teamStore';
import {space} from 'sentry/styles/space';
import type {Actor, Organization, Project} from 'sentry/types';
import getDynamicText from 'sentry/utils/getDynamicText';
import type {Incident} from 'sentry/views/alerts/types';
import {IncidentStatus} from 'sentry/views/alerts/types';
import {alertDetailsLink} from 'sentry/views/alerts/utils';
type Props = {
incident: Incident;
organization: Organization;
projects: Project[];
projectsLoaded: boolean;
};
function AlertListRow({incident, projectsLoaded, projects, organization}: Props) {
const slug = incident.projects[0];
const started = moment(incident.dateStarted);
const duration = moment
.duration(moment(incident.dateClosed || new Date()).diff(started))
.as('seconds');
const project = useMemo(() => projects.find(p => p.slug === slug), [slug, projects]);
const alertLink = {
pathname: alertDetailsLink(organization, incident),
query: {alert: incident.identifier},
};
const ownerId = incident.alertRule.owner?.split(':')[1];
let teamName = '';
if (ownerId) {
teamName = TeamStore.getById(ownerId)?.name ?? '';
}
const teamActor = ownerId
? {type: 'team' as Actor['type'], id: ownerId, name: teamName}
: null;
return (
<ErrorBoundary>
<FlexCenter>
<Title data-test-id="alert-title">
<Link to={alertLink}>{incident.title}</Link>
</Title>
</FlexCenter>
<NoWrapNumeric>
{getDynamicText({
value: <TimeSince date={incident.dateStarted} unitStyle="extraShort" />,
fixed: '1w ago',
})}
</NoWrapNumeric>
<NoWrapNumeric>
{incident.status === IncidentStatus.CLOSED ? (
<Duration seconds={getDynamicText({value: duration, fixed: 1200})} />
) : (
<Tag type="warning">{t('Still Active')}</Tag>
)}
</NoWrapNumeric>
<FlexCenter>
<ProjectBadge avatarSize={18} project={!projectsLoaded ? {slug} : project} />
</FlexCenter>
<NoWrapNumeric>#{incident.id}</NoWrapNumeric>
<FlexCenter>
{teamActor ? (
<Fragment>
<StyledActorAvatar actor={teamActor} size={18} hasTooltip={false} />{' '}
<TeamWrapper>{teamActor.name}</TeamWrapper>
</Fragment>
) : (
'-'
)}
</FlexCenter>
</ErrorBoundary>
);
}
const Title = styled('div')`
${p => p.theme.overflowEllipsis}
min-width: 130px;
`;
const ProjectBadge = styled(IdBadge)`
flex-shrink: 0;
`;
const FlexCenter = styled('div')`
${p => p.theme.overflowEllipsis}
display: flex;
align-items: center;
line-height: 1.6;
`;
const NoWrapNumeric = styled(FlexCenter)`
white-space: nowrap;
font-variant-numeric: tabular-nums;
`;
const TeamWrapper = styled('span')`
${p => p.theme.overflowEllipsis}
`;
const StyledActorAvatar = styled(ActorAvatar)`
margin-right: ${space(1)};
`;
export default AlertListRow;