import styled from '@emotion/styled';
import {IconArrow, IconMute, IconNot} from 'sentry/icons';
import {t} from 'sentry/locale';
import {space} from 'sentry/styles/space';
import type {ColorOrAlias} from 'sentry/utils/theme';
import {hasActiveIncident} from 'sentry/views/alerts/list/rules/utils';
import {getThresholdUnits} from 'sentry/views/alerts/rules/metric/constants';
import {
AlertRuleComparisonType,
AlertRuleThresholdType,
AlertRuleTriggerType,
} from 'sentry/views/alerts/rules/metric/types';
import {type CombinedMetricIssueAlerts, IncidentStatus} from 'sentry/views/alerts/types';
import {isIssueAlert} from 'sentry/views/alerts/utils';
interface Props {
rule: CombinedMetricIssueAlerts;
}
export default function AlertRuleStatus({rule}: Props) {
const activeIncident = hasActiveIncident(rule);
function renderSnoozeStatus(): React.ReactNode {
return (
{t('Muted')}
);
}
if (isIssueAlert(rule)) {
if (rule.status === 'disabled') {
return (
{t('Disabled')}
);
}
if (rule.snooze) {
return renderSnoozeStatus();
}
return null;
}
if (rule.snooze) {
return renderSnoozeStatus();
}
const criticalTrigger = rule.triggers.find(
({label}) => label === AlertRuleTriggerType.CRITICAL
);
const warningTrigger = rule.triggers.find(
({label}) => label === AlertRuleTriggerType.WARNING
);
const resolvedTrigger = rule.resolveThreshold;
const trigger =
activeIncident && rule.latestIncident?.status === IncidentStatus.CRITICAL
? criticalTrigger
: warningTrigger ?? criticalTrigger;
let iconColor: ColorOrAlias = 'successText';
let iconDirection: 'up' | 'down' | undefined;
let thresholdTypeText =
activeIncident && rule.thresholdType === AlertRuleThresholdType.ABOVE
? t('Above')
: t('Below');
// Anomaly detection alerts have different labels
const statusLabel = activeIncident ? t('Critical') : t('Resolved');
if (activeIncident) {
iconColor =
trigger?.label === AlertRuleTriggerType.CRITICAL
? 'errorText'
: trigger?.label === AlertRuleTriggerType.WARNING
? 'warningText'
: 'successText';
iconDirection = rule.thresholdType === AlertRuleThresholdType.ABOVE ? 'up' : 'down';
} else {
// Use the Resolved threshold type, which is opposite of Critical
iconDirection = rule.thresholdType === AlertRuleThresholdType.ABOVE ? 'down' : 'up';
thresholdTypeText =
rule.thresholdType === AlertRuleThresholdType.ABOVE ? t('Below') : t('Above');
}
return (
{rule.detectionType !== AlertRuleComparisonType.DYNAMIC && (
)}
{rule.detectionType !== AlertRuleComparisonType.DYNAMIC ? (
{`${thresholdTypeText} ${
rule.latestIncident || (!rule.latestIncident && !resolvedTrigger)
? trigger?.alertThreshold?.toLocaleString()
: resolvedTrigger?.toLocaleString()
}`}
{getThresholdUnits(
rule.aggregate,
rule.comparisonDelta
? AlertRuleComparisonType.CHANGE
: AlertRuleComparisonType.COUNT
)}
) : (
{statusLabel}
)}
);
}
const IssueAlertStatusWrapper = styled('div')`
display: flex;
align-items: center;
gap: ${space(1)};
line-height: 2;
`;
const TriggerText = styled('div')`
margin-left: ${space(1)};
white-space: nowrap;
font-variant-numeric: tabular-nums;
`;
// TODO: explore utilizing the FlexContainer from app/components/container/flex.tsx
const FlexCenter = styled('div')`
display: flex;
align-items: center;
`;