Skip to content

A field authored in Studio as "Checkbox — shown as a checkbox" renders as a toggle switch on the Studio canvas and in the runtime create form #27519

Closed

Description

@objectstack-fleet

domain:devx#1 · sunhaolin · session_017xRBcUoS2G4jgqRskpExS7

Found in the 18.3.0 release-candidate browser walkthrough (wave anchor #27377, card W3-UX), at framework main @ c4c515ad, Console built in-repo from the same commit.

Repro (fresh boot)

  1. Boot examples/app-showcase with --seed-admin and sign in as admin. Viewport 1440×900.
  2. From Home choose New in Studio, create a package (e.g. "Field Service"), and create an object Work Order with an optional Number field Estimated Hours and a Picklist Status (option value new, label New Request). Create a second object, Site.
  3. On Work Order, choose Add field. The type picker offers both "Checkbox — shown as a checkbox" and "Toggle — shown as a switch". Pick Checkbox and name it Urgent.
  4. Look at the field on the Form canvas. Publish, then open the app in the Console and click New.

Expected

A checkbox, as the type picker promises. Only a field authored as Toggle draws a switch.

Actual

Urgent draws as a switch on the Studio canvas and in the runtime create dialog. On the record detail page, the unchecked value is an empty circle.

QA-source: #27377 · ux-walkthrough · track 3


Generated by Claude Code

Activity

  1. added
    area:recordsBusiness objects, records, the views that show data, usable forms, search
    bugSomething isn't working
    on Oct 29, 2026
  2. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: 能用的表单 | none | P②

    Triage: p2 · domain:ui · area:records · 2026-10-29T11:11Z

    ⛔ Not a claim.

    • Read fresh. A field authored as type boolean, which the picker labels Checkbox, draws as a switch on the Studio canvas and in the runtime form, so the spec's distinct boolean and toggle types look the same. The authored choice is silently dropped: p2.
    • Use one type-to-widget map, shared by the canvas and the runtime form: boolean draws a checkbox and toggle draws a switch. No per-surface override.
    • bug, pm:queue.

    Generated by Claude Code

  3. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#2 · os-bill · session_01Utp6CY2n1JmZZKrHgtp9jC

    Claim: PM loop round 1 · 2026-10-29T14:19Z
    Session: session_01Utp6CY2n1JmZZKrHgtp9jC (seat; implementation by a card thread, mode:thread)
    Account: os-bill
    Branch: claude/project-thread-6ybbdj (the card thread's harness push branch, self-reported — the measured platform exception to claude/issue-N-slug)
    Worktree: objectstack-issue-27519
    Domain: domain:ui
    Seat: domain:ui#2
    File surface: ui/packages/fields/src/** (alias map, BooleanField, FieldEditWidget, cell renderer), ui/packages/components/src/renderers/form/form.tsx (boolean widget resolution only), ui/packages/app-shell/src/views/studio-design/ObjectFormDesigner.tsx (FieldControlPreview only, agreed with seat 3), tests beside, a changeset (stop on breach; explain in the report)
    Container & model: M, mode:thread, model: TIER_DEFAULT (dispatch-gates --tier: no path-derived mandate), effort: high
    Clause-②: yes (widening) — corrected by the seat from the diff: new exports resolveBooleanControl and type BooleanControl on @object-ui/fields; owes a TIER_DEFAULT declaration review at the final head. Accepted deviations: one import line in ObjectFormDesigner.tsx beside FieldControlPreview; four existing tests elsewhere (console ×2, plugin-detail, plugin-kanban) updated from switch to checkbox for boolean rows
    Metadata-protocol: none (expected; the dev measures from the diff)
    Responsibility: ui/packages/fields/src/field-type-alias.ts + widgets/BooleanField.tsx (both types collapse to one widget) and the Studio canvas preview | none | every author who picks Checkbox, and every user of such a form, today
    Thread-read: 6495088373
    Premise: corrected — on origin/main ee9a8d6e there is no shared type-to-widget map: the runtime collapses boolean and toggle into field:boolean and the canvas has its own switch; the fix builds the one resolution triage names
    Serial constraints cleared: form.tsx is shared with this seat's #27247 (submit bar) and #27483 (field validation): different regions, ordinary concurrency, later lander merges main. ObjectFormDesigner.tsx: seat 3 confirmed none of its claims declare it; its #27511/#27485 thread (claude/project-thread-ufaqzz) stays out of FieldControlPreview.

    Dispatch order: /mnt/project-files/ui-seat2/dispatch-27519.md in the Claude Code project (not on GitHub); its ruling section quotes the triage/maintainer text above verbatim.


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#2 · os-bill · session_01Utp6CY2n1JmZZKrHgtp9jC
    os-dev-report

    {
      "issue": 27519,
      "status": "done",
      "branch": "claude/project-thread-6ybbdj",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/27665",
      "head": "302bcb25deb838acee2d21a1944b91923222e19c",
      "session": "session_01Utp6CYXVQFhXabW3ZQcxWt (card thread; seat session_01Utp6CY2n1JmZZKrHgtp9jC)",
      "premise_still_valid": true,
      "summary": "New resolveBooleanControl (ui/packages/fields/src/widgets/booleanControl.ts, exported from @object-ui/fields) is the one type-to-widget map: an explicit boolean widget (checkbox/boolean -> checkbox, switch/toggle -> switch) wins, else type (boolean -> checkbox, toggle -> switch), else checkbox. BooleanField (record form field:boolean, and FieldEditWidget inline edit) and the Studio canvas FieldControlPreview both read it; form.tsx and the alias map needed no behaviour change. Six existing tests updated to the new faces, none deleted; field-type-coverage unchanged and green.",
      "tests": "Ten boolean files: Test Files 10 passed (10), Tests 227 passed (227). Pre-merge wide run (fields, plugin-detail, plugin-kanban, plugin-form, components form renderer): Test Files 989 passed | 2 skipped (991), Tests 10835 passed | 43 skipped. Post-merge head 302bcb25 (closure rebuilt): components form renderer + plugin-form + app-shell studio-design + ten boolean files: Test Files 555 passed (555), Tests 4955 passed | 18 skipped. type-check fields/app-shell/plugin-detail/plugin-kanban exit 0. eslint on 13 changed ui files 0 errors. Ablation via scripts/ablation-replace.mjs (resolution return -> old widget==='checkbox' ? checkbox : switch; anchor 1->0): 3 files red, 13 of 28 cases incl. the canvas case; restored, blob == HEAD 5ea9e94e, git diff HEAD empty.",
      "gates": "dispatch-gates --commands on 302bcb25: 34 families, all exit 0, recorded in /mnt/project-files/ui-seat2/27519-gates-ran.txt (project folder) — incl. node scripts/check-sdui-manifest.mjs :: exit 0, pnpm check:type-check-debt :: exit 0 (under the verify lock; the pre-merge run exited 3 queue-timeout behind my own test run and was re-run), pnpm --dir ui exec vitest run scripts/ :: exit 0. --ran: 34 derived, 34 run, 0 NOT-MEASURED, 0 UNRUN. pnpm check:new-line-citations: 0 new. CI check-runs: in_progress at report time.",
      "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
      "line_budget": "14 files, +308 / -54 vs origin/main",
      "files_changed": [
        ".changeset/27519-boolean-checkbox-toggle-switch.md",
        "ui/packages/fields/src/widgets/booleanControl.ts",
        "ui/packages/fields/src/widgets/BooleanField.tsx",
        "ui/packages/fields/src/field-type-alias.ts",
        "ui/packages/fields/src/index.tsx",
        "ui/packages/app-shell/src/views/studio-design/ObjectFormDesigner.tsx",
        "tests: fields booleanControl-27519, boolean-label-association-e2e, standard-widgets; app-shell ObjectFormDesigner.booleanControl-27519; console formPageRequiredMarker-10178, FormPage.sharedWidgets-10179; plugin-detail InlineFieldInput.delegation; plugin-kanban RequiredFieldsDialog.ariaInvalidText-7126"
      ],
      "deviations": [
        "ObjectFormDesigner.tsx: one import line added at the file head besides the FieldControlPreview body (needed to read the shared resolution); no other line outside the function.",
        "Test files outside the declared surface updated (apps/console two, plugin-detail one, plugin-kanban one): they asserted a switch for a boolean row, updated to the ruled face, not deleted.",
        "PR attribution link points at this card thread (session-context instruction), not the seat thread the dispatch order named.",
        "No assignee and no reviewer on the PR (maintainer rule); the harness post-PR assign/review step skipped."
      ],
      "mcp_calls": "3 — mcp__github__issue_read x3 (get, get_comments x2); no write tools",
      "api_writes": "2 — relay pr_create (POST /repos/objectstack-ai/objectstack/pulls, draft, read back identical 8977 bytes), post-stamped issue comment on #27519 (this report); plus git pushes (not REST)",
      "open_questions": [],
      "out_of_scope_findings": [
        "observation, not filed · record detail 'empty circle' for an unchecked boolean: not the same collapse and not reproduced in a browser; an editable boolean row draws BooleanCellRenderer's disabled square checkbox (rounded-sm, opacity-50), a non-boolean draws the em-dash EmptyValue, and the only round boolean face is the name-gated completion indicator · carrier: seat",
        "observation, not filed · BooleanCellRenderer draws a disabled checkbox for both boolean and toggle, so a toggle cell reads as a checkbox in the grid and on an editable detail row; outside the ruling's canvas + runtime form · carrier: seat",
        "observation, not filed · the canvas previews by type only: SortableField passes FieldControlPreview type={type}, so an authored widget override is not shown on the canvas without that one caller line (seat 3's area) · carrier: seat"
      ]
    }
  5. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#2 · os-bill · session_01Utp6CY2n1JmZZKrHgtp9jC

    ACCEPT → PR #27665 comment 6503328013 (head f2a547f9); contract review (declaration, TIER_DEFAULT) PASS 6502998669; landing through the merge queue.


    Generated by Claude Code

  6. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#2 · os-bill · session_01Utp6CY2n1JmZZKrHgtp9jC

    Landed · 2026-10-29T18:17Z

    probe reading
    PR #27665 merged through the queue at 2026-10-29T18:16Z, merge commit 50d05cb1cb9795df412dce0ae18f21386ebf9579
    this card closed completed by the PR's Fixes line

    State: pm:dispatched removed; the assignee stays as the record of who carried it.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:recordsBusiness objects, records, the views that show data, usable forms, searchbugSomething isn't workingdomain:uipriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions