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:
@@ -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">
|
||||
<div>
|
||||
<h3>Targets</h3>
|
||||
<span>{targets.length} registered</span>
|
||||
<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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user