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
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:
@@ -0,0 +1,53 @@
|
||||
import { expect, test } from "@playwright/test"
|
||||
import { api, apiPage, deleteAll } from "./utils/api"
|
||||
|
||||
/**
|
||||
* The global search: the only way to reach a node without knowing its flow.
|
||||
*
|
||||
* The load-bearing part is what the flat index turns back into — a node hit is
|
||||
* a flow address with that node in focus, which no list endpoint could have
|
||||
* answered.
|
||||
*/
|
||||
|
||||
const flowName = `test_search_${Date.now().toString(36)}`
|
||||
|
||||
test.use({ storageState: "playwright/.auth/user.json" })
|
||||
test.describe.configure({ mode: "serial" })
|
||||
|
||||
test.beforeAll(async ({ browser }) => {
|
||||
const page = await apiPage(browser)
|
||||
await api(page, `/flows/${flowName}`, {
|
||||
method: "PUT",
|
||||
data: {
|
||||
name: flowName,
|
||||
title: "Searchable flow",
|
||||
nodes: [{ id: "findme", type: "python", title: "Find me" }],
|
||||
},
|
||||
})
|
||||
await page.close()
|
||||
})
|
||||
|
||||
test.afterAll(async ({ browser }) => {
|
||||
await deleteAll(browser, [`/flows/${flowName}`])
|
||||
})
|
||||
|
||||
test("finds a node by name and opens its flow on it", async ({ page }) => {
|
||||
await page.goto("/")
|
||||
await page.getByRole("button", { name: "Search", exact: true }).click()
|
||||
|
||||
await page.getByTestId("global-search-input").fill("findme")
|
||||
await page.getByRole("option", { name: /Find me/ }).click()
|
||||
|
||||
await expect(page).toHaveURL(new RegExp(`/flows/${flowName}\\?node=findme$`))
|
||||
})
|
||||
|
||||
test("opens on the keyboard from anywhere", async ({ page }) => {
|
||||
await page.goto("/dashboards")
|
||||
// The binding lives in the sidebar, so wait for it to be there to press at.
|
||||
await expect(
|
||||
page.getByRole("button", { name: "Search", exact: true }),
|
||||
).toBeVisible()
|
||||
await page.keyboard.press("ControlOrMeta+k")
|
||||
|
||||
await expect(page.getByTestId("global-search-input")).toBeFocused()
|
||||
})
|
||||
Reference in New Issue
Block a user