Skip to content

feat(admin): WorkOS Users list page (1.0.5)#20

Merged
bordoni merged 1 commit into
mainfrom
feature/workos-users-admin-page
May 19, 2026
Merged

feat(admin): WorkOS Users list page (1.0.5)#20
bordoni merged 1 commit into
mainfrom
feature/workos-users-admin-page

Conversation

@bordoni
Copy link
Copy Markdown
Owner

@bordoni bordoni commented May 18, 2026

Summary

  • New WorkOS → Users admin submenu — paginated, searchable React list of WorkOS users for the active environment.
  • Each row exposes an Open in WorkOS deep-link to dashboard.workos.com/{env}/users/{id}/details so admins can re-enable a suppressed email (and otherwise triage the user) from the Dashboard's Emails tab.
  • Backed by GET /wp-json/workos/v1/admin/users (gated by manage_options), a thin sanitizing proxy over Api\Client::list_users(). Cursor pagination (after / before, after wins when both supplied), limit clamped to 1..100, email substring + organization_id pass-through. Each user record is enriched server-side with a dashboard_url.

Refs CONS-273 — Re-enable WorkOS emails for affected portal users. Targets the 1.0.5 milestone.

Why list-only — no bulk re-enable

This PR intentionally does not ship a bulk re-enable action. WorkOS exposes the "Re-enable email" suppression-clear action only through the Dashboard UI as of 2026-05-18. Verified against:

  • workos.com/docs/email and workos.com/docs/reference — Dashboard-only flow, no curl example.
  • workos.com/docs/reference/user-management/user — the User schema has no email_disabled, suppressed, or email_status field.
  • workos.com/docs/events — no email.suppressed / user.email.bounced event.
  • workos/workos-node, workos-python, workos-ruby, workos-go on GitHub — zero matches for suppression, reenable, or email_disabled.
  • The 2026-03-13 email-suppression-management changelog announcing the Dashboard feature, with no API counterpart mentioned.

The deep-link UI gets admins one click closer to the action they need today. Once WorkOS ships a public suppression endpoint, a row + bulk "Re-enable email" action wires into the existing list page without a UI rewrite.

Architecture notes

  • Mirrors the admin-profiles precedent end-to-end: single-file index.tsx, plain fetch() + X-WP-Nonce, wp_localize_script hydration on #workos-users-admin-root, scoped CSS, DI-container registration in src/WorkOS/Controller.php. No new libraries.
  • New files:
    • src/WorkOS/Admin/Users/Controller.php — service-provider wiring.
    • src/WorkOS/Admin/Users/AdminPage.php — submenu + asset enqueue + localization.
    • src/WorkOS/Admin/Users/RestApi.php — REST proxy + dashboard_url enrichment.
    • src/js/admin-users/index.tsx + styles.css — React user list.
    • tests/wpunit/AdminUsersRestApiTest.php — 8 cases (33 assertions).
  • Version bumped to 1.0.5 in integration-workos.php, src/WorkOS/Plugin.php, readme.txt, AGENTS.md. Changelog entries added in CHANGELOG.md + readme.txt.

Test plan

  • bun run build — emits build/admin-users.{js,css,asset.php} cleanly (6.88 KB JS, 1.93 KB CSS).
  • bun run lint:ts — clean.
  • composer lint — clean.
  • composer phpstan — clean (PHPStan level 5, 89 files).
  • slic run tests/wpunit/AdminUsersRestApiTest.php — 8 tests, 33 assertions, all green. Covers: anonymous + subscriber forbidden, shaped response with dashboard_url, limit clamping to 100, email substring forwarding, after cursor forwarding, after wins over before, upstream error surfacing in envelope.
  • Full slic run wpunit — 460 tests, 4 failures pre-existing on main, unrelated to this branch (confirmed by reproducing on main with no changes applied).
  • Manual smoke in wp-admin: confirm the Users submenu appears under WorkOS for manage_options users and is absent for editors; first load returns ≤25 users in < 2 s; search by email narrows the list; Next/Prev cursor pagination round-trips; Open in WorkOS opens the user's Dashboard page in a new tab.
  • Capability check via REST: editor session receives 403 from GET /wp-json/workos/v1/admin/users.

Follow-ups (separate tickets, not in this PR)

  • File a WorkOS feature request for a public email_suppressions / re-enable endpoint and a user.email_suppressed webhook event.
  • Once that API exists: add row + bulk "Re-enable email" action, plumb through POST /wp-json/workos/v1/admin/users/bulk-reenable.
  • Optional later polish: column sort (currently blocked by WorkOS API not supporting sort), organization filter, CSV export.

New "WorkOS → Users" admin submenu mounts a paginated, searchable React
list of WorkOS users for the active environment. Each row exposes an
"Open in WorkOS" deep-link to dashboard.workos.com/{env}/users/{id}/details
so admins can re-enable a suppressed email (and otherwise triage the user)
in the Dashboard's Emails tab.

Backed by GET /wp-json/workos/v1/admin/users (manage_options) which
proxies Api\Client::list_users() with sanitized limit (1..100), cursor
(after/before, after wins), email substring and organization_id
pass-through. Each user record is enriched server-side with a
dashboard_url so the React client doesn't reconstruct it.

No bulk re-enable in this release: WorkOS exposes the "Re-enable email"
action only through the Dashboard. Verified against the API reference,
the User schema, the Events catalogue, and the public workos-node /
-python / -ruby / -go SDK sources — there is no email-suppression API,
no email_disabled field, and no email.suppressed webhook event as of
2026-05-18. The page is built so a future bulk action wires in without
a UI rewrite.

Refs CONS-273.
@bordoni bordoni added this to the 1.0.5 milestone May 18, 2026
@bordoni bordoni self-assigned this May 18, 2026
@bordoni bordoni merged commit 455d166 into main May 19, 2026
7 checks passed
@bordoni bordoni deleted the feature/workos-users-admin-page branch May 19, 2026 02:04
bordoni added a commit that referenced this pull request May 19, 2026
Now that the WorkOS Users admin page from #20 has landed in main, wire
the per-row "Send password reset" trigger that was deferred until the
two PRs converged.

- `Admin\Users\RestApi::shape_user()` now resolves the linked WP user
  id via `_workos_user_id` user-meta and includes it as `wp_user_id` on
  every row. Empty (0) when the WorkOS user has no WP counterpart yet.
- `Admin\Users\AdminPage::maybe_enqueue_assets()` enqueues the shared
  `PasswordResetAdmin\Assets` script + style so the page already has
  the click handler when the row buttons mount.
- React row in `src/js/admin-users/index.tsx` renders a
  `.workos-pwreset-trigger` button next to the "Open in WorkOS" link
  whenever `wp_user_id > 0`. The shared delegated click handler picks
  it up and posts to the admin endpoint exactly like the row action on
  wp-admin/users.php.

No new tests — the row resolution path is covered by the existing
`AdminUsersRestApiTest` (the shape exporter is the only changed
surface), the click handler by `PasswordResetAdminRestApiTest`, and
both files have been re-run green locally.
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.

2 participants