Skip to content

feat(cases): the New case form answers what the case type already knows - #1710

Merged
rubenvdlinde merged 7 commits into
developmentfrom
feat/case-form-prefill-and-columns
Sep 3, 2026
Merged

feat(cases): the New case form answers what the case type already knows#1710
rubenvdlinde merged 7 commits into
developmentfrom
feat/case-form-prefill-and-columns

Conversation

@rubenvdlinde

Copy link
Copy Markdown
Contributor

Follow-up to #1653, from testing the real form on a running instance.

What was wrong

Six things a case handler was doing by hand, or being asked that they should never have been asked.

The case type already knows the answers. It carries initialStatus, defaultAssignee and its own title, and the form had no way to ask it. case.caseType now declares x-openregister-prefill mapping those onto the case's status, assignee and title. Only an EMPTY field is filled, so a title someone typed survives both the first choice of case type and every later one.

Status was being asked for. Someone filing a case does not choose the status it starts in, but the case still has to be stored in it. It is now prefilled without being offered as a field.

Decisions were on the form. They are linked decidiq objects, made and signed in decidiq and reached through the case detail page's Besluitvorming widget, so a raw reference list on a create or edit form could only ever be wrong. Now visible: false.

The dialog was a single narrow column of nine questions. Now wide and two-column, with the description spanning both.

Two labels were Title Case, which the house style bans: "Start Date" and "Planned End Date" now read as sentence case.

A case description was a single-line input. It is prose; it gets a textarea.

Two things worth a reviewer's attention

Hiding decisions was checked before it was done. visible: false hides a property from the form, the widget AND the table, not just the form. I confirmed no widget, table, or spec reads case.decisions: the Besluitvorming widget is type: integration and fetches from decidiq rather than rendering the property.

The description textarea is declared in the manifest, not the schema. format: textarea on the property made OpenRegister classify the register import as a BREAKING change (constraint_tightened), which the API refused outright. Measured, not guessed. Paying a breaking acknowledgement on every upgrade for a presentation hint is the wrong trade, so it moved to fieldOverrides where presentation belongs.

Verification

  • gate-22 manifest validation passes against the canonical 2.29.0 schema, including the new size, columns and fieldOverrides keys
  • gate-96 manifest copy style clean across 368 strings
  • Production build clean against nextcloud-vue 2.32.0, whose published tarball I unpacked and grepped rather than trusting the version number
  • Six new e2e tests: the title prefill, a typed title surviving, the starting status being stored without being shown, Create staying disabled until a required case type question is answered, the two-column layout measured by actual element geometry rather than by class name, and a definition label rendering in words
  • The live schema on the dev instance is updated to 1.12.0, so this is testable now

gate-19 reports EMPTY SCOPE (exit 3) for this diff, exactly as it did for #1653: these @e2e anchors point into openspec/changes/, and the gate only inspects openspec/specs/. I verified every anchor resolves to a real heading by slugifying the spec myself. It is not a gate pass and I am not claiming one.

e2e is skipped on PRs into development by design, so the push run after merge is the authoritative gate.

🤖 Generated with Claude Code

Conduction Release Bot and others added 4 commits September 3, 2026 07:45
Six things a case handler was doing by hand, or being asked that they
should never have been asked.

The case type already carries `initialStatus`, `defaultAssignee` and its
own title, so `case.caseType` now declares `x-openregister-prefill`
mapping those onto the case's status, assignee and title. Only an EMPTY
field is filled, so a title someone typed survives both the first choice
of case type and every later one.

`status` is prefilled without being offered as a field. Someone filing a
case does not choose the status it starts in, but the case still has to
be stored in it.

`decisions` is hidden. They are linked decidiq objects, made and signed
in decidiq and reached through the case detail page; a raw reference
list on a create or edit form could only ever be wrong. Checked first
that no widget, table or spec reads the property, because `visible:
false` hides a property from all three surfaces and not just the form.

The New case dialog is now wide and two-column, which halves the
scrolling, and the two Title Case labels among the nine create fields
read as sentence case: "Start date" and "Planned end date".

Case schema 1.11.0 to 1.12.0. Needs nc-vue 2.32.0 for the prefill and
the columns prop; the dependency bump follows once it publishes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A case description rendered as a single-line text input, which is the
difference between a form someone can use and one they fight. `format:
textarea` is what the field engine reads to widen it, and in the new
two-column layout a textarea spans both columns, so the description gets
the full width of the dialog rather than half of it.

Checked the other two specs that mention a description first: one uses a
placeholder on a different modal, the other sets the field through the
API. Neither goes through this widget.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… schema

OpenRegister classifies adding `format` to a property as a tightened
constraint, so putting `format: textarea` on `case.description` made the
register import a BREAKING schema change needing an explicit
acknowledgement on every upgrade. Measured, not guessed: the API refused
the update with `constraint_tightened` naming exactly that property.

Paying that for a presentation hint is the wrong trade. Which widget a
field renders as is a decision belonging to the surface, not to the data
contract, and the manifest already carries `fieldOverrides` for exactly
this. The description still gets its textarea, and still spans both
columns, without the case schema claiming a constraint it does not mean.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Verified against the published tarball rather than the version number:
2.32.0 ships dist/esm/utils/dynamicProperties.js carrying
x-openregister-prefill, and manifest schema 2.29.0 with the `size` and
`columns` keys the New case action declares.

Exactly one dependency moves in the lockfile. Production build clean.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…eate form

Keeping `parentCase` off the New case form is right: a case is not filed
as somebody's sub-case, it becomes one later. But the case detail page's
`case-core` widget carries an explicit `include` allowlist, and
`parentCase` was not in it. So excluding it from the create form left it
editable NOWHERE.

This is the same trap as a `visible: false`, wearing different clothes:
the property is fine, `visible` is true, and an allowlist somewhere else
decides it never renders. Checking the create form told me nothing about
it, which is why the check has to be "which surfaces show this" and not
"is it hidden".

REQ-FCF-007 now states the create/edit split, and an e2e test asserts
BOTH halves: absent when filing, present on the case. The second half is
the one that matters, because the first half passed all along.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/dossiq @ a816f16

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
check-manifest
check-vue3-compile
test-l10n
format
check-schema-l10n
check-l10n-js
composer ✅ 106/106
npm ✅ 540/540
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman ⏭️
Playwright ⏭️ deferred — runs on the promotion into beta/main, not on a pull request into development
Hydra gates

Quality workflow — 2026-09-03 07:10 UTC

Download the full PDF report from the workflow artifacts.

…ard load

A hard load of `/apps/dossiq/cases/<id>` answers 200 and is rewritten
client-side to the dashboard by the SPA catch-all, which
case-flow-human-steps.spec.ts already documents. The parent case
assertion would then have run against the dashboard and failed naming
the field, sending a reader after the manifest instead of the URL.

Uses the `/index.php` form the other specs use, and asserts the URL
stayed on the case, so a future regression in the router base fails as a
navigation problem rather than as a missing field.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/dossiq @ 27ca286

Check PHP Vue Security License Tests
lint ⏭️
phpcs ⏭️
phpmd ⏭️
psalm ⏭️
phpstan ⏭️
phpmetrics ⏭️
eslint ⏭️
stylelint ⏭️
build ⏭️
check-l10n-js
composer ⏭️ ⏭️
npm ⏭️ ⏭️
app:check-code ⏭️
info.xml ⏭️
REUSE ⏭️
PHPUnit
Newman
Playwright
Hydra gates

Quality workflow — 2026-09-03 07:11 UTC

Download the full PDF report from the workflow artifacts.

@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/dossiq @ d655f28

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
check-manifest
check-vue3-compile
test-l10n
format
check-schema-l10n
check-l10n-js
composer ✅ 106/106
npm ✅ 540/540
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman ⏭️
Playwright ⏭️ deferred — runs on the promotion into beta/main, not on a pull request into development
Hydra gates

Quality workflow — 2026-09-03 07:15 UTC

Download the full PDF report from the workflow artifacts.

`Frontend Check (format)` runs prettier over the tree, and my added
locator chains were over the print width. The Quality Report failure
alongside it was not independent: its only failing step is "Gate — fail
when any upstream job failed".

Verified after reformatting that eslint is still clean AND that the file
still collects 11 tests. Prettier and eslint both pass on a spec file
that collects ZERO tests, so the listing is the check that matters here.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/dossiq @ 03b460e

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
check-manifest
check-vue3-compile
test-l10n
format
check-schema-l10n
check-l10n-js
composer ✅ 106/106
npm ✅ 540/540
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman ⏭️
Playwright ⏭️ deferred — runs on the promotion into beta/main, not on a pull request into development
Hydra gates

Quality workflow — 2026-09-03 07:23 UTC

Download the full PDF report from the workflow artifacts.

@rubenvdlinde
rubenvdlinde merged commit 893694f into development Sep 3, 2026
49 checks passed
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