Improve alert handling and UI for Alerts and Dashboard pages
Added expandable alert details to the Alerts page, providing more insights into each warning or alert. Enhanced the Dashboard to display distinct counts for warnings and alerts, along with updated KPIs and improved styling for better visual hierarchy. These changes improve usability and clarity in monitoring alert statuses.
This commit is contained in:
@@ -6,6 +6,7 @@ import { useAuth } from "../state";
|
||||
export function DashboardPage() {
|
||||
const { tokens, refresh } = useAuth();
|
||||
const [targets, setTargets] = useState([]);
|
||||
const [alertStatus, setAlertStatus] = useState({ warnings: [], alerts: [], warning_count: 0, alert_count: 0 });
|
||||
const [search, setSearch] = useState("");
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState("");
|
||||
@@ -14,8 +15,14 @@ export function DashboardPage() {
|
||||
let active = true;
|
||||
(async () => {
|
||||
try {
|
||||
const data = await apiFetch("/targets", {}, tokens, refresh);
|
||||
if (active) setTargets(data);
|
||||
const [targetRows, alerts] = await Promise.all([
|
||||
apiFetch("/targets", {}, tokens, refresh),
|
||||
apiFetch("/alerts/status", {}, tokens, refresh),
|
||||
]);
|
||||
if (active) {
|
||||
setTargets(targetRows);
|
||||
setAlertStatus(alerts);
|
||||
}
|
||||
} catch (e) {
|
||||
if (active) setError(String(e.message || e));
|
||||
} finally {
|
||||
@@ -30,8 +37,16 @@ export function DashboardPage() {
|
||||
if (loading) return <div className="card">Loading dashboard...</div>;
|
||||
if (error) return <div className="card error">{error}</div>;
|
||||
|
||||
const alerts = targets.filter((t) => !t.host || !t.dbname).length;
|
||||
const okCount = Math.max(0, targets.length - alerts);
|
||||
const targetSeverities = new Map();
|
||||
for (const item of alertStatus.warnings || []) {
|
||||
if (!targetSeverities.has(item.target_id)) targetSeverities.set(item.target_id, "warning");
|
||||
}
|
||||
for (const item of alertStatus.alerts || []) {
|
||||
targetSeverities.set(item.target_id, "alert");
|
||||
}
|
||||
|
||||
const affectedTargetCount = targetSeverities.size;
|
||||
const okCount = Math.max(0, targets.length - affectedTargetCount);
|
||||
const filteredTargets = targets.filter((t) => {
|
||||
const q = search.trim().toLowerCase();
|
||||
if (!q) return true;
|
||||
@@ -46,7 +61,7 @@ export function DashboardPage() {
|
||||
<div className="dashboard-page">
|
||||
<h2>Dashboard Overview</h2>
|
||||
<p className="dashboard-subtitle">Real-time snapshot of monitored PostgreSQL targets.</p>
|
||||
<div className="grid three dashboard-kpis">
|
||||
<div className="dashboard-kpis-grid">
|
||||
<div className="card stat kpi-card">
|
||||
<div className="kpi-orb blue" />
|
||||
<strong>{targets.length}</strong>
|
||||
@@ -57,9 +72,14 @@ export function DashboardPage() {
|
||||
<strong>{okCount}</strong>
|
||||
<span className="kpi-label">Status OK</span>
|
||||
</div>
|
||||
<div className="card stat kpi-card alert">
|
||||
<div className="card stat kpi-card warning">
|
||||
<div className="kpi-orb amber" />
|
||||
<strong>{alerts}</strong>
|
||||
<strong>{alertStatus.warning_count || 0}</strong>
|
||||
<span className="kpi-label">Warnings</span>
|
||||
</div>
|
||||
<div className="card stat kpi-card alert">
|
||||
<div className="kpi-orb red" />
|
||||
<strong>{alertStatus.alert_count || 0}</strong>
|
||||
<span className="kpi-label">Alerts</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -81,21 +101,21 @@ export function DashboardPage() {
|
||||
|
||||
<div className="dashboard-target-list">
|
||||
{filteredTargets.map((t) => {
|
||||
const hasAlert = !t.host || !t.dbname;
|
||||
const severity = targetSeverities.get(t.id) || "ok";
|
||||
return (
|
||||
<article className="dashboard-target-card" key={t.id}>
|
||||
<div className="target-main">
|
||||
<div className="target-title-row">
|
||||
<h4>{t.name}</h4>
|
||||
<span className={`status-chip ${hasAlert ? "alert" : "ok"}`}>
|
||||
{hasAlert ? "Alert" : "OK"}
|
||||
<span className={`status-chip ${severity}`}>
|
||||
{severity === "alert" ? "Alert" : severity === "warning" ? "Warning" : "OK"}
|
||||
</span>
|
||||
</div>
|
||||
<p><strong>Host:</strong> {t.host}:{t.port}</p>
|
||||
<p><strong>DB:</strong> {t.dbname}</p>
|
||||
</div>
|
||||
<div className="target-actions">
|
||||
<Link className="details-btn" to={`/targets/${t.id}`}>Details <span aria-hidden="true">→</span></Link>
|
||||
<Link className="details-btn" to={`/targets/${t.id}`}>Details <span aria-hidden="true">{"->"}</span></Link>
|
||||
</div>
|
||||
</article>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user