Skip to content

Commit 7b9ab7e

Browse files
ofershapcursoragent
andcommitted
feat: add toggle to disable info-level anomalies (default off)
Plan exhaustion notifications were flooding the anomalies page. Added enableInfoAnomalies setting with toggle in settings UI. Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 8812115 commit 7b9ab7e

4 files changed

Lines changed: 49 additions & 1 deletion

File tree

src/app/settings/settings-client.tsx

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,15 @@ export function SettingsClient({ config: initial }: SettingsClientProps) {
182182
</div>
183183
</Section>
184184

185+
<Section title="Alerting Behavior" description="Control which anomaly types are generated">
186+
<Toggle
187+
label="Info-level anomalies"
188+
description="Plan exhaustion notifications (can be noisy for large teams)"
189+
checked={config.enableInfoAnomalies}
190+
onChange={(v) => setConfig({ ...config, enableInfoAnomalies: v })}
191+
/>
192+
</Section>
193+
185194
<Section
186195
title="Team Budget Alert"
187196
description="Get notified when total team spend reaches this amount. Set to 0 to disable."
@@ -1221,6 +1230,42 @@ function Section({
12211230
);
12221231
}
12231232

1233+
function Toggle({
1234+
label,
1235+
description,
1236+
checked,
1237+
onChange,
1238+
}: {
1239+
label: string;
1240+
description?: string;
1241+
checked: boolean;
1242+
onChange: (v: boolean) => void;
1243+
}) {
1244+
return (
1245+
<div className="flex items-center justify-between">
1246+
<div>
1247+
<span className="text-xs text-zinc-300">{label}</span>
1248+
{description && <p className="text-[10px] text-zinc-600">{description}</p>}
1249+
</div>
1250+
<button
1251+
type="button"
1252+
role="switch"
1253+
aria-checked={checked}
1254+
onClick={() => onChange(!checked)}
1255+
className={`relative inline-flex h-5 w-9 shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors ${
1256+
checked ? "bg-blue-600" : "bg-zinc-700"
1257+
}`}
1258+
>
1259+
<span
1260+
className={`pointer-events-none inline-block h-4 w-4 rounded-full bg-white shadow transition-transform ${
1261+
checked ? "translate-x-4" : "translate-x-0"
1262+
}`}
1263+
/>
1264+
</button>
1265+
</div>
1266+
);
1267+
}
1268+
12241269
function Field({
12251270
label,
12261271
value,

src/lib/anomaly/thresholds.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ export function detectThresholdAnomalies(config: DetectionConfig): Anomaly[] {
8686
};
8787
const cycleStart = cycleStartRow?.cs;
8888

89-
if (cycleStart) {
89+
if (cycleStart && config.enableInfoAnomalies) {
9090
const planExhausted = db
9191
.prepare(
9292
`SELECT du.email, m.name, MIN(du.date) as exhausted_on,

src/lib/db.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -818,6 +818,7 @@ export function getConfig(): DetectionConfig {
818818
zscore: { ...DEFAULT_CONFIG.zscore, ...stored.zscore },
819819
trends: { ...DEFAULT_CONFIG.trends, ...stored.trends },
820820
cronIntervalMinutes: stored.cronIntervalMinutes ?? DEFAULT_CONFIG.cronIntervalMinutes,
821+
enableInfoAnomalies: stored.enableInfoAnomalies ?? DEFAULT_CONFIG.enableInfoAnomalies,
821822
};
822823
}
823824

src/lib/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,7 @@ export interface DetectionConfig {
393393
cycleOutlierMultiplier: number;
394394
};
395395
cronIntervalMinutes: number;
396+
enableInfoAnomalies: boolean;
396397
}
397398

398399
export const DEFAULT_CONFIG: DetectionConfig = {
@@ -410,4 +411,5 @@ export const DEFAULT_CONFIG: DetectionConfig = {
410411
cycleOutlierMultiplier: 10,
411412
},
412413
cronIntervalMinutes: 60,
414+
enableInfoAnomalies: false,
413415
};

0 commit comments

Comments
 (0)