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) <noreply@anthropic.com>
This commit is contained in:
9
ui/package-lock.json
generated
9
ui/package-lock.json
generated
@@ -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"
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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 (
|
||||
<AppShell
|
||||
sidebar={
|
||||
@@ -217,6 +225,7 @@ function LayoutContent() {
|
||||
onClose={() => setPaletteOpen(false)}
|
||||
onOpen={() => setPaletteOpen(true)}
|
||||
onSelect={handlePaletteSelect}
|
||||
onSubmit={handlePaletteSubmit}
|
||||
onQueryChange={setPaletteQuery}
|
||||
data={searchData}
|
||||
/>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<string | undefined>()
|
||||
const [panelOpen, setPanelOpen] = useState(false)
|
||||
const [sortField, setSortField] = useState<string>('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 */}
|
||||
<div className={styles.tableSection}>
|
||||
<div className={styles.tableHeader}>
|
||||
<span className={styles.tableTitle}>Recent Exchanges</span>
|
||||
<span className={styles.tableTitle}>
|
||||
{textFilter ? (
|
||||
<>
|
||||
<Search size={14} style={{ marginRight: 4, verticalAlign: -2 }} />
|
||||
Search: “{textFilter}”
|
||||
<button
|
||||
className={styles.clearSearch}
|
||||
onClick={() => setSearchParams({})}
|
||||
title="Clear search"
|
||||
>
|
||||
<X size={12} />
|
||||
</button>
|
||||
</>
|
||||
) : 'Recent Exchanges'}
|
||||
</span>
|
||||
<div className={styles.tableRight}>
|
||||
<span className={styles.tableMeta}>
|
||||
{rows.length.toLocaleString()} of {(searchResult?.total ?? 0).toLocaleString()} exchanges
|
||||
</span>
|
||||
<Badge label="LIVE" color="success" />
|
||||
{!textFilter && <Badge label="LIVE" color="success" />}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user