Render search suggestions on the server
The typeahead requests /_search via htmx (debounced, newer requests replace in-flight ones) and gets rendered rows with the match highlighting done in Go. Rows are links, so picking in the header is plain navigation; the editor's link dialog reads data-name instead. The editor's [[ autocomplete keeps the JSON response. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -270,3 +270,71 @@ test("mobile: FOLDERS opens the tree in an overlay", async ({ page }) => {
|
||||
await overlay.getByRole("link", { name: "Projects" }).click();
|
||||
await expect(overlay).toHaveCount(0);
|
||||
});
|
||||
|
||||
async function seedSearch(page) {
|
||||
for (const n of ["Zebra Crossing", "Zebra Finch", "Zeta1", "Zeta2", "Zeta3", "Zeta4", "Zeta5", "Zeta6"]) {
|
||||
mkpage(`Suggest/${n}`, n);
|
||||
}
|
||||
expect((await page.request.post("/_reindex")).status()).toBe(204);
|
||||
}
|
||||
const suggest = (page) => page.locator("header .suggest-dropdown");
|
||||
|
||||
test("header typeahead: highlight, keyboard pick", async ({ page }) => {
|
||||
await seedSearch(page);
|
||||
await page.goto("/");
|
||||
const input = page.locator("header .search-input");
|
||||
await input.fill("finch");
|
||||
await expect(suggest(page)).toBeVisible();
|
||||
await expect(suggest(page).locator(".suggest-row").first().locator("strong")).toHaveText("Finch");
|
||||
await input.press("ArrowDown");
|
||||
await expect(suggest(page).locator(".suggest-row.is-active")).toContainText("Zebra Finch");
|
||||
await input.press("Enter");
|
||||
await expect(page).toHaveURL(/\/Suggest\/Zebra%20Finch\/$/);
|
||||
});
|
||||
|
||||
test("header typeahead: click, footer, escape, short query", async ({ page }) => {
|
||||
await seedSearch(page);
|
||||
await page.goto("/");
|
||||
const input = page.locator("header .search-input");
|
||||
await input.fill("z");
|
||||
await page.waitForTimeout(300);
|
||||
await expect(suggest(page)).toBeHidden();
|
||||
await input.fill("zeta");
|
||||
const footer = suggest(page).locator(".suggest-footer");
|
||||
const { total } = await (await page.request.get("/_search?q=zeta")).json();
|
||||
expect(total).toBeGreaterThan(5);
|
||||
await expect(footer).toHaveText(`Show all ${total} matches`);
|
||||
await expect(suggest(page).locator(".suggest-row:not(.suggest-footer)")).toHaveCount(5);
|
||||
await input.press("Escape");
|
||||
await expect(suggest(page)).toBeHidden();
|
||||
await input.fill("zebra c");
|
||||
await suggest(page).locator(".suggest-name", { hasText: "Zebra Crossing" }).click();
|
||||
await expect(page).toHaveURL(/\/Suggest\/Zebra%20Crossing\/$/);
|
||||
await page.goto("/");
|
||||
await page.locator("header .search-input").fill("zeta");
|
||||
await suggest(page).locator(".suggest-footer").click();
|
||||
await expect(page).toHaveURL(/\/\?q=zeta$/);
|
||||
});
|
||||
|
||||
test("editor link dialog fills the query from a suggestion", async ({ page }) => {
|
||||
await seedSearch(page);
|
||||
await page.goto("/Suggest/Zeta1/?edit");
|
||||
await page.locator(".cm-content").click();
|
||||
await page.keyboard.press("Alt+Shift+P");
|
||||
const query = modal(page).getByPlaceholder("Search query");
|
||||
await query.fill("crossing");
|
||||
await modal(page).locator(".suggest-row", { hasText: "Zebra Crossing" }).click();
|
||||
await expect(query).toHaveValue("Zebra Crossing");
|
||||
await expect(modal(page).getByPlaceholder("Display text (optional)")).toBeFocused();
|
||||
await modal(page).getByRole("button", { name: "INSERT" }).click();
|
||||
await expect(page.locator(".cm-content")).toContainText("[[Zebra Crossing]]");
|
||||
});
|
||||
|
||||
test("editor [[ autocomplete still uses the JSON endpoint", async ({ page }) => {
|
||||
await seedSearch(page);
|
||||
await page.goto("/Suggest/Zeta2/?edit");
|
||||
await page.locator(".cm-content").click();
|
||||
await page.keyboard.press("Control+End");
|
||||
await page.keyboard.type("\n[[finc");
|
||||
await expect(page.locator(".cm-tooltip-autocomplete")).toContainText("Zebra Finch");
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user