Skip to content

Normalize repeated form choices and table layouts#1866

Merged
stefan-burke merged 7 commits into
mainfrom
normalize/declarative-inputs
Jul 19, 2026
Merged

Normalize repeated form choices and table layouts#1866
stefan-burke merged 7 commits into
mainfrom
normalize/declarative-inputs

Conversation

@stefan-burke

@stefan-burke stefan-burke commented Jul 19, 2026

Copy link
Copy Markdown
Member

Summary

  • reject unknown repeated form choices while keeping accepted choices in their declared order
  • preserve repeated checkbox choices when a rejected form is shown again
  • validate listing and attendee column settings once, then pass typed layouts to every table renderer
  • keep schema-only layout parsing out of the Liquid rendering dependency path
  • use shared form-data, field-definition, weekday, and layout sources instead of parallel helpers and duplicated values
  • derive form section lookups from field definitions and fail clearly for unknown fields or sections
  • make test form data match browser submissions and strengthen parser, route, validation, and rendering coverage

Review fixes

  • keep editors independent of malformed owner-only listing layouts
  • preserve custom and explicitly blank validation errors for invalid checkbox choices
  • keep every repeated checkbox choice after an unrelated validation error
  • validate column keys through the existing Valibot picklist and derive public options from the same schema
  • split layout parsing from Liquid cell rendering and create the Liquid engine only when filtered rendering is used
  • derive Monday-first bookable days from the canonical weekday tuple
  • validate field options while building the shared field-name map with #fp
  • correct the attendee layout contract comment and validation helper return type
  • move dashboard route tests beside their source and close the mutation gaps they exposed
  • reply to and resolve every review thread

Checks

  • nix develop -c deno task precommit
  • focused form validation, rejected listing form, editor layout, dashboard, CSV, activity-log, column layout, attendee table, and weekday/date tests
  • exhaustive mutation: column layouts 106/106, column rendering 36/36, form data 27/27, dashboard routes 71/71
  • earlier exhaustive targeted mutation suites for form definitions, form validation, aggregate recalculation, and listing defaults

Summary by CodeRabbit

  • New Features

    • Added configurable, validated column layouts for attendee and listing tables, including saved column order and per-column filters.
    • Added support for repeated form selections and improved preservation of submitted values when forms are redisplayed after errors.
    • Added admin aggregate recalculation field selection with validation.
  • Bug Fixes

    • Improved validation for select fields, checkbox groups, and bookable days (including clearer error messages and stricter choice handling).
    • Admin activity logs now consistently display the latest 200 entries with correct truncation messaging.
    • Corrected listing column layout and default handling across admin pages and editor views.

@coderabbitai

coderabbitai Bot commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This change introduces typed column-layout registries, repeated picklist parsing, updated form validation and rendering APIs, typed test form values, and expanded admin/settings coverage for layouts, recalculation fields, listing defaults, and form behavior.

Changes

Typed column layouts

Layer / File(s) Summary
Layout contracts and parsing
src/shared/column-layout.ts, src/shared/column-order.ts, src/shared/columns/*
Column layouts now expose typed parsing, validation, filters, defaults, and explicit unknown-column errors.
Settings and admin layout wiring
src/shared/db/settings.ts, src/features/admin/*, src/ui/templates/admin/*, src/ui/templates/attendee-table.tsx
Admin routes and templates consume parsed listing and attendee layouts instead of raw column-order strings.
Layout and rendering validation
test/shared/*column*.test.ts, test/integration/server/settings/column-order.test.ts, test/ui/templates/**/*table*.test.ts
Tests cover layout parsing, defaults, filters, invalid columns, settings round trips, and typed table rendering.

Repeated form values

Layer / File(s) Summary
Repeated picklist and form validation
src/shared/form-data.ts, src/shared/forms/*
Repeated picklists, checkbox-group validation, saved values, and the renderField/validateForm APIs are updated.
Admin form consumers
src/features/admin/aggregate-recalculation.ts, src/features/admin/settings-listing-defaults.ts, src/features/admin/*
Recalculation fields and bookable days use allowlisted repeated selections, while rejected forms preserve repeated values for rendering.
Form behavior tests
test/features/admin/*, test/shared/forms/*, test/shared/form-data.test.ts
Tests cover repeated selections, checkbox groups, select values, rendering, recalculation responses, and listing defaults.
Test form value infrastructure
test/test-utils/*, test/lib/*, test/ui/templates/fields/listing.test.ts
Test request helpers and listing form builders support arrays, nullable values, and shared form serialization.
Form rendering call sites
src/ui/templates/admin/{ledger,news,questions,site-pages}.tsx, test/ui/templates/admin/ledger/forms.test.ts
Admin templates and tests use the consolidated form rendering methods.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: normalizing repeated form choices and table layout handling.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch normalize/declarative-inputs

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@scripts/mutation/equivalent-mutants.txt`:
- Around line 36-37: Remove the suppressions for the validatedColumnLayout
brand-symbol description mutants in equivalent-mutants.txt. Update the
column-layout tests to reflect on the returned layout’s own symbols and assert
the expected brand symbol description, covering both the normal and mutated
descriptions.

In `@src/shared/forms/validation.ts`:
- Around line 74-88: Add a test covering validateCheckboxField when
readRepeatedPicklist produces an invalid selection and the field’s custom
validate function returns an error message. Assert that the result is invalid
and preserves the custom error instead of using invalidFieldError(field).

In `@src/ui/templates/attendee-table.tsx`:
- Around line 75-77: Update the doc comment above columnLayout in the attendee
table props to describe its current AttendeeColumnLayout object contract, not
the removed Liquid string-template format. Mention that it is a pre-parsed
layout, and remove the obsolete template example and historical wording.

In `@test/test-utils/validation.ts`:
- Around line 21-27: Annotate the outer expectInvalid factory with its explicit
curried function return type, specifying the returned function accepts readonly
Field[] and TestFormValues and returns void. Keep the existing validation and
assertion logic unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 9d459f73-cbd4-4824-a0ac-a398c9a50061

📥 Commits

Reviewing files that changed from the base of the PR and between 054111a and 4af4187.

📒 Files selected for processing (43)
  • scripts/mutation/equivalent-mutants.txt
  • src/features/admin/aggregate-recalculation.ts
  • src/features/admin/dashboard.ts
  • src/features/admin/settings-general.ts
  • src/features/admin/settings-listing-defaults.ts
  • src/shared/column-order.ts
  • src/shared/columns/attendee-columns.ts
  • src/shared/columns/listing-columns.ts
  • src/shared/day-names.ts
  • src/shared/db/settings.ts
  • src/shared/forms/definition.ts
  • src/shared/forms/repeated-picklist.ts
  • src/shared/forms/saved-data.ts
  • src/shared/forms/submitted-value.ts
  • src/shared/forms/validation.ts
  • src/ui/templates/admin/dashboard.tsx
  • src/ui/templates/admin/groups/overview.tsx
  • src/ui/templates/admin/guide/operations.tsx
  • src/ui/templates/admin/listing-table.tsx
  • src/ui/templates/admin/settings/column-order.tsx
  • src/ui/templates/attendee-table.tsx
  • test/features/admin/aggregate-recalculation.test.ts
  • test/features/admin/settings-listing-defaults.test.ts
  • test/integration/server/settings/column-order.test.ts
  • test/integration/server/settings/listing-defaults.test.ts
  • test/lib/server-editor.test.ts
  • test/lib/server-images/attachment-edit.test.ts
  • test/lib/server-images/create.test.ts
  • test/shared/column-order.test.ts
  • test/shared/columns/attendee-columns.test.ts
  • test/shared/db/attendees/api/errors.test.ts
  • test/shared/forms/definition/field-schema.test.ts
  • test/shared/forms/repeated-picklist.test.ts
  • test/shared/forms/validation.test.ts
  • test/test-utils/db-helpers/listing-forms.ts
  • test/test-utils/db-helpers/request.ts
  • test/test-utils/form-values.test.ts
  • test/test-utils/form-values.ts
  • test/test-utils/mocks.ts
  • test/test-utils/validation.ts
  • test/ui/templates/admin/dashboard.test.ts
  • test/ui/templates/attendee-table/template.test.ts
  • test/ui/templates/fields/listing.test.ts
💤 Files with no reviewable changes (1)
  • src/shared/forms/submitted-value.ts

Comment thread scripts/mutation/equivalent-mutants.txt Outdated
Comment thread src/shared/forms/validation.ts Outdated
Comment thread src/ui/templates/attendee-table.tsx
Comment thread test/test-utils/validation.ts
@stefan-burke
stefan-burke force-pushed the normalize/declarative-inputs branch from 4af4187 to 997e33a Compare July 19, 2026 15:46
@stefan-burke stefan-burke changed the title Validate repeated form choices and table layouts Normalize repeated form choices and table layouts Jul 19, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/shared/column-order.ts (1)

88-180: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Drive column-key validation from the schema

parseColumnTemplate still does a separate options.find(...) membership check, so the allowed keys live in two places and the docstring is stale. Use the v.picklist schema as the single source of truth for validation/error reporting and update the comment to match the current behavior.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/shared/column-order.ts` around lines 88 - 180, Update parseColumnTemplate
and defineColumnLayout so column-key validation uses the existing v.picklist
schema rather than a separate options.find membership check, with unknown-key
errors derived from schema validation while preserving the current result shape.
Pass or reuse the schema where needed, and revise the stale validation doc
comment to describe schema-based parsing without claiming column extraction is
avoided.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/shared/day-names.ts`:
- Around line 19-27: Update VALID_DAY_NAMES to reuse the canonical DAY_NAMES
tuple instead of duplicating weekday literals, and derive its alternate ordering
from that shared source while preserving the existing exported order and
readonly typing.

In `@src/shared/forms/definition.ts`:
- Around line 100-107: Replace the imperative for...of traversal in the
field-validation logic with the repository’s curried collection utility from
`#fp`, preserving the existing select and checkbox-group branches and their
requireChoiceOptions and requireCheckboxOptions calls.

In `@test/shared/forms/definition/field-schema.test.ts`:
- Around line 16-18: Update the checkbox field-definition helper around the
invalidMessage construction to distinguish an omitted value from an explicitly
empty string: use an undefined check rather than truthiness, preserving `""` as
the configured error message. Add coverage for an invalid checkbox submission
configured with an empty invalidMessage.

---

Outside diff comments:
In `@src/shared/column-order.ts`:
- Around line 88-180: Update parseColumnTemplate and defineColumnLayout so
column-key validation uses the existing v.picklist schema rather than a separate
options.find membership check, with unknown-key errors derived from schema
validation while preserving the current result shape. Pass or reuse the schema
where needed, and revise the stale validation doc comment to describe
schema-based parsing without claiming column extraction is avoided.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: e1dc01be-0f0e-4134-8a78-1ebd20de0523

📥 Commits

Reviewing files that changed from the base of the PR and between 4af4187 and 997e33a.

📒 Files selected for processing (49)
  • scripts/mutation/equivalent-mutants.txt
  • src/features/admin/aggregate-recalculation.ts
  • src/features/admin/dashboard.ts
  • src/features/admin/settings-general.ts
  • src/features/admin/settings-listing-defaults.ts
  • src/shared/column-order.ts
  • src/shared/columns/attendee-columns.ts
  • src/shared/columns/listing-columns.ts
  • src/shared/day-names.ts
  • src/shared/db/settings.ts
  • src/shared/form-data.ts
  • src/shared/forms/definition.ts
  • src/shared/forms/saved-data.ts
  • src/shared/forms/submitted-value.ts
  • src/shared/forms/validation.ts
  • src/ui/templates/admin/dashboard.tsx
  • src/ui/templates/admin/groups/overview.tsx
  • src/ui/templates/admin/guide/operations.tsx
  • src/ui/templates/admin/ledger/entry-pages.tsx
  • src/ui/templates/admin/listing-table.tsx
  • src/ui/templates/admin/news.tsx
  • src/ui/templates/admin/questions.tsx
  • src/ui/templates/admin/settings/column-order.tsx
  • src/ui/templates/admin/site-pages.tsx
  • src/ui/templates/attendee-table.tsx
  • test/features/admin/aggregate-recalculation.test.ts
  • test/features/admin/settings-listing-defaults.test.ts
  • test/integration/server/settings/column-order.test.ts
  • test/integration/server/settings/listing-defaults.test.ts
  • test/lib/server-editor.test.ts
  • test/lib/server-images/attachment-edit.test.ts
  • test/lib/server-images/create.test.ts
  • test/shared/column-order.test.ts
  • test/shared/columns/attendee-columns.test.ts
  • test/shared/db/attendees/api/errors.test.ts
  • test/shared/form-data.test.ts
  • test/shared/forms/definition/define-form.test.ts
  • test/shared/forms/definition/field-schema.test.ts
  • test/shared/forms/validation.test.ts
  • test/test-utils/db-helpers/listing-forms.ts
  • test/test-utils/db-helpers/request.ts
  • test/test-utils/form-values.test.ts
  • test/test-utils/form-values.ts
  • test/test-utils/mocks.ts
  • test/test-utils/validation.ts
  • test/ui/templates/admin/dashboard.test.ts
  • test/ui/templates/admin/ledger/forms.test.ts
  • test/ui/templates/attendee-table/template.test.ts
  • test/ui/templates/fields/listing.test.ts
💤 Files with no reviewable changes (1)
  • src/shared/forms/submitted-value.ts

Comment thread src/shared/day-names.ts Outdated
Comment thread src/shared/forms/definition.ts Outdated
Comment thread test/shared/forms/definition/field-schema.test.ts
@stefan-burke

Copy link
Copy Markdown
Member Author

Resolved the outside-diff src/shared/column-order.ts finding in 1384659. Column parsing now validates each extracted key with the existing Valibot picklist, uses that schema’s options for errors and the public options list, and removes the stale comment. Exhaustive mutation testing killed all 136 mutants.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1384659ed4

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/features/admin/dashboard.ts Outdated
Comment thread src/shared/forms/validation.ts
Comment thread src/shared/db/settings.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/shared/column-layout.ts`:
- Around line 39-54: Refactor the tag scan in the column-layout parser to use
the project’s `#fp` collector style with a small curried helper instead of the
current for...of loop. Keep parseTagBody, schema validation, deduplication,
filter storage, and column accumulation equivalent, and preserve the immediate
error result when an unknown column is encountered.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: d25ac3ef-c93c-418a-93e6-36e97a0025c1

📥 Commits

Reviewing files that changed from the base of the PR and between 1384659 and 01056a5.

📒 Files selected for processing (29)
  • scripts/mutation/equivalent-mutants.txt
  • src/features/admin/dashboard.ts
  • src/features/admin/entity-write-tab.ts
  • src/features/admin/listings-edit.ts
  • src/features/admin/logistics-agent-page.tsx
  • src/features/admin/modifiers.ts
  • src/features/admin/settings-general.ts
  • src/shared/column-layout.ts
  • src/shared/column-order.ts
  • src/shared/columns/attendee-columns.ts
  • src/shared/columns/listing-columns.ts
  • src/shared/db/settings.ts
  • src/shared/form-data.ts
  • src/ui/templates/admin/dashboard.tsx
  • src/ui/templates/admin/guide/operations.tsx
  • src/ui/templates/admin/settings/column-order.tsx
  • src/ui/templates/attendee-table.tsx
  • test/features/admin/dashboard.test.ts
  • test/features/admin/dashboard/listings-csv.test.ts
  • test/features/admin/dashboard/log.test.ts
  • test/integration/server/listings/create-validation.test.ts
  • test/lib/server-listings/log-and-activity.test.ts
  • test/shared/column-layout.test.ts
  • test/shared/column-order.test.ts
  • test/shared/columns/attendee-columns.test.ts
  • test/shared/form-data.test.ts
  • test/test-utils/session.ts
  • test/ui/templates/admin/dashboard.test.ts
  • test/ui/templates/attendee-table/template.test.ts

Comment thread src/shared/column-layout.ts Outdated
@stefan-burke
stefan-burke added this pull request to the merge queue Jul 19, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6c5e34572f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +42 to +43
if (!selection.ok) {
throw new Error(`Invalid recalculation field: ${selection.error}`);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Return a validation response for bad recalc fields

When an authenticated listing/modifier/answer recalculate POST contains a stale or tampered recalculate_fields value, this exception bubbles through runRecalculatePost/withAuth without being converted to a response, so the operator gets a 500 instead of the same 400 re-render used for the empty-selection validation path. Treat the unknown choice as a form validation error at this boundary so bad request data fails closed without crashing the route.

Useful? React with 👍 / 👎.

Merged via the queue into main with commit 7cd215d Jul 19, 2026
5 checks passed
@stefan-burke
stefan-burke deleted the normalize/declarative-inputs branch July 19, 2026 21:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant