Skip to content

feat(docs-page): distinguish the no-endpoints-at-all empty state - #456

Merged
mikewheeleer merged 4 commits into
Agentpay-Org:mainfrom
thlpkee20-wq:feature/docs-page-01-states
Jul 29, 2026
Merged

feat(docs-page): distinguish the no-endpoints-at-all empty state#456
mikewheeleer merged 4 commits into
Agentpay-Org:mainfrom
thlpkee20-wq:feature/docs-page-01-states

Conversation

@thlpkee20-wq

Copy link
Copy Markdown
Contributor

Closes #390

`DocsFilter` already had a clear, accessible empty state for "no
results for this search term". Added a distinct one for "no endpoints
were passed in at all" (`sections.length === 0`) — a
content/configuration gap rather than something a different search
term could fix, so the search box (and the "try a different search
term" guidance) isn't offered as a way out. The `aria-live`
announcement is suppressed in this state too, since there's no search
interaction to announce the result of.

On the "error state" half of this issue: `DocsPage` builds
`sections` synchronously via `getSections(baseUrl)` — there's no
fetch/async operation to fail, so no loading state is possible either.
The one call that can throw (`resolveApiBase()`, invoked directly in
the server component with no local `try`/`catch`) is already caught by
the app's root `error.tsx` boundary (`role="alert"`, keyboard-operable
"Try again" retry via Next.js's `reset()`) — adding a second, redundant
error UI local to this page would just duplicate that existing,
already-tested mechanism rather than add real coverage. Scoped this PR
to the empty-state distinction, which is the part with no existing
behavior or coverage.

Adds a test for the new state and confirms the search box and the
per-query empty state are absent when it renders.

Test plan

  • `npx eslint src/app/docs/DocsFilter.tsx src/app/docs/tests/DocsFilter.test.tsx`
  • `npx jest src/app/docs --coverage --collectCoverageFrom="src/app/docs/DocsFilter.tsx" --collectCoverageFrom="src/app/docs/page.tsx"` — 13/13 passing, 100% statements/branches/functions/lines on both locked files
  • `npx jest --coverage` (full suite) — no coverage-threshold failures; same pre-existing, unrelated `api-keys/page.test.tsx` failure noted in fix(test): run the theme SSR-guard tests under the node Jest environment #450
  • `npm run build`

Note

Stacked on #450 and #455 (fork-only, can't target a non-`main` base —
same caveat as noted on the other PRs in this series).

The window-undefined tests for readTheme/writeTheme/effectiveTheme
failed on unmodified main: globalThis.window in this jest-environment-jsdom
version is a non-configurable getter
(Object.getOwnPropertyDescriptor(globalThis, "window").configurable ===
false), so Object.defineProperty/jest.replaceProperty both throw trying
to redefine it to simulate an SSR context.

Moved the three affected tests into theme.ssr.test.ts with a
`@jest-environment node` docblock, where window is genuinely absent
rather than simulated, exercising the real typeof window === "undefined"
guard branch. No source change; theme.test.ts keeps every other case
under jsdom as before.
DocsFilter already memoized its aria-live announcement (useMemo), but
the actual filteredSections derivation was a plain .filter() call on
every render — including every keystroke before the 300ms debounce
settles, since `query` state changes trigger a re-render even though
`debouncedQuery` (the value the filter actually depends on) hasn't
changed yet. Wrapped it in useMemo keyed on [sections, debouncedQuery]
so it only recomputes when the value driving the filter changes.

Behavior and output unchanged, verified by the existing 12-case test
suite (page.test.tsx + DocsFilter.test.tsx) passing unmodified. No new
dependencies.
DocsFilter already had a clear, accessible empty state for "no results
for this search term". Added a distinct one for "no endpoints were
passed in at all" (sections.length === 0) — a content/configuration gap
rather than something a different search term could fix, so the search
box (and the "try a different search term" guidance) isn't offered as
a way out. The aria-live announcement is suppressed in this state too,
since there's no search interaction to announce the result of.

Error state: DocsPage builds `sections` synchronously via
getSections(baseUrl) — there's no fetch/async operation to fail, so no
loading state is possible either. The one call that can throw
(resolveApiBase(), invoked directly in the server component with no
local try/catch) is already caught by the app's root error.tsx boundary
(role="alert", keyboard-operable "Try again" retry via Next.js's
reset()) — adding a second, redundant error UI local to this page would
just duplicate that. Scoped this change to the empty-state distinction,
which is the part with no existing coverage.

Adds a test for the new state and confirms the search box and the
per-query empty state are absent when it renders.
@mikewheeleer

Copy link
Copy Markdown
Contributor

clean work @thlpkee20-wq — does exactly what #390 asked. merging 🎉

@mikewheeleer
mikewheeleer merged commit 7093745 into Agentpay-Org:main Jul 29, 2026
1 check failed
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.

Add explicit empty and error states to the docs-page view

2 participants