import {Fragment} from 'react';
import styled from '@emotion/styled';
import {deleteMonitor} from 'sentry/actionCreators/monitors';
import {openConfirmModal} from 'sentry/components/confirm';
import {DropdownMenu, MenuItemProps} from 'sentry/components/dropdownMenu';
import IdBadge from 'sentry/components/idBadge';
import Link from 'sentry/components/links/link';
import List from 'sentry/components/list';
import ListItem from 'sentry/components/list/listItem';
import Text from 'sentry/components/text';
import TextOverflow from 'sentry/components/textOverflow';
import TimeSince from 'sentry/components/timeSince';
import {IconEllipsis} from 'sentry/icons';
import {t, tct, tn} from 'sentry/locale';
import {space} from 'sentry/styles/space';
import {Organization} from 'sentry/types';
import useApi from 'sentry/utils/useApi';
import {normalizeUrl} from 'sentry/utils/withDomainRequired';
import {crontabAsText} from 'sentry/views/monitors/utils';
import {
Monitor,
MonitorConfig,
MonitorEnvironment,
MonitorStatus,
ScheduleType,
} from '../types';
import {MonitorBadge} from './monitorBadge';
interface MonitorRowProps {
monitor: Monitor;
onDelete: () => void;
organization: Organization;
monitorEnv?: MonitorEnvironment;
}
function scheduleAsText(config: MonitorConfig) {
// Crontab format uses cronstrue
if (config.schedule_type === ScheduleType.CRONTAB) {
const parsedSchedule = crontabAsText(config.schedule);
return parsedSchedule ?? t('Unknown schedule');
}
// Interval format is simpler
const [value, timeUnit] = config.schedule;
if (timeUnit === 'minute') {
return tn('Every minute', 'Every %s minutes', value);
}
if (timeUnit === 'hour') {
return tn('Every hour', 'Every %s hours', value);
}
if (timeUnit === 'day') {
return tn('Every day', 'Every %s days', value);
}
if (timeUnit === 'week') {
return tn('Every week', 'Every %s weeks', value);
}
if (timeUnit === 'month') {
return tn('Every month', 'Every %s months', value);
}
return t('Unknown schedule');
}
function MonitorRow({monitor, monitorEnv, organization, onDelete}: MonitorRowProps) {
const api = useApi();
const lastCheckin = monitorEnv?.lastCheckIn ? (
) : null;
const deletionModalMessage = (
{tct('Are you sure you want to permanently delete "[name]"?', {
name: monitor.name,
})}
{monitor.environments.length > 1 && (
{t(
`This will delete check-in data for this monitor associated with these environments:`
)}
{monitor.environments.map(environment => (
{environment.name}
))}
)}
);
const actions: MenuItemProps[] = [
{
key: 'edit',
label: t('Edit'),
to: normalizeUrl(`/organizations/${organization.slug}/crons/${monitor.slug}/edit/`),
},
{
key: 'delete',
label: t('Delete'),
priority: 'danger',
onAction: () => {
openConfirmModal({
onConfirm: async () => {
await deleteMonitor(api, organization.slug, monitor.slug);
onDelete();
},
header: t('Delete Monitor?'),
message: deletionModalMessage,
confirmText: t('Delete Monitor'),
priority: 'danger',
});
},
},
];
const monitorDetailUrl = `/organizations/${organization.slug}/crons/${monitor.slug}/${
monitorEnv ? `?environment=${monitorEnv.name}` : ''
}`;
// TODO(davidenwang): Change accordingly when we have ObjectStatus on monitor
const monitorStatus = monitorEnv ? monitorEnv.status : monitor.status;
return (
{monitor.name}
{monitor.slug}
{monitorStatus === MonitorStatus.DISABLED
? t('Paused')
: monitorStatus === MonitorStatus.ACTIVE || !lastCheckin
? t('Waiting for first check-in')
: monitorStatus === MonitorStatus.OK
? tct('Check-in [lastCheckin]', {lastCheckin})
: monitorStatus === MonitorStatus.MISSED_CHECKIN
? tct('Missed [lastCheckin]', {lastCheckin})
: monitorStatus === MonitorStatus.ERROR
? tct('Failed [lastCheckin]', {lastCheckin})
: null}
{scheduleAsText(monitor.config)}
{monitorEnv?.nextCheckIn &&
monitorEnv.status !== MonitorStatus.DISABLED &&
monitorEnv.status !== MonitorStatus.ACTIVE ? (
) : (
'\u2014'
)}
{monitorEnv?.name ?? '\u2014'}
,
showChevron: false,
}}
/>
);
}
export {MonitorRow};
const MonitorName = styled('div')`
display: flex;
align-items: center;
gap: ${space(2)};
font-size: ${p => p.theme.fontSizeLarge};
`;
const NameAndSlug = styled('div')`
display: flex;
flex-direction: column;
gap: ${space(0.25)};
`;
const MonitorSlug = styled('div')`
font-size: ${p => p.theme.fontSizeSmall};
color: ${p => p.theme.subText};
`;
const MonitorColumn = styled('div')`
display: flex;
align-items: center;
`;
const ActionsColumn = styled('div')`
display: flex;
align-items: center;
justify-content: center;
`;
const AdditionalEnvironmentWarning = styled('div')`
margin: ${space(1)} 0;
`;