Repository navigation
Commit 0d45c0e
fix(ui): a wizard form view keeps layout horizontal, and the form page draws it as steps (#27267)
<!-- claude-projects-attribution: {"github_login":"os-warren"} -->
_Requested by **Warren** · [project
thread](https://claude.ai/code/project/chan_01U5RdnAAmkSQmZbqh6FtqZ8?thread=cmsg_01U5RdnAAmkSQmZbqh6FtqZ858UZPVazGF5N8yCfayxT1g)_
Fixes #27224
Clause-②: no
Metadata-protocol: none
## 维护者速读
- 改了什么:分步表单(`type: 'wizard'`)写 `layout: 'horizontal'`
时每一步的字段标签都放到输入框左侧;`/forms/:name` 与 `/f/:slug`
表单页把分步表单画成逐步填写(步骤条、下一步/上一步、最后一步提交)。
- 为什么改:这两项都能保存发布,但分步表单把 layout 固定成 vertical,表单页把所有分节堆在一页,作者以为生效了其实没有。
- 风险与回滚:只改 WizardForm 的一处 layout 传值和表单页的 wizard 分支;simple、tabbed 与不写
layout 的表单行为不变(有对照测试);回滚即 revert 本 PR。
-
先看:`ui/apps/console/src/components/FormPage.tsx`(`renderWizardSteps`、`handleWizardNext`、提交被拒时跳到出错步骤)、`ui/packages/plugin-form/src/WizardForm.tsx`(`layout:
schema.layout ?? 'vertical'`)。
- 两分钟验证:`pnpm --dir ui exec vitest run
apps/console/src/components/FormPage.wizardSteps-27224.test.tsx`,预期 11
个测试全绿。
- 需要你做的:无,席位落地。
## What changes
1. **A wizard form keeps `layout: 'horizontal'`.** `ObjectForm` hands
the authored key to `WizardForm` in its `{...schema}` spread, and the
step form node `WizardForm` built said `layout: 'vertical'` whatever the
form view said. It now passes `schema.layout ?? 'vertical'`, the shape
`TabbedForm` got in PR #27222, and declares `layout` on
`WizardFormSchema` as `ObjectFormSchema['layout']`. Every field on every
step draws its label beside the control from `sm` up, through the form
renderer's existing horizontal arrangement. The auto-stepper path
(`mobile.stepper`) spreads the same schema, so it keeps the key too.
2. **The form page draws `type: 'wizard'` as steps.** `/forms/:name` and
the public `/f/:slug` read `type` only for `tabbed`, so a wizard view
drew every section stacked on one page. A wizard view with more than one
section now draws, with the semantics of the app's wizard form and the
spec's FormView wizard contract (D4 step gate, D5 derived progress):
- a step indicator, one step per section in array order, labelled by the
section heading (else the `wizard.stepFallback` text), hidden by
`showStepIndicator: false`;
- **Next** checks the current step's fields with the same rules the
final submit applies (`findSubmitRefusals` over that one section) and
opens the next step only when none is refused; a refused step is marked
in the indicator and the refusal message is the page's existing one;
- **Back** is always free; a later step opens from the indicator once
completed, or at once under `allowSkip` (`canOpenWizardStep`, the rule
`WizardForm`'s `canOpenStep` applies);
- **Submit** appears on the last step only and carries every step's
fields (the page's one `values` map); a submit refused for a missing
field, or a faulted `visibleWhen`, opens the step holding the first
field it names and marks every step a refused field sits on;
- Enter in a field before the last step is that step's Next; a
`continue` submit behaviour starts the wizard over from step one;
- every step stays mounted and only the current one is drawn (the
`hidden` attribute), so a control on another step keeps its widget
state, an upload in flight included;
- a step with no fields shows the `wizard.emptyStep` text, as the app's
wizard does;
- a wizard view with a single section draws it stacked, as a
single-section tabbed view does.
The refusal reporting that `handleSubmit` inlined is lifted into
`reportRefusals` so Next and the final submit put the same messages on
the same channel. Every string the wizard draws is an existing catalogue
key (`wizard.progressLabel`, `wizard.stepFallback`, `wizard.back`,
`wizard.emptyStep`, `common.next`, `form.stepOf`), so no locale pack
changes.
`FORM_SPEC_TYPES` is left as it is; its split/drawer/modal entries
belong to #27159.
## Why
Both keys are authorable and saved, and both drew as if absent: a wizard
form view's `layout: 'horizontal'` and the form page's `type: 'wizard'`.
This is the wizard arm of the defect PR #27222 closed for simple and
tabbed forms (triage 6468472559: the filer's Expected stands).
## Tests
-
`ui/packages/plugin-form/src/__tests__/wizardFormLayout-27224.test.tsx`
(3): horizontal on step one and, after Next, on step two; CONTROLS: no
`layout`, and `vertical`, draw vertical.
- `ui/apps/console/src/components/FormPage.wizardSteps-27224.test.tsx`
(11): steps drawn, only the current one shown, Next and no Back or
Submit on step one; Next and Back, completed steps reopen from the
indicator and an uncompleted one does not; Next refuses an outstanding
required field and writes nothing; Enter is Next; the submit carries
every step's fields; `allowSkip` opens any step and a refused submit
opens the step holding the field; `showStepIndicator: false`; horizontal
rows on every step; `canOpenWizardStep` unit cases. CONTROLS: a
single-section wizard draws stacked with Submit and no indicator; a
`simple` view draws every section stacked with Submit and no steps.
Ablations, each through `scripts/ablation-replace.mjs` on the committed
head `15589ba4`, restored to the HEAD blob with `git diff HEAD` empty:
- `WizardForm.tsx` back to `layout: 'vertical'`: the horizontal test
reds (1 failed, 2 passed: both controls stay green).
- `FormPage.tsx` with `wizardView` forced to `false`: all 8 wizard tests
red, the 3 controls (single section, simple view, `canOpenWizardStep`)
stay green.
## Acceptance notes
- The page's step gate checks what the page can check: `required`,
`requiredWhen`, `readonlyWhen` and a faulted `visibleWhen`, through the
rules its final submit already applies. Like the app's wizard, it is a
UI admission rule, never authorization; the server re-validates the
record on submit.
- `nextText` / `prevText` are not FormView keys (they live on the
`object-form` component props), so the page draws the catalogue's Next
and Back.
## Verification
Measured on `objectstack-ai/objectstack` at `15589ba4` (merge base
`295699d5`). `origin/main` has since moved to `3beb2240`; none of its
commits touch `ui/packages/plugin-form`, `FormPage.tsx` or the form
renderer, so the branch is not merged with it.
<details><summary>Builds, suites and type-checks</summary>
- Closure `pnpm --workspace-concurrency=2 --filter
'@object-ui/console^...' build` under the lock: VERDICT command-exit 0
(11m36s).
- `pnpm --dir ui exec vitest run --maxWorkers=2 packages/plugin-form/
apps/console/src/components/FormPage`: Test Files 243 passed (243),
Tests 2792 passed, 1 skipped; VERDICT command-exit 0.
- `pnpm --filter @object-ui/plugin-form run type-check && pnpm --filter
@object-ui/console run type-check`: VERDICT command-exit 0.
- `pnpm check:new-line-citations` (from `ui/`): 0 new citations.
</details>
<details><summary>Derived gates: 34 derived, 34 run, all exit 0
(dispatch-gates --ran: 0 NOT-MEASURED)</summary>
- `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 --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
- `pnpm --dir ui exec vitest run scripts/` :: exit 0
</details>
## Human Minimum
- [x] 1. Schemas start as Zod; `packages/spec` holds no runtime logic.
(not touched)
- [x] 2. Every name I added uses the casing for its kind.
- [x] 3. No formatter ran; `pnpm lint` is CI's run.
- [x] 4. One issue, one branch off an up-to-date `main`, one pull
request.
- [x] 5. A change that publishes carries a changeset, and both
declaration lines are filled in here and in the changeset.
- [x] 6. `packages/spec` touched: not touched.
- [x] 7. No hand edits to `content/docs/references/`,
`packages/*/CHANGELOG.md` or `content/docs/releases/`.
- [x] 8. Title, body and comments are in English.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01JQwxbZ31aDwuL2615F85BS
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 3af6022 commit 0d45c0e
5 files changed
Lines changed: 642 additions & 29 deletions
File tree
- .changeset
- ui
- apps/console/src/components
- packages/plugin-form/src
- __tests__
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1026 | 1026 | | |
1027 | 1027 | | |
1028 | 1028 | | |
| 1029 | + | |
| 1030 | + | |
| 1031 | + | |
| 1032 | + | |
| 1033 | + | |
| 1034 | + | |
| 1035 | + | |
| 1036 | + | |
| 1037 | + | |
| 1038 | + | |
| 1039 | + | |
| 1040 | + | |
| 1041 | + | |
| 1042 | + | |
| 1043 | + | |
| 1044 | + | |
| 1045 | + | |
1029 | 1046 | | |
1030 | 1047 | | |
1031 | 1048 | | |
| |||
2276 | 2293 | | |
2277 | 2294 | | |
2278 | 2295 | | |
| 2296 | + | |
| 2297 | + | |
| 2298 | + | |
| 2299 | + | |
| 2300 | + | |
| 2301 | + | |
| 2302 | + | |
| 2303 | + | |
| 2304 | + | |
| 2305 | + | |
2279 | 2306 | | |
2280 | 2307 | | |
2281 | 2308 | | |
| |||
2374 | 2401 | | |
2375 | 2402 | | |
2376 | 2403 | | |
| 2404 | + | |
| 2405 | + | |
| 2406 | + | |
| 2407 | + | |
| 2408 | + | |
| 2409 | + | |
| 2410 | + | |
| 2411 | + | |
| 2412 | + | |
| 2413 | + | |
| 2414 | + | |
2377 | 2415 | | |
2378 | 2416 | | |
2379 | 2417 | | |
| |||
2421 | 2459 | | |
2422 | 2460 | | |
2423 | 2461 | | |
2424 | | - | |
2425 | | - | |
2426 | | - | |
2427 | | - | |
2428 | | - | |
2429 | | - | |
2430 | | - | |
2431 | | - | |
2432 | | - | |
2433 | | - | |
2434 | | - | |
2435 | | - | |
2436 | | - | |
2437 | | - | |
2438 | | - | |
2439 | | - | |
2440 | | - | |
2441 | | - | |
2442 | | - | |
2443 | | - | |
2444 | | - | |
2445 | | - | |
| 2462 | + | |
| 2463 | + | |
| 2464 | + | |
| 2465 | + | |
| 2466 | + | |
| 2467 | + | |
| 2468 | + | |
| 2469 | + | |
| 2470 | + | |
| 2471 | + | |
2446 | 2472 | | |
2447 | 2473 | | |
2448 | 2474 | | |
2449 | 2475 | | |
2450 | 2476 | | |
2451 | 2477 | | |
2452 | | - | |
| 2478 | + | |
2453 | 2479 | | |
2454 | 2480 | | |
2455 | 2481 | | |
2456 | 2482 | | |
2457 | | - | |
| 2483 | + | |
2458 | 2484 | | |
2459 | 2485 | | |
2460 | 2486 | | |
| |||
2464 | 2490 | | |
2465 | 2491 | | |
2466 | 2492 | | |
2467 | | - | |
| 2493 | + | |
2468 | 2494 | | |
2469 | 2495 | | |
2470 | 2496 | | |
2471 | 2497 | | |
| 2498 | + | |
| 2499 | + | |
| 2500 | + | |
| 2501 | + | |
| 2502 | + | |
| 2503 | + | |
| 2504 | + | |
| 2505 | + | |
| 2506 | + | |
| 2507 | + | |
| 2508 | + | |
| 2509 | + | |
| 2510 | + | |
| 2511 | + | |
| 2512 | + | |
| 2513 | + | |
| 2514 | + | |
| 2515 | + | |
| 2516 | + | |
| 2517 | + | |
| 2518 | + | |
| 2519 | + | |
| 2520 | + | |
| 2521 | + | |
| 2522 | + | |
| 2523 | + | |
| 2524 | + | |
| 2525 | + | |
| 2526 | + | |
| 2527 | + | |
| 2528 | + | |
| 2529 | + | |
| 2530 | + | |
| 2531 | + | |
| 2532 | + | |
| 2533 | + | |
| 2534 | + | |
| 2535 | + | |
| 2536 | + | |
| 2537 | + | |
| 2538 | + | |
| 2539 | + | |
| 2540 | + | |
| 2541 | + | |
| 2542 | + | |
2472 | 2543 | | |
2473 | 2544 | | |
| 2545 | + | |
| 2546 | + | |
| 2547 | + | |
| 2548 | + | |
| 2549 | + | |
| 2550 | + | |
| 2551 | + | |
| 2552 | + | |
| 2553 | + | |
| 2554 | + | |
| 2555 | + | |
| 2556 | + | |
| 2557 | + | |
| 2558 | + | |
| 2559 | + | |
| 2560 | + | |
| 2561 | + | |
| 2562 | + | |
| 2563 | + | |
| 2564 | + | |
| 2565 | + | |
| 2566 | + | |
| 2567 | + | |
| 2568 | + | |
| 2569 | + | |
2474 | 2570 | | |
2475 | 2571 | | |
2476 | 2572 | | |
| |||
2561 | 2657 | | |
2562 | 2658 | | |
2563 | 2659 | | |
| 2660 | + | |
| 2661 | + | |
| 2662 | + | |
2564 | 2663 | | |
2565 | 2664 | | |
2566 | 2665 | | |
| |||
2806 | 2905 | | |
2807 | 2906 | | |
2808 | 2907 | | |
| 2908 | + | |
| 2909 | + | |
| 2910 | + | |
| 2911 | + | |
| 2912 | + | |
| 2913 | + | |
| 2914 | + | |
| 2915 | + | |
| 2916 | + | |
| 2917 | + | |
| 2918 | + | |
| 2919 | + | |
| 2920 | + | |
| 2921 | + | |
| 2922 | + | |
| 2923 | + | |
| 2924 | + | |
| 2925 | + | |
| 2926 | + | |
| 2927 | + | |
| 2928 | + | |
| 2929 | + | |
| 2930 | + | |
| 2931 | + | |
| 2932 | + | |
| 2933 | + | |
| 2934 | + | |
| 2935 | + | |
| 2936 | + | |
| 2937 | + | |
| 2938 | + | |
| 2939 | + | |
| 2940 | + | |
| 2941 | + | |
| 2942 | + | |
| 2943 | + | |
| 2944 | + | |
| 2945 | + | |
| 2946 | + | |
| 2947 | + | |
| 2948 | + | |
| 2949 | + | |
| 2950 | + | |
| 2951 | + | |
| 2952 | + | |
| 2953 | + | |
| 2954 | + | |
| 2955 | + | |
| 2956 | + | |
| 2957 | + | |
| 2958 | + | |
| 2959 | + | |
| 2960 | + | |
| 2961 | + | |
| 2962 | + | |
| 2963 | + | |
| 2964 | + | |
| 2965 | + | |
| 2966 | + | |
| 2967 | + | |
| 2968 | + | |
| 2969 | + | |
| 2970 | + | |
| 2971 | + | |
| 2972 | + | |
| 2973 | + | |
| 2974 | + | |
| 2975 | + | |
| 2976 | + | |
| 2977 | + | |
| 2978 | + | |
| 2979 | + | |
| 2980 | + | |
| 2981 | + | |
| 2982 | + | |
| 2983 | + | |
| 2984 | + | |
| 2985 | + | |
| 2986 | + | |
| 2987 | + | |
| 2988 | + | |
| 2989 | + | |
| 2990 | + | |
2809 | 2991 | | |
2810 | 2992 | | |
2811 | 2993 | | |
| |||
2856 | 3038 | | |
2857 | 3039 | | |
2858 | 3040 | | |
2859 | | - | |
| 3041 | + | |
2860 | 3042 | | |
2861 | 3043 | | |
2862 | 3044 | | |
| |||
2887 | 3069 | | |
2888 | 3070 | | |
2889 | 3071 | | |
2890 | | - | |
| 3072 | + | |
| 3073 | + | |
| 3074 | + | |
| 3075 | + | |
| 3076 | + | |
| 3077 | + | |
2891 | 3078 | | |
2892 | 3079 | | |
2893 | 3080 | | |
| |||
2903 | 3090 | | |
2904 | 3091 | | |
2905 | 3092 | | |
2906 | | - | |
| 3093 | + | |
| 3094 | + | |
| 3095 | + | |
| 3096 | + | |
| 3097 | + | |
| 3098 | + | |
| 3099 | + | |
| 3100 | + | |
| 3101 | + | |
| 3102 | + | |
| 3103 | + | |
| 3104 | + | |
| 3105 | + | |
| 3106 | + | |
| 3107 | + | |
| 3108 | + | |
| 3109 | + | |
| 3110 | + | |
| 3111 | + | |
| 3112 | + | |
| 3113 | + | |
2907 | 3114 | | |
2908 | 3115 | | |
2909 | 3116 | | |
| |||
0 commit comments