From 1702200a60a8e331949a2b06da61a33f425cd5d3 Mon Sep 17 00:00:00 2001 From: hsiegeln <37154749+hsiegeln@users.noreply.github.com> Date: Fri, 27 Mar 2026 23:33:39 +0100 Subject: [PATCH] feat: Cmd+K Enter applies full-text search to dashboard When pressing Enter in the command palette without explicitly selecting a result (via arrow keys or mouse), the search query is now applied as a server-side full-text filter on the Dashboard table. Explicit selection still navigates to the exchange. Updates design system to v0.1.18 for the new onSubmit prop. Co-Authored-By: Claude Opus 4.6 (1M context) --- ui/package-lock.json | 9 ++++--- ui/package.json | 2 +- ui/src/components/LayoutShell.tsx | 9 +++++++ ui/src/pages/Dashboard/Dashboard.module.css | 23 ++++++++++++++++ ui/src/pages/Dashboard/Dashboard.tsx | 29 ++++++++++++++++----- 5 files changed, 61 insertions(+), 11 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index f5b2abdd..04b06ad0 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -8,7 +8,7 @@ "name": "ui", "version": "0.0.0", "dependencies": { - "@cameleer/design-system": "^0.1.17", + "@cameleer/design-system": "^0.1.18", "@tanstack/react-query": "^5.90.21", "lucide-react": "^1.7.0", "openapi-fetch": "^0.17.0", @@ -277,10 +277,11 @@ } }, "node_modules/@cameleer/design-system": { - "version": "0.1.17", - "resolved": "https://gitea.siegeln.net/api/packages/cameleer/npm/%40cameleer%2Fdesign-system/-/0.1.17/design-system-0.1.17.tgz", - "integrity": "sha512-THK6yN+xSrxEJadEQ4AZiVhPvoI2rq6gvmMonpxVhUw93dOPO5p06pRS5csJc1miFD1thOrazsoDzSTAbNaELw==", + "version": "0.1.18", + "resolved": "https://gitea.siegeln.net/api/packages/cameleer/npm/%40cameleer%2Fdesign-system/-/0.1.18/design-system-0.1.18.tgz", + "integrity": "sha512-uvGr4PFw6Eya+h9DSD0wBnzjIXhZpcndR2dDJX2tMvQqgy+32WTTTQ8BZZWZjOKLSv63UpBN/fwVSXtkA4dnqA==", "dependencies": { + "lucide-react": "^1.7.0", "react": "^19.0.0", "react-dom": "^19.0.0", "react-router-dom": "^7.0.0" diff --git a/ui/package.json b/ui/package.json index 1a03b332..e0ae3b77 100644 --- a/ui/package.json +++ b/ui/package.json @@ -14,7 +14,7 @@ "generate-api:live": "curl -s http://localhost:8081/api/v1/api-docs -o src/api/openapi.json && openapi-typescript src/api/openapi.json -o src/api/schema.d.ts" }, "dependencies": { - "@cameleer/design-system": "^0.1.17", + "@cameleer/design-system": "^0.1.18", "@tanstack/react-query": "^5.90.21", "lucide-react": "^1.7.0", "openapi-fetch": "^0.17.0", diff --git a/ui/src/components/LayoutShell.tsx b/ui/src/components/LayoutShell.tsx index 4f875a40..7112f01f 100644 --- a/ui/src/components/LayoutShell.tsx +++ b/ui/src/components/LayoutShell.tsx @@ -199,6 +199,14 @@ function LayoutContent() { setPaletteOpen(false); }, [navigate, setPaletteOpen]); + const handlePaletteSubmit = useCallback((query: string) => { + // Navigate to dashboard with full-text search applied + const currentPath = location.pathname; + // Stay on the current app/route context if we're already there + const basePath = currentPath.startsWith('/apps/') ? currentPath.split('/').slice(0, 4).join('/') : '/apps'; + navigate(`${basePath}?text=${encodeURIComponent(query)}`); + }, [navigate, location.pathname]); + return ( setPaletteOpen(false)} onOpen={() => setPaletteOpen(true)} onSelect={handlePaletteSelect} + onSubmit={handlePaletteSubmit} onQueryChange={setPaletteQuery} data={searchData} /> diff --git a/ui/src/pages/Dashboard/Dashboard.module.css b/ui/src/pages/Dashboard/Dashboard.module.css index efb40da7..dcba04e2 100644 --- a/ui/src/pages/Dashboard/Dashboard.module.css +++ b/ui/src/pages/Dashboard/Dashboard.module.css @@ -30,11 +30,34 @@ } .tableTitle { + display: flex; + align-items: center; + gap: 4px; font-size: 13px; font-weight: 600; color: var(--text-primary); } +.clearSearch { + display: inline-flex; + align-items: center; + justify-content: center; + width: 18px; + height: 18px; + margin-left: 4px; + border: none; + background: var(--bg-hover, #F5F0EA); + color: var(--text-secondary, #5C5347); + border-radius: 50%; + cursor: pointer; + padding: 0; +} + +.clearSearch:hover { + background: var(--border, #E4DFD8); + color: var(--text-primary, #1A1612); +} + .tableRight { display: flex; align-items: center; diff --git a/ui/src/pages/Dashboard/Dashboard.tsx b/ui/src/pages/Dashboard/Dashboard.tsx index 2f77266f..16862364 100644 --- a/ui/src/pages/Dashboard/Dashboard.tsx +++ b/ui/src/pages/Dashboard/Dashboard.tsx @@ -1,6 +1,6 @@ import { useState, useMemo, useCallback } from 'react' -import { useParams, useNavigate } from 'react-router' -import { ExternalLink, AlertTriangle } from 'lucide-react' +import { useParams, useNavigate, useSearchParams } from 'react-router' +import { ExternalLink, AlertTriangle, X, Search } from 'lucide-react' import { DataTable, DetailPanel, @@ -196,6 +196,8 @@ const SHORTCUTS = [ export default function Dashboard() { const { appId, routeId } = useParams<{ appId: string; routeId: string }>() const navigate = useNavigate() + const [searchParams, setSearchParams] = useSearchParams() + const textFilter = searchParams.get('text') || undefined const [selectedId, setSelectedId] = useState() const [panelOpen, setPanelOpen] = useState(false) const [sortField, setSortField] = useState('startTime') @@ -226,12 +228,13 @@ export default function Dashboard() { routeId: routeId || undefined, application: appId || undefined, status: statusParam, + text: textFilter, sortField, sortDir, offset: 0, - limit: 50, + limit: textFilter ? 200 : 50, }, - true, + !textFilter, ) const { data: detail } = useExecutionDetail(selectedId ?? null) const { data: diagram } = useDiagramLayout(detail?.diagramContentHash ?? null) @@ -398,12 +401,26 @@ export default function Dashboard() { {/* Exchanges table */}
- Recent Exchanges + + {textFilter ? ( + <> + + Search: “{textFilter}” + + + ) : 'Recent Exchanges'} +
{rows.length.toLocaleString()} of {(searchResult?.total ?? 0).toLocaleString()} exchanges - + {!textFilter && }