Add a global search, and stop the sidebar logo squeezing
Docs / docs (push) Successful in 22s
Playwright Tests / test-playwright (1, 2) (push) Successful in 3m14s
Playwright Tests / test-playwright (2, 2) (push) Successful in 1m53s
pre-commit / pre-commit (push) Failing after 2m13s
Test Backend / test-backend (push) Successful in 2m38s
Compose Smoke Test / test-compose (push) Successful in 38s
Playwright Tests / merge-reports (push) Successful in 1m8s

`GET /api/v1/search/` hands the client one flat index of everything worth
jumping to — flows and the nodes inside them, dashboards and the widgets on
them, panels, secrets, modules, workers and alert channels — and cmdk matches
it in the browser, so results narrow while typing without a round trip per
keystroke. A node hit is the one thing no list endpoint could answer: it opens
its flow with that node in focus.

The panel is reached from **Search** above Documentation in the sidebar, or
⌘K anywhere. The flow canvas palette moves to ⌘P, being the narrower of the two.

The panels dialog gains an address (`/dashboards?panels`) so a panel hit has
somewhere to land, and the sidebar logo gets `shrink-0`: the rail's width
animates while the logo is already back, and a flex item short of room is
squeezed rather than clipped.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016vGH7jqcXxWKP9wZFPyVdU
This commit is contained in:
2026-08-28 22:19:08 +02:00
co-authored by Claude Opus 5
parent 971bd430c7
commit 4215e057d1
17 changed files with 642 additions and 39 deletions
@@ -35,8 +35,15 @@ import {
import useCustomToast from "@/hooks/useCustomToast"
import { handleError } from "@/utils"
type Search = { panels?: boolean }
export const Route = createFileRoute("/_layout/dashboards/")({
component: Dashboards,
// The panels dialog has no route of its own, so the address is how anything
// else — the global search among them — arrives at it.
validateSearch: (search: Record<string, unknown>): Search => ({
panels: search.panels === true || search.panels === "true" || undefined,
}),
})
function Dashboards() {
@@ -47,8 +54,12 @@ function Dashboards() {
const [name, setName] = useState("")
const [search, setSearch] = useState("")
const [dialogOpen, setDialogOpen] = useState(false)
const [panelsOpen, setPanelsOpen] = useState(false)
const [deleteOpen, setDeleteOpen] = useState(false)
// Which screens exist is a question with an address, so anything can link to
// it — the global search lands a panel here.
const { panels: panelsOpen } = Route.useSearch()
const setPanelsOpen = (open: boolean) =>
navigate({ to: "/dashboards", search: open ? { panels: true } : {} })
const create = useMutation({
mutationFn: (dashboard: string) =>
@@ -110,7 +121,7 @@ function Dashboards() {
{/* Its own root rather than a nested one: which screens exist is a
different question from which dashboards do. */}
<Dialog open={panelsOpen} onOpenChange={setPanelsOpen}>
<Dialog open={panelsOpen ?? false} onOpenChange={setPanelsOpen}>
<PanelsDialog />
</Dialog>