feat: unified global search & filter system with Cmd-K navigation
Replace per-page filtering with a single GlobalFilterProvider (time range + status) consumed by a redesigned TopBar across all pages. Lift CommandPalette to App level so Cmd-K works globally with filtered results that navigate to exchanges, routes, agents, and applications. Sidebar auto-reveals and selects the target entry on Cmd-K navigation via location state. - Extract shared time preset utilities (computePresetRange, DEFAULT_PRESETS) - Add GlobalFilterProvider (time range + status) and CommandPaletteProvider - Add TimeRangeDropdown primitive with Popover preset list - Redesign TopBar: breadcrumb | time dropdown | status pills | search | env - Add application category to Cmd-K search - Remove FilterBar and local DateRangePicker from Dashboard/Metrics pages - Filter AgentHealth EventFeed by global time range - Remove shift/onSearchClick props from TopBar Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2,6 +2,7 @@ import {
|
||||
useState,
|
||||
useRef,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
type ReactNode,
|
||||
type KeyboardEvent,
|
||||
@@ -31,6 +32,7 @@ export interface SidebarTreeProps {
|
||||
className?: string
|
||||
filterQuery?: string
|
||||
persistKey?: string // sessionStorage key to persist expand state across remounts
|
||||
autoRevealPath?: string | null // when set, auto-expand the parent of the matching node
|
||||
}
|
||||
|
||||
// ── Star icon SVGs ───────────────────────────────────────────────────────────
|
||||
@@ -138,6 +140,7 @@ export function SidebarTree({
|
||||
className,
|
||||
filterQuery,
|
||||
persistKey,
|
||||
autoRevealPath,
|
||||
}: SidebarTreeProps) {
|
||||
const navigate = useNavigate()
|
||||
|
||||
@@ -146,6 +149,27 @@ export function SidebarTree({
|
||||
() => persistKey ? readExpandState(persistKey) : new Set(),
|
||||
)
|
||||
|
||||
// Auto-expand parent when autoRevealPath changes (e.g. from Cmd-K navigation)
|
||||
useEffect(() => {
|
||||
if (!autoRevealPath) return
|
||||
for (const node of nodes) {
|
||||
// Check if a child of this node matches the reveal path
|
||||
if (node.children?.some((child) => child.path === autoRevealPath)) {
|
||||
if (!userExpandedIds.has(node.id)) {
|
||||
setUserExpandedIds((prev) => {
|
||||
const next = new Set(prev)
|
||||
next.add(node.id)
|
||||
if (persistKey) writeExpandState(persistKey, next)
|
||||
return next
|
||||
})
|
||||
}
|
||||
break
|
||||
}
|
||||
// Also check if the node itself matches (top-level node, no parent to expand)
|
||||
if (node.path === autoRevealPath) break
|
||||
}
|
||||
}, [autoRevealPath]) // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
// Filter
|
||||
const { filtered, matchedParentIds } = useMemo(
|
||||
() => filterNodes(nodes, filterQuery ?? ''),
|
||||
|
||||
Reference in New Issue
Block a user