Repository navigation
fix(app-shell): hold a new item whose name the client refuses; one message per mistake on the Setup metadata edit page - #27938
Merged
Conversation
…age per mistake (#27865) New Permission Set sent a name the client validator had already refused, then stacked the server refusal, the summary banner and the inline error. A create whose identity field the live pass refuses is now held with no request, the Save attempt reveals the create form's deferred field errors, and an error the form draws on its field is no longer repeated by the summary banner or the refusal line. Claude-Session: https://claude.ai/code/session_01Utp6CZcCCHhGAp4cezRhuD Co-authored-by: Claude <noreply@anthropic.com>
…gistration (#27865) Claude-Session: https://claude.ai/code/session_01Utp6CZcCCHhGAp4cezRhuD Co-authored-by: Claude <noreply@anthropic.com>
#27865) Claude-Session: https://claude.ai/code/session_01Utp6CZcCCHhGAp4cezRhuD Co-authored-by: Claude <noreply@anthropic.com>
…n an effect, not during render (#27865) Claude-Session: https://claude.ai/code/session_01Utp6CZcCCHhGAp4cezRhuD Co-authored-by: Claude <noreply@anthropic.com>
…out beside the advisory suite (#27865) A good Name beside a client-refused non-identity key (the server-gained-a-key skew shape) still sends on the create door, so widening the hold to any live issue goes red. The advisory suite's header names the carve-out and points at the suite that pins both of its halves. Claude-Session: https://claude.ai/code/session_01Utp6CZcCCHhGAp4cezRhuD Co-authored-by: Claude <noreply@anthropic.com>
) Claude-Session: https://claude.ai/code/session_01Utp6CZcCCHhGAp4cezRhuD Co-authored-by: Claude <noreply@anthropic.com>
Contributor
Author
|
domain:ui#3 · os-bill · session_01Utp6CaJoinvGQSbHeDaWBe 席位核对ACCEPT · head
Generated by Claude Code |
3 tasks
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.
domain:ui#3 · os-bill · session_01Utp6CaJoinvGQSbHeDaWBe
Requested by Bill · project thread
维护者速读
ResourceEditPage.tsx的doSave(新增的暂缓分支与 422 分支里的drawnInline)、SchemaForm.tsx的useInlineIssueFieldRegister与revealIssues、新测试ResourceEditPage.heldBadName-27865.test.tsx。pnpm --dir ui exec vitest run packages/app-shell/src/views/metadata-admin/ResourceEditPage.heldBadName-27865.test.tsx,预期 1 个文件 4 条全部通过(坏名零请求只剩内联错误、服务端点名 name 只说一次、标签生成的坏名同样暂缓、好名照常保存)。Fixes #27865
Clause-②: no
Metadata-protocol: none
What changes
Measured first, on
mainate6553619against the stock showcase (objectstack dev --seed-admin --fresh, admin, Chromium 1440×900), Setup › Permission Sets › New, Name typed asBad Name:metadata-validation-banner, "does not match the spec — 1 validation error(s)", listing Name) and the inline error under Name, for the one mistake;PUT /api/v1/meta/permission/Bad%20Nameleft, answered 400 with "is not a legal metadata item name"; the page drew that refusal and cleared the inline error, so the next edit brought the summary banner and the inline error back beside the still-standing refusal: three messages.Now, re-driven on the same stack at this branch: typing
Bad Nameshows only the inline error; Save sends no request and the inline error stays the one message;probe_setstill creates (onePUT).doSave). On the create door, before any request, the page runs the same live client validator the form already shows (validateMetadataDraft, modecreate, on the same draft; no second rule), awaited so a Save inside the 200 ms debounce cannot slip past it. When it refuses the identity field, nothing is sent: the issues are put back on the form and the Save attempt ends. This is the one place a predicted verdict holds Save, and it is bounded so the dead-bolt the advisory ruling guards against stays out of reach (see Acceptance notes): onlycreateMode, only the identity field.SchemaFormrevealIssues). The create form defers a field's error until the field is touched. A Save attempt ends that deferral, so a Name derived from the Label and never touched (LabelAgivesa, under the spec's two-character floor) shows its error inline instead of nowhere.SchemaFormnow reports which top-level fields draw their issues inline (a row registers while mounted and not deferred; nested forms do not register; the register is held in state, not memoised, perui/AGENTS.mdchore: version packages #10). The page then:setError), so the server's refusal is said once, on the field. Only where a client validator exists, because that is where the summary banner reads these issues: if the field later leaves the screen, the banner lists it again.Errors the form cannot draw on a field (root, nested key, a field off screen or in a closed section) stay in the banner, unchanged.
The Save button gate, the autosave timer and the ⌘S door are untouched: the hold lives in
doSave, which all three call.Tests
ResourceEditPage.heldBadName-27865.test.tsx: the real page over a realMetadataClientwhose in-memory transport records everyPUTand answers like the save door (an ungrammatical name 400INVALID_REQUESTwith no issues, read from the spec's ownMETADATA_ITEM_NAME_PATTERN;taken_set422 with an issue atname). The live permission registration (registerBuiltinAnchors: Label → Name derive,createLive) is mounted. (a) bad Name, Save clicked inside the debounce, then again: zeroPUT, exactly one inline issue whose text appears nowhere else, no summary banner, no server refusal; (b) a Name the client accepts and the server refuses atname: onePUT, one message, inline; (c) LabelAderivesa, untouched: held, zeroPUT, the error shown inline; (d) control: a good Name saves.ResourceEditPage.schemaAdvisory.test.tsx(the advisory half: a stored item with a key the bundled spec does not declare still saves) andResourceEditPage.serverRefusalGate.test.tsxpass unchanged.Readings
main(ab56afe9;PackageFormDialog, which hostsSchemaForm, moved onmainmeanwhile): every test file underui/namingResourceEditPage,SchemaFormorPackageFormDialog, 187 files: Test Files 187 passed, Tests 1921 passed; lock VERDICT command-exit 0 (6m59s). Before the merge, the same set withoutPackageFormDialog(169 files): 1765 passed.scripts/ablation-replace.mjs; app-shell tests importsrc, so no dist leg; each restored blob equal to HEAD,git diff HEADempty):ok_name,ab,a,x1,crm_lead.pipeline,a.b,abc_,a__band a 67-character name, judged by the client create pass against the server's registry schema plus the door's name grammar: no type where the client refuses a Name the server accepts (scratch run, not committed).pnpm --filter @object-ui/app-shell run type-check(both thesrcand the test program), after rebuilding@object-ui/app-shell^...onab56afe9: lock VERDICT command-exit 0.uicheck:new-line-citations: 0 new.dispatch-gates --commands), run onab56afe9: 34 derived, 34 run, 0 NOT-MEASURED, all exit 0 (also all exit 0 ona18abd01, before the merge).Acceptance notes
ResourceEditPagerecords, andResourceEditPage.schemaAdvisory.test.tsxpins, that the live client Zod pass stays advisory because a client stricter than the server would dead-bolt Save "on a draft the server accepts, with no on-screen editor able to take the key back out". This card asks for a hold on that same verdict, so the hold is bounded to where that failure cannot occur: the create door's identity field, which the create form always offers as an input, so the author can always type a name both ends accept. Every other live issue stays advisory, the Save button gate is unchanged, and an edit is never held. The boundary is written beside the ruling inResourceEditPage.tsxand at the hold itself. The seat kept it (review onab56afe9). The bound is pinned on the create door by case (e) ofheldBadName-27865: a good Name beside a client-refused non-identity key still sends. Widening the hold to any issue turns (e) red, and only (e).schemaAdvisory's header names the carve-out beside itsserverRefusalGateparagraph, with no assertion changed (rework headfc4cb80a).SnakeCaseIdentifierSchemais at least as strict as the door's grammar.Generated by Claude Code