feat(client): API client layer (PMC-2) #26

Closed
David wants to merge 0 commits from feat/pmc-2-api-client-layer into main
Owner

Summary

Lands the API-client layer story (PMC-2) in five commits, one per remaining valid sub-task. The stale PMC-3 (api_client scaffold) and OIDC-obsoleted PMC-4/PMC-5 were already closed against main; PMC-9 (portal wire) is blocked on the server's /api/v1/portal/* 501 surface and was closed with a follow-up note.

  • PMC-10: typed ApiError enum + _typed get/post/put/delete wrappers that decode the server's ErrorResponse envelope, plus a global Toast surface mounted once in AppLayout so any page can push via push_toast / push_api_error. Existing string-returning helpers stay so live callers (companies, calendar, system_version) compile unchanged.
  • PMC-11: drives TableLoading / TableEmpty off the use_resource snapshot on companies, establishing the loading/empty pattern that the rest of the PR follows.
  • PMC-6: TicketListPage fetches /tickets and renders live rows; demo rows stay behind a Demo source for envs without a live backend. Detail/create/add-note are tracked separately under PMC-28/PMC-27/PMC-25.
  • PMC-7: ContactListPage fetches /contacts. Companies was wired earlier; both list views in the contacts module now ride the same pattern.
  • PMC-8: TenantManagementPage (multi-tenant only) fetches /tenants. Tenant switcher itself remains on Bunyip per the SSO migration; this surface is a super_admin read-only roster.

Test plan

  • cargo check --features web clean
  • cargo check --features web,multi-tenant clean
  • Companies / Contacts / Tickets list show loading skeleton on first paint, then live or demo rows with the right banner
  • Admin / Tenants page (multi-tenant build) shows loading skeleton, then live rows or demo fallback
  • Force an error from a debug push: crate::hooks::toast::push_toast(AlertType::Error, "test") renders bottom-right and dismisses

YouTrack

PMC-6, PMC-7, PMC-8, PMC-9, PMC-10, PMC-11 closed by this branch. PMC-2 parent story moves to Done with the final commit chain.

🤖 Generated with Claude Code

## Summary Lands the API-client layer story (PMC-2) in five commits, one per remaining valid sub-task. The stale `PMC-3` (api_client scaffold) and OIDC-obsoleted `PMC-4`/`PMC-5` were already closed against main; `PMC-9` (portal wire) is blocked on the server's `/api/v1/portal/*` 501 surface and was closed with a follow-up note. - `PMC-10`: typed `ApiError` enum + `_typed` get/post/put/delete wrappers that decode the server's `ErrorResponse` envelope, plus a global `Toast` surface mounted once in `AppLayout` so any page can push via `push_toast` / `push_api_error`. Existing string-returning helpers stay so live callers (companies, calendar, system_version) compile unchanged. - `PMC-11`: drives `TableLoading` / `TableEmpty` off the `use_resource` snapshot on companies, establishing the loading/empty pattern that the rest of the PR follows. - `PMC-6`: `TicketListPage` fetches `/tickets` and renders live rows; demo rows stay behind a `Demo` source for envs without a live backend. Detail/create/add-note are tracked separately under PMC-28/PMC-27/PMC-25. - `PMC-7`: `ContactListPage` fetches `/contacts`. Companies was wired earlier; both list views in the contacts module now ride the same pattern. - `PMC-8`: `TenantManagementPage` (multi-tenant only) fetches `/tenants`. Tenant switcher itself remains on Bunyip per the SSO migration; this surface is a super_admin read-only roster. ## Test plan - [ ] `cargo check --features web` clean - [ ] `cargo check --features web,multi-tenant` clean - [ ] Companies / Contacts / Tickets list show loading skeleton on first paint, then live or demo rows with the right banner - [ ] Admin / Tenants page (multi-tenant build) shows loading skeleton, then live rows or demo fallback - [ ] Force an error from a debug push: `crate::hooks::toast::push_toast(AlertType::Error, "test")` renders bottom-right and dismisses ## YouTrack PMC-6, PMC-7, PMC-8, PMC-9, PMC-10, PMC-11 closed by this branch. PMC-2 parent story moves to Done with the final commit chain. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Adds an `ApiError` enum (`Network`, `Status { code, message }`, `Decode`) alongside the existing string-returning fetch helpers, plus `_typed` variants of get_authed/post_authed/put_authed/delete_authed that decode the server's `ErrorResponse` envelope so callers can react to 401/403/404/422/etc. without re-parsing strings. `ApiError::user_message` produces the copy that gets dropped straight into a toast.

The toast surface is a `GlobalSignal<Vec<Toast>>` driven by `push_toast`/`push_toast_with_title` plus a `push_api_error` convenience that maps an `ApiError` to an Error-variant toast. `ToastRoot` mounts once inside `AppLayout` so every authed page is already wired; no per-page plumbing needed.

The existing `Result<T, String>` helpers stay so live callers (companies, calendar, system version) keep compiling. New call sites should prefer the typed variants going forward.

#PMC-10 State Done
CompanyListPage now drives `loading` from the in-flight state of the live-backend resource and swaps the table body to `TableLoading` skeleton rows while the first fetch is outstanding, instead of flashing the demo rows on every page load. When the backend responds with zero rows it shows `TableEmpty` rather than silently falling back to demo data, which had been masking real "the tenant has no companies yet" cases.

This is the reference wiring for the loading/empty pattern; subsequent list-page wires (tickets, contacts, admin tenants) will follow the same shape.

#PMC-11 State Done
TicketListPage now fetches from `GET /api/v1/tickets` via `use_resource` and renders the live rows when the backend answers, while keeping the existing hardcoded TKT-* rows behind a `Demo` source so the page stays demoable when the tenant has no rows yet or the user is signed out.

Status and priority names are humanized from the server's lowercase values; `assigned_to_name` falls back to "Unassigned"; `updated_at` is rendered relative via `relative_time`. Loading and empty states ride the same `TableLoading`/`TableEmpty` pattern just landed on companies.

Detail-page, create-ticket POST, and add-note POST wiring are out of scope here and tracked under PMC-28/PMC-27/PMC-25 respectively.

#PMC-6 State Done
ContactListPage now fetches from `GET /api/v1/contacts` via `use_resource` and renders the live rows when the backend answers, falling back to the seeded demo rows when the route is missing or the user is signed out. Email/phone/role/company columns tolerate missing fields (server contact records frequently have nulls there).

Companies list was already wired in a prior commit; combined with this change, both list views in the contacts module now drive off the same progressive-enablement pattern. Detail and create wires are tracked under PMC-46/PMC-47/PMC-48/PMC-49 in the contacts UI story.

#PMC-7 State Done
feat(admin): wire TenantManagementPage to /tenants with demo fallback (PMC-8)
Some checks failed
Check / clippy + fmt + tests (pull_request) Failing after 8s
Create release / Create release from merged PR (pull_request) Has been skipped
eaea8c6fd6
TenantManagementPage now fetches the live tenant list via `GET /api/v1/tenants` when the multi-tenant feature is on, falling back to the seeded demo rows when the endpoint isn't reachable or the user is signed out. The same TableLoading/TableEmpty progressive-enablement pattern that landed on companies/contacts is used here.

User counts and MRR are not yet on `TenantResponse` and are tracked under PMC-91; this commit renders "0" / "-" placeholders for those columns so the table layout stays stable until the server adds aggregate fields.

The Bunyip hub now owns the day-to-day tenant switcher; this admin surface remains useful as a super_admin read-only roster, hence the wiring per the project decision to keep PMC-88 in scope.

#PMC-8 State Done
vas2000-work closed this pull request 2026-05-21 01:21:54 +02:00
Some checks failed
Check / clippy + fmt + tests (pull_request) Failing after 8s
Required
Details
Create release / Create release from merged PR (pull_request) Has been skipped

Pull request closed

Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
psa-systems/mokosh-apps!26
No description provided.