feat(search): unified search page for projects and documents - #882
Open
danieltruong wants to merge 13 commits into
Open
feat(search): unified search page for projects and documents#882danieltruong wants to merge 13 commits into
danieltruong wants to merge 13 commits into
Conversation
Add types/{projects,documents,record-type,index} defining the
`and[]` filter contract per record type, and use-type-counts with
404 fallback when a type has no results endpoint yet. Extend
typeahead and search-filter-template to consume the shared types,
add matching test-utils support.
Add legacy-search route loader mapping the four Angular-era list pages (/projects-list, /search, /news, /project-notifications) to the unified /search page with the right record type and filter params, so bookmarks, emails and search engine results keep resolving after the route swap. Table of old to new address in docs/deviations-from-angular.md.
Fixture rows used the prototype's own field names, so the unified page read nothing the real backend returns. Values are unchanged; only keys move to the wire shape (displayName/datePosted, dateUpdated, headline). - and[<id>] resolves a List or Organization id to the label the row carries, which is what the <field>Id aliases do server side - and[<field>Start|End] date ranges, inclusive - meta[0].dropped names fields the dataset does not carry
One page for every record type: the keyword carries across the four record-type pills while filters, sort and selection belong to the type that set them. Projects fall back to name order when the index reports it dropped the date sort, one way only - the index answers per sort asked for, so flipping back re-asks with the field it just refused. Not routed yet; /search still renders the old documents page. Also drop a date draft in the advanced panel when the applied filter set empties: a date that never parsed has no applied text to change, so Clear all used to leave it on screen with its format error.
The Angular-era document search and project list pages are gone. A loader on /search rewrites an old-style address before the page renders, and /projects-list redirects into it. /news, /project-notifications and /search/content keep their own pages until Phases 3 and 4 build their tabs; the mapping for those three stays in routes/legacy-search.ts with its unit tests.
The old search and projects-list pages are gone, so their specs went red. search.spec.ts answers reads from the demi-search fixture so counts and row order are asserted values, not live data. projects-list.spec.ts folds into it; the redirect cases already live in routing.spec.ts.
danieltruong
requested review from
Ckoelewyn,
tolkamps1 and
tom0827
as code owners
September 12, 2026 06:06
The prototype keeps its body as a 900px scroller, so fullPage captures held one fold over blank canvas and nothing below the fold was compared. The capture script now expands the page, refuses a clipped reference, and every PNG is recaptured. The app capture drops the environment banner, waits at most 10s per action, stops at 10 failures in CI, refuses a reused server, and skips states whose phase has not shipped.
Three parity rounds against the recaptured references: stacked cards and a sort bar below 720px, breadcrumb instead of intro text, Documents as the default record, one-line cells, record links, year filter on the date column, grid-owned pager and page-size chips that stay on empty results, handoff column widths and panel tokens. Also: error state distinct from empty, decision date range on projects, one debounce, dead config fields removed, and the a11y audit fixes (popover roles, date error description, copy-link announcement, focus after paging, control names).
The 560px scroll box keeps the header sticky but its track rendered as a blank gap in browsers with classic scrollbars. Give the track and thumb visible colours so the gap reads as a scrollbar.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Second unified search PR (PUBLIC-146). Builds on #881, so the base is
feat/unified-search-p1; retarget toreactonce that merges./searchis now one page with four record pills (Projects, Documents, Activities & updates, Project notifications) and the display grid from #881. This PR wires Projects and Documents. Activities and notifications get their tabs in the next PR.What changes
pages/search/unified-search.tsxcomposes the grid: 48px keyword field, pills with live counts, in-header filter row, advanced filter panel, chip row, column picker, copy link, and bulk download on documents when enabled.pages/search/types/holds one config per record type (dataset, default sort, columns, filter ids, advanced fields, option sources). Every filter goes to demi-search asand[<id>]=.use-type-counts.tsreads/search/countsonce per pause. If the endpoint answers 404 it falls back to fourpageSize=1reads for the session, so the page works against a DEMI without the new endpoint.routes/legacy-search.tsmaps old URLs into the new page./projects-listredirects to/search?record=projectswith keywords, paging, sort and filters kept. A bare/searchwith Angular document params lands on the documents tab. Old#/...hash addresses re-enter the path routes.pages/search/search.tsx,search.config.ts,search-documents-table-rows.tsxandpages/project-list/are deleted.SEARCH_TABSmoves tosearch-tabs.tsbecausecontent-search.tsxstill uses it./news,/project-notificationsand/search/contentkeep their current pages for now.Parity
Reference renders of the design prototype live in
e2e/parity/unified-search/reference/.yarn test:paritypasses every state at 924 and 400 (53 checks). The projects default sort is-dateUpdated; the page falls back to+namewhen demi-search reports the field dropped.Tests
search.spec.tsrewritten against/searchwith the demi-search fixture;projects-list.spec.tsfolded into it;interactions,smoke,css-scopingrepointed. 79 passing.docs/deviations-from-angular.mdgains a URLs section.Known gaps, tracked in
TODO.mdsortableflags and cell renderers sit in the page's column mapping; they belong in the type configs.api.tsconcatenatessortBywithout encoding, so an ascending+namereaches the wire asname. Pre-existing; the live backend accepts it.