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:
@@ -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>
|
||||
);
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user