feat(ui/alerts): SilenceRuleMenu — 1h/8h/24h/custom duration menu
Used by InboxPage row + bulk actions to silence an alert's underlying rule for a chosen preset window. 'Custom…' routes to /alerts/silences?ruleId=<id> (T13 adds the prefill wire). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
71
ui/src/pages/Alerts/SilenceRuleMenu.tsx
Normal file
71
ui/src/pages/Alerts/SilenceRuleMenu.tsx
Normal file
@@ -0,0 +1,71 @@
|
||||
import { BellOff } from 'lucide-react';
|
||||
import { useNavigate } from 'react-router';
|
||||
import { Button, Dropdown, useToast } from '@cameleer/design-system';
|
||||
import type { DropdownItem } from '@cameleer/design-system';
|
||||
import { useCreateSilence } from '../../api/queries/alertSilences';
|
||||
|
||||
interface Props {
|
||||
ruleId: string;
|
||||
ruleTitle?: string;
|
||||
onDone?: () => void;
|
||||
variant?: 'row' | 'bulk';
|
||||
}
|
||||
|
||||
const PRESETS: Array<{ label: string; hours: number }> = [
|
||||
{ label: '1 hour', hours: 1 },
|
||||
{ label: '8 hours', hours: 8 },
|
||||
{ label: '24 hours', hours: 24 },
|
||||
];
|
||||
|
||||
export function SilenceRuleMenu({ ruleId, ruleTitle, onDone, variant = 'row' }: Props) {
|
||||
const navigate = useNavigate();
|
||||
const { toast } = useToast();
|
||||
const createSilence = useCreateSilence();
|
||||
|
||||
const handlePreset = (hours: number) => async () => {
|
||||
const now = new Date();
|
||||
const reason = ruleTitle
|
||||
? `Silenced from inbox (${ruleTitle})`
|
||||
: 'Silenced from inbox';
|
||||
try {
|
||||
await createSilence.mutateAsync({
|
||||
matcher: { ruleId },
|
||||
reason,
|
||||
startsAt: now.toISOString(),
|
||||
endsAt: new Date(now.getTime() + hours * 3_600_000).toISOString(),
|
||||
});
|
||||
toast({ title: `Silenced for ${hours}h`, variant: 'success' });
|
||||
onDone?.();
|
||||
} catch (e) {
|
||||
toast({ title: 'Silence failed', description: String(e), variant: 'error' });
|
||||
}
|
||||
};
|
||||
|
||||
const handleCustom = () => {
|
||||
navigate(`/alerts/silences?ruleId=${encodeURIComponent(ruleId)}`);
|
||||
};
|
||||
|
||||
const items: DropdownItem[] = [
|
||||
...PRESETS.map(({ label, hours }) => ({
|
||||
label,
|
||||
disabled: createSilence.isPending,
|
||||
onClick: handlePreset(hours),
|
||||
})),
|
||||
{ divider: true, label: '' },
|
||||
{ label: 'Custom…', onClick: handleCustom },
|
||||
];
|
||||
|
||||
const buttonLabel = variant === 'bulk' ? 'Silence rules' : 'Silence rule…';
|
||||
|
||||
return (
|
||||
<Dropdown
|
||||
trigger={
|
||||
<Button variant="secondary" size="sm">
|
||||
<BellOff size={14} style={{ marginRight: 4 }} />
|
||||
{buttonLabel}
|
||||
</Button>
|
||||
}
|
||||
items={items}
|
||||
/>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user