Skip to content

fix(ui): draw a refused list or related-list read as no-access, not a retryable failure - #27856

Merged
objectstack-fleet[bot] merged 3 commits into
mainfrom
claude/project-thread-8rp5dl
Oct 30, 2026
Merged

objectstack-fleet[bot] merged 3 commits into
mainfrom
claude/project-thread-8rp5dl

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Bill · project thread

维护者速读

  • 改了什么:列表读取被拒(403)时不再显示「重试」按钮;记录页相关列表读取被拒时改画一行中性的「无权访问」提示,不再是红框加「你无权执行此操作」。
  • 为什么改:成员只是没有读权限,重试不可能变好;红色的动作拒绝句让只来查看记录的人以为自己做错了事。
  • 风险与回滚:只动两个组件的拒绝态分支,5xx、网络失败、api-disabled 的画法不变;回滚即还原本 PR 两个源文件。
  • 先看:ui/packages/plugin-detail/src/RelatedList.tsx 的 RelatedListLoadFailed;ui/packages/plugin-list/src/ListView.tsx 的 list-error-retry 条件。
  • 两分钟验证:pnpm --dir ui exec vitest run packages/plugin-list/src/__tests__/ListView.forbiddenNoRetry.test.tsx packages/plugin-detail/src/__tests__/RelatedList.readFailed-26415.test.tsx,预期全绿。
  • 需要你做的:无,席位落地。

Fixes #27841

Clause-②: no
Metadata-protocol: none

What changes

  • List view (plugin-list ListView). The load-error panel no longer draws the Retry button for the forbidden kind (a 403 / PERMISSION_DENIED read), joining api-disabled. A refusal is a grant only an administrator can give, so a retry re-reaches the same refusal. network (network failures and 5xx), unauthorized and rejected keep Retry.
  • Related list (plugin-detail RelatedListLoadFailed). A forbidden read is drawn as a neutral line: role="status" instead of alert, border-border bg-muted/40 and a muted icon instead of the destructive tint, no Retry, and always the list's existing no-access sentence (list.loadErrorForbiddenTitle / list.loadErrorForbiddenMessage). A producer's userMessage on a 403 is no longer shown there: the server marks the generic action refusal ("You do not have permission to perform this action. Contact your administrator if you need access.") on a refused read, which was the red sentence the card saw. Every other kind is drawn exactly as before.
  • No new i18n key; no copy changed.

Tests

  • New plugin-list/src/__tests__/ListView.forbiddenNoRetry.test.tsx: a 403 draws the no-access panel with no Retry; controls: a 500 and a network failure still draw Retry.
  • plugin-detail/src/__tests__/RelatedList.readFailed-26415.test.tsx gains a describe: a 403 carrying the action-refusal userMessage draws role="status", no destructive class on the line or its icon, the no-access title and sentence, no "perform this action", no Retry; controls: a 5xx keeps role="alert", the destructive styling and Retry; a readable related list draws its rows.
  • ListView.errorStateComponent-7143.test.tsx: the "retry button is still rendered" arm now fails with a 500 instead of a 403, since a 403 no longer offers one.

Acceptance notes

  • Repro on main = the ablation. Both source files restored to the base 38651598 (tests unchanged): the two new refusal tests fail (ListView: Retry button present; RelatedList: role="alert" received where status expected), and their 14 sibling tests, the controls included, pass. Restored by git checkout HEAD, git diff HEAD empty, blob hashes equal HEAD. The red action sentence on main is read from the code (declaredUserMessage wins over the fixed copy) and is asserted absent by the new test on the fixed tree; it was not measured on a live stack.
  • unauthorized (401, "Sign in required") still offers Retry in both places. The card names 403 only; left as is.
  • The ListView forbidden panel still uses its text-destructive/60 icon; the card asks only that it drop Retry.
  • Seat 4's draft PR fix(console): a declared same-origin type: 'api' click goes through the action door #27793 regions (RelatedList.tsx docblock near the API-door note, RecordDetailView.tsx apiHandler) are not touched; this diff edits only RelatedListLoadFailed and its docblock.

Verification

All readings on head fa457cd3 (branch merged with origin/main).

Tests and type-check
  • pnpm --dir ui exec vitest run --maxWorkers=2 on ListView.forbiddenNoRetry.test.tsx, ListView.errorStateComponent-7143.test.tsx, ListView.loadErrorKind.test.tsx, RelatedList.readFailed-26415.test.tsx: Test Files 4 passed (4), Tests 39 passed (39); os-verify-lock VERDICT command-exit 0.
  • Ablation (base source, new tests): Tests 2 failed, 14 passed (16); VERDICT command-exit 1; the two failures are the two refusal tests.
  • pnpm --filter @object-ui/plugin-list --filter @object-ui/plugin-detail run type-check (tsc --noEmit and tsconfig.test.json): VERDICT command-exit 0, on the pre-merge head; the merge brought nothing under these packages.
Gates
  • dispatch-gates --commands derived 34 families; all 34 ran, exit 0. --ran reconciliation: 34 derived, 34 run, 0 NOT-MEASURED, 0 UNRUN. node scripts/check-sdui-manifest.mjs among them, exit 0.
  • pnpm check:new-line-citations (ui): 0 new citation(s), exit 0.
  • Repo-wide families and Test UI belong to CI; see this PR's check-runs.

🤖 Generated with Claude Code


Generated by Claude Code

… retryable failure

A 403 list read no longer offers Retry; a refused related-list read draws a
neutral status line with the list's no-access sentence instead of a red
action-refusal line.

Claude-Session: https://claude.ai/code/session_01Utp6CqyAqjJmMJkdAQoyqn
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added size/m documentation Improvements or additions to documentation tooling labels Oct 30, 2026
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:ui#4 · os-bill · session_01Utp6CbDAucNyQ4UtzCJKyh

席位核对

ACCEPT · head fa457cd38802fa456d7892346b8cbb9c409458ee · 2026-10-30T02:29Z

  • Shape: draft → main, Fixes #27841. Clause-②: no and Metadata-protocol: none. No new i18n key. The changeset is patch on @object-ui/plugin-list and @object-ui/plugin-detail.
  • Change, read (6 files, +163/−12 against origin/main):
    • ListView.tsx: a forbidden load error draws no Retry, alongside api-disabled. Network and 5xx keep Retry.
    • RelatedList.tsx RelatedListLoadFailed: a forbidden read is drawn as role="status" with a neutral border and a muted icon, and no Retry. It always says the list's no-access sentence (list.loadErrorForbidden*). The producer's 403 userMessage, the generic "perform this action" refusal, is no longer shown for a read. Every other kind keeps role="alert", its styling, Retry and userMessage.
    • The RelatedList.tsx ~L811 docblock and RecordDetailView.tsx apiHandler (in-flight PR fix(console): a declared same-origin type: 'api' click goes through the action door #27793) are untouched.
  • Evidence (report 6513310163): 4 test files, 39/39 green. The ablation, with both sources restored to 38651598, turns the two refusal tests red and keeps 14 siblings and controls green. Both packages type-check green. Derived gates: 34/34 exit 0.
  • Deviation: the three commits' Claude-Session trailer misspells the thread session id. It is declared, and history on the thread branch is not rewritten. The PR body footer is correct. There is no live-stack reproduction; the reading on main is the ablation.
  • Gates (check-runs on the head): 44 success, 11 skipped, 0 failure. check-governed-merges --pr 27856: NOT governed, 175 changed lines.
  • Landing: non-governed, all green, mergeable_state clean, so the seat lands it with pr_ready and automerge_enable.

Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/m tooling

Projects

None yet

1 participant