Skip to content

Add a per-Constraint severity control to the Schema editor - #1301

Open
alistair3149 wants to merge 1 commit into
masterfrom
feature/1149-severity-control
Open

Add a per-Constraint severity control to the Schema editor#1301
alistair3149 wants to merge 1 commit into
masterfrom
feature/1149-severity-control

Conversation

@alistair3149

@alistair3149 alistair3149 commented Aug 17, 2026

Copy link
Copy Markdown
Member

Fixes #1149. Follows-up to #1227, which made the editor round-trip the object Constraint form.

Adds a per-Constraint severity control to the Schema editor, so marking a Constraint error (ADR 26) no longer requires hand-editing the JSON.

The control

  • SeverityInput.vue: a CdxMenuButton whose face is the current level's icon (grey cdxIconAlert for warning, red cdxIconError for error) at size="small" plus an x-small chevron. The menu offers Warning and Error, each with its icon in the Codex warning/error colour and a one-line meaning; the Error line depends on $wgNeoWikiEnforceValidation ("Flags the value as an error and blocks saving" / "Flags the value as an error"), which FrontendModuleLoader now exposes as wgNeoWikiEnforceValidation. Accessible name and tooltip name the Constraint too, since several controls can sit on one property: "Severity of "Minimum": Warning".
  • Placement: the end of the Constraint's label row (label at the start, input untouched below), or the end of the checkbox row for boolean Constraints. The trigger keeps Codex's 32px hit area but takes 20px in the flow through negative block margins, so label rows and checkbox rows keep their height. The two placement helper classes (ext-neowiki-severity-field, ext-neowiki-severity-row) live with the component.
  • Shown only once the Constraint is set: required checked, a bound with a value, uniqueItems checked, at least one option. Unticking required or uniqueItems, or removing the last option, drops the severity with it; a cleared bound keeps its severity until save (a number input reports interim text such as 1. as empty, so pruning there would lose the choice mid-typing), and serialization drops the severity of any Constraint still absent. Changing the Property Type keeps required with its severity and drops the type-specific ones.
  • Sites: required (PropertyDefinitionEditor), minimum / maximum (Number, Date, DateTime), minLength / maxLength / uniqueItems (Text), uniqueItems (Url), options (Select). Display Attributes (precision) and shape fields (multiple, relation, targetSchema) get none, matching what the backend accepts.

Wiring

  • withConstraintSeverity( property, name, severity ) returns the Partial an attributes editor emits: it sets the annotation, removes it for warning (the default), and drops an emptied map, so unannotated definitions stay identical to factory-built ones. withoutSeveritiesOfClearedConstraints prunes the annotations of Constraints a change unticks or empties; PropertyDefinitionEditor applies it to every attribute change.
  • NeoNestedField gap 8px → 16px so a bound's control does not crowd the next bound's label.
  • New messages, cdxIconError in the icon allowlist, and SeverityInput exported through the public API for extension attributes editors.
  • Tests: SeverityInput, withConstraintSeverity and withoutSeveritiesOfClearedConstraints get their own specs; each site's spec covers reveal-once-set and the emitted constraintSeverities; PropertyDefinitionEditor covers unsetting and the type change; FrontendModuleLoaderTest and NeoWikiExtension.spec.ts cover the new config var.

Considered, omitted

  • A boxed CdxSelect per Constraint: four boxed fields on a fully constrained text property.
  • A collapsed per-property "Severity" section: the author would pick a severity without the rule's value in view.
  • Toggle buttons: the glyph could not change with the level, and Codex's pressed state reads as blue rather than error.
  • A help sentence on the form: the menu descriptions carry the meaning at the moment of choice.

Manual Browser Check

  1. On a dev wiki with demo data, open Schema:Validation Demo and click the edit pencil.
  2. Select Score: each bound's label row ends with a small grey ⚠▾ and the inputs keep full width. Open the Maximum one: a menu with Warning (yellow) and Error (red), each with a one-line meaning. Pick Error — the trigger turns red and its tooltip reads "Severity: Error".
  3. Select Title: the trigger ends the "Require a value" row. Untick the box and it disappears; tick it and it is back.
  4. Select Status: the trigger ends the "Options" label row; the chip input keeps full width.
  5. Save. The stored JSON has "maximum": { "value": 100, "severity": "error" } while the untouched Constraints stay bare. Reopen the editor: the trigger shows Error again.
  6. With $wgNeoWikiEnforceValidation = true in LocalSettings.php, the Error item reads "Flags the value as an error and blocks saving"; without it, "Flags the value as an error".

AI-authored — Claude Code, Fable 5; design settled with Alistair, then implemented; verified with vitest (124 files, 1351 tests), PHPUnit for the loader, vue-tsc/vite build, eslint/stylelint/phpcs/phpstan, mutation-tested new specs, an adversarial code review whose confirmed findings are addressed, and a browser round trip on a dev wiki in both enforcement settings.

@alistair3149
alistair3149 force-pushed the feature/1149-severity-control branch from b80194b to 761cee7 Compare August 17, 2026 21:57
@alistair3149

Copy link
Copy Markdown
Member Author
image

^ The hover state background is clipping a bit. I left it as it is intentionally to preserve the 32px clickable height, the hover affordance, and the compact height of the label without introducing more spacing.

@alistair3149
alistair3149 marked this pull request as ready for review August 17, 2026 22:12
Fixes #1149. Follows-up to #1227, which made the editor round-trip the object Constraint form.

Adds a per-Constraint severity control to the Schema editor, so marking a Constraint `error` ([ADR 26](https://github.com/ProfessionalWiki/NeoWiki/blob/master/docs/adr/026-validation-severity-levels.md)) no longer requires hand-editing the JSON.

* `SeverityInput.vue`: a `CdxMenuButton` whose face is the current level's icon (grey `cdxIconAlert` for warning, red `cdxIconError` for error) at `size="small"` plus an x-small chevron. The menu offers Warning and Error, each with its icon in the Codex warning/error colour and a one-line meaning; the Error line depends on `$wgNeoWikiEnforceValidation` ("Flags the value as an error and blocks saving" / "Flags the value as an error"), which `FrontendModuleLoader` now exposes as `wgNeoWikiEnforceValidation`. Accessible name and tooltip name the Constraint too, since several controls can sit on one property: "Severity of "Minimum": Warning".
* Placement: the end of the Constraint's label row (label at the start, input untouched below), or the end of the checkbox row for boolean Constraints. The trigger keeps Codex's 32px hit area but takes 20px in the flow through negative block margins, so label rows and checkbox rows keep their height. The two placement helper classes (`ext-neowiki-severity-field`, `ext-neowiki-severity-row`) live with the component.
* Shown only once the Constraint is set: `required` checked, a bound with a value, `uniqueItems` checked, at least one option. Unticking `required` or `uniqueItems`, or removing the last option, drops the severity with it; a cleared bound keeps its severity until save (a number input reports interim text such as `1.` as empty, so pruning there would lose the choice mid-typing), and serialization drops the severity of any Constraint still absent. Changing the Property Type keeps `required` with its severity and drops the type-specific ones.
* Sites: `required` (`PropertyDefinitionEditor`), `minimum` / `maximum` (Number, Date, DateTime), `minLength` / `maxLength` / `uniqueItems` (Text), `uniqueItems` (Url), `options` (Select). Display Attributes (`precision`) and shape fields (`multiple`, `relation`, `targetSchema`) get none, matching what the backend accepts.

* `withConstraintSeverity( property, name, severity )` returns the `Partial` an attributes editor emits: it sets the annotation, removes it for warning (the default), and drops an emptied map, so unannotated definitions stay identical to factory-built ones. `withoutSeveritiesOfClearedConstraints` prunes the annotations of Constraints a change unticks or empties; `PropertyDefinitionEditor` applies it to every attribute change.
* `NeoNestedField` gap 8px → 16px so a bound's control does not crowd the next bound's label.
* New messages, `cdxIconError` in the icon allowlist, and `SeverityInput` exported through the public API for extension attributes editors.
* Tests: `SeverityInput`, `withConstraintSeverity` and `withoutSeveritiesOfClearedConstraints` get their own specs; each site's spec covers reveal-once-set and the emitted `constraintSeverities`; `PropertyDefinitionEditor` covers unsetting and the type change; `FrontendModuleLoaderTest` and `NeoWikiExtension.spec.ts` cover the new config var.

* A boxed `CdxSelect` per Constraint: four boxed fields on a fully constrained text property.
* A collapsed per-property "Severity" section: the author would pick a severity without the rule's value in view.
* Toggle buttons: the glyph could not change with the level, and Codex's pressed state reads as blue rather than error.
* A help sentence on the form: the menu descriptions carry the meaning at the moment of choice.

1. On a dev wiki with demo data, open `Schema:Validation Demo` and click the edit pencil.
2. Select *Score*: each bound's label row ends with a small grey ⚠▾ and the inputs keep full width. Open the *Maximum* one: a menu with Warning (yellow) and Error (red), each with a one-line meaning. Pick Error — the trigger turns red and its tooltip reads "Severity: Error".
3. Select *Title*: the trigger ends the "Require a value" row. Untick the box and it disappears; tick it and it is back.
4. Select *Status*: the trigger ends the "Options" label row; the chip input keeps full width.
5. Save. The stored JSON has `"maximum": { "value": 100, "severity": "error" }` while the untouched Constraints stay bare. Reopen the editor: the trigger shows Error again.
6. With `$wgNeoWikiEnforceValidation = true` in `LocalSettings.php`, the Error item reads "Flags the value as an error and blocks saving"; without it, "Flags the value as an error".

<sub>AI-authored — Claude Code, Fable 5; design settled with Alistair, then implemented; verified with vitest (124 files, 1351 tests), PHPUnit for the loader, vue-tsc/vite build, eslint/stylelint/phpcs/phpstan, mutation-tested new specs, an adversarial code review whose confirmed findings are addressed, and a browser round trip on a dev wiki in both enforcement settings.</sub>

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@alistair3149
alistair3149 force-pushed the feature/1149-severity-control branch from 761cee7 to 52d177a Compare August 20, 2026 15:21
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.

Add a per-Constraint severity control to the Schema editor

1 participant