Add search functionality to the Dashboard targets list

Implemented a search input to filter targets based on name, host, or database fields. Updated the UI to show filtered results and display a message if no targets match the search. Adjusted styles for improved responsiveness and usability.
This commit is contained in:
2026-02-12 12:27:53 +01:00
parent afd30e3897
commit c6da398574
2 changed files with 67 additions and 10 deletions

View File

@@ -6,6 +6,7 @@ import { useAuth } from "../state";
export function DashboardPage() {
const { tokens, refresh } = useAuth();
const [targets, setTargets] = useState([]);
const [search, setSearch] = useState("");
const [loading, setLoading] = useState(true);
const [error, setError] = useState("");
@@ -31,6 +32,15 @@ export function DashboardPage() {
const alerts = targets.filter((t) => !t.host || !t.dbname).length;
const okCount = Math.max(0, targets.length - alerts);
const filteredTargets = targets.filter((t) => {
const q = search.trim().toLowerCase();
if (!q) return true;
return (
(t.name || "").toLowerCase().includes(q) ||
(t.host || "").toLowerCase().includes(q) ||
(t.dbname || "").toLowerCase().includes(q)
);
});
return (
<div className="dashboard-page">
@@ -56,12 +66,21 @@ export function DashboardPage() {
<div className="card dashboard-targets-card">
<div className="dashboard-targets-head">
<h3>Targets</h3>
<span>{targets.length} registered</span>
<div>
<h3>Targets</h3>
<span>{filteredTargets.length} shown of {targets.length} registered</span>
</div>
<div className="dashboard-target-search">
<input
value={search}
onChange={(e) => setSearch(e.target.value)}
placeholder="Search by name, host, or database..."
/>
</div>
</div>
<div className="dashboard-target-list">
{targets.map((t) => {
{filteredTargets.map((t) => {
const hasAlert = !t.host || !t.dbname;
return (
<article className="dashboard-target-card" key={t.id}>
@@ -81,6 +100,9 @@ export function DashboardPage() {
</article>
);
})}
{filteredTargets.length === 0 && (
<div className="dashboard-empty">No targets match your search.</div>
)}
</div>
</div>
</div>

View File

@@ -291,9 +291,10 @@ button {
.dashboard-targets-head {
display: flex;
align-items: center;
align-items: flex-end;
justify-content: space-between;
margin-bottom: 12px;
gap: 12px;
}
.dashboard-targets-head h3 {
@@ -305,6 +306,18 @@ button {
font-size: 13px;
}
.dashboard-target-search {
min-width: 320px;
max-width: 420px;
width: 100%;
}
.dashboard-target-search input {
width: 100%;
height: 36px;
padding: 8px 10px;
}
.kpi-orb {
position: absolute;
right: 14px;
@@ -334,7 +347,10 @@ button {
.dashboard-target-list {
display: grid;
gap: 14px;
gap: 10px;
max-height: 460px;
overflow: auto;
padding-right: 2px;
}
.dashboard-targets-card {
@@ -348,7 +364,7 @@ button {
align-items: center;
border: 1px solid #2b5b8f;
border-radius: 12px;
padding: 16px;
padding: 12px 14px;
background: linear-gradient(180deg, #143462, #102a4f);
box-shadow: inset 0 1px 0 #6fc5ff1a;
transition: transform 0.16s ease, border-color 0.16s ease, box-shadow 0.16s ease;
@@ -362,15 +378,15 @@ button {
.target-main h4 {
margin: 0;
font-size: 24px;
font-size: 20px;
font-weight: 800;
letter-spacing: 0.01em;
}
.target-main p {
margin: 6px 0 0 0;
margin: 4px 0 0 0;
color: #d5e7ff;
font-size: 17px;
font-size: 15px;
}
.target-title-row {
@@ -402,7 +418,7 @@ button {
.details-btn {
display: inline-block;
padding: 10px 14px;
padding: 7px 12px;
border-radius: 10px;
font-weight: 700;
border: 1px solid #4db8f1;
@@ -416,6 +432,14 @@ button {
filter: brightness(1.05);
}
.dashboard-empty {
border: 1px dashed #34689f;
border-radius: 10px;
padding: 14px;
color: #9fb9d8;
text-align: center;
}
.query-insights-page .query-toolbar {
display: grid;
grid-template-columns: minmax(220px, 320px) minmax(320px, 1fr);
@@ -1020,4 +1044,15 @@ select:-webkit-autofill {
height: auto;
overflow: visible;
}
.dashboard-target-search {
min-width: 0;
}
.dashboard-targets-head {
flex-direction: column;
align-items: stretch;
}
.dashboard-target-list {
max-height: none;
overflow: visible;
}
}