Skip to content

feat(search): unified search page for projects and documents - #882

Open
danieltruong wants to merge 13 commits into
feat/unified-search-p1from
feat/unified-search-p2
Open

feat(search): unified search page for projects and documents#882
danieltruong wants to merge 13 commits into
feat/unified-search-p1from
feat/unified-search-p2

Conversation

@danieltruong

Copy link
Copy Markdown
Collaborator

Second unified search PR (PUBLIC-146). Builds on #881, so the base is feat/unified-search-p1; retarget to react once that merges.

/search is 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.tsx composes 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 as and[<id>]=.
  • use-type-counts.ts reads /search/counts once per pause. If the endpoint answers 404 it falls back to four pageSize=1 reads for the session, so the page works against a DEMI without the new endpoint.
  • routes/legacy-search.ts maps old URLs into the new page. /projects-list redirects to /search?record=projects with keywords, paging, sort and filters kept. A bare /search with Angular document params lands on the documents tab. Old #/... hash addresses re-enter the path routes.
  • Old pages/search/search.tsx, search.config.ts, search-documents-table-rows.tsx and pages/project-list/ are deleted. SEARCH_TABS moves to search-tabs.ts because content-search.tsx still uses it.
  • /news, /project-notifications and /search/content keep their current pages for now.

Parity

Reference renders of the design prototype live in e2e/parity/unified-search/reference/. yarn test:parity passes every state at 924 and 400 (53 checks). The projects default sort is -dateUpdated; the page falls back to +name when demi-search reports the field dropped.

Tests

  • Unit: 1050 passing.
  • e2e: search.spec.ts rewritten against /search with the demi-search fixture; projects-list.spec.ts folded into it; interactions, smoke, css-scoping repointed. 79 passing.
  • docs/deviations-from-angular.md gains a URLs section.

Known gaps, tracked in TODO.md

  • Column sortable flags and cell renderers sit in the page's column mapping; they belong in the type configs.
  • api.ts concatenates sortBy without encoding, so an ascending +name reaches the wire as name. Pre-existing; the live backend accepts it.
  • Projects has no Legislation filter (no index field).

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.
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.
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