Repository navigation
feat(console): name the records a bulk run wrote, hint which required fields to fill, and show CRM expected revenue as money - #28378
Conversation
The result step said only 'Succeeded N / M'. It now lists the records the run wrote, named as the confirm step names them, whenever every failure is attributed to a record of the run; a count-only shortfall keeps the count. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L9qibzF2YJvme2ABRytQ9o
…to fill in The action route's refusal carries details.fields, and the dispatch kept only its text. The failed ActionResult now carries those entries (fieldErrors), and the console's server-action wrapper follows the server's sentence with 'Fill in <fields>, then run <action> again.' The CRM Expected Revenue formula declares its currency return type, so it reads as money beside Deal Value. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L9qibzF2YJvme2ABRytQ9o
…ation Intl.ListFormat is outside the app-shell lib target, and the form's field lists already join with validation.formInvalidJoiner. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L9qibzF2YJvme2ABRytQ9o
Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L9qibzF2YJvme2ABRytQ9o
Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L9qibzF2YJvme2ABRytQ9o
Both sides raised the de pack's quoted-span census by one; the pins now count both spans (103). Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L9qibzF2YJvme2ABRytQ9o
|
domain:ui#1 · os-tesla · session_01L9qibw58ehQ2gRHP2h2Puz Contract-review-claim: |
|
domain:ui#1 · os-tesla · session_01L9qibw58ehQ2gRHP2h2Puz Contract reviewServed-tier: Inputs: card #27520 (rows 8, 11 and 16 of the 18.3.0 RC walkthrough; the seat's claim 6539394970 and its amendment 6539593257 widening the surface and allowing the one example edit; the dev report 6541061691 with its deviations), PR #28378 (body with the live before and after on showcase and CRM, the file list of 24 files, the diff of 873 lines against ① Derived judgments
② Semver level
③ Boundary flags
④ Design judgment
Verdict reasoning. The three rows are fixed where each one's cause lives, the per-field entries are read from the contract the spec already declares and carried on a declared optional member, the bulk list never names an unproven success, the example declares what the renderer reads, the declarations and the patch level are right, the pins hold both ways, and every check is green or skipped. Implemented-by: VERDICT: PASS |
|
domain:ui#1 · os-tesla · session_01L9qibzC6RxMfB59EsgAoNN 席位核对ACCEPT · seat 席位意见:批量执行操作后,如果部分记录成功、部分失败,结果对话框现在会列出成功的记录名称,而不只是一个数字;只有每条失败都能对应到具体记录时才列出,避免把未成功的记录误列为成功。服务器因必填字段为空而拒绝操作时,提示会在服务器原文后补一句「请填写某某字段,然后再运行该操作」,字段用显示名称,中文界面使用中文标点。CRM 示例里「预期收入」公式字段补上了货币返回类型,现在显示为金额而不是普通数字。
|
Requested by Tesla · project thread
Part of #27520 (rows 8, 11 and 16; every other row stays on the card)
Clause-②: yes (widening:
ActionResultgains the optionalfieldErrorsmember,ActionFieldErroris a new export of@object-ui/types, andActionResponseOutcomegainsfieldErrors; no accept set moves)Metadata-protocol: none
维护者速读
$16,000.00。required字段项;ActionResult多一个可选成员(放宽,不收紧)。回滚即 revert 本 PR。ui/packages/app-shell/src/utils/consoleServerAction.ts(withRequiredFieldsHint);ui/packages/core/src/actions/actionResponse.ts(refusalFieldErrors);ui/packages/plugin-grid/src/components/BulkActionDialog.tsx(succeededRows)。What changes
Row 8, bulk result names the records.
BulkActionDialog's result step now lists the records the run wrote under the "Succeeded N / M" line, named the way the confirm step names the affected records (affectedRecordName, the object'snameField), five at most plus "… and N more". The list is drawn only when every failure in the result sits under a record of the run, so the rows left over are exactly the successes. When a bulk call answered a bare count (executeBulkBatch'sbatch_<offset>entry), which records failed is unknown and the result keeps to its count. No server read and no executor change. New keygrid.bulk.succeededRecords(the list's accessible name) in all ten packs.Row 11, a required-field refusal says what to fill in. The action route answers a refused write with
error.details.fields(one entry per failed rule, measured live:{ field: 'issued_on', code: 'required', message: 'Issued On is required', label: 'Issued On' }).interpretActionResponsekept only the text. Now:interpretActionResponsereads the entries (current envelopeerror.details.fields, legacy inner envelopefields), drops entries without a stringfield, and returns them asfieldErrors;createServerActionHandlerpasses them on the failedActionResult(fieldErrors?: ActionFieldError[], new optional member in@object-ui/types);createConsoleServerActionHandlerfollows the server's sentence withconsole.serverAction.fillRequiredThenRetry("Fill in {{fields}}, then run “{{action}}” again.") or, for an action with no label,fillRequiredFirst. Onlyrequiredentries on a field count (_recordand every other code keep the server's text alone). Field names are the server's labels, deduplicated and joined withvalidation.formInvalidJoiner, the key the form's field lists already join with (Intl.ListFormatis outside app-shell's lib target, and aunitlist joins zh with no separator). The server's text stays first and whole; a stop is added only when it has none (a CJK one after CJK text). The wrapper'stnow takes interpolation values; both call sites (useConsoleActionRuntime,RecordDetailView) pass them through to i18next as{ defaultValue, ...values }.errorMessagestill replaces the whole text in the runner, hint included, as before.Row 16, money formula declares money.
examples/app-crm/src/objects/opportunity.object.ts:expected_revenuedeclaresreturnType: 'currency'. The renderer readsreturnTypeand never infers money from an expression (FormulaCellRenderer, objectui#11683 / #11748), so the undeclared formula drew the number face (16,000) beside theField.currencyDeal Value ($80,000.00). The seat lifted the order's no-examples line for exactly this edit (claim amendment 6539593257). No renderer change.Tests
New
ui/packages/plugin-grid/src/__tests__/bulkResultSucceededNames-27520.test.tsx(3): a clean run lists both titles under the accessible name; a run with one refusal lists only the two that landed and keeps the refused one under its refusal; abulkUpdateanswering a bare count names nobody.New
ui/packages/core/src/actions/__tests__/actionRefusalFields-27520.test.ts(5): the measured answer yieldsfieldErrors; an answer that also carries a producer-markederror.userMessagekeeps them (the hint keys off the entries, never the text, so it survives auserMessage); field-less entries are dropped; the legacy inner list is read; the dispatch's failed result carries the entries.New
ui/packages/app-shell/src/utils/__tests__/consoleServerAction.requiredFieldsHint-27520.test.ts(6): the hint after the server's sentence; several fields deduplicated and joined with the pack joiner (zh、); a label-less field and a label-less action;minand_recordentries left alone; the hosttreceives the values; the server's own stop kept and a CJK stop added.Adapted
ui/packages/i18n/src/__tests__/de-quote-pairing-3876.test.ts: the de census counts the new „{{action}}“ span, with the same one-line history note its earlier rises carry. main's feat(app-shell): Setup pages for position holders and permission-set assignment #28310 raised the same pins by one while this was open, so after merging main (6a3bd4e) they read 103 paired spans and 103 / 103 / 0, both rises noted.pnpm --dir ui exec vitest run --maxWorkers=2 packages/i18n/on the merge head: 93 files passed (1433 tests, 13 skipped).Ablations (one-time, not kept, at 714e376, before the
userMessagecase was added), throughscripts/ablation-replace.mjs, each restored to the HEAD blob withgit diff HEADempty: succeeded list never drawn → 2 failed of 3; count guard removed → 1 failed of 3; core stops returningfieldErrors→ 8 failed of 10 (core + wrapper files); wrapper returns the refusal unhinted → 5 failed of 6. The suites resolve@object-ui/*to source, so no dist leg applies.pnpm --dir ui exec vitest run --maxWorkers=2 packages/types/ packages/core/ packages/i18n/ packages/plugin-grid/: at 714e376: 963 files passed, 1 failed (de-quote-pairing-3876, 2 tests: its census counted 101 paired „…“ spans and the newfillRequiredThenRetryadds one). The pins were raised to 102 in 9f34e7d and the file reran 9/9 passed. The newuserMessagecase in e578f93 ran alone, 5/5 passed.app-shell, the wrapper and both call sites:
pnpm --dir ui exec vitest run --maxWorkers=2 packages/app-shell/src/utils/__tests__/consoleServerAction packages/app-shell/src/hooks/__tests__/useConsoleActionRuntime packages/app-shell/src/views/RecordDetailView: 108 files / 761 tests passed (lock VERDICT command-exit 0). The wholepackages/app-shell/run sat 80 minutes under the lock without finishing on this shared box and was stopped; the rest of app-shell is left to CI.type-checkof@object-ui/types,core,i18n,plugin-grid,app-shell(full dts closure built first): all Done, 0error TS.@objectstack/example-crm:typecheckexit 0,test7 files / 48 tests passed,validateexit 0 (only the pre-existingfield-no-consumerswarnings onrenewal_of/line_total).Dogfood that reads the CRM example's metadata (asked for by the seat for the example edit), against the built
examples/app-crm/dist/objectstack.jsonthat carriesreturnType: 'currency':pnpm --filter @objectstack/dogfood exec vitest run test/install-local-purge-sample-data.dogfood.test.ts test/wall-environment-metadata-refusal.dogfood.test.ts test/guest-grants-channel.dogfood.test.ts→ 3 files / 53 tests passed (lock VERDICT command-exit 0). The other dogfood files read only the CRM's flows or views, which this PR leaves alone.Acceptance notes
examples/app-showcase/src/ui/actions/index.tsMarkDoneActionpatchesdoneandprogresson purpose, becausestatusis governed bytask_status_flow(onlyin_review -> doneis legal), and its doc comment says so.issued_onrequiredWhen: record.status in ['sent', 'paid']), and the edit form evaluates it on the record as it stands, so a draft correctly shows Issued On as optional. Saying "required for Submit for Sign-off" means tying a field's rule to an action'spatch, which no spec door declares. The seat files that as a spec card.actionErrorDetail, which readserror.messageand nevererror.userMessage(a flow-action refusal can carry one). That is unchanged here; the hint rides after whichever text is shown, because it is keyed offdetails.fields. Noted, not filed.returnTypedraws a plain number by rule.os validatedoes not warn about it. Noted, not filed.Verification
Live before/after (showcase and CRM on --fresh stacks, admin, 1440x900)
Base
origin/mainb1e1dcf (before) and this branch (after), full dts build pluspnpm console:build,LANG=en_US.UTF-8 pnpm dev -- --fresh -p 38611(showcase) andpnpm --filter @objectstack/example-crm dev -- --fresh -p 38612, driven with Playwright.Mark Done | Succeeded 2 / 2 | Done. After:Mark Done | Succeeded 2 / 2 | • Evidence collection | • Content backlog | Done.400 {"success":false,"error":{"code":"VALIDATION_FAILED","message":"Issued On is required","httpStatus":400,"details":{"fields":[{"field":"issued_on","code":"required","message":"Issued On is required","label":"Issued On"}]}}}. Toast before:Issued On is required. After:Issued On is required. Fill in Issued On, then run “Submit for Sign-off” again.$80,000.00, Expected Revenue16,000. After:$80,000.00,$16,000.00.Derived gates
At 6a3bd4e (this branch merged with main 0f29a88):
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackderived 54 families against the diff. All 54 ran with</dev/null, exit codes recorded (27520-actions-gates-ran-6a3bd4e7.listin the seat's out folder).dispatch-gates --ran: "54 derived famil(ies) accounted for — 54 run, 0 NOT-MEASURED".pnpm check:type-check-debtfirst exited 3 (not measured): the closure build could not resolve@objectstack/observability, a package main added, because the tree had not been reinstalled after the merge. Afterpnpm install --frozen-lockfileit reran: exit 0, "0 raw tsc error(s) total, none above its recorded number". The list records the rerun.pnpm --dir ui exec vitest run scripts/ran under the verify lock: exit 0.pnpm --dir ui run check:new-line-citationsexit 0;node scripts/check-sdui-manifest.mjsexit 0.Generated by Claude Code