Skip to content

Add Boolean property type#837

Merged
malberts merged 2 commits into
masterfrom
feature/703-boolean-property-type
May 23, 2026
Merged

Add Boolean property type#837
malberts merged 2 commits into
masterfrom
feature/703-boolean-property-type

Conversation

@malberts

@malberts malberts commented May 16, 2026

Copy link
Copy Markdown
Contributor

Fixes #703

Summary

Adds a new boolean property type for true/false values, following the established core property type pattern (most recently the select type, #711). BooleanValue and the ValueType::Boolean deserialization path already existed in both PHP and TS; this PR adds the property-type wrapper, definition, UI, and registration.

Schema JSON format: { "type": "boolean" }. No type-specific attributes; default may be true, false, or null.

Screenshots

Schema editor: type dropdown. "Boolean" appears in the type-picker dropdown with its check icon, alongside Text/URL/Number/Select/Relation/Date & Time/Date. 703-4-type-dropdown
Schema editor: Boolean property attributes. BooleanAttributesEditor is intentionally empty (nothing renders between "Require a value" and "Initial value"); the initial-value control is the same CdxToggleSwitch used in the subject editor. 703-5-boolean-property-editor
Schema read view. The Is public · Boolean · No · Yes row confirms PHP serialization of the Boolean property and its default round-trip and render. 703-3-schema-table
Subject edit: BooleanInput value editor. "Is public" rendered as CdxToggleSwitch on the ACME Inc subject form, currently on. 703-2-subject-editor-toggle
Subject edit: full dialog. The whole subject editor dialog with the toggle visible at the bottom of the form. 703-2b-subject-editor-full
Subject display: BooleanDisplay. The infobox shows Is public: Yes after toggling and saving (full PHP/Neo4j round-trip). 703-1-infobox-display-yes

Design decisions

  • Type name is boolean (not checkbox/toggle): it names the data, not a widget, so the UI can change without a schema migration.
  • Editor uses an inline toggle switch (label + switch in a single row); display renders the value as "Yes" / "No" text.
  • BooleanInput always emits a BooleanValue, so a boolean is never "unset"; this matches checkbox/toggle semantics, and the input renders as a single inline label [switch] row matching the schema editor's Require a value row. One residual cosmetic: the schema editor's Require a value switch still renders for Boolean properties because it's owned by the shared PropertyDefinitionEditor chrome rather than gated per type. It has no effect on Boolean validation (the toggle always satisfies required), so it reads oddly but is harmless. Hiding it cleanly would need a small per-type opt-out hook on TypeSpecificComponentRegistry or BasePropertyType; deferred as a follow-up so the same hook can serve any future always-has-a-value types.

Test plan

  • PHP tests pass (BooleanPropertyTest: serialization round-trips, non-boolean default rejected); full suite 1032 tests green.
  • TS tests pass (Boolean.spec.ts: type, factory, validation); full suite 875 tests green.
  • PHPCS + PHPStan clean; ESLint + Stylelint + build clean.
  • New tests fail when the production code is reverted.
  • Test review (mutation testing): 6/6 mutations caught across both test files (default-validation removal/inversion, wrong type name, required-error removal, example-value flip, === to !==).
  • UI (Playwright), schema editor: "Boolean" in type selector; no spurious attributes; Initial value is a toggle; saved schema persists and the schema table shows "Yes".
  • UI (Playwright), subject editor: "Is public" renders as a toggle on the ACME Inc Company subject; toggled on, saved, and the infobox now displays "Is public: Yes" (full PHP/Neo4j round-trip). 0 console errors.

🤖 Generated with Claude Code

@malberts
malberts force-pushed the feature/703-boolean-property-type branch 8 times, most recently from 08d7bf4 to f177304 Compare May 22, 2026 17:28
Adds a `boolean` property type for true/false values, mirroring the
recently-merged Select pattern. `BooleanValue` and the
`ValueType::Boolean` deserialization path already existed in both PHP
and TS; this PR adds the type wrapper, property definition, schema and
subject UI, and registration.

Schema JSON: `{ "type": "boolean" }`. No type-specific attributes;
`default` may be `true`, `false`, or `null`. The construction-time check
rejects non-boolean defaults, slightly stricter than siblings.

`BooleanInput` always emits a `BooleanValue`, so a Boolean field is
never "unset" once interacted with. The input renders as a single
inline `label [switch]` row to match the `Require a value` row directly
above it in the schema editor.

Demo data: `Is public` on the Company schema (true on ACME Inc), plus
three Boolean variants in the Everything showcase schema.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@malberts
malberts force-pushed the feature/703-boolean-property-type branch from f177304 to 652b3a0 Compare May 22, 2026 19:01
@malberts

malberts commented May 22, 2026

Copy link
Copy Markdown
Contributor Author

I went with the toggle, because that's what we use elsewhere for boolean inputs. However, I have a feeling there's a slight difference between "toggling config" and "setting a yes/no value". With the latter falling more into checkbox category for me. On the other hand, mixing toggles and checkboxes might look odd, and in this case the checkbox would not be for selecting items in a list.

In either case, for displaying the value I went with "yes/no" text, because the rest of the infobox is also text. We could go with some kind of checkmark/cross icon, but that would be inconsistent with what we have now.

@malberts
malberts marked this pull request as ready for review May 22, 2026 20:18
@JeroenDeDauw

Copy link
Copy Markdown
Member

Sidenote: every time i see those codex toggles with the text on the left and the toggle on the far right i think they look bad

image

@alistair3149

alistair3149 commented May 23, 2026

Copy link
Copy Markdown
Member

Sidenote: every time i see those codex toggles with the text on the left and the toggle on the far right i think they look bad

There's an option to have it next to text. They look nicer when there is a description field.

On a form with multiple toggle switches, it's more scannable and less ugly if they are all aligned at the end.

@alistair3149

Copy link
Copy Markdown
Member

I went with the toggle, because that's what we use elsewhere for boolean inputs. However, I have a feeling there's a slight difference between "toggling config" and "setting a yes/no value". With the latter falling more into checkbox category for me. On the other hand, mixing toggles and checkboxes might look odd, and in this case the checkbox would not be for selecting items in a list.

In either case, for displaying the value I went with "yes/no" text, because the rest of the infobox is also text. We could go with some kind of checkmark/cross icon, but that would be inconsistent with what we have now.

I had a deep dive on the Codex docs, and you are right. It is recommended to use checkbox over toggle switch when the option does not trigger immediate response (e.g. having a submit button): https://doc.wikimedia.org/codex/main/style-guide/constructing-forms.html#field-type-usage

In that case, we should switch to checkbox for forms. I can file up a follow-up issue for adapting checkbox. This is not a blocker for this PR.

@alistair3149

Copy link
Copy Markdown
Member

Code review PR: #848

@alistair3149
alistair3149 removed their request for review May 23, 2026 02:14
…+ specs

Follows-up to #837

Three follow-ups surfaced during code review of #837:

- `PropertyDefinitionDeserializer` was dropping `default: false`. The truthy
  check in `propertyDefinitionFromJson` discarded any falsy default (`false`,
  `0`). Pre-existing, but #837 was the first PR with demo data that exercises
  it (`Everything.json` ships `boolean (default false)`). Replaced with an
  explicit `undefined`/`null` guard and added regression tests for the false
  boolean, zero number, and null cases.
- `public-api.ts` was missing the three Boolean Vue components while every
  other property type re-exports its `*Display`, `*Input`, and
  `*AttributesEditor`. Added them for parity.
- Added specs for `BooleanInput`, `BooleanDisplay`, and
  `BooleanAttributesEditor` to lock down the current behavior of these
  components against future regressions.

Two design concerns from the review are deliberately left as-is because they
conflict with #837's explicit "a boolean is never 'unset'" choice and the
deferred "hide `Require a value` for Boolean" follow-up referenced in the
#837 description: `BooleanInput.getCurrentValue()` returning
`BooleanValue(false)` for an untouched input with `modelValue === undefined`,
and the unreachable `required && value === undefined` branch in
`BooleanType.validate()`. Raising them properly should pair with that
follow-up since both touch the same per-type opt-out hook.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@malberts

malberts commented May 23, 2026

Copy link
Copy Markdown
Contributor Author

I'll do a follow-up checkbox version for this property so we can compare.

I suppose it is generally a good idea to follow the Codex usage guidelines. But my understanding of that explanation then is that our Schema Editor should also use checkboxes, since the changes are non-instant and require a save button. My impression is also that "non-instant" includes dynamic form element changes, but which do not actually persist and update the global UI (as opposed to the form). Not 100% confident, though.

Swapping all toggle switches to checkboxes might be trivial, but also seems like unnecessary change right now.

@malberts
malberts merged commit 3197ba7 into master May 23, 2026
9 checks passed
@malberts
malberts deleted the feature/703-boolean-property-type branch May 23, 2026 19:48
malberts added a commit that referenced this pull request May 24, 2026
Codex's ToggleSwitch usage guideline says:

  Use the ToggleSwitch component only where an instant change in the
  user-interface based on their assigned action is intended. For
  non-instant selections and selection groups, use Checkbox instead.

BooleanInput is the value editor for boolean properties, used in two
non-instant contexts:

- Subject editor: the value lands in a form gated by Save.
- Schema editor's "Initial value" control: also lives inside the
  property-definition form, gated by Save.

Both fit the "non-instant selection" case, so Checkbox is the
guideline-correct widget. Swap CdxToggleSwitch to CdxCheckbox in
BooleanInput.vue; same :model-value / @update:model-value wiring,
same BooleanValue(true/false) emission shape, same default-to-false
for undefined / wrong-type input.

Field labelling is shaped to fit both call sites:

- The CdxCheckbox's inline label is the property's own name (e.g.
  "Is public"). This is what the subject editor showed before the
  swap and what users see when they toggle the value.
- The CdxField #label heading shows the caller-supplied props.label,
  but only when it differs from the property name. The schema editor
  passes "Initial value" so the heading renders and clarifies what
  the bare checkbox at the bottom of the property-definition form
  represents (the default for new subjects, not a value on the
  property itself). The subject editor passes the property name as
  the label, so the heading would just repeat the inline checkbox
  label; suppressed.
- :optional is not set on the CdxField, because a Boolean value is
  always defined, so an "(optional)" affordance would be misleading.

A short template comment documents both the heading-rule and the
:optional omission so they don't read as oversights.

Tests assert against CdxCheckbox (not CdxToggleSwitch), pin the
inline-label-is-the-property-name behaviour, and cover both heading
branches (shown when label differs from property name; hidden when
they match). Behavioural assertions (modelValue prop binding, emit
on update, BooleanValue emission, default-to-false, type-mismatch
fallback, external-modelValue reactivity, getCurrentValue) are
unchanged from PR #837.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
malberts added a commit that referenced this pull request May 24, 2026
Codex's ToggleSwitch usage guideline says:

  Use the ToggleSwitch component only where an instant change in the
  user-interface based on their assigned action is intended. For
  non-instant selections and selection groups, use Checkbox instead.

BooleanInput is used in two non-instant contexts:

- Subject editor: the value lands in a form gated by Save.
- Schema editor's "Initial value" control: also lives inside the
  property-definition form, gated by Save.

Both fit the "non-instant selection" case, so Checkbox is the
guideline-correct widget.

Local to BooleanInput.vue: same :model-value / @update:model-value
wiring; the toggle's :align-switch and :label props are dropped (no
Checkbox equivalents), the label text and optional description icon
move into the Checkbox default slot.

No data-shape change: BooleanInput still emits BooleanValue(true/false)
on change, still renders checked iff modelValue.boolean === true, and
still defaults to false for undefined / wrong-type input (the "Boolean
is never unset" choice from PR #837).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
JeroenDeDauw pushed a commit that referenced this pull request May 26, 2026
* Boolean property: use CdxCheckbox instead of CdxToggleSwitch

Codex's ToggleSwitch usage guideline says:

  Use the ToggleSwitch component only where an instant change in the
  user-interface based on their assigned action is intended. For
  non-instant selections and selection groups, use Checkbox instead.

BooleanInput is used in two non-instant contexts:

- Subject editor: the value lands in a form gated by Save.
- Schema editor's "Initial value" control: also lives inside the
  property-definition form, gated by Save.

Both fit the "non-instant selection" case, so Checkbox is the
guideline-correct widget.

Local to BooleanInput.vue: same :model-value / @update:model-value
wiring; the toggle's :align-switch and :label props are dropped (no
Checkbox equivalents), the label text and optional description icon
move into the Checkbox default slot.

No data-shape change: BooleanInput still emits BooleanValue(true/false)
on change, still renders checked iff modelValue.boolean === true, and
still defaults to false for undefined / wrong-type input (the "Boolean
is never unset" choice from PR #837).

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

* BooleanInput: field heading and inline label match the call site

Shape field labelling to fit both call sites:

- Inline checkbox label is the property's own name (e.g. "Is public").
  This is what the subject editor showed before the swap and what
  users see when they toggle the value.
- The CdxField #label heading shows the caller-supplied props.label,
  but only when it differs from the property name. The schema editor
  passes "Initial value" so the heading renders and clarifies what
  the bare checkbox at the bottom of the property-definition form
  represents (the default for new subjects, not a value on the
  property itself). The subject editor passes the property name as
  the label, so the heading would just repeat the inline checkbox
  label; suppressed.
- :optional is not set on the CdxField, because a Boolean value is
  always defined, so an "(optional)" affordance would be misleading.

A short template comment documents both the heading-rule and the
:optional omission so they don't read as oversights.

Tests grow by two cases pinning both heading branches (shown when
label differs from property name, hidden when they match). The
fixture now sets a stable property name "Is public" so the inline
label has a meaningful assertion target.

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

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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 Boolean property type

3 participants