Repository navigation
fix(ui): list each failed validation rule as its own line in the form banner and toast - #28151
Merged
Merged
Conversation
… line A refused write keeps one fields[] entry per failed rule; only its top-level message joins them with '; '. The form renderer and FormPage now mark what they can inline and say the rest one line per entry, falling back to the envelope's message when there is no entry list. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L9qibwcER4bPAfAhbS8zYY
Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L9qibwcER4bPAfAhbS8zYY
…target types Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L9qibwcER4bPAfAhbS8zYY
Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L9qibwcER4bPAfAhbS8zYY
Contributor
Author
|
domain:ui#1 · os-tesla · session_01L9qibzC6RxMfB59EsgAoNN 席位核对ACCEPT · seat 席位意见:一次保存同时违反多条校验规则时,表单横幅和提示现在一条规则一行;指向表单上可见字段的规则仍标在该字段下,横幅只说其余的。服务端返回的拒收信封不变,控制台只是读取它本来就带的每条规则一项。新增一个公开辅助函数
|
9 tasks done
This was referenced Oct 30, 2026
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#1 · os-tesla · session_01L9qibzC6RxMfB59EsgAoNN
Requested by Tesla · project thread
Fixes #28053
Clause-②: yes (widening: @object-ui/react gains the public export unmarkedRefusalLines; no accept set moves)
Metadata-protocol: none
维护者速读
;拼起来的一句话,用户读成一句长句,往往只改第一处;HotCRM 为此把两条预测规则改成互斥来绕开。fields[]);单条规则的拒绝在表单渲染器上不变;回滚即 revert 本 PR。ui/packages/react/src/utils/error-message.ts的unmarkedRefusalLines、form.tsx提交 catch 里的shownInline、FormPage.tsx提交 catch。pnpm --dir ui exec vitest run packages/components/src/renderers/form/__tests__/form-refusal-lines-28053.test.tsx,预期 3 个用例全绿。What changes
The server already says each failed rule separately:
ValidationErrorkeeps onefields[]entry per rule, located on the field the rule names, else on_record; only its top-level message is the;-join. The console threw the entries away whenever one of them had no drawn input and showed the joined text instead. Now:@object-ui/reactaddsunmarkedRefusalLines(err, isShownInline): one line perfields[]entry the caller could not show under a visible input, in server order. It answersnull(the caller keeps the envelope's message) when the refusal has no entry list, or when an entry it would have to say carries no human-readablemessage; it answers[]when every entry is inline. It reads the same three shapesextractFieldErrorsreads (the adapter'svalidationErrors, the client'sdetails.fields, a barefields), now through one privatefieldEntriesreader.ui/packages/components/src/renderers/form/form.tsx): the submit catch records which rejected fields it wrote under a DRAWN input (fieldWrapper), and the banner and toast say only the other entries, one list item each. One remaining entry stays a plain string, so a single-rule refusal reads exactly as before. The permission, delegated-scope and author-markeduserMessagepaths keep their precedence.ui/apps/console/src/components/FormPage.tsx): the same rule over the rows it marks. Its banner and toast used to showSubmit failed (400):plus the raw response body for every server refusal; a refusal with entries no row carries now shows those entries' messages instead. A refusal whose every entry is marked on a row, or that has no entry list, still shows what it showed before.Both surfaces draw several lines as a
ulofli, in the banner and in the toast. No server, spec or envelope change.Tests
ui/packages/react/src/utils/error-message.unmarked-refusal-lines.test.ts(new, 8 cases): the measured two-rule body; located entry left out; all inline gives[]; two_recordrules give two lines; adapter, client and hand-rolled shapes agree; an entry with no field is said; an entry with no message givesnull; no entry list givesnull.ui/packages/components/src/renderers/form/__tests__/form-refusal-lines-28053.test.tsx(new): two record-level rules give two banner items and two toast items and no;; one located plus one record-level rule gives the inline mark and one banner line; a single record-level rule is unchanged (the toast gets the plain string).form-server-field-errors.test.tsx: the case for a rejected field the form does not render now asserts the toast says only that field's reason (it asserted a substring of the joined text).FormPage.refusalMarks-27417.test.tsx: two#28053cases (two_recordrules; one row-marked plus one record-level rule), and the undrawn-field case now asserts the banner says the reason and no row carries it (it asserted the reason appeared nowhere, which was the defect).Reverse verification. With both submit catches restored to the base (
git restore --source=6410029dofform.tsxandFormPage.tsx, helper kept), 6 of the 22 cases in the three consumer files went red (the four new consumer cases and the two updated ones); the single-rule case stayed green, as it should. Restored withgit checkout HEAD --, proven bygit diff HEADempty and both blob hashes equal toHEAD's.Acceptance notes
origin/main6410029d,POST /api/v1/data/:objectthroughRestServerover a realObjectQLand an SQLiteSqlDriver(a throwaway probe inpackages/rest, not committed), with threecross_fieldrules:bestplus one naming no field answered400witherror= the;-join andfields=[{field: best, code: rule_violation, message: …}, {field: _record, code: rule_violation, message: …}];_recordentries, each with its own message.So this is not a Seam; the ui lane fixes it.
Submit failed (400):plus the raw JSON body; it now shows that entry's message. Same rule as the multi-entry case.messagefalls back to the envelope's top-level text for the whole banner rather than putting an untranslated code on a line by itself.fields[]list, or whose every entry is marked on a row, still showSubmit failed (STATUS):plus the raw response body. Noted, not filed.ui/packages/app-shell/src/console/AppContent.tsx,providers/writeWarningToast.ts,views/RecordFormPage.tsx(held by Console: a save that passes a warning-severity rule shows one toast, the record-named save toast carrying the warning #27999).Verification
f4877f89adds only the changeset'sClause-②line over767d45bb; the Check Changeset scripts (check-adr-0087-registration,check-changeset-no-major,check-empty-changeset, each--base origin/main) re-ran there, exit 0.767d45bb: the dispatch-derived gate list, every line run with stdin from /dev/null, exit codes on disk, reconciled withdispatch-gates.mjs --ran.Derived gates (local)
Targeted tests
Generated by Claude Code