Skip to content

fix(plugin-form): a sectioned object-form clears after a save on submitBehavior continue and resetOnSuccess - #27663

Merged
objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/project-thread-pwdhvq
Oct 29, 2026
Merged

objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/project-thread-pwdhvq

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

domain:ui#2 · os-bill · session_01Utp6CY2n1JmZZKrHgtp9jC

Requested by Bill · project thread
Fixes #27602

Clause-②: no
Metadata-protocol: none

维护者速读

  • 改了什么:object-form 的分组(sections)表单现在与平铺表单读同一条「保存后清空」规则,submitBehavior: { kind: 'continue' } 或新建表单上的 resetOnSuccess: true 在保存后清空表单。
  • 为什么改:分组表单原先不带这条规则,「保存并新增下一条」保存后仍留着上一条的值,用户再存一次就是一条近似重复记录;平铺表单早已正确。
  • 风险与回滚:风险低,只是把平铺路径已有的同一表达式提成一个常量,两条路径共读;两个键都没声明的表单行为不变。回滚即 revert 本 PR。
  • 先看:ui/packages/plugin-form/src/ObjectForm.tsx 的 resetOnSubmit 常量及分组路径 form 节点新加的一行;再看 ObjectForm.resetOnSubmit-27602.test.tsx。
  • 两分钟验证:pnpm --dir ui exec vitest run packages/plugin-form/src/ObjectForm.resetOnSubmit-27602.test.tsx,预期 6 个测试全绿(平铺、分组各 3 个)。
  • 需要你做的:无,席位落地。

What changes

SimpleObjectForm renders an object-form block through one of two form nodes: the flat one, and the sectioned one (explicit sections, or sections derived from the object's field groups). Only the flat node carried resetOnSubmit, so a sectioned "save and add another" form kept the saved record's values while the same declaration on a flat form cleared it.

The rule is now one named const, resetOnSubmit, declared once beside formLayout and read by both nodes:

const resetOnSubmit = schema.submitBehavior?.kind === 'continue'
  || (!schema.submitBehavior && schema.resetOnSuccess && schema.mode === 'create');

The expression is unchanged from the flat path's; the flat node now reads the const instead of its own copy, and the sectioned node gains the same key. Nothing else resets the form imperatively: the continue arm of the submit-behaviour switch is a no-op whose comment already defers to resetOnSubmit, and the form renderer's single form.reset() call after a successful submit is the only reader.

Changeset: @object-ui/plugin-form patch.

Tests

ui/packages/plugin-form/src/ObjectForm.resetOnSubmit-27602.test.tsx renders the same block flat and sectioned (describe.each over both paths) and saves name: 'Alpha', reading the field once the submit button is enabled again (the form disables it for the whole submit, reset included):

  • submitBehavior: { kind: 'continue' } clears, on both paths;
  • resetOnSuccess: true on a create form clears, on both paths;
  • neither key declared keeps Alpha, on both paths.

Ablation, run once, on the committed fix (97c6b181), through scripts/ablation-replace.mjs. The mutation deleted the sectioned node's resetOnSubmit, line (anchor 1 → 0, blob 1fa7f7aa0930 → 5c7ae6369dbf). Result: the two sectioned clear cases went red and the other four stayed green (Tests 2 failed | 4 passed (6)). The restore was verified with blob == HEAD and an empty git diff HEAD. The test imports ./ObjectForm from source, so no build sits between the mutation and the run.

Acceptance notes

  • Not reproduced in a browser; the defect and the fix are both measured at the component layer, through the same ObjectForm the block registers.
  • Lint on the two touched files: 0 errors. The warnings are no-explicit-any; the new test's four come from the same as any schema and data-source casts its sibling ObjectForm.showReset-27247.test.tsx uses.

Verification

Local runs below were taken on head 57e13970.

Targeted tests, type-check, lint
pnpm --dir ui exec vitest run --maxWorkers=2 --reporter=verbose packages/plugin-form/src/ObjectForm.resetOnSubmit-27602.test.tsx packages/plugin-form/src/ObjectForm.submitBehavior.test.tsx packages/plugin-form/src/ObjectForm.showReset-27247.test.tsx packages/plugin-form/src/sectionedFormValues.test.tsx packages/components/src/renderers/form/__tests__/form-invalid-input-refuses-submit-27483.test.tsx :: exit 0
  Test Files  5 passed (5) · Tests  30 passed (30) · the new file's 6 named, flat and sectioned
pnpm --filter @object-ui/plugin-form run type-check :: exit 0   (tsc --noEmit && tsc -p tsconfig.test.json)
pnpm --filter @object-ui/plugin-form exec eslint src/ObjectForm.tsx src/ObjectForm.resetOnSubmit-27602.test.tsx :: exit 0   (0 errors)
pnpm --dir ui run check:new-line-citations :: exit 0   (0 new citations)
pnpm --dir ui exec vitest run --maxWorkers=2 packages/plugin-form/ :: exit 0   (on 97c6b181, before the main merge: Test Files 212 passed (212) · Tests 2357 passed | 1 skipped)

The whole-package run is from the pre-merge commit. The merge brought no change under plugin-form, so after it the five files above were run again, including the form renderer test the merge added beside the resetOnSubmit reader in form.tsx.

Derived gate families (dispatch-gates --commands, reconciled with --ran)
node scripts/check-adr-0087-registration.mjs --base origin/main :: exit 0
node scripts/check-adr-0087-registration.mjs --self-test :: exit 0
node scripts/check-changeset-no-major.mjs --base origin/main :: exit 0
node scripts/check-closing-keyword-parity.mjs :: exit 0
node scripts/check-closing-keyword-parity.mjs --self-test :: exit 0
node scripts/check-comment-mask-corpus.mjs :: exit 0
node scripts/check-empty-changeset.mjs --base origin/main :: exit 0
node scripts/check-empty-changeset.mjs --self-test :: exit 0
node scripts/check-sdui-manifest.mjs :: exit 0
node scripts/check-sdui-manifest.mjs --self-test :: exit 0
node scripts/pm/release-rehearsal-clone.mjs --self-test :: exit 0
node scripts/release-pending-publish.mjs --self-test :: exit 0
pnpm --dir ui exec vitest run scripts/ :: exit 0
pnpm --filter @objectstack/spec run check:duration-unit-keys :: exit 0
pnpm check:changeset-gate-self-tests :: exit 0
pnpm check:closed-ceremony-text :: exit 0
pnpm check:cross-package-test-inputs :: exit 0
pnpm check:dispatcher-error-vocabulary :: exit 0
pnpm check:driver-memory-census :: exit 0
pnpm check:engine-double-contract :: exit 0
pnpm check:gitlink-declared :: exit 0
pnpm check:nul-bytes :: exit 0
pnpm check:pm-changeset-deadline-census :: exit 0
pnpm check:published-files :: exit 0
pnpm check:query-options-erasure :: exit 0
pnpm check:refd-timer-probe :: exit 0
pnpm check:skill-identifier-liveness :: exit 0
pnpm check:test-source-alias :: exit 0
pnpm check:tier-file-adoption :: exit 0
pnpm check:type-check-coverage :: exit 0
pnpm check:type-check-debt :: exit 0
pnpm check:undeclared-dep-imports :: exit 0
pnpm check:watch-hint-literal :: exit 0
pnpm check:where-matcher :: exit 0

node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --ran FILE printed: 34 derived famil(ies) accounted for — 34 run, 0 NOT-MEASURED. Every family CI runs beyond these (lint, type-check lanes, Test UI, Build & E2E UI) is read from this PR's check-runs.


Generated by Claude Code

…inue and resetOnSuccess

SimpleObjectForm's flat and sectioned form nodes now read one shared
resetOnSubmit expression; the sectioned node carried none, so a grouped
"save and add another" form kept the saved record's values.

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

Copy link
Copy Markdown
Contributor Author

domain:ui#2 · os-bill · session_01Utp6CY2n1JmZZKrHgtp9jC

席位核对

ACCEPT · head 57e1397000235584862d2cdd636a8246d45723eb · 2026-10-29T17:03Z

  1. Shape: draft → main, Fixes #27602 only, attribution block on top. Three files: ui/packages/plugin-form/src/ObjectForm.tsx, a new test beside it, and one changeset. No assignee, no reviewer.
  2. Premise measured: the seat read the diff. SimpleObjectForm now declares one resetOnSubmit const, submitBehavior?.kind === 'continue' || (!submitBehavior && resetOnSuccess && mode === 'create'), next to formLayout. Both the sectioned form node (which had none) and the flat node (which had its own copy) read it. This is "one shared expression, not a copy" per triage 6500569550. The test pins both paths with describe.each: continue clears, resetOnSuccess clears, and declaring neither keeps the values. The dev's ablation of the sectioned line turned exactly the two sectioned clear cases red. No packages/spec/** path.
  3. Gates (check-runs on this head): 44 success, 11 skipped, 0 red. That includes Lint & Repo Gates 123594804485, TypeScript Type Check 123593652371, Test UI 123600564075 and Lint · PM dispatch-gates 123591253052. The dev's derived gates were 34/34, all exit 0, on this head.
  4. Contract review: not owed. Clause-②: no holds because no export changes, and Metadata-protocol: none holds because the keys are the ones the type already declares.
  5. Accepted deviations / out of scope: none. The dev ran the whole-package test before the main merge, which touched nothing under plugin-form, and the targeted files after it. I read the changeset sentence by sentence against the diff, and it matches.
  6. Landing: not governed (check-governed-merges --pr 27663: NOT governed, 0 of 3 paths), 120 lines < 3000. The seat lands it: ready + auto-merge now.

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

Development

Successfully merging this pull request may close these issues.

ObjectForm: a sectioned form ignores submitBehavior: { kind: 'continue' } and resetOnSuccess, so it keeps the saved values while the flat form clears

1 participant