diff --git a/ui/src/pages/Alerts/RulesListPage.tsx b/ui/src/pages/Alerts/RulesListPage.tsx
index ee769393..cdd2bd6a 100644
--- a/ui/src/pages/Alerts/RulesListPage.tsx
+++ b/ui/src/pages/Alerts/RulesListPage.tsx
@@ -1,3 +1,115 @@
+import { Link, useNavigate } from 'react-router';
+import { Button, SectionHeader, Toggle, useToast, Badge } from '@cameleer/design-system';
+import { PageLoader } from '../../components/PageLoader';
+import { SeverityBadge } from '../../components/SeverityBadge';
+import {
+ useAlertRules,
+ useDeleteAlertRule,
+ useSetAlertRuleEnabled,
+ type AlertRuleResponse,
+} from '../../api/queries/alertRules';
+import { useEnvironments } from '../../api/queries/admin/environments';
+import { useSelectedEnv } from '../../api/queries/alertMeta';
+import sectionStyles from '../../styles/section-card.module.css';
+
export default function RulesListPage() {
- return
RulesListPage — coming soon
;
+ const navigate = useNavigate();
+ const env = useSelectedEnv();
+ const { data: rules, isLoading, error } = useAlertRules();
+ const { data: envs } = useEnvironments();
+ const setEnabled = useSetAlertRuleEnabled();
+ const deleteRule = useDeleteAlertRule();
+ const { toast } = useToast();
+
+ if (isLoading) return ;
+ if (error) return Failed to load rules: {String(error)}
;
+
+ const rows = rules ?? [];
+ const otherEnvs = (envs ?? []).filter((e) => e.slug !== env);
+
+ const onToggle = async (r: AlertRuleResponse) => {
+ try {
+ await setEnabled.mutateAsync({ id: r.id, enabled: !r.enabled });
+ toast({ title: r.enabled ? 'Disabled' : 'Enabled', description: r.name, variant: 'success' });
+ } catch (e) {
+ toast({ title: 'Toggle failed', description: String(e), variant: 'error' });
+ }
+ };
+
+ const onDelete = async (r: AlertRuleResponse) => {
+ if (!confirm(`Delete rule "${r.name}"? Fired alerts are preserved via rule_snapshot.`)) return;
+ try {
+ await deleteRule.mutateAsync(r.id);
+ toast({ title: 'Deleted', description: r.name, variant: 'success' });
+ } catch (e) {
+ toast({ title: 'Delete failed', description: String(e), variant: 'error' });
+ }
+ };
+
+ const onPromote = (r: AlertRuleResponse, targetEnvSlug: string) => {
+ navigate(`/alerts/rules/new?promoteFrom=${env}&ruleId=${r.id}&targetEnv=${targetEnvSlug}`);
+ };
+
+ return (
+
+
+ Alert rules
+
+
+
+
+
+ {rows.length === 0 ? (
+
No rules yet. Create one to start evaluating alerts for this environment.
+ ) : (
+
+
+
+ | Name |
+ Kind |
+ Severity |
+ Enabled |
+ Targets |
+ |
+
+
+
+ {rows.map((r) => (
+
+ | {r.name} |
+ |
+ |
+
+ onToggle(r)}
+ disabled={setEnabled.isPending}
+ />
+ |
+ {r.targets.length} |
+
+ {otherEnvs.length > 0 && (
+
+ )}
+
+ |
+
+ ))}
+
+
+ )}
+
+
+ );
}