Commit 69acb3d
authored
feat: add Page Break field type for multistep forms (#150)
* feat: add Page Break display-only field type
* test: integration test for Page Break form save and DocType sync
* chore: add Page Break to auto-generated TypeScript types
* refactor: map Page Break to Tab Break instead of HTML
Tab Break is a native Frappe layout field that renders proper tabs in
Desk view, replacing the raw HTML <hr> workaround.
* docs: add section navigation bar implementation plan
* Revert "docs: add section navigation bar implementation plan"
This reverts commit b34cec1.
* chore: gitignore screenshot PNGs
* feat: register Page Break field type in frontend
Add Page Break to fieldTypes registry, FieldRenderer, form_fields utils,
and hide it from the sidebar. Filter it out in submission field display.
* feat: multi-section form builder with section navigation
Add section navigation bar for multi-page forms. Sections are derived
from Page Break fields. Supports renaming (double-click), adding, and
removing sections with field merge or deletion options.
* feat: multi-step submission form with step navigation
Add step indicator and Next/Back navigation for multi-page form
submissions. Validates current step fields before advancing.
* feat: polish multi-step submission UI and lift step state into store
- Move step state (useFormSteps) into submissionForm store; FormRenderer
reads steps/navigation off the store instead of the composable
- Add stepDirection (forward/backward) to drive slide animations
- Redesign StepIndicator as numbered-circle stepper with animated check
and progress-fill connectors
- Compact step header on step 2+, full header on step 1
- Footer progress pills + Back/Next/Submit/Draft buttons; success fade-up
- Rename builder terminology page -> Step (addSection -> addStep)
* refactor: use frappe-ui semantic color tokens in stepper UI
Replace hardcoded Tailwind grays with surface/ink/outline tokens so the
multi-step submission UI respects theming. Kept the translucent halo ring
on the active step (no opaque token equivalent).
* fix: make multi-step stepper responsive on small screens
Drop the fixed percentage stepper width that starved nodes of space and
collapsed connectors. Use a scrollable w-max/mx-auto row with fixed-width
connectors, bounded nodes, and truncated labels so the stepper centers
when it fits and scrolls cleanly when many steps overflow narrow screens.
* refactor: rename "Section" to "Step" in form editor UI
User-facing labels and dialog text only. Default page-break labels now
read "Step N", and the remove-step dialog and nav aria-labels follow.
Internal symbols and section_* fieldnames unchanged.
* refactor: extract step logic into pure form_steps util
Step grouping was duplicated between editForm store and useFormSteps
composable and had drifted (label fallback, empty-form behavior).
Both now consume one parameterized groupFieldsIntoSteps core.
- form_steps.ts: grouping, page-break index helpers, step mutations
- form_fields.ts: compact/lastRowIndex/scrubFieldname (now take fields
param instead of reading the store resource)
- editForm store keeps state, persistence, and thin action wrappers;
step actions renamed removeSection* -> removeStep*, renameSection ->
renameStep to finish the Section->Step migration
* test: add e2e coverage for multi-step builder and submission
Add Playwright specs for step navigation in the builder (add/rename/
remove/persist) and the public multi-step submission flow (next/back,
value retention, done/current/todo stepper, conditional across steps,
guest path).
Supporting changes to make flows testable + correct:
- SectionNavBar: fix Escape during rename leaking into the next save;
add aria-label "Remove step" and "Add Step" labels
- StepIndicator: emit data-step-* hooks for stable step assertions
- submission helper: resolve field inputs via label sibling
Two known limitations pinned as test.fixme: getActiveStepEndIndex
leading-PageBreak offset, and REST seeding of empty-label Page Breaks.
* fix: make step remove control keyboard-accessible and harden rename
Address review findings on the multi-step builder:
- SectionNavBar: replace the nested <X role="button"> (mouse-only,
interactive element inside <Button>) with a real frappe-ui ghost
icon Button rendered as a sibling of the step tab. Now focusable and
Enter/Space activatable, and no longer invalid nested-interactive HTML.
- SectionNavBar: reset cancelRename in startRename so an Escape whose
@blur never fires (DOM removal doesn't reliably blur) can't leak into
and silently drop the next rename.
- e2e: seed helper now asserts the Form PUT succeeded, failing loudly
instead of as a downstream locator timeout.
- e2e: scope the remove control via the new [data-step-tab] group since
it is no longer a child of the tab button.
* refactor: nest step remove control back into the tab button
Keep the remove "X" inside the step tab's suffix slot so it shares the
tab's pill background instead of floating beside it. Keyboard access is
handled on the icon itself: tabindex, Enter/Space activation, and a
focus-visible ring.
Nesting changes the tab's accessible name to "<label> Remove step", so
the e2e stepTab locator now matches the label with that suffix optional.
* fix: render Submit button on fieldless published forms
groupFieldsIntoSteps returns no steps for an empty field list, so
isLastStep was false on step 0 and FormRenderer showed Next instead
of Submit. Pass alwaysIncludeTrailing so there is always >= 1 step.
* fix: add Page Break to FormField fieldtype literal
Runtime map already supported it; the TYPE_CHECKING union lagged behind
the doctype JSON options.
* fix(frontend): keep row_index unique when inserting fields into steps
Field insertion computed row_index from the active section only, so an
empty or middle section produced rows colliding with other sections —
moveField and compact() treat row_index as global. Centralize insertion
in insertFieldAtStepEnd, which numbers the new row from everything
before the insertion point and shifts later rows.
Also fixed along the way:
- addFieldFromDoctype appended to the form end instead of the active
section; it now uses the same helper
- getActiveStepEndIndex was off by one step when the form has a leading
Page Break (un-fixmes the palette e2e test)
- renameStep step 0 inserted a leading Page Break at row 0 without
shifting existing fields off that row
Pure grid helpers moved to form_layout.ts so vitest can import them
without the component registry; form_fields.ts re-exports them.1 parent 6155a26 commit 69acb3d
32 files changed
Lines changed: 2284 additions & 267 deletions
File tree
- forms_pro
- api/submission
- forms_pro/doctype/form_field
- tests
- frontend
- e2e
- helpers
- specs
- src
- components
- builder
- sidebar
- fields
- form/submissions
- submission
- composables
- config
- pages
- stores
- types/FormsPro
- utils
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
76 | 76 | | |
77 | 77 | | |
78 | 78 | | |
79 | | - | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
243 | 243 | | |
244 | 244 | | |
245 | 245 | | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
| 265 | + | |
| 266 | + | |
| 267 | + | |
| 268 | + | |
| 269 | + | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
| 274 | + | |
| 275 | + | |
| 276 | + | |
| 277 | + | |
| 278 | + | |
| 279 | + | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
40 | 40 | | |
41 | 41 | | |
42 | 42 | | |
43 | | - | |
| 43 | + | |
44 | 44 | | |
45 | 45 | | |
46 | 46 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
34 | 34 | | |
35 | 35 | | |
36 | 36 | | |
| 37 | + | |
37 | 38 | | |
38 | 39 | | |
39 | 40 | | |
40 | | - | |
| 41 | + | |
41 | 42 | | |
42 | 43 | | |
43 | 44 | | |
| |||
78 | 79 | | |
79 | 80 | | |
80 | 81 | | |
| 82 | + | |
81 | 83 | | |
82 | 84 | | |
83 | 85 | | |
| |||
114 | 116 | | |
115 | 117 | | |
116 | 118 | | |
117 | | - | |
118 | | - | |
119 | | - | |
120 | | - | |
121 | | - | |
122 | | - | |
123 | | - | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
124 | 125 | | |
125 | 126 | | |
126 | 127 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
304 | 304 | | |
305 | 305 | | |
306 | 306 | | |
| 307 | + | |
| 308 | + | |
| 309 | + | |
| 310 | + | |
| 311 | + | |
| 312 | + | |
| 313 | + | |
| 314 | + | |
| 315 | + | |
| 316 | + | |
| 317 | + | |
| 318 | + | |
| 319 | + | |
| 320 | + | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
| 324 | + | |
| 325 | + | |
| 326 | + | |
| 327 | + | |
| 328 | + | |
| 329 | + | |
| 330 | + | |
| 331 | + | |
| 332 | + | |
| 333 | + | |
| 334 | + | |
| 335 | + | |
| 336 | + | |
| 337 | + | |
| 338 | + | |
| 339 | + | |
| 340 | + | |
| 341 | + | |
| 342 | + | |
| 343 | + | |
| 344 | + | |
| 345 | + | |
| 346 | + | |
| 347 | + | |
| 348 | + | |
| 349 | + | |
| 350 | + | |
| 351 | + | |
| 352 | + | |
| 353 | + | |
| 354 | + | |
| 355 | + | |
| 356 | + | |
| 357 | + | |
| 358 | + | |
| 359 | + | |
| 360 | + | |
| 361 | + | |
| 362 | + | |
| 363 | + | |
| 364 | + | |
| 365 | + | |
| 366 | + | |
| 367 | + | |
| 368 | + | |
| 369 | + | |
| 370 | + | |
| 371 | + | |
307 | 372 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | | - | |
| 1 | + | |
2 | 2 | | |
3 | 3 | | |
4 | 4 | | |
| |||
7 | 7 | | |
8 | 8 | | |
9 | 9 | | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
10 | 18 | | |
11 | | - | |
| 19 | + | |
12 | 20 | | |
13 | 21 | | |
14 | 22 | | |
| |||
19 | 27 | | |
20 | 28 | | |
21 | 29 | | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
22 | 62 | | |
0 commit comments