diff --git a/frontend/src/pages/AlertsPage.jsx b/frontend/src/pages/AlertsPage.jsx index 2d96407..b684606 100644 --- a/frontend/src/pages/AlertsPage.jsx +++ b/frontend/src/pages/AlertsPage.jsx @@ -24,6 +24,56 @@ function formatTs(ts) { return new Date(ts).toLocaleString(); } +function buildAlertSuggestions(item) { + const name = (item?.name || "").toLowerCase(); + const category = (item?.category || "").toLowerCase(); + const source = (item?.source || "").toLowerCase(); + const value = Number(item?.value || 0); + const suggestions = []; + + if (name.includes("reachability") || name.includes("connectivity") || category === "availability") { + suggestions.push("Verify host, port, firewall rules, and network routing between backend container and DB target."); + suggestions.push("Check PostgreSQL `listen_addresses` and `pg_hba.conf` on the monitored instance."); + } + if (name.includes("freshness") || item?.message?.toLowerCase().includes("no metrics")) { + suggestions.push("Check collector logs and polling interval. Confirm the target credentials are still valid."); + suggestions.push("Run a manual connection test in Targets Management and verify SSL mode."); + } + if (name.includes("cache hit") || category === "performance") { + suggestions.push("Inspect slow queries and add/adjust indexes for frequent WHERE/JOIN columns."); + suggestions.push("Review shared buffers and query patterns that cause high disk reads."); + } + if (name.includes("lock") || category === "contention") { + suggestions.push("Inspect blocking sessions in `pg_stat_activity` and long transactions."); + suggestions.push("Reduce transaction scope/duration and add missing indexes to avoid lock escalation."); + } + if (name.includes("deadlock")) { + suggestions.push("Enforce a consistent table access order in transactions to prevent deadlocks."); + suggestions.push("Retry deadlocked transactions in the application with backoff."); + } + if (name.includes("checkpoint") || category === "io") { + suggestions.push("Review `max_wal_size`, `checkpoint_timeout`, and write burst patterns."); + suggestions.push("Check disk throughput and WAL pressure during peak load."); + } + if (name.includes("rollback")) { + suggestions.push("Investigate application errors causing transaction rollbacks."); + suggestions.push("Validate constraints/input earlier to reduce failed writes."); + } + if (name.includes("query") || category === "query" || source === "custom") { + suggestions.push("Run `EXPLAIN (ANALYZE, BUFFERS)` for the affected query and optimize highest-cost nodes."); + suggestions.push("Prioritize fixes for high total-time queries first, then high mean-time queries."); + } + if (value > 0 && item?.comparison && item?.alert_threshold !== null && item?.alert_threshold !== undefined) { + suggestions.push(`Current value is ${value.toFixed(2)} with threshold rule ${item.comparison} ${Number(item.alert_threshold).toFixed(2)}.`); + } + if (!suggestions.length) { + suggestions.push("Start with target activity, locks, and query insights to isolate the root cause."); + suggestions.push("Compare current values to the last stable period and tune threshold sensitivity if needed."); + } + + return suggestions.slice(0, 4); +} + export function AlertsPage() { const { tokens, refresh, me } = useAuth(); const [targets, setTargets] = useState([]); @@ -196,6 +246,7 @@ export function AlertsPage() {
{status.warnings.map((item) => { const isOpen = expandedKey === item.alert_key; + const suggestions = buildAlertSuggestions(item); return (
Checked At{formatTs(item.checked_at)}
Target ID{item.target_id}
{item.sql_text &&
{item.sql_text}
} +
+

Recommended actions

+ +
)} @@ -239,6 +296,7 @@ export function AlertsPage() {
{status.alerts.map((item) => { const isOpen = expandedKey === item.alert_key; + const suggestions = buildAlertSuggestions(item); return (
Checked At{formatTs(item.checked_at)}
Target ID{item.target_id}
{item.sql_text &&
{item.sql_text}
} +
+

Recommended actions

+ +
)} diff --git a/frontend/src/styles.css b/frontend/src/styles.css index 469060b..811ab5e 100644 --- a/frontend/src/styles.css +++ b/frontend/src/styles.css @@ -936,6 +936,31 @@ td { font-size: 12px; } +.alert-suggestions { + grid-column: 1 / -1; + margin-top: 2px; + padding: 8px; + border-radius: 8px; + border: 1px solid #3d689d; + background: #0a1f3fb3; +} + +.alert-suggestions h4 { + margin: 0 0 6px 0; + font-size: 13px; +} + +.alert-suggestions ul { + margin: 0; + padding-left: 16px; +} + +.alert-suggestions li { + margin-bottom: 4px; + color: #d4e7ff; + font-size: 12px; +} + .alert-form .field-full { grid-column: 1 / -1; }