Skip to content

Add paginated Content search with filters and result previews - #4600

Open
3mdistal wants to merge 4 commits into
mainfrom
codex/content-sidebar-search-sb04
Open

Add paginated Content search with filters and result previews#4600
3mdistal wants to merge 4 commits into
mainfrom
codex/content-sidebar-search-sb04

Conversation

@3mdistal

@3mdistal 3mdistal commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Problem

People searching Content need to find a page even when many documents match, and distinguish pages that share a title. The command picker previously stopped at eight document hits and searched databases separately, with no way to page through the remaining matches. It also omitted parent context, making similarly named results difficult to identify before opening them.

Approach

Use one server search operation for pages and databases, with filters applied to the eligible collection before counting and pagination. The picker searches one Content space at a time—a personal or workspace collection—and visibly identifies that scope. People can narrow the results, inspect a preview, and open the intended page with the keyboard.

This improves the existing text search. It does not complete indexed retrieval across every connected source, introduce global cross-workspace search, or add author filtering where authoritative author data has not been established.

What changed

  • Extend the shared search-documents action, which both the UI and agent can call, with title-only and modification-date filters. The picker combines these with page/database type filtering and returns 20 results per page.
  • Use case-insensitive literal matching, preserving wildcard escaping. Exclude hidden matches on the server so counts and page boundaries reflect the eligible results.
  • Show authorized parent titles, object type, modification dates, highlighted matches, and an expanded preview for the selected result. Parent identifiers and titles receive a separate access check and are omitted when inaccessible.
  • Keep input focus through pagination and Retry, restore invocation focus on dismissal, and show distinct loading, empty, and error states. Unrelated theme commands no longer remain selected during a document query; an empty search result does not submit an agent prompt.
  • Add the new interface strings in all 11 existing locales, focused tests, a changelog entry, and bounded product evidence.

Safety and integration

#4601 is merged. This PR currently conflicts with main in the React imports in root.tsx and needs a branch update before integration. The companion connects sidebar Search to this picker and fixes the shared dialog layering needed above the mobile drawer. This PR includes the identical root focus-return change but does not include the companion's sidebar or dialog-layer implementation.

Search remains access-scoped, and changing filters never broadens the query to all spaces. There are no schema migrations, backfills, credential changes, or content writes. The existing shortcut continues to ignore text fields. The full Search product capability remains marked in progress.

Verification

  • Automated: nine focused database/helper tests passed, covering pagination, title/body distinction, date/type filters, literal matching, private-parent suppression, and hidden-result counts. Content TypeScript, required package builds, and the product-docs guard passed. Independent static access/query review found no remaining findings.
  • Browser: on the current source (18f9cf7ef; head 84f27a3ad adds evidence only), 27 authorized matches paginated 20/7. Keyboard selection opened exact destinations, equal-title previews distinguished parents, and filters, empty states, controlled request failure, and Retry behaved correctly.
  • Combined mobile/sidebar: a temporary composition with Make sidebar Search and resizing accessible #4601 at c774d3eaa passed collapsed Search and 390×844 drawer checks: visible picker/filter menus, Escape focus return, and drawer closure after opening a result. The overlay was removed and every affected file matched its original byte hash. Make sidebar Search and resizing accessible #4601 has since advanced to 1052cd39; this browser evidence names the tested revision, not a rerun of that newer head.
  • CI: current-head checks have no failures or pending jobs. The PGlite job initially failed before tests when an external dependency download returned HTTP 500; its targeted rerun passed all 14 tests without code changes.

Local localization checks still report repository-wide debt, and the changed-copy check inspects zero imported catalog surfaces; neither is claimed as complete translation validation. Local product-impact tests hit Windows line-ending/subprocess assumptions, while the CI advisory passed. No guards were weakened. Browser evidence covers visual and keyboard behavior, not screen-reader speech or production deployment.

Review focus

  • Do access checks prevent result counts and parent context from exposing inaccessible content?
  • Do filter changes, pagination, and retry preserve a clear query and keyboard destination?
  • Does integration with Make sidebar Search and resizing accessible #4601 preserve one search entry and correct drawer/dialog focus behavior?
content_product_impact:
  lane: contract_fulfillment
  features:
    - content.feature.durable-foundations
    - content.feature.find-your-place-again
  capabilities:
    - content.knowledge.search
    - content.navigation.sidebar
    - content.access.visibility-closure
    - content.workspace.multi-scope
  record_change: included
  proof:
    - corepack pnpm --filter content exec vitest run actions/document-discovery.db.test.ts app/lib/content-command-search.test.ts --maxWorkers=1
    - corepack pnpm --filter content exec tsc --noEmit
    - corepack pnpm guard:content-product-docs
  rationale: Implements bounded access-scoped search and picker behavior without promoting the full indexed search or cross-context policy contract.

@netlify

This comment has been minimized.

@3mdistal 3mdistal changed the title Improve scoped Content search and keyboard navigation Add paginated Content search with filters and result previews Sep 9, 2026
@3mdistal
3mdistal marked this pull request as ready for review September 9, 2026 23:23

@builder-io-integration builder-io-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Builder reviewed your changes and found 1 potential issue 🟡

Review Details

Code Review Summary

PR #4600 replaces the Content command picker’s separate document/database lookups with a scoped, paginated search-documents action and adds title/type/date filters, parent context, highlighted previews, retry/empty states, and focus restoration. The overall architecture is sound: filtering is composed into the access-scoped query before count and pagination, hidden results are excluded server-side, and parent metadata is fetched through a separate authorization-scoped query. The UI keeps navigation in the shared command menu and uses the existing action surface rather than adding a parallel API.

Risk assessment: Standard (shared search/business logic plus user-facing UI, without writes, schema changes, or credential handling).

Key Findings

🟡 MEDIUM — Modified-date predicates compare the updatedAt text column directly with ISO timestamps, which can produce incorrect lexical ordering when stored timestamps use PostgreSQL’s space-separated representation. This can omit recently modified documents and make counts/pages wrong.

The focused action and helper tests reported by reviewers passed, and the randomized reviews found no additional access-scope, pagination, or navigation defects. The dev server was healthy, but browser verification could not run because no Chrome automation tools were available to the planner or executors.

🧪 Browser testing: Skipped — infrastructure unavailable; all 16 planned cases were unable to verify because Chrome MCP tools were not exposed.

Comment on lines +148 to +149
args.modifiedAfter
? gte(schema.documents.updatedAt, args.modifiedAfter)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Compare modification filters as timestamps rather than text

documents.updatedAt is a text column, but this predicate compares it directly with ISO-8601 T/Z strings. Rows written through the schema's now() default can use a space-separated PostgreSQL timestamp representation, so lexical ordering can exclude documents that fall within the requested date range and make filtered counts/pagination incorrect. Cast/normalize the column and bound to timestamps before comparing.

Additional Info
Reported by 1 of 4 randomized code-review agents; browser probe could not verify due unavailable Chrome tooling.

Fix in Builder

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant