Skip to content

ui: show an organization's sandboxes and API keys on its page - #1262

Merged
ac-pplx merged 5 commits into
ac/admin-ui-usersfrom
ac/admin-ui-org-detail
Nov 3, 2026
Merged

ac-pplx merged 5 commits into
ac/admin-ui-usersfrom
ac/admin-ui-org-detail

Conversation

@ac-pplx

@ac-pplx ac-pplx commented Oct 31, 2026 •

Copy link
Copy Markdown
Contributor

Summary

An organization's page now shows the organization's sandboxes and API keys.

Looking up an organization during a support case needs its users, sandboxes and keys together. The page showed only users (with per-user sandbox counts), branding and BYOK, so the rest meant switching pages and re-selecting the organization.

Changes:

  • Sandboxes: the organization's own sandbox rows, each linking to its page, plus a link to the sandbox list filtered to this organization. The org-scoped admin list can also carry rowless node-reported rows (warm-pool slots, observed-local sandboxes) that belong to no organization; they are left out of the card, its title and the users table's counts. The list counts as capped when the organization's own rows reach the 5000-row limit: the API's limit counts only database rows, all of which belong to the organization, and it appends node-reported rows beyond the limit. When capped, the title reads "5000+", the users' sandbox counts read as lower bounds ("≥n"), and a note says they cover only the newest 5000. After a failed load the card titles and the users total read "not loaded".
  • API keys: name, key ID, allowed APIs, creator and creation time, plus a link to the API Keys page opened on this organization (?org=, which that page now reads).
  • Both cards show loading while they load, and their own error with Retry and "Not loaded" instead of an empty list when they fail.
  • User names link to their pages.
  • Turning BYOK on or off now asks for confirmation and says what changes. Before, a single click toggled it. The confirmation and the card's own text now say what the flag does on every path that reads it: a new sandbox that is not a fork runs on an encrypted volume, and never comes from a warm pool, only when the organization's flag and the cluster's SPACE_BYOK_VOLUME_ENCRYPTION setting are both on; with the flag on, whatever that setting, create admission never claims a warm-pool slot for the organization (both in crates/libs/api/src/controllers/sandbox/queries.rs); a fork keeps its source's encryption, so with the flag on a fork of an encrypted sandbox stays encrypted whatever that setting and a fork of an unencrypted sandbox is refused, and with it off a fork of an encrypted sandbox is refused (crates/libs/api/src/fork_operation_executor.rs); the flag is shared with credential encryption (credential-manager reads organizations.byok_enabled); and existing sandboxes keep the encryption they were created with.

Quota usage is not shown. Per-organization sandbox limits are environment configuration (SPACE_NATIVE_ORG_SANDBOX_LIMIT*), and no API returns them.

Stack

Stacked on #1253 (user page), which is stacked on #1247. Merge those first. This branch is restacked on #1253's third review follow-up. Merge #1248 before it as well: the "Open in Sandboxes" link filters the sandbox list with ?org=, which #1248 adds, and #1248 stops the organization-scoped sandbox list, which this page reads, from including rowless warm-pool slots.

Validation

  • npm ci, npm test (60 pass) and npm run build in ui/.
  • A Playwright loop against a local Kind stack with synthetic data, on this branch (the Kind space-ui image):
    • organization pages link their sandboxes and show their keys;
    • toggling BYOK opens a confirmation, and both BYOK texts name the cluster setting, the shared flag, forks (which keep their source's encryption) and create-admission pool claims;
    • synthetic node-reported rows in the org list are not counted; 5000 organization rows plus ten node-reported rows read "5000+", with "≥n" per-user counts and the note, and 4990 organization rows plus ten node-reported rows read "4990", with no cap note; a failed card shows its error with Retry, and its title and the users total read "not loaded"; "Manage API keys" opens the API Keys page on this organization;
    • cancelling it leaves byok_enabled unchanged in the API.
  • No new console errors, page errors or failed requests compared with main.

Visual confirmation

Before After
before after

The BYOK confirmation:

BYOK confirmation

Severity and risk

Severity: medium.

Risk: low. The page makes one more read per load (the organization's keys). Roll back by reverting the commit.

AI assistance: Claude Code wrote the code and this description, and ran the validation; a maintainer reviews it.

@github-actions github-actions Bot added the triage:pending Waiting for a maintainer to triage label Oct 31, 2026
@github-actions

Copy link
Copy Markdown

Thanks for opening this pull request! A SPACE maintainer will take a look.

CONTRIBUTING.md explains how we review outside contributions.

zibi-pplx
zibi-pplx previously approved these changes Nov 1, 2026
@zibi-pplx
zibi-pplx dismissed their stale review November 1, 2026 22:30

Withdrawing this approval for now. Any feedback above still stands.

@ac-pplx
ac-pplx added this pull request to stack #1282 November 2, 2026 04:30
@ac-pplx
ac-pplx force-pushed the ac/admin-ui-org-detail branch from 168088f to 94933f1 Compare November 2, 2026 04:44
Looking up an organization during a support case needs its users,
sandboxes and keys together; the organization page showed only users
(with per-user sandbox counts), branding and BYOK, so the rest meant
switching pages and re-selecting the organization.

The page now lists the organization's sandboxes (linking to each, and to
the sandbox list filtered to the organization) and its API keys, and
user names link to their pages. Turning BYOK on or off, which changes
how every new sandbox in the organization is created, now asks for
confirmation and says what changes.
The org page's BYOK confirmation and card text said that enabling BYOK
puts new sandboxes on encrypted volumes. A new sandbox is encrypted only
when the org flag and the cluster's SPACE_BYOK_VOLUME_ENCRYPTION setting
are both on, and only then does it skip warm pools; the flag is also
shared with credential encryption. Both texts now say so, and that
existing sandboxes keep the encryption they were created with.
- The org page's Sandboxes card, its title and the users table's
  counts took every row of the org-scoped admin list, which can also
  carry rowless node-reported rows (warm-pool slots, observed-local
  sandboxes) that belong to no org. Only the org's sandbox rows count
  now, and a full 5000-row answer reads "5000+".
- The BYOK texts now hold on every path that reads the flag: with it
  on, create admission never claims a warm-pool slot and a fork of an
  unencrypted sandbox is refused, whatever the cluster's
  SPACE_BYOK_VOLUME_ENCRYPTION setting; with it off, a fork of an
  encrypted sandbox is refused.
- The Sandboxes and API keys cards show loading while they load, and
  their own error with Retry, and "Not loaded" instead of an empty
  list, when they fail.
- "Manage API keys" opens the API Keys page on this organization; the
  page takes the organization from `?org=`.
…PI's rows

- The BYOK enable confirmation, the card text and the code comments said
  new sandboxes are encrypted only where the cluster enables BYOK volume
  encryption. That is false for forks: a fork keeps its source's
  encryption, so forks of the organization's encrypted sandboxes stay
  encrypted whatever that setting, and forks of its unencrypted
  sandboxes are refused (fork_operation_executor.rs). The texts say so.
- The sandbox list counts as capped when the API returned its limit of
  rows, not when the organization's own rows reach it: the rowless
  node-reported rows it leaves out count against the limit too. When
  capped, the users' sandbox counts read as lower bounds (≥n) and the
  note says they cover only the listed sandboxes.
- After a failed load the card titles and the users total read "not
  loaded" instead of "…" forever, and each load resets the capped flag.
The previous change counted every row of the org-scoped answer against
the 5000-row limit. The admin list's limit applies only to database
rows, all of which belong to the org, and it appends node-reported rows
(rowless warm-pool slots, observed-local sandboxes) beyond the limit.
So an org with 4,900 sandboxes and 150 node-reported rows read as
capped. The list is capped again only when the org's own rows reach the
limit.

@johnlouie-pplx johnlouie-pplx 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.

Approving.

6dccec9 is the same patch as 168088f, rebased. On main the org-scoped admin sandbox list no longer appends node-reported rows (include_observed_only is false when org_id is set), so the page's own-rows filter and the API's 5000-row cap now count the same rows. "Open in Sandboxes" filters by org now that #1248 is in. The key cards still show only ApiKeyMetadata, with no secret or hash. npm test (151 pass), tsc and next build pass on 6dccec9. I didn't run it in a browser.

@ac-pplx
ac-pplx added this pull request to the merge queue Nov 3, 2026
Merged via the queue into main with commit 09e37a2 Nov 3, 2026
23 checks passed
@ac-pplx
ac-pplx deleted the ac/admin-ui-org-detail branch November 3, 2026 04:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

triage:pending Waiting for a maintainer to triage

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants