Revamp Dashboard UI and enhance target display.

Refactored the dashboard page to improve layout and clarity, including updated KPIs with better alert and status representation. Redesigned the target list to a card-based layout with clear status indicators and actionable buttons. Updated styles for consistency and better user experience.
This commit is contained in:
2026-02-12 12:14:03 +01:00
parent c63e08748c
commit c191a67fa7
3 changed files with 139 additions and 33 deletions

View File

@@ -29,45 +29,55 @@ 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);
return (
<div>
<div className="dashboard-page">
<h2>Dashboard Overview</h2>
<div className="grid three">
<div className="card stat">
<div className="grid three dashboard-kpis">
<div className="card stat kpi-card">
<strong>{targets.length}</strong>
<span>Targets</span>
<span>Total Targets</span>
</div>
<div className="card stat">
<strong>{targets.length}</strong>
<span>Status OK (placeholder)</span>
<div className="card stat kpi-card ok">
<strong>{okCount}</strong>
<span>Status OK</span>
</div>
<div className="card stat">
<strong>0</strong>
<span>Alerts (placeholder)</span>
<div className="card stat kpi-card alert">
<strong>{alerts}</strong>
<span>Alerts</span>
</div>
</div>
<div className="card">
<h3>Targets</h3>
<table>
<thead>
<tr>
<th>Name</th>
<th>Host</th>
<th>DB</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{targets.map((t) => (
<tr key={t.id}>
<td>{t.name}</td>
<td>{t.host}:{t.port}</td>
<td>{t.dbname}</td>
<td><Link to={`/targets/${t.id}`}>Details</Link></td>
</tr>
))}
</tbody>
</table>
<div className="dashboard-targets-head">
<h3>Targets</h3>
<span>{targets.length} registered</span>
</div>
<div className="dashboard-target-list">
{targets.map((t) => {
const hasAlert = !t.host || !t.dbname;
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>
</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</Link>
</div>
</article>
);
})}
</div>
</div>
</div>
);

View File

@@ -137,7 +137,7 @@ export function TargetsPage() {
</small>
</div>
<div className="field submit-field">
<div className="target-actions">
<div className="form-actions">
<button type="button" className="secondary-btn" onClick={testConnection} disabled={testState.loading}>
{testState.loading ? "Testing..." : "Test connection"}
</button>

View File

@@ -253,6 +253,102 @@ button {
color: #bfd0ea;
}
.dashboard-kpis .kpi-card {
border-left: 4px solid #2f7eca;
}
.dashboard-kpis .kpi-card.ok {
border-left-color: #2fa86f;
}
.dashboard-kpis .kpi-card.alert {
border-left-color: #d47a2a;
}
.dashboard-targets-head {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 12px;
}
.dashboard-targets-head h3 {
margin: 0;
}
.dashboard-targets-head span {
color: #9eb8d6;
font-size: 13px;
}
.dashboard-target-list {
display: grid;
gap: 12px;
}
.dashboard-target-card {
display: grid;
grid-template-columns: 1fr auto;
gap: 12px;
align-items: center;
border: 1px solid #2b5b8f;
border-radius: 12px;
padding: 14px;
background: linear-gradient(180deg, #132c58, #102549);
}
.target-main h4 {
margin: 0;
font-size: 20px;
font-weight: 800;
}
.target-main p {
margin: 5px 0 0 0;
color: #d5e7ff;
}
.target-title-row {
display: flex;
align-items: center;
gap: 10px;
}
.status-chip {
display: inline-block;
padding: 4px 10px;
border-radius: 999px;
font-size: 11px;
font-weight: 700;
border: 1px solid transparent;
}
.status-chip.ok {
color: #bbf7d0;
background: #123827;
border-color: #2f8f63;
}
.status-chip.alert {
color: #fde68a;
background: #3a2c12;
border-color: #9b7b2f;
}
.details-btn {
display: inline-block;
padding: 8px 14px;
border-radius: 10px;
font-weight: 700;
border: 1px solid #2d9adb;
background: linear-gradient(180deg, #1c6aab, #17568c);
color: #eaf5ff;
}
.details-btn:hover {
border-color: #6ed2ff;
}
.query-insights-page .query-toolbar {
display: grid;
grid-template-columns: minmax(220px, 320px) minmax(320px, 1fr);
@@ -448,7 +544,7 @@ button {
align-self: end;
}
.target-actions {
.form-actions {
display: flex;
justify-content: flex-end;
gap: 8px;