From b93bd439b89d1173cf797ca417fce3331522969a Mon Sep 17 00:00:00 2001
From: Jean du Plessis
Date: Fri, 31 Jul 2026 15:49:56 +0200
Subject: [PATCH 1/2] fix(cost-insights): refine spend chart states
---
.../overview/SpendEvidenceCard.tsx | 29 ++--
.../settings/CostInsightsSettingsView.tsx | 128 +++++++++---------
2 files changed, 74 insertions(+), 83 deletions(-)
diff --git a/apps/web/src/components/cost-insights/overview/SpendEvidenceCard.tsx b/apps/web/src/components/cost-insights/overview/SpendEvidenceCard.tsx
index 322e20443d..8a0250d669 100644
--- a/apps/web/src/components/cost-insights/overview/SpendEvidenceCard.tsx
+++ b/apps/web/src/components/cost-insights/overview/SpendEvidenceCard.tsx
@@ -36,8 +36,7 @@ export function SpendEvidenceCard({
const totals = evidence.map(point => point.variableUsd + point.scheduledUsd);
const axisMax = niceCeil(Math.max(0, ...totals));
const hasSpend = axisMax > 0;
- const hasIncompleteEvidence = evidence.some(point => point.coverage !== 'complete');
- const shouldRenderChart = hasSpend || hasIncompleteEvidence;
+ const hasIncompleteEvidence = hasSpend && evidence.some(point => point.coverage !== 'complete');
const rangeLabel = {
'1h': 'This hour',
'24h': 'Last 24 hours',
@@ -46,7 +45,7 @@ export function SpendEvidenceCard({
'90d': 'Last 90 days',
}[range];
const highest = evidence
- .filter(point => point.coverage !== 'unavailable')
+ .filter(point => point.variableUsd + point.scheduledUsd > 0)
.reduce<(typeof evidence)[number] | undefined>((currentHighest, point) => {
if (!currentHighest) return point;
const currentTotal = currentHighest.variableUsd + currentHighest.scheduledUsd;
@@ -112,7 +111,7 @@ export function SpendEvidenceCard({
Use Left and Right Arrow keys to inspect each period. Use Home and End to jump to the
first or last period.
- {shouldRenderChart ? (
+ {hasSpend ? (
From e1103a5dc8b26084c6200d286f02900c05a02726 Mon Sep 17 00:00:00 2001
From: Jean du Plessis
Date: Fri, 31 Jul 2026 16:10:02 +0200
Subject: [PATCH 2/2] fix(cost-insights): preserve hidden state semantics
---
.../CostInsightsOverviewClient.tsx | 6 +++-
.../CostInsightsSettingsClient.tsx | 21 +++++++-----
.../overview/SpendEvidenceCard.tsx | 33 ++++++++++---------
.../settings/CostInsightsSettingsView.tsx | 10 +++++-
4 files changed, 45 insertions(+), 25 deletions(-)
diff --git a/apps/web/src/components/cost-insights/CostInsightsOverviewClient.tsx b/apps/web/src/components/cost-insights/CostInsightsOverviewClient.tsx
index 77f5b7c4c6..b2127b4c55 100644
--- a/apps/web/src/components/cost-insights/CostInsightsOverviewClient.tsx
+++ b/apps/web/src/components/cost-insights/CostInsightsOverviewClient.tsx
@@ -159,7 +159,11 @@ export function CostInsightsOverviewClient({
: alert.type === 'threshold_7d'
? 'spend-threshold-7d'
: 'spend-threshold-24h';
- router.push(`${basePath}/config#${thresholdAnchor}`);
+ router.push(
+ dashboard?.enabled
+ ? `${basePath}/config#${thresholdAnchor}`
+ : `${basePath}/config#spend-alert-options-hidden`
+ );
return;
}
diff --git a/apps/web/src/components/cost-insights/CostInsightsSettingsClient.tsx b/apps/web/src/components/cost-insights/CostInsightsSettingsClient.tsx
index e0e8dc9cbb..38a34f8ba7 100644
--- a/apps/web/src/components/cost-insights/CostInsightsSettingsClient.tsx
+++ b/apps/web/src/components/cost-insights/CostInsightsSettingsClient.tsx
@@ -235,9 +235,11 @@ function CostInsightsSettingsForm({
threshold7DayUsd: validateThresholdUsd(form.threshold7DayUsd),
threshold30DayUsd: validateThresholdUsd(form.threshold30DayUsd),
};
- const hasValidationError = Boolean(
- validations.thresholdUsd || validations.threshold7DayUsd || validations.threshold30DayUsd
- );
+ const hasValidationError =
+ form.enabled &&
+ Boolean(
+ validations.thresholdUsd || validations.threshold7DayUsd || validations.threshold30DayUsd
+ );
const dirty =
form.enabled !== settings.enabled ||
form.anomalyAlertsEnabled !== settings.anomalyAlertsEnabled ||
@@ -266,15 +268,18 @@ function CostInsightsSettingsForm({
const handleSave = () => {
if (!dirty || hasValidationError || settings.readOnly) return;
+ const thresholdUsd = form.enabled ? form.thresholdUsd : settings.thresholdUsd;
+ const threshold7DayUsd = form.enabled
+ ? form.threshold7DayUsd
+ : (settings.threshold7DayUsd ?? '');
+ const threshold30DayUsd = form.enabled ? form.threshold30DayUsd : settings.threshold30DayUsd;
onSave({
spendAlertsEnabled: form.enabled,
anomalyAlertsEnabled: form.anomalyAlertsEnabled,
costSuggestionsEnabled: form.suggestionsEnabled,
- spendThresholdUsd: form.thresholdUsd.trim() === '' ? null : form.thresholdUsd.trim(),
- spend7DayThresholdUsd:
- form.threshold7DayUsd.trim() === '' ? null : form.threshold7DayUsd.trim(),
- spend30DayThresholdUsd:
- form.threshold30DayUsd.trim() === '' ? null : form.threshold30DayUsd.trim(),
+ spendThresholdUsd: thresholdUsd.trim() === '' ? null : thresholdUsd.trim(),
+ spend7DayThresholdUsd: threshold7DayUsd.trim() === '' ? null : threshold7DayUsd.trim(),
+ spend30DayThresholdUsd: threshold30DayUsd.trim() === '' ? null : threshold30DayUsd.trim(),
});
};
diff --git a/apps/web/src/components/cost-insights/overview/SpendEvidenceCard.tsx b/apps/web/src/components/cost-insights/overview/SpendEvidenceCard.tsx
index 8a0250d669..fa7ed094e3 100644
--- a/apps/web/src/components/cost-insights/overview/SpendEvidenceCard.tsx
+++ b/apps/web/src/components/cost-insights/overview/SpendEvidenceCard.tsx
@@ -36,7 +36,8 @@ export function SpendEvidenceCard({
const totals = evidence.map(point => point.variableUsd + point.scheduledUsd);
const axisMax = niceCeil(Math.max(0, ...totals));
const hasSpend = axisMax > 0;
- const hasIncompleteEvidence = hasSpend && evidence.some(point => point.coverage !== 'complete');
+ const hasIncompleteEvidence = evidence.some(point => point.coverage !== 'complete');
+ const shouldRenderChart = hasSpend || hasIncompleteEvidence;
const rangeLabel = {
'1h': 'This hour',
'24h': 'Last 24 hours',
@@ -45,7 +46,7 @@ export function SpendEvidenceCard({
'90d': 'Last 90 days',
}[range];
const highest = evidence
- .filter(point => point.variableUsd + point.scheduledUsd > 0)
+ .filter(point => point.coverage !== 'unavailable' && point.variableUsd + point.scheduledUsd > 0)
.reduce<(typeof evidence)[number] | undefined>((currentHighest, point) => {
if (!currentHighest) return point;
const currentTotal = currentHighest.variableUsd + currentHighest.scheduledUsd;
@@ -111,7 +112,7 @@ export function SpendEvidenceCard({
Use Left and Right Arrow keys to inspect each period. Use Home and End to jump to the
first or last period.
- {hasSpend ? (
+ {shouldRenderChart ? (
- {data.enabled && (
+ {data.enabled ? (
onChange?.({ threshold30DayUsd })}
/>
+ ) : (
+
+ Turn on Spend Alerts to manage anomaly and threshold settings.
+
)}