fix(web-studio): address #2309 review feedback + edge-case polish#2313
Open
ZaynJarvis wants to merge 3 commits into
Open
fix(web-studio): address #2309 review feedback + edge-case polish#2313ZaynJarvis wants to merge 3 commits into
ZaynJarvis wants to merge 3 commits into
Conversation
…follow-up) - Wrap navigator.clipboard.writeText calls in try/catch so a denied permission or insecure-context failure surfaces a toast instead of silently disappearing (`void copyKey(...)` was swallowing rejections). - Trim accountId / userId / adminUserId on dialog submit so users can't accidentally create entities with leading/trailing whitespace. - AddUserDialog: drop defaultAccountId from the reset effect deps so a parent re-rendering with a new managedAccountId while the dialog is open no longer wipes whatever the user already typed. - Add a defaultValue fallback to the serverMode badge translation so an unknown mode renders the mode key instead of the raw i18n path. - Add settings.toast.copyFailed strings (en, zh-CN) for the new error.
PR Reviewer Guide 🔍Here are some key observations to aid the review process:
|
PR Code Suggestions ✨Explore these optional code suggestions:
|
…only Qodo flagged the missing defaultAccountId dep — restoring it directly would re-introduce the input-wipe bug the previous commit was fixing (parent re-render with new managedAccountId blanks the draft mid-typing). Use a prevOpenRef so the reset only fires when `open` transitions false→true. defaultAccountId stays in the deps to satisfy exhaustive-deps, but a change to it while the dialog is already open no longer triggers a reset.
…ckers)
1. Revert transport-layer connection defaults to empty (was `default`
/ `default`). The earlier defaults caused non-root keys
(`acme/alice`) to be rejected because ovClient was sending
`X-OpenViking-Account: default` / `X-OpenViking-User: default`
headers that override the key's identity. The settings UI still
shows `default` as a display fallback via `value || DEFAULT_X`.
2. Decouple `adminUnavailable` from `accountsQuery` so an
account-admin key (whose `GET /admin/accounts` returns 403) can
still list/regenerate/create users in its own account.
- New `isRootRestricted = accountsQuery.isError` flag.
- Connection card and management filter both fall back to a free-
text `<Input>` (instead of a dropdown) when `isRootRestricted`,
so the user can type their accountId.
- "Add account" button is disabled when `isRootRestricted`
(POST /admin/accounts is root-only); "Add user" and "Regenerate"
stay enabled (per-account, allowed for account admins).
- New effect syncs `managedAccountId` to whatever the user types
in the connection card when `isRootRestricted`, so they don't
have to enter it twice.
3. Fix `totalUsers` fallback: `reduce(...) || managedUsers.length`
would mask a legitimate 0 from the reduce with the managed users
count. Switched to `accountOptions.length ? reduce : managedUsers`
so an account list with 0 users is shown as 0 (and the fallback
only kicks in when there's no visible account list at all).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Follow-up PR for #2309. Originally just edge-case polish for the settings page; expanded to address the two blocking review comments from @qin-ctx on #2309 (auth-boundary regressions) plus the qodo bot's totalUsers bug.
Related Issue
Follow-up to #2309. Addresses inline review comments on:
web-studio/src/hooks/use-app-connection.tsx#L36— non-default keys gettingdefault/defaultheadersweb-studio/src/routes/settings/route.tsx#L687— account-admin keys locked out by root-onlyaccountsQueryweb-studio/src/routes/settings/route.tsx#R682-R684(qodo) —totalUsers || managedUsers.lengthmasks legitimate 0Type of Change
Changes Made
Blocker fixes (from @qin-ctx)
Restore empty transport defaults.
DEFAULT_CONNECTIONhadaccountId: 'default'anduserId: 'default', which madeovClientsendX-OpenViking-Account: default/X-OpenViking-User: defaultheaders on every request. Any user with a non-default API key (e.g.acme/alice) would get those headers overriding their key's identity and the server would reject the call before the user even chose anything. Reverted to empty strings; the settings UI still showsdefaultas a display fallback viavalue || DEFAULT_X, so the visual behavior is unchanged.Decouple account-admin flow from root-only
GET /admin/accounts. PreviouslyaccountsQuery.isErrorfed intoadminUnavailable, so an account-admin key (whose root-only call returns 403) saw the emptyAdmin access requiredstate and couldn't manage users in their own account. NewisRootRestricted = accountsQuery.isErrorflag splits the two cases:<Input>(instead of a<Select>) whenisRootRestricted, so the user can type their accountId.isRootRestricted(the underlyingPOST /admin/accountsis root-only). "Add user" and "Regenerate" stay enabled — they're per-account and account-admins can use them on their own account.managedAccountIdto whatever the user types in the connection card whenisRootRestricted, so an account admin doesn't have to enter the same accountId twice.Fix
totalUsersfallback.accountOptions.reduce(...) || managedUsers.lengthwould mask a legitimate sum of 0 from the reduce with the managed users count. Switched to a ternary so the fallback only kicks in when there's no visible account list at all.Edge-case polish (original scope)
Clipboard errors no longer disappear.
navigator.clipboard.writeTextcan reject (permission denied, insecure context, locked-down browser). BothcopyKeycallers wereawait-ing the call and then immediatelytoast.success, but in the table the click handler used() => void copyKey(user.apiKey)which discarded the rejection — the user saw nothing. Both call sites nowtry/catchand emittoast.error(t('toast.copyFailed', { message })).Trim account / user IDs before submitting the dialogs.
AddAccountDialogandAddUserDialogused to passdraftstraight toonCreate, so leading/trailing whitespace would have been persisted as part ofaccount_id/user_id.AddUserDialogreset effect: only fire on closed→open. Now uses aprevOpenRefso a parent re-render with a newmanagedAccountIdwhile the dialog is open no longer wipes whatever the user already typed.defaultAccountIdstays in the deps to satisfyreact-hooks/exhaustive-depsif/when it's ever enabled.Robust
serverModelabel.t(\serverMode.${serverMode}`)now passesdefaultValue: serverModeso a future mode (e.g.oauth`) renders as the mode key instead of the raw translation path.i18n strings. Added
settings.toast.copyFailedfor bothenandzh-CNto back the new error toast.Testing
Commands run on this iMac (darwin-arm64, Node 22.22.0, pnpm 10.33.0):
node_modules/.bin/tsc --noEmit— cleanpnpm run lint— 0 errors, 15 warnings (the same 15 pre-existingi18next/no-literal-stringwarnings insrc/routes/resources/-components/file-preview.tsxflagged in feat: add web studio account user management #2309)pnpm run build— greenhttp://localhost:3000/settings:Connection & Identity, both account/user dropdowns showdefaultfallback, all stats show-.accountsQueryto 404 →isRootRestricted=true): Account field becomes a typeable<Input>withteam-accountplaceholder, management filter becomes a typeable<Input>, "Add account" is correctly disabled, "Add user" stays enabled.I did not run live admin mutations — these fixes are pure client-side identity routing and UI gating and don't change request shapes.
Checklist