Skip to content

feat(ui): add OrganizationProfileApiKeysPanel mosaic component#9075

Merged
alexcarpenter merged 4 commits into
mainfrom
feat/mosaic-org-profile-api-keys-panel
Jul 9, 2026
Merged

feat(ui): add OrganizationProfileApiKeysPanel mosaic component#9075
alexcarpenter merged 4 commits into
mainfrom
feat/mosaic-org-profile-api-keys-panel

Conversation

@alexcarpenter

@alexcarpenter alexcarpenter commented Jul 2, 2026

Copy link
Copy Markdown
Member

Summary

Org API keys as Mosaic component. machine → controller → view split (mirrors DeleteSection/ProfileSection). Parity w/ legacy components/APIKeys/APIKeys.tsx (org scope). Standalone on main (profile-section merged #9068).

Preview: https://swingset-git-feat-mosaic-org-profile-api-keys-panel.clerkstage.dev/organization/organization-profile-api-keys-panel

Included

  • *-create.machine.ts — create + copy-secret (closed→editing→creating→showingSecret), name-length guard, injected createAPIKey.
  • *-revoke.machine.ts — revoke (idle→confirming→revoking), "Revoke" word guard.
  • *.controller.tsx — only Clerk-touching layer: useOrganization/useSession gating, org:sys_api_keys:read/:manage, useAPIKeys list+search+paginate, wires machines to clerk.apiKeys.create/revoke+revalidate, maps APIKeyResource→row, mapCreateApiKeyError.
  • *.view.tsx — props-only plain HTML (search, create form, table+per-row revoke, prev/next, copy-secret dialog, revoke confirm).
  • *.tsx — wrapper gating status === "ready".
  • Wired into OrganizationProfile.ApiKeysPanel namespace only. No public/experimental export.

Scope

  • Plain HTML, behavior-first. Styling/shared primitives follow-up.
  • Org-only.
  • Legacy OrganizationAPIKeysPage routing untouched (backwards-compat).

Tests

TDD, 47 tests (create 9, revoke 6, controller 14, view 18). Machines use createActor; controller mocks @clerk/shared/react; view renders fake snapshots.

Changeset

Empty — no user-facing surface (mosaic not publicly exported).

Summary by CodeRabbit

  • New Features
    • Added an Organization Profile “API keys” section with search, pagination, and a dedicated tab.
    • Included API key creation with optional description/expiration handling, secret reveal with “Copy & Close”, and key revocation with confirmation and error messaging.
    • Panel behavior is permission-aware (hidden when API key reads aren’t allowed; manage actions depend on manage permissions).
  • Tests
    • Added interaction, state-flow, controller, and view coverage for create/revoke, including success, validation gates, and failure/error scenarios.

@changeset-bot

changeset-bot Bot commented Jul 2, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 94ca494

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 0 packages

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel

vercel Bot commented Jul 2, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
clerk-js-sandbox Ready Ready Preview, Comment Jul 9, 2026 7:47pm
swingset Ready Ready Preview, Comment Jul 9, 2026 7:47pm

Request Review

@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Repository UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: f552c9b5-9204-446b-9489-8e27c2c41bba

📥 Commits

Reviewing files that changed from the base of the PR and between f392bbf and 94ca494.

📒 Files selected for processing (2)
  • packages/ui/src/mosaic/organization/__tests__/organization-profile-api-keys-panel.view.test.tsx
  • packages/ui/src/mosaic/organization/organization-profile-api-keys-panel.view.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/ui/src/mosaic/organization/tests/organization-profile-api-keys-panel.view.test.tsx
  • packages/ui/src/mosaic/organization/organization-profile-api-keys-panel.view.tsx

📝 Walkthrough

Walkthrough

Adds an Organization API Keys panel with create/revoke state machines, a controller hook, a presentational view, OrganizationProfile tab wiring, and Storybook/docs registration.

Changes

Organization API Keys Panel

Layer / File(s) Summary
Create API key machine
packages/ui/src/mosaic/organization/organization-profile-api-keys-panel-create.machine.ts, packages/ui/src/mosaic/organization/__tests__/organization-profile-api-keys-panel-create.machine.test.ts
Defines the create-flow state machine and tests its open, submit, error, cancel, and secret-reveal transitions.
Revoke API key machine
packages/ui/src/mosaic/organization/organization-profile-api-keys-panel-revoke.machine.ts, packages/ui/src/mosaic/organization/__tests__/organization-profile-api-keys-panel-revoke.machine.test.ts
Defines the revoke-flow state machine and tests request, confirmation, success, failure, and cancel behavior.
Panel controller hook
packages/ui/src/mosaic/organization/organization-profile-api-keys-panel.controller.tsx, packages/ui/src/mosaic/organization/__tests__/organization-profile-api-keys-panel.controller.test.tsx
Implements Clerk-backed list fetching, permission gating, debounced search, machine wiring, and error mapping, with controller tests.
Panel view rendering
packages/ui/src/mosaic/organization/organization-profile-api-keys-panel.view.tsx, packages/ui/src/mosaic/organization/__tests__/organization-profile-api-keys-panel.view.test.tsx
Renders the API keys list, create form, revoke flow, pagination, and secret dialog, with interaction tests.
Panel wrapper and OrganizationProfile integration
packages/ui/src/mosaic/organization/organization-profile-api-keys-panel.tsx, packages/ui/src/mosaic/organization/organization-profile-view.tsx, packages/ui/src/mosaic/organization/organization-profile.tsx
Adds the wrapper component and exposes the API keys panel as a new OrganizationProfile tab and compound export.
Storybook and docs registration
packages/swingset/src/components/DocsViewer.tsx, packages/swingset/src/lib/registry.ts, packages/swingset/src/stories/organization-profile-api-keys-panel.*, packages/swingset/src/stories/organization-profile.mdx, packages/swingset/src/stories/organization-profile.stories.tsx, .changeset/org-profile-api-keys-panel.md
Registers the new story and docs entry, updates the organization profile demo composition, and adds a changeset.

Estimated code review effort: 4 (Complex) | ~60 minutes

Suggested reviewers: wobsoriano, mauricioabreu

Poem

I nibbled a key and hopped with delight,
Two machines went churning from morning to night.
A tab for the secrets, a story to see,
This bunny says: “ship the API key spree!” 🐰

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 12.50% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: adding the OrganizationProfileApiKeysPanel Mosaic component.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

Comment @coderabbitai help to get the list of available commands.

Rebuilds the organization API keys experience (list, search, paginate, create + copy-secret, revoke-with-confirmation, permission gating) as a Mosaic machine/controller/view component, exposed via the OrganizationProfile compound namespace.
@pkg-pr-new

pkg-pr-new Bot commented Jul 9, 2026

Copy link
Copy Markdown

Open in StackBlitz

@clerk/astro

npm i https://pkg.pr.new/@clerk/astro@9075

@clerk/backend

npm i https://pkg.pr.new/@clerk/backend@9075

@clerk/chrome-extension

npm i https://pkg.pr.new/@clerk/chrome-extension@9075

@clerk/clerk-js

npm i https://pkg.pr.new/@clerk/clerk-js@9075

@clerk/electron

npm i https://pkg.pr.new/@clerk/electron@9075

@clerk/electron-passkeys

npm i https://pkg.pr.new/@clerk/electron-passkeys@9075

@clerk/eslint-plugin

npm i https://pkg.pr.new/@clerk/eslint-plugin@9075

@clerk/expo

npm i https://pkg.pr.new/@clerk/expo@9075

@clerk/expo-passkeys

npm i https://pkg.pr.new/@clerk/expo-passkeys@9075

@clerk/express

npm i https://pkg.pr.new/@clerk/express@9075

@clerk/fastify

npm i https://pkg.pr.new/@clerk/fastify@9075

@clerk/hono

npm i https://pkg.pr.new/@clerk/hono@9075

@clerk/localizations

npm i https://pkg.pr.new/@clerk/localizations@9075

@clerk/nextjs

npm i https://pkg.pr.new/@clerk/nextjs@9075

@clerk/nuxt

npm i https://pkg.pr.new/@clerk/nuxt@9075

@clerk/react

npm i https://pkg.pr.new/@clerk/react@9075

@clerk/react-router

npm i https://pkg.pr.new/@clerk/react-router@9075

@clerk/shared

npm i https://pkg.pr.new/@clerk/shared@9075

@clerk/tanstack-react-start

npm i https://pkg.pr.new/@clerk/tanstack-react-start@9075

@clerk/testing

npm i https://pkg.pr.new/@clerk/testing@9075

@clerk/ui

npm i https://pkg.pr.new/@clerk/ui@9075

@clerk/upgrade

npm i https://pkg.pr.new/@clerk/upgrade@9075

@clerk/vue

npm i https://pkg.pr.new/@clerk/vue@9075

commit: 94ca494

@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

API Changes Report

Generated by Break Check on 2026-07-09T19:48:52.861Z

Summary

Metric Count
Packages analyzed 19
Packages with changes 0
🔴 Breaking changes 0
🟡 Non-breaking changes 0
🟢 Additions 0

No API Changes Detected

All packages have stable APIs with no detected changes.


Report generated by Break Check

Last ran on 94ca494.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (3)
packages/ui/src/mosaic/organization/organization-profile-api-keys-panel.tsx (1)

6-13: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add JSDoc to the public OrganizationProfileApiKeysPanel component.

This component is exposed via OrganizationProfile.ApiKeysPanel and as a flat export, making it reference-facing. It currently has per-prop inline comments but no top-level JSDoc describing purpose/usage, which Docs generation relies on.

As per path instructions, "check whether the corresponding JSDoc is present, accurate, and aligned with the implementation" for public/reference-facing APIs, and "leave a review note reminding the contributor that the Docs team may need to review the change."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/ui/src/mosaic/organization/organization-profile-api-keys-panel.tsx`
around lines 6 - 13, Add top-level JSDoc for OrganizationProfileApiKeysPanel so
the public component has a clear purpose/usage description for Docs generation.
Keep the existing prop comments, but add a concise component-level doc above
OrganizationProfileApiKeysPanel that matches its implementation and mentions its
reference-facing exposure through OrganizationProfile.ApiKeysPanel and the flat
export; also leave a brief review note that the Docs team may need to review the
change.

Source: Path instructions

packages/ui/src/mosaic/organization/organization-profile-api-keys-panel.view.tsx (1)

119-124: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add an explicit return type to the exported view component.

As per coding guidelines, **/*.{ts,tsx} files should "Always define explicit return types for functions, especially public APIs."

♻️ Proposed fix
+import type { ReactElement } from 'react';
+
 export function OrganizationProfileApiKeysPanelView({
   list,
   canManage,
   create,
   revoke,
-}: OrganizationProfileApiKeysPanelViewProps) {
+}: OrganizationProfileApiKeysPanelViewProps): ReactElement {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/ui/src/mosaic/organization/organization-profile-api-keys-panel.view.tsx`
around lines 119 - 124, The exported OrganizationProfileApiKeysPanelView
component is missing an explicit return type, which violates the TypeScript API
guideline for public functions. Update the OrganizationProfileApiKeysPanelView
declaration to include a clear return type annotation for the JSX it renders,
keeping the component signature explicit while preserving its current behavior.

Source: Coding guidelines

packages/ui/src/mosaic/organization/__tests__/organization-profile-api-keys-panel.controller.test.tsx (1)

104-196: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add coverage for the debounce and page-clamp effects.

The debounced search reset (controller lines 81-87) and the page-clamp-after-deletion effect (lines 89-94) aren't exercised by any test here.

As per coding guidelines, **/*.{test,spec}.{ts,tsx,js,jsx} requires that tests "Verify proper error handling and edge cases."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/ui/src/mosaic/organization/__tests__/organization-profile-api-keys-panel.controller.test.tsx`
around lines 104 - 196, The test suite for
useOrganizationProfileApiKeysPanelController is missing coverage for the
debounce-based search reset and the page-clamp-after-deletion effect. Add
focused tests in organization-profile-api-keys-panel.controller.test.tsx that
exercise the search-related state path driven by the controller’s debounce logic
and verify the selected page is reset/clamped when deletions reduce the total
page count. Use the existing Harness, apiKeysArgs, and revalidate/setup patterns
to locate and assert the behavior around the controller’s search and pagination
effects.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/swingset/src/stories/organization-profile-api-keys-panel.mdx`:
- Around line 7-17: `OrganizationProfileApiKeysPanel` is a leaf panel, so its
MDX should not declare `OrganizationProfile` in the Story composition. Update
the `Story` in `organization-profile-api-keys-panel.mdx` to remove the inverted
`composition` entry and keep the file focused on the panel itself; use
`OrganizationProfile` only in the parent `organization-profile.mdx` where the
wiring actually happens.

In
`@packages/ui/src/mosaic/organization/organization-profile-api-keys-panel.view.tsx`:
- Around line 244-253: The per-row Revoke button is still clickable while the
revoke flow is already in `confirming` or `revoking`, but `revoke.send({ type:
'REQUEST', ... })` is ignored in those states, causing a silent dead click.
Update the `organization-profile-api-keys-panel.view.tsx` row action around the
`Revoke` button to disable it or otherwise block clicks whenever the revoke
machine is not idle, using the existing `revoke` state in the component so a
second row cannot trigger a no-op request.

---

Nitpick comments:
In
`@packages/ui/src/mosaic/organization/__tests__/organization-profile-api-keys-panel.controller.test.tsx`:
- Around line 104-196: The test suite for
useOrganizationProfileApiKeysPanelController is missing coverage for the
debounce-based search reset and the page-clamp-after-deletion effect. Add
focused tests in organization-profile-api-keys-panel.controller.test.tsx that
exercise the search-related state path driven by the controller’s debounce logic
and verify the selected page is reset/clamped when deletions reduce the total
page count. Use the existing Harness, apiKeysArgs, and revalidate/setup patterns
to locate and assert the behavior around the controller’s search and pagination
effects.

In `@packages/ui/src/mosaic/organization/organization-profile-api-keys-panel.tsx`:
- Around line 6-13: Add top-level JSDoc for OrganizationProfileApiKeysPanel so
the public component has a clear purpose/usage description for Docs generation.
Keep the existing prop comments, but add a concise component-level doc above
OrganizationProfileApiKeysPanel that matches its implementation and mentions its
reference-facing exposure through OrganizationProfile.ApiKeysPanel and the flat
export; also leave a brief review note that the Docs team may need to review the
change.

In
`@packages/ui/src/mosaic/organization/organization-profile-api-keys-panel.view.tsx`:
- Around line 119-124: The exported OrganizationProfileApiKeysPanelView
component is missing an explicit return type, which violates the TypeScript API
guideline for public functions. Update the OrganizationProfileApiKeysPanelView
declaration to include a clear return type annotation for the JSX it renders,
keeping the component signature explicit while preserving its current behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Repository UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 7b9397c6-e4c3-4dd9-9cca-77808db29f9d

📥 Commits

Reviewing files that changed from the base of the PR and between 80a2b4d and f392bbf.

📒 Files selected for processing (18)
  • .changeset/org-profile-api-keys-panel.md
  • packages/swingset/src/components/DocsViewer.tsx
  • packages/swingset/src/lib/registry.ts
  • packages/swingset/src/stories/organization-profile-api-keys-panel.mdx
  • packages/swingset/src/stories/organization-profile-api-keys-panel.stories.tsx
  • packages/swingset/src/stories/organization-profile.mdx
  • packages/swingset/src/stories/organization-profile.stories.tsx
  • packages/ui/src/mosaic/organization/__tests__/organization-profile-api-keys-panel-create.machine.test.ts
  • packages/ui/src/mosaic/organization/__tests__/organization-profile-api-keys-panel-revoke.machine.test.ts
  • packages/ui/src/mosaic/organization/__tests__/organization-profile-api-keys-panel.controller.test.tsx
  • packages/ui/src/mosaic/organization/__tests__/organization-profile-api-keys-panel.view.test.tsx
  • packages/ui/src/mosaic/organization/organization-profile-api-keys-panel-create.machine.ts
  • packages/ui/src/mosaic/organization/organization-profile-api-keys-panel-revoke.machine.ts
  • packages/ui/src/mosaic/organization/organization-profile-api-keys-panel.controller.tsx
  • packages/ui/src/mosaic/organization/organization-profile-api-keys-panel.tsx
  • packages/ui/src/mosaic/organization/organization-profile-api-keys-panel.view.tsx
  • packages/ui/src/mosaic/organization/organization-profile-view.tsx
  • packages/ui/src/mosaic/organization/organization-profile.tsx

REQUEST is only handled in the revoke machine's idle state, so clicking another row's Revoke while a revoke was confirming/revoking was a silent no-op. Disable the per-row button whenever the machine is not idle.
@alexcarpenter alexcarpenter enabled auto-merge (squash) July 9, 2026 19:51
@alexcarpenter alexcarpenter merged commit 85df1cc into main Jul 9, 2026
53 checks passed
@alexcarpenter alexcarpenter deleted the feat/mosaic-org-profile-api-keys-panel branch July 9, 2026 19:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants