From fd11d59c10e60b2284a45b037d0307d7f9b5b37d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 7 Jun 2026 15:11:33 +0000 Subject: [PATCH] chore: release packages --- .changeset/action-modal-transport.md | 7 - .changeset/action-result-dialog.md | 50 -- .changeset/adr-0032-condition-validation.md | 12 - .changeset/adr-0033-draft-discoverability.md | 11 - .changeset/adr-0033-phase-b-draft-review.md | 21 - .changeset/adr-0033-publish-app-button.md | 7 - .changeset/adr-0034-objectview-seam.md | 5 - .../adr-0034-runtime-persistence-seam.md | 5 - .changeset/ai-workspace-page-polish.md | 5 - .changeset/app-hidden-shell-wiring.md | 14 - .changeset/b1-page-create-fields.md | 7 - .changeset/b1-page-seam.md | 7 - .changeset/b1-seed-record-page.md | 7 - .changeset/b2-client-field-rules.md | 8 - .changeset/b2-grid-rules-and-submit.md | 11 - .changeset/bell-inbox-message-cutover.md | 31 -- .changeset/block-config-complete.md | 5 - .changeset/block-config-elements.md | 5 - .changeset/block-config-expand.md | 5 - .changeset/block-config-pickers.md | 5 - .changeset/chat-window-flow-polish.md | 6 - .changeset/core-shell-i18n-polish.md | 6 - .../data-objectstack-listviews-form-family.md | 17 - .changeset/drawer-recordpage-subforms.md | 21 - .changeset/external-datasource-studio.md | 58 --- .changeset/flow-designer-visual-polish.md | 36 -- .../flow-empty-start-and-edge-insert.md | 20 - .changeset/flow-palette-grouped.md | 23 - .changeset/flow-runner-screen-flows.md | 22 - .changeset/form-reset-identity-churn.md | 23 - .changeset/gate-runtime-editors-admin.md | 5 - .changeset/grid-reference-cell-render.md | 20 - .changeset/i18n-language-switch.md | 30 -- .changeset/line-grid-item-autofill.md | 7 - .changeset/line-grid-p1-affordances.md | 9 - .changeset/line-grid-spreadsheet-editor.md | 15 - .changeset/line-items-lookup-cells.md | 5 - .changeset/master-detail-atomic-batch.md | 24 - .changeset/master-detail-auto-derive.md | 28 -- .changeset/master-detail-edit-atomic.md | 25 - .changeset/master-detail-subform.md | 11 - .changeset/master-detail-submit-feedback.md | 15 - .../master-detail-submit-reliability.md | 22 - .changeset/md-totals-stack.md | 7 - .../notifications-sdk-receipt-cutover.md | 38 -- .changeset/objectform-subforms.md | 21 - .changeset/objectview-rules-of-hooks.md | 7 - .changeset/package-discard-delete-buttons.md | 12 - .changeset/page-block-config-panels.md | 5 - .changeset/page-edit-in-studio.md | 5 - .changeset/page-editor-nested.md | 5 - .changeset/page-editor-slotted.md | 5 - .changeset/perf-detail-rail-poller-fanout.md | 24 - .changeset/relationship-inline-edit.md | 18 - .changeset/runtime-dashboard-editor-studio.md | 5 - .changeset/runtime-report-editor-studio.md | 5 - .../runtime-view-editor-studio-inspector.md | 6 - .changeset/runtime-viewkind-form-family.md | 24 - .changeset/studio-package-scope-home.md | 8 - .changeset/subform-ui-polish.md | 10 - .changeset/tier0-console-subforms.md | 22 - .changeset/url-action-cross-origin.md | 12 - .changeset/view-inspector-i18n.md | 5 - .changeset/view-subforms-passthrough.md | 11 - apps/console/CHANGELOG.md | 2 + apps/console/package.json | 2 +- packages/app-shell/CHANGELOG.md | 463 ++++++++++++++++++ packages/app-shell/package.json | 2 +- packages/auth/CHANGELOG.md | 36 ++ packages/auth/package.json | 2 +- packages/cli/CHANGELOG.md | 18 + packages/cli/package.json | 2 +- packages/collaboration/CHANGELOG.md | 9 + packages/collaboration/package.json | 2 +- packages/components/CHANGELOG.md | 69 +++ packages/components/package.json | 2 +- packages/core/CHANGELOG.md | 65 +++ packages/core/package.json | 2 +- packages/create-plugin/CHANGELOG.md | 2 + packages/create-plugin/package.json | 2 +- packages/data-objectstack/CHANGELOG.md | 51 ++ packages/data-objectstack/package.json | 2 +- packages/fields/CHANGELOG.md | 92 ++++ packages/fields/package.json | 2 +- packages/i18n/CHANGELOG.md | 36 ++ packages/i18n/package.json | 2 +- packages/layout/CHANGELOG.md | 19 + packages/layout/package.json | 2 +- packages/mobile/CHANGELOG.md | 9 + packages/mobile/package.json | 2 +- packages/permissions/CHANGELOG.md | 9 + packages/permissions/package.json | 2 +- packages/plugin-ai/CHANGELOG.md | 19 + packages/plugin-ai/package.json | 2 +- packages/plugin-calendar/CHANGELOG.md | 34 ++ packages/plugin-calendar/package.json | 2 +- packages/plugin-charts/CHANGELOG.md | 23 + packages/plugin-charts/package.json | 2 +- packages/plugin-chatbot/CHANGELOG.md | 37 ++ packages/plugin-chatbot/package.json | 2 +- packages/plugin-dashboard/CHANGELOG.md | 31 ++ packages/plugin-dashboard/package.json | 2 +- packages/plugin-designer/CHANGELOG.md | 41 ++ packages/plugin-designer/package.json | 2 +- packages/plugin-detail/CHANGELOG.md | 23 + packages/plugin-detail/package.json | 2 +- packages/plugin-editor/CHANGELOG.md | 19 + packages/plugin-editor/package.json | 2 +- packages/plugin-form/CHANGELOG.md | 197 ++++++++ packages/plugin-form/package.json | 2 +- packages/plugin-gantt/CHANGELOG.md | 29 ++ packages/plugin-gantt/package.json | 2 +- packages/plugin-grid/CHANGELOG.md | 28 ++ packages/plugin-grid/package.json | 2 +- packages/plugin-kanban/CHANGELOG.md | 33 ++ packages/plugin-kanban/package.json | 2 +- packages/plugin-list/CHANGELOG.md | 2 + packages/plugin-list/package.json | 2 +- packages/plugin-map/CHANGELOG.md | 19 + packages/plugin-map/package.json | 2 +- packages/plugin-markdown/CHANGELOG.md | 19 + packages/plugin-markdown/package.json | 2 +- packages/plugin-report/CHANGELOG.md | 32 ++ packages/plugin-report/package.json | 2 +- packages/plugin-timeline/CHANGELOG.md | 20 + packages/plugin-timeline/package.json | 2 +- packages/plugin-view/CHANGELOG.md | 41 ++ packages/plugin-view/package.json | 2 +- packages/plugin-workflow/CHANGELOG.md | 19 + packages/plugin-workflow/package.json | 2 +- packages/providers/CHANGELOG.md | 9 + packages/providers/package.json | 2 +- packages/react/CHANGELOG.md | 97 ++++ packages/react/package.json | 2 +- packages/runner/CHANGELOG.md | 21 + packages/runner/package.json | 2 +- packages/tenant/CHANGELOG.md | 9 + packages/tenant/package.json | 2 +- packages/types/CHANGELOG.md | 38 ++ packages/types/package.json | 2 +- packages/vscode-extension/CHANGELOG.md | 13 + packages/vscode-extension/package.json | 2 +- 142 files changed, 1772 insertions(+), 970 deletions(-) delete mode 100644 .changeset/action-modal-transport.md delete mode 100644 .changeset/action-result-dialog.md delete mode 100644 .changeset/adr-0032-condition-validation.md delete mode 100644 .changeset/adr-0033-draft-discoverability.md delete mode 100644 .changeset/adr-0033-phase-b-draft-review.md delete mode 100644 .changeset/adr-0033-publish-app-button.md delete mode 100644 .changeset/adr-0034-objectview-seam.md delete mode 100644 .changeset/adr-0034-runtime-persistence-seam.md delete mode 100644 .changeset/ai-workspace-page-polish.md delete mode 100644 .changeset/app-hidden-shell-wiring.md delete mode 100644 .changeset/b1-page-create-fields.md delete mode 100644 .changeset/b1-page-seam.md delete mode 100644 .changeset/b1-seed-record-page.md delete mode 100644 .changeset/b2-client-field-rules.md delete mode 100644 .changeset/b2-grid-rules-and-submit.md delete mode 100644 .changeset/bell-inbox-message-cutover.md delete mode 100644 .changeset/block-config-complete.md delete mode 100644 .changeset/block-config-elements.md delete mode 100644 .changeset/block-config-expand.md delete mode 100644 .changeset/block-config-pickers.md delete mode 100644 .changeset/chat-window-flow-polish.md delete mode 100644 .changeset/core-shell-i18n-polish.md delete mode 100644 .changeset/data-objectstack-listviews-form-family.md delete mode 100644 .changeset/drawer-recordpage-subforms.md delete mode 100644 .changeset/external-datasource-studio.md delete mode 100644 .changeset/flow-designer-visual-polish.md delete mode 100644 .changeset/flow-empty-start-and-edge-insert.md delete mode 100644 .changeset/flow-palette-grouped.md delete mode 100644 .changeset/flow-runner-screen-flows.md delete mode 100644 .changeset/form-reset-identity-churn.md delete mode 100644 .changeset/gate-runtime-editors-admin.md delete mode 100644 .changeset/grid-reference-cell-render.md delete mode 100644 .changeset/i18n-language-switch.md delete mode 100644 .changeset/line-grid-item-autofill.md delete mode 100644 .changeset/line-grid-p1-affordances.md delete mode 100644 .changeset/line-grid-spreadsheet-editor.md delete mode 100644 .changeset/line-items-lookup-cells.md delete mode 100644 .changeset/master-detail-atomic-batch.md delete mode 100644 .changeset/master-detail-auto-derive.md delete mode 100644 .changeset/master-detail-edit-atomic.md delete mode 100644 .changeset/master-detail-subform.md delete mode 100644 .changeset/master-detail-submit-feedback.md delete mode 100644 .changeset/master-detail-submit-reliability.md delete mode 100644 .changeset/md-totals-stack.md delete mode 100644 .changeset/notifications-sdk-receipt-cutover.md delete mode 100644 .changeset/objectform-subforms.md delete mode 100644 .changeset/objectview-rules-of-hooks.md delete mode 100644 .changeset/package-discard-delete-buttons.md delete mode 100644 .changeset/page-block-config-panels.md delete mode 100644 .changeset/page-edit-in-studio.md delete mode 100644 .changeset/page-editor-nested.md delete mode 100644 .changeset/page-editor-slotted.md delete mode 100644 .changeset/perf-detail-rail-poller-fanout.md delete mode 100644 .changeset/relationship-inline-edit.md delete mode 100644 .changeset/runtime-dashboard-editor-studio.md delete mode 100644 .changeset/runtime-report-editor-studio.md delete mode 100644 .changeset/runtime-view-editor-studio-inspector.md delete mode 100644 .changeset/runtime-viewkind-form-family.md delete mode 100644 .changeset/studio-package-scope-home.md delete mode 100644 .changeset/subform-ui-polish.md delete mode 100644 .changeset/tier0-console-subforms.md delete mode 100644 .changeset/url-action-cross-origin.md delete mode 100644 .changeset/view-inspector-i18n.md delete mode 100644 .changeset/view-subforms-passthrough.md diff --git a/.changeset/action-modal-transport.md b/.changeset/action-modal-transport.md deleted file mode 100644 index 1acc953d7..000000000 --- a/.changeset/action-modal-transport.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"@object-ui/app-shell": minor ---- - -Action modal transport with placement (SDUI opt #2). - -`useActionModal` provides a reusable `onModal` handler that renders an action's modal envelope in the right container by `placement`: `center` (Dialog), `side` (Sheet), `bottom` (Drawer), `fullscreen`. `content` is an arbitrary SchemaNode rendered via `SchemaRenderer`, so a modal action can open any page/form/list; string targets / `{objectName, mode}` keep opening a `ModalForm`. Wired into `RecordDetailView` so `type:'modal'` actions open client-side (previously routed to a server POST). diff --git a/.changeset/action-result-dialog.md b/.changeset/action-result-dialog.md deleted file mode 100644 index 332803257..000000000 --- a/.changeset/action-result-dialog.md +++ /dev/null @@ -1,50 +0,0 @@ ---- -'@object-ui/core': minor -'@object-ui/react': minor -'@object-ui/app-shell': minor ---- - -Add resultDialog + target interpolation for one-shot action reveals - -Some platform actions return values the user MUST copy now because the -server will not surface them again — 2FA TOTP URI + backup codes, freshly -minted OAuth client_secret, regenerated recovery codes. Previously these -had to ship as bespoke pages in `apps/account` because actions only -emitted a fire-and-forget toast. - -**`@object-ui/core` — ActionRunner** - -- New `ActionDef.resultDialog: ResultDialogSpec` field. When set on a - successful action, the runner suppresses the `successMessage` toast and - awaits the registered `ResultDialogHandler` instead. Missing handler is - non-fatal (logs a warning); rejected handler is treated as acknowledged. -- New `setResultDialogHandler(handler)` setter. -- New types: `ResultDialogSpec`, `ResultDialogFieldSpec`, - `ResultDialogHandler`. -- `executeUrl` and `executeAPI` now run `${param.X}` and `${ctx.X}` - interpolation against `target` before fetching / navigating. Values are - `encodeURIComponent`'d, missing keys resolve to empty string. `ctx` - exposes `origin`, `user`, `org`, `recordId` by default; consumers can - inject more via `context.ctx`. - -**`@object-ui/react`** - -- `ActionProvider` and `useActionRunner` both gained an `onResultDialog` - option that wires straight through to the runner. - -**`@object-ui/app-shell`** - -- New `ActionResultDialog` component — promise-based, blocks click-outside - and Escape (the user MUST click acknowledge), renders five field - formats: `qrcode` (client-side via the `qrcode` package — never sent - off-device, so 2FA URIs stay secret), `code-list`, `secret`, `text`, - `json`. Falls back to `json` when a value's shape doesn't match its - declared format. -- `ObjectView` and `RecordDetailView` install the handler and mount the - dialog automatically, so any action with `resultDialog` declared in - metadata now works without code changes. -- New dependency: `qrcode@^1.5.x` for client-side QR rendering. - -Pairs with the framework-side `Action.resultDialog` schema added in -`@objectstack/spec` and the `sys_two_factor` / `sys_oauth_application` / -`sys_account` updates in `@objectstack/platform-objects`. diff --git a/.changeset/adr-0032-condition-validation.md b/.changeset/adr-0032-condition-validation.md deleted file mode 100644 index 90c160887..000000000 --- a/.changeset/adr-0032-condition-validation.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -"@object-ui/app-shell": minor ---- - -ADR-0032: author-time condition validation in the flow inspectors. - -Flow node and edge condition editors now flag a malformed predicate **as you -type** — most importantly the `{record.x}` template-brace-in-CEL mistake (#1491), -which `{…}` parses as a CEL map literal and silently fails — with the same -corrective message the build and the `validate_expression` agent tool emit. -Client-side check for now (no CEL parser in the browser); swaps to -`@objectstack/formula`'s shared `validateExpression` once it is published. diff --git a/.changeset/adr-0033-draft-discoverability.md b/.changeset/adr-0033-draft-discoverability.md deleted file mode 100644 index a7ea55b65..000000000 --- a/.changeset/adr-0033-draft-discoverability.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -'@object-ui/data-objectstack': minor -'@object-ui/app-shell': minor ---- - -feat(studio): surface pending drafts on the package detail (ADR-0033) - -After an AI builds an app, its objects/views land as drafts bound to the app package — but Studio's active-only browsers hid them, so the package looked empty and there was no obvious way to find what to review/publish. - -- `MetadataClient.listDrafts({ packageId?, type? })` calls the new `GET /api/v1/meta/_drafts` endpoint, returning pending draft headers (with `packageId`). -- The package detail sheet (PackagesPage) now shows a **Pending changes** section listing each drafted item, each linking to the existing per-item review/diff (`?review=1`) so the user can publish it. A just-built app package is no longer shown as empty. diff --git a/.changeset/adr-0033-phase-b-draft-review.md b/.changeset/adr-0033-phase-b-draft-review.md deleted file mode 100644 index d6e97e532..000000000 --- a/.changeset/adr-0033-phase-b-draft-review.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -'@object-ui/plugin-chatbot': minor -'@object-ui/app-shell': minor ---- - -feat(studio): ADR-0033 Phase B — draft review surface (chat → designer → generic diff) - -Closes the AI metadata-authoring loop in Studio. The framework (ADR-0033 Phases A + C) makes the assistant stage every change as a DRAFT; this lets a human see and review those drafts. - -**`@object-ui/plugin-chatbot`** - -- `mapMessages` now detects the framework's draft envelopes — `{ status:'drafted', type, name, … }` (single) and `{ status:'drafted', drafted:[{type,name}] }` (apply_blueprint batch) — and lifts the reviewable targets onto `ChatToolInvocation.draftReview` (mirrors the existing HITL `pendingActionId` path; the Vercel `{type:'text',value}` wrapper is peeled). `blueprint_proposed` is intentionally not surfaced (no draft yet). -- `ChatbotEnhanced` renders a **"Review N change(s)"** button on drafted tool results, driven by a new `onReviewDraft` callback prop. - -**`@object-ui/app-shell`** - -- `assistantBus` gains a review channel (`requestReview` / `requestAssistantReview`); `ConsoleFloatingChatbot` wires the chat button to it; a small navigator inside `AppContent` (which knows the app base) routes to `/apps/:appName/metadata/:type/:name?review=1`. -- `ResourceEditPage` honours `?review=1`: it force-reloads the pending draft (covers the case where the AI drafted the item after the page mounted) and opens the review/diff. -- New **`DraftReviewPanel`** — a generic, type-agnostic draft↔published structural diff (added / changed / removed by key), reusing `LayeredDiff`'s `computeDiffRows`. It gives **every** metadata type (view, dashboard, flow, …) a real "what will publishing change" review, surfaced as a toolbar affordance + sheet whenever a draft exists. The object designer keeps its richer per-field review. - -Nothing is published by any of this — the human still clicks Publish. diff --git a/.changeset/adr-0033-publish-app-button.md b/.changeset/adr-0033-publish-app-button.md deleted file mode 100644 index 3444ee6dc..000000000 --- a/.changeset/adr-0033-publish-app-button.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@object-ui/app-shell': minor ---- - -feat(studio): add "Publish app" button to publish all package drafts (ADR-0033) - -The package detail's Pending changes section gains a primary **Publish app (N)** button that calls `POST /api/v1/packages/:id/publish-drafts` to promote every drafted item of the app in one shot, then refreshes the pending list. Complements the per-item review/publish links — so after an AI builds an app you can review item-by-item or publish the whole thing at once. diff --git a/.changeset/adr-0034-objectview-seam.md b/.changeset/adr-0034-objectview-seam.md deleted file mode 100644 index cc58f65c0..000000000 --- a/.changeset/adr-0034-objectview-seam.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@object-ui/app-shell": patch ---- - -ADR-0034 step 2: route ObjectView's view-config save through the runtime persistence seam, completing the seam's coverage of all three runtime editors (view/report/dashboard). Corrects the seam's `view` branch to mirror ObjectView's real update path (`dataSource.updateViewConfig(...)`, the ADR-0005 overlay API) rather than a raw `sys_view` write. Behaviour is unchanged while the `VITE_RUNTIME_EDIT_VIA_META` flag is off; flag on routes the view update to the studio `/meta` draft. The view CREATE path (`createView` + default-column/kanban/gallery massaging) and the draft/publish UI remain deferred. diff --git a/.changeset/adr-0034-runtime-persistence-seam.md b/.changeset/adr-0034-runtime-persistence-seam.md deleted file mode 100644 index 21777d126..000000000 --- a/.changeset/adr-0034-runtime-persistence-seam.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@object-ui/app-shell": patch ---- - -ADR-0034 step 1: introduce a flag-gated runtime metadata persistence seam. `persistRuntimeMetadata` / `publishRuntimeMetadata` centralise where the runtime view/report/dashboard editors save. Behind the `VITE_RUNTIME_EDIT_VIA_META` flag (default **off**) they reproduce today's `sys_*` writes exactly (zero behaviour change); flag **on** routes to the studio `/meta` per-item draft/publish model (`MetadataClient.save(..., { mode: 'draft' })` + `publish`). ReportView and DashboardView now save through the seam; ObjectView (view) and the draft/publish UI are deliberately deferred. No `sys_*` table is removed and no data is migrated. Also adds the finalized ADR-0034. diff --git a/.changeset/ai-workspace-page-polish.md b/.changeset/ai-workspace-page-polish.md deleted file mode 100644 index f70b61843..000000000 --- a/.changeset/ai-workspace-page-polish.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@object-ui/app-shell": patch ---- - -Polish the full-page AI workspace with a responsive conversation drawer, clearer page context, constrained chat width, and accessible conversation row actions. diff --git a/.changeset/app-hidden-shell-wiring.md b/.changeset/app-hidden-shell-wiring.md deleted file mode 100644 index 9f7cd1cca..000000000 --- a/.changeset/app-hidden-shell-wiring.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -'@object-ui/app-shell': minor ---- - -**Wire `App.hidden` shell hint — App Switcher + avatar dropdown** - -Honour the new `App.hidden` field from `@objectstack/spec/ui`: - -- **`AppSwitcher.tsx`** — filter `app.hidden === true` out of the top-bar app dropdown so personal-settings-style apps don't appear next to business apps. -- **`AppHeader.tsx`** — render hidden apps as entries in the avatar / user dropdown (immediately after the hardcoded Profile / Settings items). Uses the app's `icon` + `label` via the existing `getIcon` + `appLabel` utilities, and navigates to `/apps/${app.name}`. - -This is the front-end side of the Account-app split: the `account` app shipped by `@objectstack/platform-objects` declares `hidden: true` and now surfaces through the avatar menu — same pattern as GitHub Settings, Google account chip, and Salesforce Personal Settings. - -No new dependencies; pure metadata-driven wiring. diff --git a/.changeset/b1-page-create-fields.md b/.changeset/b1-page-create-fields.md deleted file mode 100644 index 378db77f6..000000000 --- a/.changeset/b1-page-create-fields.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"@object-ui/app-shell": minor ---- - -Studio: the "New page" form can now create a record page bound to an object. - -The page create form was identity-only (label/name/icon/description), so it couldn't make a `pageType: 'record'` page or bind it to an object — even though the page edit form and protocol schema fully support those fields. Mirror the `view` resource's create config: the page create form now exposes **Object**, **Page type** (default `record`), and **Kind** (`full`/`slotted`), so a record page can be created and bound in Studio (#1541). The block layout is then composed in the editor's PagePreview canvas. diff --git a/.changeset/b1-page-seam.md b/.changeset/b1-page-seam.md deleted file mode 100644 index 359a94001..000000000 --- a/.changeset/b1-page-seam.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"@object-ui/app-shell": minor ---- - -Runtime persistence seam: add `'page'` artifact type (record-page draft/publish). - -`RuntimeArtifactType` now includes `'page'`, so a record `PageSchema` stages and publishes through the same ADR-0034 `/meta` draft model as views/reports/dashboards (#1541). New pure helpers `recordPageName(objectName, existing?)` (prefers an assigned page name, else mints `_record`) and `recordPageEnvelope(objectName, schema, name?)` (sets the `name`/`object`/`pageType:'record'`/`kind:'full'` identity fields the resolver matches on) — foundation for the record-page edit loop. diff --git a/.changeset/b1-seed-record-page.md b/.changeset/b1-seed-record-page.md deleted file mode 100644 index ce2d715d9..000000000 --- a/.changeset/b1-seed-record-page.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"@object-ui/app-shell": minor ---- - -Studio: new record pages seed their layout from the object's default detail page. - -Creating a `pageType: 'record'` page bound to an object previously started from a blank canvas. The `page` resource now has a `createSeed` hook that, on create, fetches the bound object and seeds the page's `regions` from `buildDefaultPageSchema(objectDef)` — the same auto-generated detail layout the runtime renders by default. Authors start by tweaking the default page, not rebuilding it. A generic async `createSeed` hook was added to `MetadataResourceConfig` (merged into the create body after `createBuildBody`/`createDefaults`; best-effort). Completes #1541's Studio authoring path. diff --git a/.changeset/b2-client-field-rules.md b/.changeset/b2-client-field-rules.md deleted file mode 100644 index befc55c2a..000000000 --- a/.changeset/b2-client-field-rules.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -"@object-ui/core": minor -"@object-ui/types": minor -"@object-ui/components": patch -"@object-ui/plugin-form": patch ---- - -B2 step 3: client-side field-level conditional rules (`visibleWhen` / `readonlyWhen` / `requiredWhen`). The form renderer now evaluates these CEL predicates reactively against the live record and gates each field's visibility, read-only state, and required-ness accordingly. Evaluation delegates to the canonical `@objectstack/formula` `ExpressionEngine` — the *same* dialect the server enforces (`requiredWhen` in the rule-validator, `readonlyWhen` in `stripReadonlyWhenFields`) — so the UX and the persisted verdict always agree. New core helpers `evalFieldPredicate` / `resolveFieldRuleState` (zero-React, fail-open). `FormField` gains `visibleWhen` / `readonlyWhen` / `requiredWhen` (+ deprecated `conditionalRequired` alias), and `ObjectForm` carries them through from object metadata. diff --git a/.changeset/b2-grid-rules-and-submit.md b/.changeset/b2-grid-rules-and-submit.md deleted file mode 100644 index dd55d8f22..000000000 --- a/.changeset/b2-grid-rules-and-submit.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -"@object-ui/core": patch -"@object-ui/fields": patch -"@object-ui/plugin-form": patch -"@object-ui/components": patch ---- - -B2 follow-ups (A): field conditional rules in inline grids + submit-time enforcement. - -- **Grids**: a line-item column's `readonlyWhen` / `requiredWhen` CEL rule is now honored per row — `deriveMasterDetail` carries the props onto the `GridColumn` and `GridField` evaluates them against each row via `resolveFieldRuleState` (a `readonlyWhen`-TRUE cell locks; a `requiredWhen`-TRUE empty cell flags inline-invalid). Rules are row-scoped (`record.*`); the core helpers gained an optional `scope` (and `GridField` a `contextRecord` prop) so a future header-driven lock can bind `parent.*` — that wiring is deferred (it needs the master-detail header's re-renders isolated). -- **Submit enforcement**: `requiredWhen` already drove react-hook-form's `required` rule, so submit is blocked with a field error when the predicate is TRUE and the value is empty. Added a reactive cleanup so a stale *required* error clears when the predicate flips FALSE (and all errors clear when a field is hidden by `visibleWhen`). diff --git a/.changeset/bell-inbox-message-cutover.md b/.changeset/bell-inbox-message-cutover.md deleted file mode 100644 index 08758fb2d..000000000 --- a/.changeset/bell-inbox-message-cutover.md +++ /dev/null @@ -1,31 +0,0 @@ ---- -'@object-ui/app-shell': minor ---- - -Repoint the Console bell to `sys_inbox_message` + `sys_notification_receipt` (ADR-0030) - -The notification bell read the legacy `sys_notification` object's -`recipient_id`/`is_read`/`title`/`body` columns. ADR-0030 re-modeled -`sys_notification` into the L2 *event* (no recipient/read-state), so the bell -returned nothing — every notification the new pipeline produced was invisible. - -The bell now reads the L5 in-app materialization instead: - -- **List**: `sys_inbox_message` filtered by `user_id` (the `mine` scope), 20 - most-recent, ordered by `created_at`. -- **Read-state**: joins `sys_notification_receipt` (filtered by `user_id` + - `channel:'inbox'`). A message is unread until its event has a - `read`/`clicked`/`dismissed` receipt; the unread count drives the badge. -- **Mark-read**: `UPDATE`s the existing `delivered` receipt to `read` - (keyed `(notification_id, user_id, channel)`), inserting only as a fallback - when no receipt exists. Replaces the old `sys_notification.is_read` write. -- **Navigation**: follows the materialization's `action_url` (absolute, - `/apps/...`, or app-relative `/{object}/{id}`), falling back to the legacy - `source_object`/`source_id` pointer. -- **"View all"**: routes to `/apps/setup/sys_inbox_message?view=mine`. - -Pairs with the framework ADR-0030 pipeline (`@objectstack/service-messaging`). -Verified in-browser (showcase Console): a materialized inbox message + its -`delivered` receipt lit the bell badge; the popover rendered the row; -"mark all read" flipped the receipt to `read` in place (no duplicate) and -cleared the badge. diff --git a/.changeset/block-config-complete.md b/.changeset/block-config-complete.md deleted file mode 100644 index d6be4d1ee..000000000 --- a/.changeset/block-config-complete.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@object-ui/app-shell": minor ---- - -Complete the page-editor block configuration and prune shell-only blocks. Adds configurable property panels for the remaining content blocks with authorable properties — `page:accordion`, `record:path`, `record:quick_actions`, `ai:chat_window`, `ai:input` — so every page-content block in the palette is configurable in the UI (pure containers like `page:section` / `element:divider` correctly have no panel). Removes shell-singleton blocks (`app:launcher`, `global:notifications`, `user:profile`) from the page block palette — those are provided by the app shell, not authored as page content. diff --git a/.changeset/block-config-elements.md b/.changeset/block-config-elements.md deleted file mode 100644 index 27980c919..000000000 --- a/.changeset/block-config-elements.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@object-ui/app-shell": minor ---- - -Align the page-editor element palette with reality. Adds the real lightweight-list primitives — `element:definition-list` (compact key/value `
`) and `element:repeater` (data-bound, chrome-free list) — to the block palette with full config panels (object/field pickers for the repeater), and removes three palette entries that have no renderer (`element:form`, `element:filter`, `element:record_picker`) so the palette only offers blocks that actually render. diff --git a/.changeset/block-config-expand.md b/.changeset/block-config-expand.md deleted file mode 100644 index b34de157d..000000000 --- a/.changeset/block-config-expand.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@object-ui/app-shell": minor ---- - -Expand page-editor block configuration. Adds configurable property panels for more blocks (`element:number`, `element:button`, `record:alert`) and introduces array-valued property editors — a `string-list` editor (e.g. `record:highlights` fields) and an add/remove `array` editor (e.g. `page:tabs` items, `record:details` sections) — so these blocks are configurable in the UI instead of only via raw JSON. diff --git a/.changeset/block-config-pickers.md b/.changeset/block-config-pickers.md deleted file mode 100644 index 093ade474..000000000 --- a/.changeset/block-config-pickers.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@object-ui/app-shell": minor ---- - -Schema-driven object/field pickers in the page-editor block inspector. Data-reference block properties are now dropdowns populated from the live metadata instead of free-text: an object picker (e.g. `record:related_list` object, `element:number` object) and cascading field pickers that list the chosen object's actual fields (e.g. `record:related_list` relationship field, `element:number` field, `record:path` status field, `record:highlights`/`record:details` field lists). Resolves the object from the record page's bound object or a sibling block property; degrades gracefully to a text input when the metadata can't be fetched. diff --git a/.changeset/chat-window-flow-polish.md b/.changeset/chat-window-flow-polish.md deleted file mode 100644 index 5231f83fa..000000000 --- a/.changeset/chat-window-flow-polish.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"@object-ui/plugin-chatbot": patch -"@object-ui/app-shell": patch ---- - -Improve the floating chatbot flow with responsive panel bounds, safer FAB placement, inline responding and stop states, and clearer retryable error feedback. diff --git a/.changeset/core-shell-i18n-polish.md b/.changeset/core-shell-i18n-polish.md deleted file mode 100644 index 075877507..000000000 --- a/.changeset/core-shell-i18n-polish.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"@object-ui/app-shell": patch -"@object-ui/i18n": patch ---- - -Localize AI workspace, shell navigation, startup, connection, toast, and chatbot affordance text across core console screens. diff --git a/.changeset/data-objectstack-listviews-form-family.md b/.changeset/data-objectstack-listviews-form-family.md deleted file mode 100644 index a9f0ecd52..000000000 --- a/.changeset/data-objectstack-listviews-form-family.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -'@object-ui/data-objectstack': patch ---- - -fix(datasource): exclude form-family views from `listViews()` - -`OBJECTSTACKDataSource.listViews(objectName)` feeds the object list-view -switcher (`ObjectView` → `ViewTabBar`), but returned **every** view bound to -the object — including form-family ones. With the backend now exposing each -view as an independent **ViewItem** carrying a `viewKind` discriminant -(ADR-0017, "Object has-many View"), a form view such as `crm_activity.default` -(expanded from `formViews.default`) leaked in as a spurious switcher tab and, -when opened, fell back to the default grid. - -`listViews()` now filters out `viewKind` `form`/`detail` items so only -list-family views reach the switcher. Bare view specs without a `viewKind` -(legacy artifacts and user-saved views) are still treated as list views. diff --git a/.changeset/drawer-recordpage-subforms.md b/.changeset/drawer-recordpage-subforms.md deleted file mode 100644 index b43f55e22..000000000 --- a/.changeset/drawer-recordpage-subforms.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -"@object-ui/plugin-form": patch -"@object-ui/app-shell": patch ---- - -feat(form): subforms in DrawerForm + full-page record form (Tier 0 everywhere) - -Completes config-driven master-detail across all standard create/edit entry -points (after the modal in the previous change): - -- `DrawerForm` now hosts `MasterDetailForm` inside the drawer when the schema - declares `subforms` (its own Save bar; closes + refreshes on success). -- `RecordFormPage` (full-page New/Edit) sources `subforms` from the object's - form view, so the full-page form renders inline child collections too. -- `ObjectForm`'s subforms shortcut now defers to the drawer/modal variants for - those formTypes (so they keep their envelope), and only renders the - master-detail form directly for inline/simple forms. - -Declaring `formViews.default.subforms: [{ childObject }]` now yields a -master-detail experience in the modal, drawer, AND full-page form — no bespoke -page anywhere. diff --git a/.changeset/external-datasource-studio.md b/.changeset/external-datasource-studio.md deleted file mode 100644 index 88f3b66e7..000000000 --- a/.changeset/external-datasource-studio.md +++ /dev/null @@ -1,58 +0,0 @@ ---- -'@object-ui/app-shell': minor ---- - -Add the External Datasource Federation Studio surface (ADR-0015 P5) - -Federated datasources (`schemaMode !== 'managed'`) now get a dedicated -panel inside their Studio Preview tab, so connecting a mature external -database and registering its tables as ObjectStack objects is a -point-and-click flow instead of a CLI-only one. The panel pairs with the -framework backend shipped in objectstack-ai/framework#1390 -(`registerExternalDatasourceRoutes` → `/api/v1/datasources/:name/external/*`). - -ObjectStack is metadata-driven: `datasource` is a metadata type, so it is -browsed and edited through the standard metadata-admin engine -(`metadata:resource`) reached from the Studio app's left-side menu — -**not** a hand-written page. The Studio app (framework -`packages/platform-objects/src/apps/studio.app.ts`, Integration group) -gains a `Datasources` nav item pointing at -`metadata:resource?type=datasource`; the federation panel is contributed -to that standard surface via `registerMetadataPreview('datasource', …)`. - -**`@object-ui/app-shell` — `views/metadata-admin/external/`** - -- `api.ts` — a thin, typed REST client over the four federation routes - (`tables`, `tables/:remote/draft`, `refresh-catalog`, `validate`) plus an - `importObjectDraft` helper that PUTs a generated draft to `/meta/object`. - All calls go through `createAuthenticatedFetch()` (Bearer + `X-Tenant-ID` - + `Accept-Language`). A `503 external_service_unavailable` reply is mapped - to a typed `ExternalServiceUnavailableError` so the UI shows a friendly - "federation not enabled on this server" hint. Contract types are inlined - (they were added in framework 7.3; objectui pins `@objectstack/spec` - `^7.2.1`). -- `SchemaBrowser` — lists remote tables (allowedSchemas-filtered server-side) - with a text filter, on-demand Refresh (never a timer — warehouse - introspection is expensive), and a per-table Import action. -- `ImportObjectDialog` — generates an Object draft, surfaces the - type-compat matrix's `// REVIEW:` columns and the generated `*.object.ts` - source, then imports it as a real object. Never mutates the remote schema. -- `ValidationPanel` — runs validation on demand and renders per-object - structured schema diffs (missing column, type mismatch, …). Doubles as an - on-demand drift view. -- `ExternalDatasourcePanel` — Tables / Validation tabs plus a header strip - with "Refresh catalog" and the snapshot timestamp. -- `DatasourcePreview` — registered via `registerMetadataPreview('datasource', …)`, - it renders the panel automatically inside the standard resource edit - page's Preview tab when the saved datasource is federated - (`schemaMode !== 'managed'`), keyed off the item name. This is the only - wiring needed: no bespoke page, no extra route, no `@object-ui/app-shell` - surface to re-export — the metadata-admin engine + left-side nav own the - navigation. Federated datasources are read-only code artifacts (the - `datasource` type forbids runtime create), which the standard list view - already reflects (no "Create" button). - -Out of scope (blocked on backend follow-ups): the connection wizard -(driver/credentials/secrets — belongs in System Settings) and a push-based -drift inbox (needs an event feed). The framework exposes no -test-connection, secrets, or drift-feed routes yet. diff --git a/.changeset/flow-designer-visual-polish.md b/.changeset/flow-designer-visual-polish.md deleted file mode 100644 index 15b427a8f..000000000 --- a/.changeset/flow-designer-visual-polish.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -'@object-ui/app-shell': minor ---- - -Polish the Studio flow-designer canvas visuals - -A refinement pass over the metadata-admin flow designer (`FlowCanvas` + -`flow-canvas-parts`) — purely presentational, no behavioral or API changes, -theme-aware (light/dark), and still dependency-free. - -- **Node cards**: the flat 3px left-accent stripe is replaced by a tinted, - color-coded **icon chip** (the card's primary category cue), with a bolder - label, refined uppercase type caption, layered hover elevation - (`-translate-y-0.5` + soft shadow), and clearer selected / run-state rings. - Per-category `chip` tone tokens (soft bg + inset ring) added alongside the - existing icon/accent/label tones. Added distinct tones for `loop` (sky), - `screen`/`user_task` (pink) and `assignment` (purple) — previously they fell - back to the generic slate "task" tone, so every node type now reads as a - distinct color in the canvas. -- **Readable labels**: node width 188→240 and the per-node summary moved from a - right-hand column onto a second line, so the label now gets the **full card - width** (it was badly truncated — "Manager Re…", "Budget Ab…"). A native title - tooltip surfaces the full text on the rare remaining truncation. -- **No overlap on add**: adding a connected node no longer pins it directly below - its parent (which stacked every sibling on the same spot) — it's left to the - layered auto-layout, which slots it beside its siblings. -- **Canvas surface**: the dot grid now tracks pan **and** zoom (it moves with - the diagram instead of floating behind a static texture), plus a subtle inset - vignette for depth. -- **Edges**: rounded line caps, slightly stronger default stroke, and - pill-shaped (rounded-full, frosted) branch/condition labels. -- **Toolbar + add-node palette**: frosted, rounded controls with a primary - hover affordance; the palette gains an "Add node" header and matching tinted - icon chips per row. - -Verified in-browser (Studio → flow → designer) in both light and dark themes. diff --git a/.changeset/flow-empty-start-and-edge-insert.md b/.changeset/flow-empty-start-and-edge-insert.md deleted file mode 100644 index f973bada6..000000000 --- a/.changeset/flow-empty-start-and-edge-insert.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -'@object-ui/app-shell': patch ---- - -Flow designer: start a new flow with a trigger, and stop the edge "+" overlapping branch labels - -Two more dogfooding fixes for the Studio flow designer: - -- **Empty flow → Start node.** An empty editable flow's "Add node" inserted a - generic `task` node; it now seeds a `start` (trigger) node — the canonical - entry point every flow needs — so the canvas opens on the trigger and the - author builds forward from there. -- **Edge insert handle no longer collides with the branch label.** The "insert - node" `+` button and the branch/condition label pill were both centered on the - edge midpoint, so on a labeled edge (`approve`, `if …`) the `+` sat on top of - the label. The `+` now slides to the right of the label when one is present - (unlabeled edges keep the centered `+`). - -Verified in-browser: labeled edges show the label and a clear, separate insert -handle; `tsc --noEmit` clean. diff --git a/.changeset/flow-palette-grouped.md b/.changeset/flow-palette-grouped.md deleted file mode 100644 index 2aa974fa2..000000000 --- a/.changeset/flow-palette-grouped.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -'@object-ui/app-shell': minor ---- - -Group the flow add-node palette by category, and offer every node type - -The quick-add palette listed 12 node types as a flat list; `assignment`, -`screen`, `delete_record` and the parallel gateways could only be reached by -adding a node and switching its type in the inspector. Building flows, that's a -real friction point. - -- **Complete**: the palette now offers Delete record, Set variables - (assignment), Screen, Parallel split and Parallel join too — so every common - node type is one click away. -- **Grouped**: items are organised into **Data / Logic / Human / Integration / - Flow** sections with headers and dividers, so the (now longer) list stays - scannable. A new `nodeCategory(type)` helper drives the grouping and gives - engine-only / plugin-contributed node types a sensible section; `mergePalette` - preserves a base item's category and infers one for engine-only types. - -Verified in-browser: the grouped palette renders all sections with tinted icon -chips, and the newly-offered types add to the canvas with the correct icon/tone -and no overlap. diff --git a/.changeset/flow-runner-screen-flows.md b/.changeset/flow-runner-screen-flows.md deleted file mode 100644 index 64bf51cbb..000000000 --- a/.changeset/flow-runner-screen-flows.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -'@object-ui/app-shell': minor ---- - -Add FlowRunner — render & resume interactive screen-flows - -A `type: 'flow'` action whose run pauses at a `screen` node now opens a -`FlowRunner` modal that renders the screen's fields, submits the values to the -framework resume endpoint (`POST /api/v1/automation/{flow}/runs/{runId}/resume`), -and advances to the next screen or closes + refreshes on completion. Previously -such flows launched server-side but the screen was never rendered, so the input -was never collected. - -- New `FlowRunner` component (fields → form → resume loop). -- `ObjectView` + `RecordDetailView` flow handlers detect a paused-screen launch - response (`{ status:'paused', runId, screen }`) and open the runner; for - list_item actions the row's id (`_rowRecord.id`) flows in as the flow's - `recordId`. - -Pairs with the framework screen-flow runtime (`@objectstack/service-automation` -+ `@objectstack/runtime`). Verified in-browser: showcase task row → "Reassign…" -→ form → submit → the task is reassigned. diff --git a/.changeset/form-reset-identity-churn.md b/.changeset/form-reset-identity-churn.md deleted file mode 100644 index e8a66a17c..000000000 --- a/.changeset/form-reset-identity-churn.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -"@object-ui/components": patch ---- - -fix(form): stop `form.reset()` from wiping user input on re-render - -The form renderer reset react-hook-form whenever the `defaultValues` **object -identity** changed: - -```ts -useEffect(() => { form.reset(defaultValues); }, [defaultValues]); -``` - -Callers commonly pass a freshly-built `defaultValues` object every render, so an -unrelated parent re-render reset the form and discarded whatever the user had -typed. This broke master-detail "Create": a re-render between the submit click -and the (deferred) `requestSubmit` blanked the form, so RHF then failed -required-field validation on the now-empty fields and nothing was submitted — -the "click Create, nothing happens" report. - -The effect now resets only when `defaultValues` actually **changes by value** -(JSON-compared), so a genuine change (e.g. an edit-mode record finishing -loading) still resets while identity churn is ignored. diff --git a/.changeset/gate-runtime-editors-admin.md b/.changeset/gate-runtime-editors-admin.md deleted file mode 100644 index fe9efcaab..000000000 --- a/.changeset/gate-runtime-editors-admin.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@object-ui/app-shell": patch ---- - -Gate the runtime report and dashboard editors behind an admin check. Editing a report or dashboard mutates the **shared** definition (it writes the single `sys_report` / `sys_dashboard` record, not a per-user copy), but the edit buttons were shown to every user — so any viewer could change a report/dashboard for everyone. The "Edit" affordance (and its config panel) is now admin-only, matching ObjectView's existing view-config gate. This is the first step of ADR-0034 (runtime edits are an admin quick-edit of the shared definition). diff --git a/.changeset/grid-reference-cell-render.md b/.changeset/grid-reference-cell-render.md deleted file mode 100644 index 6be7661a4..000000000 --- a/.changeset/grid-reference-cell-render.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -'@object-ui/fields': patch ---- - -Render reference/lookup cells as labels, not raw JSON - -A `lookup` / `master_detail` value can arrive as a JSON-encoded object string — -e.g. an unresolved external-id reference `{"externalId":"Website Relaunch"}`. -`LookupCellRenderer` treated the whole JSON string as an opaque id, failed to -resolve it, and fell through to `String(value)`, leaking raw JSON into the grid -cell (and detail/kanban surfaces). - -- `LookupCellRenderer` now parses a JSON-object-looking string value and renders - a human label (`name` → `label` → `externalId` → `id`). -- `coerceToSafeValue` (the shared safe-render helper used by 8 cell renderers) - gains the same JSON-string parsing, and `externalId` is added to the - reference-label precedence for plain object values and arrays. - -Verified in the browser (showcase task grid: Project column shows "Website -Relaunch" instead of `{"externalId":"Website Relaunch"}`) and by unit tests. diff --git a/.changeset/i18n-language-switch.md b/.changeset/i18n-language-switch.md deleted file mode 100644 index 19ea793ce..000000000 --- a/.changeset/i18n-language-switch.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -'@object-ui/i18n': minor -'@object-ui/auth': minor -'@object-ui/app-shell': patch ---- - -Relabel metadata-driven UI on a language switch without a page refresh (#1319) - -Switching the UI language left server-resolved metadata labels (object/field/ -view labels, action-dialog text) in the old language until a hard refresh, -because renderers cache those labels by object name and never refetch on a -language change. - -**`@object-ui/auth`** — `createAuthenticatedFetch` now folds the active -`` into `Accept-Language` on API calls (never clobbering an explicit -header), so a switch carries the new locale on every subsequent request. - -**`@object-ui/app-shell`** — `ConnectedShellInner` drops the adapter's -locale-blind metadata cache in the render phase and remounts the metadata -subtree via `key={language}`, so every renderer refetches in the new locale. -The adapter and its connection sit above the key and are preserved — an in-app -relabel, not a reconnect. - -**`@object-ui/i18n`** — dev-mode missing-key warnings: `createI18n` gains -`warnMissingKeys` (default on outside production) wiring a deduped i18next -`missingKeyHandler`. `useObjectLabel`'s convention-key probes are flagged so -their intentional misses (which fall back to server metadata) stay silent. - -Pairs with the framework-side locale-aware metadata changes in -`@objectstack/client` / `@objectstack/objectql` / `@objectstack/rest`. diff --git a/.changeset/line-grid-item-autofill.md b/.changeset/line-grid-item-autofill.md deleted file mode 100644 index 867514ea5..000000000 --- a/.changeset/line-grid-item-autofill.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"@object-ui/fields": minor ---- - -Line-item grid: item-typeahead auto-fill from a lookup column. - -When a lookup cell's record is picked, `GridField` now copies any of the chosen record's fields whose names match a sibling column (e.g. a product's `unit_price` / `description` drop into the row), then recomputes computed columns — the catalog-typeahead behaviour of QuickBooks / Stripe / NetSuite. Opt out per column with `autofill: false`. `LookupField` gains an optional `onSelectRecord(record)` callback that surfaces the full selected record (not just its id). New pure export `lookupAutofillPatch(columns, col, record)`. diff --git a/.changeset/line-grid-p1-affordances.md b/.changeset/line-grid-p1-affordances.md deleted file mode 100644 index bae9f3cc1..000000000 --- a/.changeset/line-grid-p1-affordances.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"@object-ui/fields": minor ---- - -Line-item grid: inline validation, duplicate, and drag-to-reorder. - -- **Inline per-cell validation** — a required, non-computed cell that's empty on a real (non-ghost) row flags red in place (`aria-invalid` + ring), so errors are visible without submitting. -- **Duplicate row** — a hover Copy action clones a line (id stripped) directly below it, for near-identical lines. -- **Drag-to-reorder** — a hover grip handle reorders rows via native drag-and-drop. Set `sort_field` on the grid config to persist order (`row[sortField] = index` stamped on every change); otherwise reorder is order-of-entry. diff --git a/.changeset/line-grid-spreadsheet-editor.md b/.changeset/line-grid-spreadsheet-editor.md deleted file mode 100644 index 1c3bbd99c..000000000 --- a/.changeset/line-grid-spreadsheet-editor.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -"@object-ui/fields": minor -"@object-ui/plugin-form": minor ---- - -Spreadsheet-style line-item grid editor. - -`GridField`'s editable grid mode is reworked into an enterprise line-item editor (the QuickBooks / Stripe / NetSuite pattern), generalised across every inline grid: - -- **Computed read-only columns** — a child field with an arithmetic `expression` (e.g. `amount = quantity * unit_price`) renders read-only, recomputes live as its inputs change, and writes the result back into the row so it persists and the running total reflects it. A small safe arithmetic evaluator (`+ - * / %`, parens, `record.` refs; no `eval`) powers it. -- **Trailing "ghost" row** — start-with-one + auto-append: typing in the ghost materialises a real row (index-stable, so focus/caret survive), so you keep entering lines without clicking "Add". -- **Borderless click-to-focus cells** + role-based column widths (description flexes; qty/price/amount stay narrow). -- **Keyboard navigation** — Enter / ArrowUp / ArrowDown move between rows in the same column. -- Per-row "expand to full form" is gated to grids that omit fields (no redundant expand on thin lines). -- `deriveColumns` surfaces a field `expression` as a computed column; the running-total column prefers the computed/last-currency column. Blank/ghost rows are filtered from the persisted batch (`isBlankRow`). diff --git a/.changeset/line-items-lookup-cells.md b/.changeset/line-items-lookup-cells.md deleted file mode 100644 index c90952dcb..000000000 --- a/.changeset/line-items-lookup-cells.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@object-ui/fields": minor ---- - -Lookup cells in line-item grids. `LineItemsField` columns now support `type: 'lookup'` (with `reference` / `displayField` / `idField`), rendering a real lookup picker per cell that resolves display labels and stores the foreign-key id — so master-detail line grids can reference other objects (category, account, assignee, …) instead of only plain selects. diff --git a/.changeset/master-detail-atomic-batch.md b/.changeset/master-detail-atomic-batch.md deleted file mode 100644 index 6967f845e..000000000 --- a/.changeset/master-detail-atomic-batch.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -"@object-ui/data-objectstack": minor -"@object-ui/plugin-form": minor -"@object-ui/types": minor ---- - -Atomic master-detail create via the cross-object transactional batch endpoint (ObjectStack #1604). - -When the server exposes the transactional batch endpoint, a NEW parent record and its child line items are now persisted in ONE server transaction — commit all or roll back all — instead of the previous client-orchestrated "create parent → create children → best-effort cleanup on failure" sequence. - -**`@object-ui/data-objectstack` — `ObjectStackAdapter.batchTransaction(operations)`** - -- New method posting `{ operations }` to `POST /api/v1/batch`. Operations run in one server transaction. A field value of `{ $ref: }` resolves to that op's generated id, so a child can reference its parent created earlier in the same batch (master-detail FK). Throws `ObjectStackError('BATCH_ERROR')` on a non-2xx response. - -**`@object-ui/plugin-form`** - -- `MasterDetailForm` now detects `dataSource.batchTransaction` and, on a NEW parent, builds one atomic batch (parent at index 0, each child FK set to `{ $ref: 0 }`) via the new pure helper `buildMasterDetailBatch`. Client-side total rollups are merged into the parent payload before the batch. Edit mode and adapters without `batchTransaction` keep the existing client-orchestrated path. -- `ObjectForm` gained a `submitHandler` hook: when supplied, the form validates and hands the collected values to the host instead of calling `dataSource.create` / `dataSource.update`. `MasterDetailForm` uses it to own the atomic parent+children write while the parent fields are still rendered by `ObjectForm`. - -**`@object-ui/types`** - -- `ObjectFormSchema.submitHandler?: (values) => any | Promise` — typed override for host-owned persistence. - -Pairs with the framework-side ambient-transaction fix (ObjectQL `AsyncLocalStorage` transaction propagation) and the `/api/v1/batch` endpoint added in `@objectstack/rest`. diff --git a/.changeset/master-detail-auto-derive.md b/.changeset/master-detail-auto-derive.md deleted file mode 100644 index 251607d9f..000000000 --- a/.changeset/master-detail-auto-derive.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -"@object-ui/plugin-form": minor ---- - -feat(master-detail): derive child columns + relationship FK from metadata - -A master-detail child collection can now be configured with **just the child -object name** — the relationship FK and the editable grid columns are derived -from the child object's schema (via `DataSource.getObjectSchema`), instead of a -hand-authored columns block. - -```ts -// before: ~40 lines of columns + relationshipField -details: [{ childObject: 'task', relationshipField: 'project', columns: [ ...12 lines... ] }] -// after: -details: [{ childObject: 'task' }] -``` - -- `relationshipField` is auto-detected from the child's `master_detail`/`lookup` - field that references the parent (master_detail preferred). -- `columns` are derived from the child's fields, skipping system/audit fields, - the back-reference FK, and non-editable types (formula/summary/autonumber/ - file/json/…); select options and lookup references carry through. -- `amountField` (running-total source) defaults to the first numeric/currency - column. -- Any of these can still be set explicitly to override the derived defaults. -- Save is gated until derivation resolves; new pure helpers - (`deriveDetail`/`deriveColumns`/`findRelationshipField`) are unit-tested. diff --git a/.changeset/master-detail-edit-atomic.md b/.changeset/master-detail-edit-atomic.md deleted file mode 100644 index 21fc32692..000000000 --- a/.changeset/master-detail-edit-atomic.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -"@object-ui/plugin-form": minor ---- - -feat(master-detail): atomic EDIT via the cross-object batch endpoint - -Edit mode now persists the parent update together with its child line-item -create/update/delete diffs in ONE server transaction (commit all or roll back -all), matching what create already did. Previously only create used the atomic -`/api/v1/batch` path; edit fell back to client-orchestrated writes with -best-effort cleanup. - -- New pure helper `buildMasterDetailEditBatch(parentObject, parentId, - parentData, details)` — emits a parent `update` op (index 0) then diffs each - child collection against its loaded snapshot into `create` / `update` / - `delete` ops (children reference the known parent id directly, no `$ref`). -- `MasterDetailForm` now treats `canBatch` as available whenever the data - source exposes `batchTransaction` (create AND edit). `submitViaBatch` builds - create-ops or edit-ops by mode; `onSuccess` → `handleSaved` ("saved" toast, - no form reset in edit). - -The server `/api/v1/batch` handler already supports `update`/`delete` actions, -and the adapter already forwards `action`/`id`, so this is a front-end change. -Unit-tested (parent update + child create/update/delete diff); the create path -remains verified by the live e2e. diff --git a/.changeset/master-detail-subform.md b/.changeset/master-detail-subform.md deleted file mode 100644 index 0d7000326..000000000 --- a/.changeset/master-detail-subform.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -"@object-ui/plugin-form": minor -"@object-ui/fields": minor -"@object-ui/components": minor ---- - -Master-detail subform + lightweight list primitives (SDUI). - -- `MasterDetailForm` (`object-master-detail-form`): enter a parent record and its child line items together; client-orchestrated transactional create (parent → FK → bulk children → rollup → cleanup). Enterprise-convention layout (header on top, line grid, single Save bar at the bottom). -- `LineItemsField` editable child grid (line numbers, right-aligned numerics, running total) and `LineItemsPanel` (`record:line_items`) for detail-page inline edit. -- `element:definition-list` and `element:repeater` — lightweight, low-chrome list primitives for simple data. diff --git a/.changeset/master-detail-submit-feedback.md b/.changeset/master-detail-submit-feedback.md deleted file mode 100644 index 39833a843..000000000 --- a/.changeset/master-detail-submit-feedback.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -"@object-ui/plugin-form": patch -"@object-ui/components": patch ---- - -fix(master-detail): never silent on save — feedback, reset, and a duplicate-submit guard - -`MasterDetailForm`'s "Create" submitted successfully but gave **no feedback**: no toast, no form reset, no navigation. A successful create looked broken, and re-clicking created duplicate records. - -- On success: a `toast.success`, and on create the form clears (line items reset + parent `` remounts) ready for the next entry. A page-supplied `onSuccess` still runs afterwards (e.g. to navigate). -- On failure (validation / network / atomic rollback): a `toast.error` surfaces the message instead of failing silently. -- In-flight guard: the Create button shows "Saving…" and is disabled while a submit is running, preventing duplicate submissions, with a safety release if client-side validation blocks the submit. -- `@object-ui/components` now re-exports `toast` (alongside `Toaster`) from its sonner wrapper. - -Tests: two new `MasterDetailForm` tests assert success → toast + form clear, and failure → error toast. diff --git a/.changeset/master-detail-submit-reliability.md b/.changeset/master-detail-submit-reliability.md deleted file mode 100644 index 83a6db8fa..000000000 --- a/.changeset/master-detail-submit-reliability.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -"@object-ui/plugin-form": patch -"@object-ui/fields": patch ---- - -fix(master-detail): reliable submit + stable e2e hooks - -Fixes the "click Create, nothing happens" report, surfaced by a new live browser -e2e harness that drives the form with real input. - -- **MasterDetailForm `handleSave`** now triggers the button-less parent form's - submit from a deferred macrotask and re-queries the live `
` inside it. - Calling `requestSubmit()` synchronously inside the click handler (right after - the `setSaving` state update) intermittently dropped the nested submit event, - so react-hook-form's `onSubmit` never ran and the click appeared to do nothing - — only the occasional click got through. Deferring makes it fire every time. - -- **Stable `data-testid`s** so automation/e2e can drive the widgets - deterministically (Radix Select + react-hook-form cannot be driven by - synthetic DOM events): `select-trigger-{field}` / `select-option-{value}` - (SelectField), `lookup-trigger-{field}` (LookupField), `line-items-add` - (GridField), `md-form-submit` / `md-form-cancel` (MasterDetailForm). diff --git a/.changeset/md-totals-stack.md b/.changeset/md-totals-stack.md deleted file mode 100644 index 62b89c01e..000000000 --- a/.changeset/md-totals-stack.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"@object-ui/plugin-form": minor ---- - -Master-detail form: live Subtotal / Tax / Total stack. - -`MasterDetailForm` now renders a right-aligned document totals stack under the line items when the parent form has a tax-rate field (`taxRateField`, default `tax_rate`): **Subtotal** (Σ line amounts) → **Tax** (header rate %) → **Total**, recomputed live as lines and the rate change. The header rate is read via scoped event delegation on the form host (no coupling into `ObjectForm` internals). When the stack is shown, the per-grid footer total is subsumed. diff --git a/.changeset/notifications-sdk-receipt-cutover.md b/.changeset/notifications-sdk-receipt-cutover.md deleted file mode 100644 index fa7dbcc1f..000000000 --- a/.changeset/notifications-sdk-receipt-cutover.md +++ /dev/null @@ -1,38 +0,0 @@ ---- -'@object-ui/react': patch ---- - -Repoint `useClientNotifications` to the ADR-0030 `@objectstack/client` surface - -The `useClientNotifications` bridge hook called `client.notifications.*` with -signatures that no longer exist on `@objectstack/client@7.x`: - -- `registerDevice(token, platform)` → the SDK takes a single - `RegisterDeviceRequest` object (`{ token, platform }`). -- `markAsRead(id)` → there is no single-id method; the SDK exposes - `markRead(ids: string[])`. The hook keeps its friendly single-id API and - adapts to the batch call. - -These helpers are the stable transport contract for ADR-0030 (Notification -Convergence): server-side they route to the L5 `sys_inbox_message` -materialization and the `sys_notification_receipt` read-state spine — the -re-modeled `sys_notification` L2 event no longer carries recipient/read -columns. (The Console bell itself reads the inbox + receipts directly via the -generic data API; see the `@object-ui/app-shell` bell cut-over.) - -## Cut-over sequence (operational — run in this order) - -The Console UI repoint must land together with the framework pipeline **and** -the data migration so the bell is never blank and read-state is never lost: - -1. Deploy the framework ADR-0030 change (objects + `emit()` + producers). New - notifications now land in `sys_inbox_message` + `sys_notification_receipt`. -2. Run the data migration **once** to carry existing notifications across — - `migrateSysNotificationToEvent({ driver, data })` from - `@objectstack/metadata/migrations`. It splits each legacy `sys_notification` - inbox row into a `sys_inbox_message` + receipt, rewrites the row to the event - shape, and clears the legacy columns. It is **idempotent** and reports - `not_applicable` on fresh installs. This runs against the ObjectStack - **server/data engine** — it is not a Console (frontend) step. -3. Deploy the objectui repoint (this change + the `@object-ui/app-shell` bell - cut-over). diff --git a/.changeset/objectform-subforms.md b/.changeset/objectform-subforms.md deleted file mode 100644 index f6fd3a3d1..000000000 --- a/.changeset/objectform-subforms.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -"@object-ui/plugin-form": minor -"@object-ui/types": minor ---- - -feat(form): inline master-detail in a plain ObjectForm via `subforms` - -`ObjectFormSchema` gains a `subforms` array. When set, a regular `object-form` -renders as a master-detail form — the object's own fields on top, an editable -grid per child collection below, persisted together in one atomic transaction — -without a bespoke `object-master-detail-form` page. - -```ts -{ type: 'object-form', objectName: 'expense_claim', - subforms: [{ childObject: 'expense_line' }] } // FK + columns auto-derived -``` - -Each subform needs only `childObject` (relationship FK and columns are derived -from the child object's metadata; override with `relationshipField`/`columns`). -This is the config-driven, page-less way to express master-detail entry — a form -view can declare its child collections directly. diff --git a/.changeset/objectview-rules-of-hooks.md b/.changeset/objectview-rules-of-hooks.md deleted file mode 100644 index 169a0e676..000000000 --- a/.changeset/objectview-rules-of-hooks.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"@object-ui/app-shell": patch ---- - -fix(app-shell): resolve 51 react-hooks/rules-of-hooks errors in ObjectView - -ObjectView had a mid-component early return (`if (!objectDef) return …`) sitting before ~50 hooks, which violated the Rules of Hooks and risked a `Rendered fewer hooks than expected` crash if `objectDef` flipped present→absent→present on a live instance (object switch, metadata refresh, reload failure). Split the component so the missing-object empty state lives in a thin `ObjectView` wrapper, while `ObjectViewInner` (mounted only when the definition exists) calls all hooks unconditionally. Behavior is unchanged. diff --git a/.changeset/package-discard-delete-buttons.md b/.changeset/package-discard-delete-buttons.md deleted file mode 100644 index 4f361e7ba..000000000 --- a/.changeset/package-discard-delete-buttons.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -'@object-ui/app-shell': minor ---- - -feat(packages): "Discard changes" and "Delete app" buttons in the package detail sheet - -Adds two one-click package-lifecycle actions next to the existing "Publish app", mirroring the new backend endpoints: - -- **Discard changes (N)** — next to "Publish app" in the Pending changes block. Drops every pending draft via `POST /packages/:id/discard-drafts`, reverting the app to its last published baseline. Non-destructive (published metadata + data untouched), then refreshes the pending list. -- **Delete app** — in the Actions row. Removes the whole package via `DELETE /packages/:id` (active + draft metadata + drops each object's table). Confirms first ("this cannot be undone"); closes the sheet on success, keeps it open and shows the error on failure. - -Together with "Publish app", this gives the full AI-build review loop a UI: publish to preview → keep, **discard all changes**, or **delete the app**. diff --git a/.changeset/page-block-config-panels.md b/.changeset/page-block-config-panels.md deleted file mode 100644 index 1f99f9afe..000000000 --- a/.changeset/page-block-config-panels.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@object-ui/app-shell": minor ---- - -Configurable property panels for page-editor blocks (SDUI). The Studio page editor's block inspector now renders typed, protocol-aligned property fields (editing the block's `properties`) for the minimal SDUI-essential content blocks — `element:text`, `element:image`, `page:header`, `page:card`, `record:related_list` — instead of only the generic `type`/`id`/`className`/`hidden` fields. Previously these properties were editable only via raw JSON. diff --git a/.changeset/page-edit-in-studio.md b/.changeset/page-edit-in-studio.md deleted file mode 100644 index 4478aad5f..000000000 --- a/.changeset/page-edit-in-studio.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@object-ui/app-shell": patch ---- - -Add an admin-only "Edit in studio" affordance to the runtime PageView. Custom pages are authored in the metadata studio (canvas + inspector), not at runtime — so instead of embedding the heavyweight page canvas, PageView now shows a lightweight top-right button (admins only) that deep-links to the page's studio editor (`/apps/:app/metadata/page/:name`). This gives view/report/dashboard/page a consistent runtime admin edit entry point. diff --git a/.changeset/page-editor-nested.md b/.changeset/page-editor-nested.md deleted file mode 100644 index 6b087e322..000000000 --- a/.changeset/page-editor-nested.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@object-ui/app-shell": minor ---- - -The Studio page editor can now edit nested sub-blocks inside container blocks. A `page:tabs`/`page:accordion` tab's children, and a `page:card`/`page:section`'s body, are surfaced as indented, selectable sub-blocks — each one can be selected, configured (via the inspector and its object/field pickers), edited, removed, and new ones added — in both full and slotted pages. Addressing is handled by extending the block-path scheme to support object-key hops (e.g. `…components[0].properties.items[0].children[0]`) and a nested sub-path under slot ids. Closes the last gap so a container's contents are fully point-and-click instead of raw JSON. diff --git a/.changeset/page-editor-slotted.md b/.changeset/page-editor-slotted.md deleted file mode 100644 index 5f588174e..000000000 --- a/.changeset/page-editor-slotted.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@object-ui/app-shell": minor ---- - -The Studio page editor can now edit slotted record pages. A `kind:'slotted'` page surfaces its 7 canonical slots (header / actions / alerts / highlights / details / tabs / discussion) as editable regions — overridden slots show their blocks (selectable + configurable via the inspector and its object/field pickers), and unoverridden slots show an "inherited — add a block to override" placeholder. Edits write back to `slots`; empty slots are omitted so they keep inheriting the synthesized default. This closes the loop for the most common low-code task — customizing a business object's detail page (highlights/tabs/details) point-and-click instead of by hand-editing JSON. diff --git a/.changeset/perf-detail-rail-poller-fanout.md b/.changeset/perf-detail-rail-poller-fanout.md deleted file mode 100644 index ea3050495..000000000 --- a/.changeset/perf-detail-rail-poller-fanout.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -'@object-ui/app-shell': patch -'@object-ui/plugin-detail': patch ---- - -perf(detail/header): lazy + dedupe related-list fan-out, coalesce header polls - -Opening a record detail fired ~50 concurrent `/api/v1` requests that -head-of-line-blocked one another on a single control-plane container. - -- `RecordDetailView` no longer eager-preloads reverse-reference children - when the reference rail renders them (that data was discarded while the - rail re-fetched the same collections). -- `record:reference_rail` now gates fetching on visibility - (`IntersectionObserver`; the rail is `hidden xl:flex`), caps concurrency - at 3, and fetches once per `(parentId + entries)` via a signature guard, - applying results through a mounted ref. -- `AppHeader` inbox/notification, approvals, and activity pollers gained - in-flight guards so bootstrap effect re-runs coalesce to one request; the - approvals poll now sends one request with all identities comma-joined - instead of one per identity. - -Measured locally: opening an environment detail dropped from ~52 to ~17 -requests, related collections from ×3–5 each to ×1, approvals from ×9 to ≤3. diff --git a/.changeset/relationship-inline-edit.md b/.changeset/relationship-inline-edit.md deleted file mode 100644 index bb1de447d..000000000 --- a/.changeset/relationship-inline-edit.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -"@object-ui/app-shell": minor ---- - -feat(metadata): relationship-level `inlineEdit` auto-renders master-detail - -A child object's `master_detail`/`lookup` field can declare `inlineEdit: true` -(in the data model) to mean "edit me inline within my parent's form". The -metadata layer now scans for these and merges the resulting child collections -into each parent object's form view as `subforms` — so the parent's **standard** -New/Edit form auto-renders an atomic master-detail form with **no view config -and no bespoke page**. The intent lives once in the data model (where e.g. an AI -modelling the schema naturally sets it); forms derive the UI. - -`master_detail` children WITHOUT `inlineEdit` are not inlined (so associations -like comments/attachments stay out of the entry form). An explicit -`form.subforms` entry overrides the derived one. Optional -`inlineTitle`/`inlineColumns`/`inlineAmountField` tune the grid. diff --git a/.changeset/runtime-dashboard-editor-studio.md b/.changeset/runtime-dashboard-editor-studio.md deleted file mode 100644 index 30c953b9a..000000000 --- a/.changeset/runtime-dashboard-editor-studio.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@object-ui/app-shell": minor ---- - -Migrate the runtime DashboardView "dashboard editor" onto the studio's spec-driven inspectors. A single app-shell `DashboardConfigPanel` now replaces both legacy `plugin-dashboard` panels (the dashboard-level config panel and the per-widget config panel): with no widget selected it hosts a new spec-driven `DashboardDefaultInspector` (registered as the studio default inspector for the `dashboard` type), and with a widget selected it hosts the existing `DashboardWidgetInspector`. Both inspectors edit the full nested Dashboard document directly, so the runtime's widget flatten/unflatten adapters are removed. The panel lives in app-shell to avoid a circular dependency on plugin-dashboard; the `sys_dashboard` persistence path is unchanged. diff --git a/.changeset/runtime-report-editor-studio.md b/.changeset/runtime-report-editor-studio.md deleted file mode 100644 index 0b088a1de..000000000 --- a/.changeset/runtime-report-editor-studio.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@object-ui/app-shell": minor ---- - -Migrate the runtime ReportView "report editor" onto the studio's spec-driven inspector. The right-rail editor now hosts the same report inspector the metadata studio uses (config fields sourced from `@objectstack/spec` `ReportSchema` / `reportForm`) instead of plugin-report's legacy `buildReportSchema` / `ConfigPanelRenderer` engine, so runtime and studio share one report-editing surface. A new spec-driven `ReportDefaultInspector` is registered as the studio default inspector for the `report` type, and a thin app-shell `ReportConfigPanel` hosts it for the runtime (kept in app-shell to avoid a circular dependency on plugin-report). Field pickers read from the in-memory object definition (no extra network fetch); the `sys_report` persistence path is unchanged. diff --git a/.changeset/runtime-view-editor-studio-inspector.md b/.changeset/runtime-view-editor-studio-inspector.md deleted file mode 100644 index 3fe721550..000000000 --- a/.changeset/runtime-view-editor-studio-inspector.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"@object-ui/app-shell": minor -"@object-ui/plugin-view": minor ---- - -Unify the runtime ObjectView "view editor" onto the studio's spec-driven inspector. The right-rail view editor now hosts the same `ViewVariantInspector` the metadata studio uses (config fields sourced straight from `@objectstack/spec`) instead of the legacy `buildViewConfigSchema` engine, so runtime and studio share one view-editing surface. A new `view-config-adapter` bridges the runtime's flat view shape and the studio's ViewItem draft, keeping the `sys_view` persistence path untouched; field pickers read from the in-memory object definition (no extra network fetch). The legacy `buildViewConfigSchema` engine and its exports are retired; `ConfigPanelRenderer` is retained for the dashboard/report config panels. diff --git a/.changeset/runtime-viewkind-form-family.md b/.changeset/runtime-viewkind-form-family.md deleted file mode 100644 index 5f91ab41b..000000000 --- a/.changeset/runtime-viewkind-form-family.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -'@object-ui/app-shell': patch ---- - -fix(metadata): keep form-family views out of the runtime list-view switcher - -The backend now exposes each view as an independent **ViewItem** (ADR-0017, -"Object has-many View"): `{ name: '.', object, viewKind: -'list' | 'form', config }`. The Studio preview was already taught this shape, -but the runtime console path was not — `MetadataProvider.mergeViewsIntoObjects` -only understood the legacy aggregated container (`{ list, form, listViews, -formViews }`) and ignored `viewKind` entirely. As a result a form-family view -(e.g. `crm_activity.default`, expanded from `formViews.default`) was neither -recognized nor excluded: navigating to its `/view/` URL silently fell -back to the default grid list instead of being treated as a record form. - -`mergeViewsIntoObjects` now recognizes the ViewItem shape and routes by -`viewKind` — `'list'` → `objectDef.listViews`, `'form'` → `objectDef.formViews` -— so FORM-family views never enter the list-view switcher (which reads only -`listViews`). Each item's `config` body is flattened to the renderer shape so -`type`/`columns`/`calendar`/… survive, the canonical `.` name is -used as the view id (so `/view/` resolves), and the legacy container is -skipped for any object that already has expanded ViewItems (no double-listing). -Objects served only as a legacy container are unaffected. diff --git a/.changeset/studio-package-scope-home.md b/.changeset/studio-package-scope-home.md deleted file mode 100644 index 90bfca711..000000000 --- a/.changeset/studio-package-scope-home.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -'@object-ui/app-shell': patch -'@object-ui/i18n': patch ---- - -Refine Studio package-scoped navigation and home overview. - -Studio now treats the selected package as the home overview scope, flattens the root Overview sidebar group, hides the duplicate all-metadata sidebar entry, redirects the invalid package metadata route to package management, preserves the selected package across package-management navigation, and adds a localized package-management sidebar label. diff --git a/.changeset/subform-ui-polish.md b/.changeset/subform-ui-polish.md deleted file mode 100644 index eb27ab75f..000000000 --- a/.changeset/subform-ui-polish.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -"@object-ui/fields": minor -"@object-ui/plugin-form": minor ---- - -Master-detail entry: lighter layout, compact lookup cells, persisted line order. - -- **De-framed line-item section** — the subform no longer double-frames the grid in a `Card` (border + `p-6`); it renders as a light label + the grid's own bordered table, reclaiming the width the line table needs. -- **Compact lookup cells** — `LookupField` gains a `compact` mode (used by grid cells): the selected value shows inline in a borderless single-line trigger instead of a chip stacked above a separate "Select…" button. -- **Persisted drag-reorder** — `deriveMasterDetail` detects a sort field (`position`/`sort_order`/…), excludes it from the editable columns/row-form, and threads it as the grid's `sort_field` so reordering stamps `row[position] = index` and survives a reload. diff --git a/.changeset/tier0-console-subforms.md b/.changeset/tier0-console-subforms.md deleted file mode 100644 index 859e8885d..000000000 --- a/.changeset/tier0-console-subforms.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -"@object-ui/plugin-form": minor -"@object-ui/app-shell": minor ---- - -feat(form): standard New/Edit modal renders form-view subforms (Tier 0) - -The console's standard create/edit record modal now renders inline child -collections when the object's form view declares `subforms` — master-detail -entry with **no bespoke page**, persisted as one atomic transaction. - -- `ModalForm` (and the create/edit modal in app-shell `AppContent`) detects - `subforms` and renders `MasterDetailForm` inside the dialog (it owns its Save - bar; the modal footer is suppressed); on success the modal closes + refreshes. -- `AppContent` sources `subforms` from the object's default form view - (`form.subforms` / `formViews.default.subforms`). -- `ModalFormSchema` gains `subforms`. - -With this, declaring `formViews.default.subforms: [{ childObject }]` is enough -to make an object's standard New/Edit screen a master-detail form — completing -the config-driven master-detail story (Tier 0 → derive everything from the -relationship + child metadata). diff --git a/.changeset/url-action-cross-origin.md b/.changeset/url-action-cross-origin.md deleted file mode 100644 index 329d978ef..000000000 --- a/.changeset/url-action-cross-origin.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -'@object-ui/core': patch -'@object-ui/app-shell': patch -'@object-ui/components': patch ---- - -Fix `type: 'url'` actions so they actually reach the backend in split-origin dev setups, and so reveal-once result dialogs render. - -- `ActionRunner.executeUrl`: when context provides `apiBase`, relative `/api/...`, `/_auth/...`, and `/_account/...` URLs are now promoted to absolute (`${apiBase}${path}`) before navigation. Same-origin API paths (with or without `apiBase`) trigger a full-page `window.location.href` rather than React-Router push — this is required for server-side OAuth redirect dances (e.g. better-auth `/sign-in/social`) that React Router would otherwise swallow into the SPA's fallback route. -- `ActionRunner.buildInterpolationContext`: surfaces `ctx.apiBase` for action targets that want to template it explicitly. -- `ObjectView`: passes `apiBase: import.meta.env.VITE_SERVER_URL` into the toolbar `ActionProvider` context so the above resolves. -- `action-button` and `action-menu` renderers now forward `resultDialog` when invoking the runner. Previously this field was silently dropped by an explicit whitelist, breaking every "show once, then hide" flow (2FA QR/backup codes, OAuth client_secret, regenerated tokens). diff --git a/.changeset/view-inspector-i18n.md b/.changeset/view-inspector-i18n.md deleted file mode 100644 index 96cdfbad8..000000000 --- a/.changeset/view-inspector-i18n.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@object-ui/app-shell": patch ---- - -Localize the View variant inspector labels. The inspector (the View "home" panel, also hosted by the runtime ObjectView right-rail view editor after the spec-driven migration) previously rendered hardcoded English labels — "Label", "View type", "Object", the view-type dropdown options, and the "spec schema unavailable" hint. These now route through the metadata-admin i18n catalog (en + zh) so the runtime console and the studio both display localized text. diff --git a/.changeset/view-subforms-passthrough.md b/.changeset/view-subforms-passthrough.md deleted file mode 100644 index e9c8b56cb..000000000 --- a/.changeset/view-subforms-passthrough.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -"@object-ui/plugin-view": patch ---- - -feat(view): pass form-view `subforms` through to ObjectForm - -`ObjectView`'s form schema now forwards `form.subforms` to `ObjectForm`, so a -form view that declares inline child collections renders as a master-detail -form (parent fields + child grids, atomic save) in ObjectView's own -create/edit form — no bespoke page. Pairs with `@objectstack/spec` -`FormViewSchema.subforms` and ObjectForm's existing `subforms` rendering. diff --git a/apps/console/CHANGELOG.md b/apps/console/CHANGELOG.md index d0747cdf6..ecb068a8c 100644 --- a/apps/console/CHANGELOG.md +++ b/apps/console/CHANGELOG.md @@ -1,5 +1,7 @@ # @object-ui/console +## 6.3.0 + ## 6.2.3 ## 6.2.2 diff --git a/apps/console/package.json b/apps/console/package.json index 88cfe29d1..2b48aaa1a 100644 --- a/apps/console/package.json +++ b/apps/console/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/console", - "version": "6.2.3", + "version": "6.3.0", "description": "ObjectStack Console — opinionated, fork-ready runtime console built on @object-ui/app-shell with the full plugin set wired up. Ships as a Hono UI plugin serving a pre-built SPA.", "license": "MIT", "type": "module", diff --git a/packages/app-shell/CHANGELOG.md b/packages/app-shell/CHANGELOG.md index b9bf566d0..ab4777799 100644 --- a/packages/app-shell/CHANGELOG.md +++ b/packages/app-shell/CHANGELOG.md @@ -1,5 +1,468 @@ # @object-ui/app-shell — Changelog +## 6.3.0 + +### Minor Changes + +- 11ef5e3: Action modal transport with placement (SDUI opt #2). + + `useActionModal` provides a reusable `onModal` handler that renders an action's modal envelope in the right container by `placement`: `center` (Dialog), `side` (Sheet), `bottom` (Drawer), `fullscreen`. `content` is an arbitrary SchemaNode rendered via `SchemaRenderer`, so a modal action can open any page/form/list; string targets / `{objectName, mode}` keep opening a `ModalForm`. Wired into `RecordDetailView` so `type:'modal'` actions open client-side (previously routed to a server POST). + +- c12986e: Add resultDialog + target interpolation for one-shot action reveals + + Some platform actions return values the user MUST copy now because the + server will not surface them again — 2FA TOTP URI + backup codes, freshly + minted OAuth client_secret, regenerated recovery codes. Previously these + had to ship as bespoke pages in `apps/account` because actions only + emitted a fire-and-forget toast. + + **`@object-ui/core` — ActionRunner** + - New `ActionDef.resultDialog: ResultDialogSpec` field. When set on a + successful action, the runner suppresses the `successMessage` toast and + awaits the registered `ResultDialogHandler` instead. Missing handler is + non-fatal (logs a warning); rejected handler is treated as acknowledged. + - New `setResultDialogHandler(handler)` setter. + - New types: `ResultDialogSpec`, `ResultDialogFieldSpec`, + `ResultDialogHandler`. + - `executeUrl` and `executeAPI` now run `${param.X}` and `${ctx.X}` + interpolation against `target` before fetching / navigating. Values are + `encodeURIComponent`'d, missing keys resolve to empty string. `ctx` + exposes `origin`, `user`, `org`, `recordId` by default; consumers can + inject more via `context.ctx`. + + **`@object-ui/react`** + - `ActionProvider` and `useActionRunner` both gained an `onResultDialog` + option that wires straight through to the runner. + + **`@object-ui/app-shell`** + - New `ActionResultDialog` component — promise-based, blocks click-outside + and Escape (the user MUST click acknowledge), renders five field + formats: `qrcode` (client-side via the `qrcode` package — never sent + off-device, so 2FA URIs stay secret), `code-list`, `secret`, `text`, + `json`. Falls back to `json` when a value's shape doesn't match its + declared format. + - `ObjectView` and `RecordDetailView` install the handler and mount the + dialog automatically, so any action with `resultDialog` declared in + metadata now works without code changes. + - New dependency: `qrcode@^1.5.x` for client-side QR rendering. + + Pairs with the framework-side `Action.resultDialog` schema added in + `@objectstack/spec` and the `sys_two_factor` / `sys_oauth_application` / + `sys_account` updates in `@objectstack/platform-objects`. + +- 1c25b56: ADR-0032: author-time condition validation in the flow inspectors. + + Flow node and edge condition editors now flag a malformed predicate **as you + type** — most importantly the `{record.x}` template-brace-in-CEL mistake (#1491), + which `{…}` parses as a CEL map literal and silently fails — with the same + corrective message the build and the `validate_expression` agent tool emit. + Client-side check for now (no CEL parser in the browser); swaps to + `@objectstack/formula`'s shared `validateExpression` once it is published. + +- 30ee761: feat(studio): surface pending drafts on the package detail (ADR-0033) + + After an AI builds an app, its objects/views land as drafts bound to the app package — but Studio's active-only browsers hid them, so the package looked empty and there was no obvious way to find what to review/publish. + - `MetadataClient.listDrafts({ packageId?, type? })` calls the new `GET /api/v1/meta/_drafts` endpoint, returning pending draft headers (with `packageId`). + - The package detail sheet (PackagesPage) now shows a **Pending changes** section listing each drafted item, each linking to the existing per-item review/diff (`?review=1`) so the user can publish it. A just-built app package is no longer shown as empty. + +- 81c0777: feat(studio): ADR-0033 Phase B — draft review surface (chat → designer → generic diff) + + Closes the AI metadata-authoring loop in Studio. The framework (ADR-0033 Phases A + C) makes the assistant stage every change as a DRAFT; this lets a human see and review those drafts. + + **`@object-ui/plugin-chatbot`** + - `mapMessages` now detects the framework's draft envelopes — `{ status:'drafted', type, name, … }` (single) and `{ status:'drafted', drafted:[{type,name}] }` (apply_blueprint batch) — and lifts the reviewable targets onto `ChatToolInvocation.draftReview` (mirrors the existing HITL `pendingActionId` path; the Vercel `{type:'text',value}` wrapper is peeled). `blueprint_proposed` is intentionally not surfaced (no draft yet). + - `ChatbotEnhanced` renders a **"Review N change(s)"** button on drafted tool results, driven by a new `onReviewDraft` callback prop. + + **`@object-ui/app-shell`** + - `assistantBus` gains a review channel (`requestReview` / `requestAssistantReview`); `ConsoleFloatingChatbot` wires the chat button to it; a small navigator inside `AppContent` (which knows the app base) routes to `/apps/:appName/metadata/:type/:name?review=1`. + - `ResourceEditPage` honours `?review=1`: it force-reloads the pending draft (covers the case where the AI drafted the item after the page mounted) and opens the review/diff. + - New **`DraftReviewPanel`** — a generic, type-agnostic draft↔published structural diff (added / changed / removed by key), reusing `LayeredDiff`'s `computeDiffRows`. It gives **every** metadata type (view, dashboard, flow, …) a real "what will publishing change" review, surfaced as a toolbar affordance + sheet whenever a draft exists. The object designer keeps its richer per-field review. + + Nothing is published by any of this — the human still clicks Publish. + +- 672f854: feat(studio): add "Publish app" button to publish all package drafts (ADR-0033) + + The package detail's Pending changes section gains a primary **Publish app (N)** button that calls `POST /api/v1/packages/:id/publish-drafts` to promote every drafted item of the app in one shot, then refreshes the pending list. Complements the per-item review/publish links — so after an AI builds an app you can review item-by-item or publish the whole thing at once. + +- 5c23088: **Wire `App.hidden` shell hint — App Switcher + avatar dropdown** + + Honour the new `App.hidden` field from `@objectstack/spec/ui`: + - **`AppSwitcher.tsx`** — filter `app.hidden === true` out of the top-bar app dropdown so personal-settings-style apps don't appear next to business apps. + - **`AppHeader.tsx`** — render hidden apps as entries in the avatar / user dropdown (immediately after the hardcoded Profile / Settings items). Uses the app's `icon` + `label` via the existing `getIcon` + `appLabel` utilities, and navigates to `/apps/${app.name}`. + + This is the front-end side of the Account-app split: the `account` app shipped by `@objectstack/platform-objects` declares `hidden: true` and now surfaces through the avatar menu — same pattern as GitHub Settings, Google account chip, and Salesforce Personal Settings. + + No new dependencies; pure metadata-driven wiring. + +- 05ff1fb: Studio: the "New page" form can now create a record page bound to an object. + + The page create form was identity-only (label/name/icon/description), so it couldn't make a `pageType: 'record'` page or bind it to an object — even though the page edit form and protocol schema fully support those fields. Mirror the `view` resource's create config: the page create form now exposes **Object**, **Page type** (default `record`), and **Kind** (`full`/`slotted`), so a record page can be created and bound in Studio (#1541). The block layout is then composed in the editor's PagePreview canvas. + +- 7c956d0: Runtime persistence seam: add `'page'` artifact type (record-page draft/publish). + + `RuntimeArtifactType` now includes `'page'`, so a record `PageSchema` stages and publishes through the same ADR-0034 `/meta` draft model as views/reports/dashboards (#1541). New pure helpers `recordPageName(objectName, existing?)` (prefers an assigned page name, else mints `_record`) and `recordPageEnvelope(objectName, schema, name?)` (sets the `name`/`object`/`pageType:'record'`/`kind:'full'` identity fields the resolver matches on) — foundation for the record-page edit loop. + +- b0d64c4: Studio: new record pages seed their layout from the object's default detail page. + + Creating a `pageType: 'record'` page bound to an object previously started from a blank canvas. The `page` resource now has a `createSeed` hook that, on create, fetches the bound object and seeds the page's `regions` from `buildDefaultPageSchema(objectDef)` — the same auto-generated detail layout the runtime renders by default. Authors start by tweaking the default page, not rebuilding it. A generic async `createSeed` hook was added to `MetadataResourceConfig` (merged into the create body after `createBuildBody`/`createDefaults`; best-effort). Completes #1541's Studio authoring path. + +- 80f9796: Repoint the Console bell to `sys_inbox_message` + `sys_notification_receipt` (ADR-0030) + + The notification bell read the legacy `sys_notification` object's + `recipient_id`/`is_read`/`title`/`body` columns. ADR-0030 re-modeled + `sys_notification` into the L2 _event_ (no recipient/read-state), so the bell + returned nothing — every notification the new pipeline produced was invisible. + + The bell now reads the L5 in-app materialization instead: + - **List**: `sys_inbox_message` filtered by `user_id` (the `mine` scope), 20 + most-recent, ordered by `created_at`. + - **Read-state**: joins `sys_notification_receipt` (filtered by `user_id` + + `channel:'inbox'`). A message is unread until its event has a + `read`/`clicked`/`dismissed` receipt; the unread count drives the badge. + - **Mark-read**: `UPDATE`s the existing `delivered` receipt to `read` + (keyed `(notification_id, user_id, channel)`), inserting only as a fallback + when no receipt exists. Replaces the old `sys_notification.is_read` write. + - **Navigation**: follows the materialization's `action_url` (absolute, + `/apps/...`, or app-relative `/{object}/{id}`), falling back to the legacy + `source_object`/`source_id` pointer. + - **"View all"**: routes to `/apps/setup/sys_inbox_message?view=mine`. + + Pairs with the framework ADR-0030 pipeline (`@objectstack/service-messaging`). + Verified in-browser (showcase Console): a materialized inbox message + its + `delivered` receipt lit the bell badge; the popover rendered the row; + "mark all read" flipped the receipt to `read` in place (no duplicate) and + cleared the badge. + +- 5e8965c: Complete the page-editor block configuration and prune shell-only blocks. Adds configurable property panels for the remaining content blocks with authorable properties — `page:accordion`, `record:path`, `record:quick_actions`, `ai:chat_window`, `ai:input` — so every page-content block in the palette is configurable in the UI (pure containers like `page:section` / `element:divider` correctly have no panel). Removes shell-singleton blocks (`app:launcher`, `global:notifications`, `user:profile`) from the page block palette — those are provided by the app shell, not authored as page content. +- 94c58ad: Align the page-editor element palette with reality. Adds the real lightweight-list primitives — `element:definition-list` (compact key/value `
`) and `element:repeater` (data-bound, chrome-free list) — to the block palette with full config panels (object/field pickers for the repeater), and removes three palette entries that have no renderer (`element:form`, `element:filter`, `element:record_picker`) so the palette only offers blocks that actually render. +- c681874: Expand page-editor block configuration. Adds configurable property panels for more blocks (`element:number`, `element:button`, `record:alert`) and introduces array-valued property editors — a `string-list` editor (e.g. `record:highlights` fields) and an add/remove `array` editor (e.g. `page:tabs` items, `record:details` sections) — so these blocks are configurable in the UI instead of only via raw JSON. +- d988090: Schema-driven object/field pickers in the page-editor block inspector. Data-reference block properties are now dropdowns populated from the live metadata instead of free-text: an object picker (e.g. `record:related_list` object, `element:number` object) and cascading field pickers that list the chosen object's actual fields (e.g. `record:related_list` relationship field, `element:number` field, `record:path` status field, `record:highlights`/`record:details` field lists). Resolves the object from the record page's bound object or a sibling block property; degrades gracefully to a text input when the metadata can't be fetched. +- 1c8f775: Add the External Datasource Federation Studio surface (ADR-0015 P5) + + Federated datasources (`schemaMode !== 'managed'`) now get a dedicated + panel inside their Studio Preview tab, so connecting a mature external + database and registering its tables as ObjectStack objects is a + point-and-click flow instead of a CLI-only one. The panel pairs with the + framework backend shipped in objectstack-ai/framework#1390 + (`registerExternalDatasourceRoutes` → `/api/v1/datasources/:name/external/*`). + + ObjectStack is metadata-driven: `datasource` is a metadata type, so it is + browsed and edited through the standard metadata-admin engine + (`metadata:resource`) reached from the Studio app's left-side menu — + **not** a hand-written page. The Studio app (framework + `packages/platform-objects/src/apps/studio.app.ts`, Integration group) + gains a `Datasources` nav item pointing at + `metadata:resource?type=datasource`; the federation panel is contributed + to that standard surface via `registerMetadataPreview('datasource', …)`. + + **`@object-ui/app-shell` — `views/metadata-admin/external/`** + - `api.ts` — a thin, typed REST client over the four federation routes + (`tables`, `tables/:remote/draft`, `refresh-catalog`, `validate`) plus an + `importObjectDraft` helper that PUTs a generated draft to `/meta/object`. + All calls go through `createAuthenticatedFetch()` (Bearer + `X-Tenant-ID` + - `Accept-Language`). A `503 external_service_unavailable` reply is mapped + to a typed `ExternalServiceUnavailableError` so the UI shows a friendly + "federation not enabled on this server" hint. Contract types are inlined + (they were added in framework 7.3; objectui pins `@objectstack/spec` + `^7.2.1`). + - `SchemaBrowser` — lists remote tables (allowedSchemas-filtered server-side) + with a text filter, on-demand Refresh (never a timer — warehouse + introspection is expensive), and a per-table Import action. + - `ImportObjectDialog` — generates an Object draft, surfaces the + type-compat matrix's `// REVIEW:` columns and the generated `*.object.ts` + source, then imports it as a real object. Never mutates the remote schema. + - `ValidationPanel` — runs validation on demand and renders per-object + structured schema diffs (missing column, type mismatch, …). Doubles as an + on-demand drift view. + - `ExternalDatasourcePanel` — Tables / Validation tabs plus a header strip + with "Refresh catalog" and the snapshot timestamp. + - `DatasourcePreview` — registered via `registerMetadataPreview('datasource', …)`, + it renders the panel automatically inside the standard resource edit + page's Preview tab when the saved datasource is federated + (`schemaMode !== 'managed'`), keyed off the item name. This is the only + wiring needed: no bespoke page, no extra route, no `@object-ui/app-shell` + surface to re-export — the metadata-admin engine + left-side nav own the + navigation. Federated datasources are read-only code artifacts (the + `datasource` type forbids runtime create), which the standard list view + already reflects (no "Create" button). + + Out of scope (blocked on backend follow-ups): the connection wizard + (driver/credentials/secrets — belongs in System Settings) and a push-based + drift inbox (needs an event feed). The framework exposes no + test-connection, secrets, or drift-feed routes yet. + +- 4e060b7: Polish the Studio flow-designer canvas visuals + + A refinement pass over the metadata-admin flow designer (`FlowCanvas` + + `flow-canvas-parts`) — purely presentational, no behavioral or API changes, + theme-aware (light/dark), and still dependency-free. + - **Node cards**: the flat 3px left-accent stripe is replaced by a tinted, + color-coded **icon chip** (the card's primary category cue), with a bolder + label, refined uppercase type caption, layered hover elevation + (`-translate-y-0.5` + soft shadow), and clearer selected / run-state rings. + Per-category `chip` tone tokens (soft bg + inset ring) added alongside the + existing icon/accent/label tones. Added distinct tones for `loop` (sky), + `screen`/`user_task` (pink) and `assignment` (purple) — previously they fell + back to the generic slate "task" tone, so every node type now reads as a + distinct color in the canvas. + - **Readable labels**: node width 188→240 and the per-node summary moved from a + right-hand column onto a second line, so the label now gets the **full card + width** (it was badly truncated — "Manager Re…", "Budget Ab…"). A native title + tooltip surfaces the full text on the rare remaining truncation. + - **No overlap on add**: adding a connected node no longer pins it directly below + its parent (which stacked every sibling on the same spot) — it's left to the + layered auto-layout, which slots it beside its siblings. + - **Canvas surface**: the dot grid now tracks pan **and** zoom (it moves with + the diagram instead of floating behind a static texture), plus a subtle inset + vignette for depth. + - **Edges**: rounded line caps, slightly stronger default stroke, and + pill-shaped (rounded-full, frosted) branch/condition labels. + - **Toolbar + add-node palette**: frosted, rounded controls with a primary + hover affordance; the palette gains an "Add node" header and matching tinted + icon chips per row. + + Verified in-browser (Studio → flow → designer) in both light and dark themes. + +- e02aedd: Group the flow add-node palette by category, and offer every node type + + The quick-add palette listed 12 node types as a flat list; `assignment`, + `screen`, `delete_record` and the parallel gateways could only be reached by + adding a node and switching its type in the inspector. Building flows, that's a + real friction point. + - **Complete**: the palette now offers Delete record, Set variables + (assignment), Screen, Parallel split and Parallel join too — so every common + node type is one click away. + - **Grouped**: items are organised into **Data / Logic / Human / Integration / + Flow** sections with headers and dividers, so the (now longer) list stays + scannable. A new `nodeCategory(type)` helper drives the grouping and gives + engine-only / plugin-contributed node types a sensible section; `mergePalette` + preserves a base item's category and infers one for engine-only types. + + Verified in-browser: the grouped palette renders all sections with tinted icon + chips, and the newly-offered types add to the canvas with the correct icon/tone + and no overlap. + +- 7130d4e: Add FlowRunner — render & resume interactive screen-flows + + A `type: 'flow'` action whose run pauses at a `screen` node now opens a + `FlowRunner` modal that renders the screen's fields, submits the values to the + framework resume endpoint (`POST /api/v1/automation/{flow}/runs/{runId}/resume`), + and advances to the next screen or closes + refreshes on completion. Previously + such flows launched server-side but the screen was never rendered, so the input + was never collected. + - New `FlowRunner` component (fields → form → resume loop). + - `ObjectView` + `RecordDetailView` flow handlers detect a paused-screen launch + response (`{ status:'paused', runId, screen }`) and open the runner; for + list_item actions the row's id (`_rowRecord.id`) flows in as the flow's + `recordId`. + + Pairs with the framework screen-flow runtime (`@objectstack/service-automation` + - `@objectstack/runtime`). Verified in-browser: showcase task row → "Reassign…" + → form → submit → the task is reassigned. + +- 652f9b2: feat(packages): "Discard changes" and "Delete app" buttons in the package detail sheet + + Adds two one-click package-lifecycle actions next to the existing "Publish app", mirroring the new backend endpoints: + - **Discard changes (N)** — next to "Publish app" in the Pending changes block. Drops every pending draft via `POST /packages/:id/discard-drafts`, reverting the app to its last published baseline. Non-destructive (published metadata + data untouched), then refreshes the pending list. + - **Delete app** — in the Actions row. Removes the whole package via `DELETE /packages/:id` (active + draft metadata + drops each object's table). Confirms first ("this cannot be undone"); closes the sheet on success, keeps it open and shows the error on failure. + + Together with "Publish app", this gives the full AI-build review loop a UI: publish to preview → keep, **discard all changes**, or **delete the app**. + +- 82195b5: Configurable property panels for page-editor blocks (SDUI). The Studio page editor's block inspector now renders typed, protocol-aligned property fields (editing the block's `properties`) for the minimal SDUI-essential content blocks — `element:text`, `element:image`, `page:header`, `page:card`, `record:related_list` — instead of only the generic `type`/`id`/`className`/`hidden` fields. Previously these properties were editable only via raw JSON. +- f12225b: The Studio page editor can now edit nested sub-blocks inside container blocks. A `page:tabs`/`page:accordion` tab's children, and a `page:card`/`page:section`'s body, are surfaced as indented, selectable sub-blocks — each one can be selected, configured (via the inspector and its object/field pickers), edited, removed, and new ones added — in both full and slotted pages. Addressing is handled by extending the block-path scheme to support object-key hops (e.g. `…components[0].properties.items[0].children[0]`) and a nested sub-path under slot ids. Closes the last gap so a container's contents are fully point-and-click instead of raw JSON. +- 14e3db5: The Studio page editor can now edit slotted record pages. A `kind:'slotted'` page surfaces its 7 canonical slots (header / actions / alerts / highlights / details / tabs / discussion) as editable regions — overridden slots show their blocks (selectable + configurable via the inspector and its object/field pickers), and unoverridden slots show an "inherited — add a block to override" placeholder. Edits write back to `slots`; empty slots are omitted so they keep inheriting the synthesized default. This closes the loop for the most common low-code task — customizing a business object's detail page (highlights/tabs/details) point-and-click instead of by hand-editing JSON. +- de3224e: feat(metadata): relationship-level `inlineEdit` auto-renders master-detail + + A child object's `master_detail`/`lookup` field can declare `inlineEdit: true` + (in the data model) to mean "edit me inline within my parent's form". The + metadata layer now scans for these and merges the resulting child collections + into each parent object's form view as `subforms` — so the parent's **standard** + New/Edit form auto-renders an atomic master-detail form with **no view config + and no bespoke page**. The intent lives once in the data model (where e.g. an AI + modelling the schema naturally sets it); forms derive the UI. + + `master_detail` children WITHOUT `inlineEdit` are not inlined (so associations + like comments/attachments stay out of the entry form). An explicit + `form.subforms` entry overrides the derived one. Optional + `inlineTitle`/`inlineColumns`/`inlineAmountField` tune the grid. + +- 010883d: Migrate the runtime DashboardView "dashboard editor" onto the studio's spec-driven inspectors. A single app-shell `DashboardConfigPanel` now replaces both legacy `plugin-dashboard` panels (the dashboard-level config panel and the per-widget config panel): with no widget selected it hosts a new spec-driven `DashboardDefaultInspector` (registered as the studio default inspector for the `dashboard` type), and with a widget selected it hosts the existing `DashboardWidgetInspector`. Both inspectors edit the full nested Dashboard document directly, so the runtime's widget flatten/unflatten adapters are removed. The panel lives in app-shell to avoid a circular dependency on plugin-dashboard; the `sys_dashboard` persistence path is unchanged. +- 7da8a57: Migrate the runtime ReportView "report editor" onto the studio's spec-driven inspector. The right-rail editor now hosts the same report inspector the metadata studio uses (config fields sourced from `@objectstack/spec` `ReportSchema` / `reportForm`) instead of plugin-report's legacy `buildReportSchema` / `ConfigPanelRenderer` engine, so runtime and studio share one report-editing surface. A new spec-driven `ReportDefaultInspector` is registered as the studio default inspector for the `report` type, and a thin app-shell `ReportConfigPanel` hosts it for the runtime (kept in app-shell to avoid a circular dependency on plugin-report). Field pickers read from the in-memory object definition (no extra network fetch); the `sys_report` persistence path is unchanged. +- 7b71cd8: Unify the runtime ObjectView "view editor" onto the studio's spec-driven inspector. The right-rail view editor now hosts the same `ViewVariantInspector` the metadata studio uses (config fields sourced straight from `@objectstack/spec`) instead of the legacy `buildViewConfigSchema` engine, so runtime and studio share one view-editing surface. A new `view-config-adapter` bridges the runtime's flat view shape and the studio's ViewItem draft, keeping the `sys_view` persistence path untouched; field pickers read from the in-memory object definition (no extra network fetch). The legacy `buildViewConfigSchema` engine and its exports are retired; `ConfigPanelRenderer` is retained for the dashboard/report config panels. +- 8426db7: feat(form): standard New/Edit modal renders form-view subforms (Tier 0) + + The console's standard create/edit record modal now renders inline child + collections when the object's form view declares `subforms` — master-detail + entry with **no bespoke page**, persisted as one atomic transaction. + - `ModalForm` (and the create/edit modal in app-shell `AppContent`) detects + `subforms` and renders `MasterDetailForm` inside the dialog (it owns its Save + bar; the modal footer is suppressed); on success the modal closes + refreshes. + - `AppContent` sources `subforms` from the object's default form view + (`form.subforms` / `formViews.default.subforms`). + - `ModalFormSchema` gains `subforms`. + + With this, declaring `formViews.default.subforms: [{ childObject }]` is enough + to make an object's standard New/Edit screen a master-detail form — completing + the config-driven master-detail story (Tier 0 → derive everything from the + relationship + child metadata). + +### Patch Changes + +- 3b5e293: ADR-0034 step 2: route ObjectView's view-config save through the runtime persistence seam, completing the seam's coverage of all three runtime editors (view/report/dashboard). Corrects the seam's `view` branch to mirror ObjectView's real update path (`dataSource.updateViewConfig(...)`, the ADR-0005 overlay API) rather than a raw `sys_view` write. Behaviour is unchanged while the `VITE_RUNTIME_EDIT_VIA_META` flag is off; flag on routes the view update to the studio `/meta` draft. The view CREATE path (`createView` + default-column/kanban/gallery massaging) and the draft/publish UI remain deferred. +- 02c3c65: ADR-0034 step 1: introduce a flag-gated runtime metadata persistence seam. `persistRuntimeMetadata` / `publishRuntimeMetadata` centralise where the runtime view/report/dashboard editors save. Behind the `VITE_RUNTIME_EDIT_VIA_META` flag (default **off**) they reproduce today's `sys_*` writes exactly (zero behaviour change); flag **on** routes to the studio `/meta` per-item draft/publish model (`MetadataClient.save(..., { mode: 'draft' })` + `publish`). ReportView and DashboardView now save through the seam; ObjectView (view) and the draft/publish UI are deliberately deferred. No `sys_*` table is removed and no data is migrated. Also adds the finalized ADR-0034. +- 5a95032: Polish the full-page AI workspace with a responsive conversation drawer, clearer page context, constrained chat width, and accessible conversation row actions. +- 40c79df: Improve the floating chatbot flow with responsive panel bounds, safer FAB placement, inline responding and stop states, and clearer retryable error feedback. +- 97c6831: Localize AI workspace, shell navigation, startup, connection, toast, and chatbot affordance text across core console screens. +- f6044fa: feat(form): subforms in DrawerForm + full-page record form (Tier 0 everywhere) + + Completes config-driven master-detail across all standard create/edit entry + points (after the modal in the previous change): + - `DrawerForm` now hosts `MasterDetailForm` inside the drawer when the schema + declares `subforms` (its own Save bar; closes + refreshes on success). + - `RecordFormPage` (full-page New/Edit) sources `subforms` from the object's + form view, so the full-page form renders inline child collections too. + - `ObjectForm`'s subforms shortcut now defers to the drawer/modal variants for + those formTypes (so they keep their envelope), and only renders the + master-detail form directly for inline/simple forms. + + Declaring `formViews.default.subforms: [{ childObject }]` now yields a + master-detail experience in the modal, drawer, AND full-page form — no bespoke + page anywhere. + +- fe69471: Flow designer: start a new flow with a trigger, and stop the edge "+" overlapping branch labels + + Two more dogfooding fixes for the Studio flow designer: + - **Empty flow → Start node.** An empty editable flow's "Add node" inserted a + generic `task` node; it now seeds a `start` (trigger) node — the canonical + entry point every flow needs — so the canvas opens on the trigger and the + author builds forward from there. + - **Edge insert handle no longer collides with the branch label.** The "insert + node" `+` button and the branch/condition label pill were both centered on the + edge midpoint, so on a labeled edge (`approve`, `if …`) the `+` sat on top of + the label. The `+` now slides to the right of the label when one is present + (unlabeled edges keep the centered `+`). + + Verified in-browser: labeled edges show the label and a clear, separate insert + handle; `tsc --noEmit` clean. + +- e133fae: Gate the runtime report and dashboard editors behind an admin check. Editing a report or dashboard mutates the **shared** definition (it writes the single `sys_report` / `sys_dashboard` record, not a per-user copy), but the edit buttons were shown to every user — so any viewer could change a report/dashboard for everyone. The "Edit" affordance (and its config panel) is now admin-only, matching ObjectView's existing view-config gate. This is the first step of ADR-0034 (runtime edits are an admin quick-edit of the shared definition). +- 18d0339: Relabel metadata-driven UI on a language switch without a page refresh (#1319) + + Switching the UI language left server-resolved metadata labels (object/field/ + view labels, action-dialog text) in the old language until a hard refresh, + because renderers cache those labels by object name and never refetch on a + language change. + + **`@object-ui/auth`** — `createAuthenticatedFetch` now folds the active + `` into `Accept-Language` on API calls (never clobbering an explicit + header), so a switch carries the new locale on every subsequent request. + + **`@object-ui/app-shell`** — `ConnectedShellInner` drops the adapter's + locale-blind metadata cache in the render phase and remounts the metadata + subtree via `key={language}`, so every renderer refetches in the new locale. + The adapter and its connection sit above the key and are preserved — an in-app + relabel, not a reconnect. + + **`@object-ui/i18n`** — dev-mode missing-key warnings: `createI18n` gains + `warnMissingKeys` (default on outside production) wiring a deduped i18next + `missingKeyHandler`. `useObjectLabel`'s convention-key probes are flagged so + their intentional misses (which fall back to server metadata) stay silent. + + Pairs with the framework-side locale-aware metadata changes in + `@objectstack/client` / `@objectstack/objectql` / `@objectstack/rest`. + +- e265a40: fix(app-shell): resolve 51 react-hooks/rules-of-hooks errors in ObjectView + + ObjectView had a mid-component early return (`if (!objectDef) return …`) sitting before ~50 hooks, which violated the Rules of Hooks and risked a `Rendered fewer hooks than expected` crash if `objectDef` flipped present→absent→present on a live instance (object switch, metadata refresh, reload failure). Split the component so the missing-object empty state lives in a thin `ObjectView` wrapper, while `ObjectViewInner` (mounted only when the definition exists) calls all hooks unconditionally. Behavior is unchanged. + +- af74a5d: Add an admin-only "Edit in studio" affordance to the runtime PageView. Custom pages are authored in the metadata studio (canvas + inspector), not at runtime — so instead of embedding the heavyweight page canvas, PageView now shows a lightweight top-right button (admins only) that deep-links to the page's studio editor (`/apps/:app/metadata/page/:name`). This gives view/report/dashboard/page a consistent runtime admin edit entry point. +- 3cc38fe: perf(detail/header): lazy + dedupe related-list fan-out, coalesce header polls + + Opening a record detail fired ~50 concurrent `/api/v1` requests that + head-of-line-blocked one another on a single control-plane container. + - `RecordDetailView` no longer eager-preloads reverse-reference children + when the reference rail renders them (that data was discarded while the + rail re-fetched the same collections). + - `record:reference_rail` now gates fetching on visibility + (`IntersectionObserver`; the rail is `hidden xl:flex`), caps concurrency + at 3, and fetches once per `(parentId + entries)` via a signature guard, + applying results through a mounted ref. + - `AppHeader` inbox/notification, approvals, and activity pollers gained + in-flight guards so bootstrap effect re-runs coalesce to one request; the + approvals poll now sends one request with all identities comma-joined + instead of one per identity. + + Measured locally: opening an environment detail dropped from ~52 to ~17 + requests, related collections from ×3–5 each to ×1, approvals from ×9 to ≤3. + +- 053a164: fix(metadata): keep form-family views out of the runtime list-view switcher + + The backend now exposes each view as an independent **ViewItem** (ADR-0017, + "Object has-many View"): `{ name: '.', object, viewKind: +'list' | 'form', config }`. The Studio preview was already taught this shape, + but the runtime console path was not — `MetadataProvider.mergeViewsIntoObjects` + only understood the legacy aggregated container (`{ list, form, listViews, +formViews }`) and ignored `viewKind` entirely. As a result a form-family view + (e.g. `crm_activity.default`, expanded from `formViews.default`) was neither + recognized nor excluded: navigating to its `/view/` URL silently fell + back to the default grid list instead of being treated as a record form. + + `mergeViewsIntoObjects` now recognizes the ViewItem shape and routes by + `viewKind` — `'list'` → `objectDef.listViews`, `'form'` → `objectDef.formViews` + — so FORM-family views never enter the list-view switcher (which reads only + `listViews`). Each item's `config` body is flattened to the renderer shape so + `type`/`columns`/`calendar`/… survive, the canonical `.` name is + used as the view id (so `/view/` resolves), and the legacy container is + skipped for any object that already has expanded ViewItems (no double-listing). + Objects served only as a legacy container are unaffected. + +- 2f31406: Refine Studio package-scoped navigation and home overview. + + Studio now treats the selected package as the home overview scope, flattens the root Overview sidebar group, hides the duplicate all-metadata sidebar entry, redirects the invalid package metadata route to package management, preserves the selected package across package-management navigation, and adds a localized package-management sidebar label. + +- 8d1195d: Fix `type: 'url'` actions so they actually reach the backend in split-origin dev setups, and so reveal-once result dialogs render. + - `ActionRunner.executeUrl`: when context provides `apiBase`, relative `/api/...`, `/_auth/...`, and `/_account/...` URLs are now promoted to absolute (`${apiBase}${path}`) before navigation. Same-origin API paths (with or without `apiBase`) trigger a full-page `window.location.href` rather than React-Router push — this is required for server-side OAuth redirect dances (e.g. better-auth `/sign-in/social`) that React Router would otherwise swallow into the SPA's fallback route. + - `ActionRunner.buildInterpolationContext`: surfaces `ctx.apiBase` for action targets that want to template it explicitly. + - `ObjectView`: passes `apiBase: import.meta.env.VITE_SERVER_URL` into the toolbar `ActionProvider` context so the above resolves. + - `action-button` and `action-menu` renderers now forward `resultDialog` when invoking the runner. Previously this field was silently dropped by an explicit whitelist, breaking every "show once, then hide" flow (2FA QR/backup codes, OAuth client_secret, regenerated tokens). + +- ef3c654: Localize the View variant inspector labels. The inspector (the View "home" panel, also hosted by the runtime ObjectView right-rail view editor after the spec-driven migration) previously rendered hardcoded English labels — "Label", "View type", "Object", the view-type dropdown options, and the "spec schema unavailable" hint. These now route through the metadata-admin i18n catalog (en + zh) so the runtime console and the studio both display localized text. +- Updated dependencies [c12986e] +- Updated dependencies [30ee761] +- Updated dependencies [ddbe4a2] +- Updated dependencies [2d47e94] +- Updated dependencies [97c6831] +- Updated dependencies [a58c6b8] +- Updated dependencies [2eb3096] +- Updated dependencies [bd398df] +- Updated dependencies [18d0339] +- Updated dependencies [66ed3ad] +- Updated dependencies [c6445b6] +- Updated dependencies [80c133c] +- Updated dependencies [5e1b838] +- Updated dependencies [d16566f] +- Updated dependencies [90acb7f] +- Updated dependencies [7913390] +- Updated dependencies [514f426] +- Updated dependencies [abe8ebc] +- Updated dependencies [300d755] +- Updated dependencies [2f31406] +- Updated dependencies [18728c1] +- Updated dependencies [8d1195d] + - @object-ui/core@6.3.0 + - @object-ui/react@6.3.0 + - @object-ui/data-objectstack@6.3.0 + - @object-ui/types@6.3.0 + - @object-ui/components@6.3.0 + - @object-ui/fields@6.3.0 + - @object-ui/i18n@6.3.0 + - @object-ui/auth@6.3.0 + - @object-ui/layout@6.3.0 + - @object-ui/plugin-editor@6.3.0 + - @object-ui/collaboration@6.3.0 + - @object-ui/permissions@6.3.0 + - @object-ui/providers@6.3.0 + ## 6.2.3 ### Patch Changes diff --git a/packages/app-shell/package.json b/packages/app-shell/package.json index e8e2f8853..467e74058 100644 --- a/packages/app-shell/package.json +++ b/packages/app-shell/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/app-shell", - "version": "6.2.3", + "version": "6.3.0", "type": "module", "license": "MIT", "description": "Minimal application shell for ObjectUI - framework-agnostic rendering engine", diff --git a/packages/auth/CHANGELOG.md b/packages/auth/CHANGELOG.md index b1ad96fc9..64bc0659e 100644 --- a/packages/auth/CHANGELOG.md +++ b/packages/auth/CHANGELOG.md @@ -1,5 +1,41 @@ # @object-ui/auth +## 6.3.0 + +### Minor Changes + +- 18d0339: Relabel metadata-driven UI on a language switch without a page refresh (#1319) + + Switching the UI language left server-resolved metadata labels (object/field/ + view labels, action-dialog text) in the old language until a hard refresh, + because renderers cache those labels by object name and never refetch on a + language change. + + **`@object-ui/auth`** — `createAuthenticatedFetch` now folds the active + `` into `Accept-Language` on API calls (never clobbering an explicit + header), so a switch carries the new locale on every subsequent request. + + **`@object-ui/app-shell`** — `ConnectedShellInner` drops the adapter's + locale-blind metadata cache in the render phase and remounts the metadata + subtree via `key={language}`, so every renderer refetches in the new locale. + The adapter and its connection sit above the key and are preserved — an in-app + relabel, not a reconnect. + + **`@object-ui/i18n`** — dev-mode missing-key warnings: `createI18n` gains + `warnMissingKeys` (default on outside production) wiring a deduped i18next + `missingKeyHandler`. `useObjectLabel`'s convention-key probes are flagged so + their intentional misses (which fall back to server metadata) stay silent. + + Pairs with the framework-side locale-aware metadata changes in + `@objectstack/client` / `@objectstack/objectql` / `@objectstack/rest`. + +### Patch Changes + +- Updated dependencies [ddbe4a2] +- Updated dependencies [d16566f] +- Updated dependencies [300d755] + - @object-ui/types@6.3.0 + ## 6.2.3 ### Patch Changes diff --git a/packages/auth/package.json b/packages/auth/package.json index 4dd638532..ded93e63f 100644 --- a/packages/auth/package.json +++ b/packages/auth/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/auth", - "version": "6.2.3", + "version": "6.3.0", "type": "module", "license": "MIT", "description": "Authentication system for Object UI with AuthProvider, useAuth hook, AuthGuard, and form components.", diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md index 94005b792..e788e4357 100644 --- a/packages/cli/CHANGELOG.md +++ b/packages/cli/CHANGELOG.md @@ -1,5 +1,23 @@ # @object-ui/cli +## 6.3.0 + +### Patch Changes + +- Updated dependencies [c12986e] +- Updated dependencies [ddbe4a2] +- Updated dependencies [2d47e94] +- Updated dependencies [2eb3096] +- Updated dependencies [d16566f] +- Updated dependencies [90acb7f] +- Updated dependencies [7913390] +- Updated dependencies [abe8ebc] +- Updated dependencies [300d755] +- Updated dependencies [8d1195d] + - @object-ui/react@6.3.0 + - @object-ui/types@6.3.0 + - @object-ui/components@6.3.0 + ## 6.2.3 ### Patch Changes diff --git a/packages/cli/package.json b/packages/cli/package.json index 6fac4c832..c12a5f2a9 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/cli", - "version": "6.2.3", + "version": "6.3.0", "description": "Standalone CLI for Object UI — scaffold, develop, build and validate JSON/YAML schema-driven applications.", "type": "module", "homepage": "https://www.objectui.org/docs/utilities/cli", diff --git a/packages/collaboration/CHANGELOG.md b/packages/collaboration/CHANGELOG.md index 95a3ac0e7..43b7685ae 100644 --- a/packages/collaboration/CHANGELOG.md +++ b/packages/collaboration/CHANGELOG.md @@ -1,5 +1,14 @@ # @object-ui/collaboration +## 6.3.0 + +### Patch Changes + +- Updated dependencies [ddbe4a2] +- Updated dependencies [d16566f] +- Updated dependencies [300d755] + - @object-ui/types@6.3.0 + ## 6.2.3 ### Patch Changes diff --git a/packages/collaboration/package.json b/packages/collaboration/package.json index c873affce..f91d27492 100644 --- a/packages/collaboration/package.json +++ b/packages/collaboration/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/collaboration", - "version": "6.2.3", + "version": "6.3.0", "type": "module", "license": "MIT", "description": "Real-time collaboration for Object UI with presence tracking, live cursors, conflict resolution, and comment threads.", diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index 5ab528528..ffe7ec8b8 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -1,5 +1,74 @@ # @object-ui/components +## 6.3.0 + +### Minor Changes + +- 90acb7f: Master-detail subform + lightweight list primitives (SDUI). + - `MasterDetailForm` (`object-master-detail-form`): enter a parent record and its child line items together; client-orchestrated transactional create (parent → FK → bulk children → rollup → cleanup). Enterprise-convention layout (header on top, line grid, single Save bar at the bottom). + - `LineItemsField` editable child grid (line numbers, right-aligned numerics, running total) and `LineItemsPanel` (`record:line_items`) for detail-page inline edit. + - `element:definition-list` and `element:repeater` — lightweight, low-chrome list primitives for simple data. + +### Patch Changes + +- ddbe4a2: B2 step 3: client-side field-level conditional rules (`visibleWhen` / `readonlyWhen` / `requiredWhen`). The form renderer now evaluates these CEL predicates reactively against the live record and gates each field's visibility, read-only state, and required-ness accordingly. Evaluation delegates to the canonical `@objectstack/formula` `ExpressionEngine` — the _same_ dialect the server enforces (`requiredWhen` in the rule-validator, `readonlyWhen` in `stripReadonlyWhenFields`) — so the UX and the persisted verdict always agree. New core helpers `evalFieldPredicate` / `resolveFieldRuleState` (zero-React, fail-open). `FormField` gains `visibleWhen` / `readonlyWhen` / `requiredWhen` (+ deprecated `conditionalRequired` alias), and `ObjectForm` carries them through from object metadata. +- 2d47e94: B2 follow-ups (A): field conditional rules in inline grids + submit-time enforcement. + - **Grids**: a line-item column's `readonlyWhen` / `requiredWhen` CEL rule is now honored per row — `deriveMasterDetail` carries the props onto the `GridColumn` and `GridField` evaluates them against each row via `resolveFieldRuleState` (a `readonlyWhen`-TRUE cell locks; a `requiredWhen`-TRUE empty cell flags inline-invalid). Rules are row-scoped (`record.*`); the core helpers gained an optional `scope` (and `GridField` a `contextRecord` prop) so a future header-driven lock can bind `parent.*` — that wiring is deferred (it needs the master-detail header's re-renders isolated). + - **Submit enforcement**: `requiredWhen` already drove react-hook-form's `required` rule, so submit is blocked with a field error when the predicate is TRUE and the value is empty. Added a reactive cleanup so a stale _required_ error clears when the predicate flips FALSE (and all errors clear when a field is hidden by `visibleWhen`). + +- 2eb3096: fix(form): stop `form.reset()` from wiping user input on re-render + + The form renderer reset react-hook-form whenever the `defaultValues` **object + identity** changed: + + ```ts + useEffect(() => { + form.reset(defaultValues); + }, [defaultValues]); + ``` + + Callers commonly pass a freshly-built `defaultValues` object every render, so an + unrelated parent re-render reset the form and discarded whatever the user had + typed. This broke master-detail "Create": a re-render between the submit click + and the (deferred) `requestSubmit` blanked the form, so RHF then failed + required-field validation on the now-empty fields and nothing was submitted — + the "click Create, nothing happens" report. + + The effect now resets only when `defaultValues` actually **changes by value** + (JSON-compared), so a genuine change (e.g. an edit-mode record finishing + loading) still resets while identity churn is ignored. + +- 7913390: fix(master-detail): never silent on save — feedback, reset, and a duplicate-submit guard + + `MasterDetailForm`'s "Create" submitted successfully but gave **no feedback**: no toast, no form reset, no navigation. A successful create looked broken, and re-clicking created duplicate records. + - On success: a `toast.success`, and on create the form clears (line items reset + parent `` remounts) ready for the next entry. A page-supplied `onSuccess` still runs afterwards (e.g. to navigate). + - On failure (validation / network / atomic rollback): a `toast.error` surfaces the message instead of failing silently. + - In-flight guard: the Create button shows "Saving…" and is disabled while a submit is running, preventing duplicate submissions, with a safety release if client-side validation blocks the submit. + - `@object-ui/components` now re-exports `toast` (alongside `Toaster`) from its sonner wrapper. + + Tests: two new `MasterDetailForm` tests assert success → toast + form clear, and failure → error toast. + +- 8d1195d: Fix `type: 'url'` actions so they actually reach the backend in split-origin dev setups, and so reveal-once result dialogs render. + - `ActionRunner.executeUrl`: when context provides `apiBase`, relative `/api/...`, `/_auth/...`, and `/_account/...` URLs are now promoted to absolute (`${apiBase}${path}`) before navigation. Same-origin API paths (with or without `apiBase`) trigger a full-page `window.location.href` rather than React-Router push — this is required for server-side OAuth redirect dances (e.g. better-auth `/sign-in/social`) that React Router would otherwise swallow into the SPA's fallback route. + - `ActionRunner.buildInterpolationContext`: surfaces `ctx.apiBase` for action targets that want to template it explicitly. + - `ObjectView`: passes `apiBase: import.meta.env.VITE_SERVER_URL` into the toolbar `ActionProvider` context so the above resolves. + - `action-button` and `action-menu` renderers now forward `resultDialog` when invoking the runner. Previously this field was silently dropped by an explicit whitelist, breaking every "show once, then hide" flow (2FA QR/backup codes, OAuth client_secret, regenerated tokens). + +- Updated dependencies [c12986e] +- Updated dependencies [ddbe4a2] +- Updated dependencies [2d47e94] +- Updated dependencies [97c6831] +- Updated dependencies [18d0339] +- Updated dependencies [d16566f] +- Updated dependencies [abe8ebc] +- Updated dependencies [300d755] +- Updated dependencies [2f31406] +- Updated dependencies [8d1195d] + - @object-ui/core@6.3.0 + - @object-ui/react@6.3.0 + - @object-ui/types@6.3.0 + - @object-ui/i18n@6.3.0 + ## 6.2.3 ### Patch Changes diff --git a/packages/components/package.json b/packages/components/package.json index bcb08830a..65e8e1951 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/components", - "version": "6.2.3", + "version": "6.3.0", "type": "module", "license": "MIT", "description": "Standard UI component library for Object UI, built with Shadcn UI + Tailwind CSS", diff --git a/packages/core/CHANGELOG.md b/packages/core/CHANGELOG.md index d68de048c..5177a2572 100644 --- a/packages/core/CHANGELOG.md +++ b/packages/core/CHANGELOG.md @@ -1,5 +1,70 @@ # @object-ui/core +## 6.3.0 + +### Minor Changes + +- c12986e: Add resultDialog + target interpolation for one-shot action reveals + + Some platform actions return values the user MUST copy now because the + server will not surface them again — 2FA TOTP URI + backup codes, freshly + minted OAuth client_secret, regenerated recovery codes. Previously these + had to ship as bespoke pages in `apps/account` because actions only + emitted a fire-and-forget toast. + + **`@object-ui/core` — ActionRunner** + - New `ActionDef.resultDialog: ResultDialogSpec` field. When set on a + successful action, the runner suppresses the `successMessage` toast and + awaits the registered `ResultDialogHandler` instead. Missing handler is + non-fatal (logs a warning); rejected handler is treated as acknowledged. + - New `setResultDialogHandler(handler)` setter. + - New types: `ResultDialogSpec`, `ResultDialogFieldSpec`, + `ResultDialogHandler`. + - `executeUrl` and `executeAPI` now run `${param.X}` and `${ctx.X}` + interpolation against `target` before fetching / navigating. Values are + `encodeURIComponent`'d, missing keys resolve to empty string. `ctx` + exposes `origin`, `user`, `org`, `recordId` by default; consumers can + inject more via `context.ctx`. + + **`@object-ui/react`** + - `ActionProvider` and `useActionRunner` both gained an `onResultDialog` + option that wires straight through to the runner. + + **`@object-ui/app-shell`** + - New `ActionResultDialog` component — promise-based, blocks click-outside + and Escape (the user MUST click acknowledge), renders five field + formats: `qrcode` (client-side via the `qrcode` package — never sent + off-device, so 2FA URIs stay secret), `code-list`, `secret`, `text`, + `json`. Falls back to `json` when a value's shape doesn't match its + declared format. + - `ObjectView` and `RecordDetailView` install the handler and mount the + dialog automatically, so any action with `resultDialog` declared in + metadata now works without code changes. + - New dependency: `qrcode@^1.5.x` for client-side QR rendering. + + Pairs with the framework-side `Action.resultDialog` schema added in + `@objectstack/spec` and the `sys_two_factor` / `sys_oauth_application` / + `sys_account` updates in `@objectstack/platform-objects`. + +- ddbe4a2: B2 step 3: client-side field-level conditional rules (`visibleWhen` / `readonlyWhen` / `requiredWhen`). The form renderer now evaluates these CEL predicates reactively against the live record and gates each field's visibility, read-only state, and required-ness accordingly. Evaluation delegates to the canonical `@objectstack/formula` `ExpressionEngine` — the _same_ dialect the server enforces (`requiredWhen` in the rule-validator, `readonlyWhen` in `stripReadonlyWhenFields`) — so the UX and the persisted verdict always agree. New core helpers `evalFieldPredicate` / `resolveFieldRuleState` (zero-React, fail-open). `FormField` gains `visibleWhen` / `readonlyWhen` / `requiredWhen` (+ deprecated `conditionalRequired` alias), and `ObjectForm` carries them through from object metadata. + +### Patch Changes + +- 2d47e94: B2 follow-ups (A): field conditional rules in inline grids + submit-time enforcement. + - **Grids**: a line-item column's `readonlyWhen` / `requiredWhen` CEL rule is now honored per row — `deriveMasterDetail` carries the props onto the `GridColumn` and `GridField` evaluates them against each row via `resolveFieldRuleState` (a `readonlyWhen`-TRUE cell locks; a `requiredWhen`-TRUE empty cell flags inline-invalid). Rules are row-scoped (`record.*`); the core helpers gained an optional `scope` (and `GridField` a `contextRecord` prop) so a future header-driven lock can bind `parent.*` — that wiring is deferred (it needs the master-detail header's re-renders isolated). + - **Submit enforcement**: `requiredWhen` already drove react-hook-form's `required` rule, so submit is blocked with a field error when the predicate is TRUE and the value is empty. Added a reactive cleanup so a stale _required_ error clears when the predicate flips FALSE (and all errors clear when a field is hidden by `visibleWhen`). + +- 8d1195d: Fix `type: 'url'` actions so they actually reach the backend in split-origin dev setups, and so reveal-once result dialogs render. + - `ActionRunner.executeUrl`: when context provides `apiBase`, relative `/api/...`, `/_auth/...`, and `/_account/...` URLs are now promoted to absolute (`${apiBase}${path}`) before navigation. Same-origin API paths (with or without `apiBase`) trigger a full-page `window.location.href` rather than React-Router push — this is required for server-side OAuth redirect dances (e.g. better-auth `/sign-in/social`) that React Router would otherwise swallow into the SPA's fallback route. + - `ActionRunner.buildInterpolationContext`: surfaces `ctx.apiBase` for action targets that want to template it explicitly. + - `ObjectView`: passes `apiBase: import.meta.env.VITE_SERVER_URL` into the toolbar `ActionProvider` context so the above resolves. + - `action-button` and `action-menu` renderers now forward `resultDialog` when invoking the runner. Previously this field was silently dropped by an explicit whitelist, breaking every "show once, then hide" flow (2FA QR/backup codes, OAuth client_secret, regenerated tokens). + +- Updated dependencies [ddbe4a2] +- Updated dependencies [d16566f] +- Updated dependencies [300d755] + - @object-ui/types@6.3.0 + ## 6.2.3 ### Patch Changes diff --git a/packages/core/package.json b/packages/core/package.json index fc024611c..2f0ae2e6f 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/core", - "version": "6.2.3", + "version": "6.3.0", "type": "module", "sideEffects": false, "license": "MIT", diff --git a/packages/create-plugin/CHANGELOG.md b/packages/create-plugin/CHANGELOG.md index 8f5f3afc2..b7c044403 100644 --- a/packages/create-plugin/CHANGELOG.md +++ b/packages/create-plugin/CHANGELOG.md @@ -1,5 +1,7 @@ # @object-ui/create-plugin +## 6.3.0 + ## 6.2.3 ## 6.2.2 diff --git a/packages/create-plugin/package.json b/packages/create-plugin/package.json index 6ed8dfa67..c1c9842cc 100644 --- a/packages/create-plugin/package.json +++ b/packages/create-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/create-plugin", - "version": "6.2.3", + "version": "6.3.0", "description": "CLI tool to scaffold ObjectUI plugins", "type": "module", "license": "MIT", diff --git a/packages/data-objectstack/CHANGELOG.md b/packages/data-objectstack/CHANGELOG.md index bea998592..463f6aead 100644 --- a/packages/data-objectstack/CHANGELOG.md +++ b/packages/data-objectstack/CHANGELOG.md @@ -1,5 +1,56 @@ # @object-ui/data-objectstack +## 6.3.0 + +### Minor Changes + +- 30ee761: feat(studio): surface pending drafts on the package detail (ADR-0033) + + After an AI builds an app, its objects/views land as drafts bound to the app package — but Studio's active-only browsers hid them, so the package looked empty and there was no obvious way to find what to review/publish. + - `MetadataClient.listDrafts({ packageId?, type? })` calls the new `GET /api/v1/meta/_drafts` endpoint, returning pending draft headers (with `packageId`). + - The package detail sheet (PackagesPage) now shows a **Pending changes** section listing each drafted item, each linking to the existing per-item review/diff (`?review=1`) so the user can publish it. A just-built app package is no longer shown as empty. + +- d16566f: Atomic master-detail create via the cross-object transactional batch endpoint (ObjectStack #1604). + + When the server exposes the transactional batch endpoint, a NEW parent record and its child line items are now persisted in ONE server transaction — commit all or roll back all — instead of the previous client-orchestrated "create parent → create children → best-effort cleanup on failure" sequence. + + **`@object-ui/data-objectstack` — `ObjectStackAdapter.batchTransaction(operations)`** + - New method posting `{ operations }` to `POST /api/v1/batch`. Operations run in one server transaction. A field value of `{ $ref: }` resolves to that op's generated id, so a child can reference its parent created earlier in the same batch (master-detail FK). Throws `ObjectStackError('BATCH_ERROR')` on a non-2xx response. + + **`@object-ui/plugin-form`** + - `MasterDetailForm` now detects `dataSource.batchTransaction` and, on a NEW parent, builds one atomic batch (parent at index 0, each child FK set to `{ $ref: 0 }`) via the new pure helper `buildMasterDetailBatch`. Client-side total rollups are merged into the parent payload before the batch. Edit mode and adapters without `batchTransaction` keep the existing client-orchestrated path. + - `ObjectForm` gained a `submitHandler` hook: when supplied, the form validates and hands the collected values to the host instead of calling `dataSource.create` / `dataSource.update`. `MasterDetailForm` uses it to own the atomic parent+children write while the parent fields are still rendered by `ObjectForm`. + + **`@object-ui/types`** + - `ObjectFormSchema.submitHandler?: (values) => any | Promise` — typed override for host-owned persistence. + + Pairs with the framework-side ambient-transaction fix (ObjectQL `AsyncLocalStorage` transaction propagation) and the `/api/v1/batch` endpoint added in `@objectstack/rest`. + +### Patch Changes + +- a58c6b8: fix(datasource): exclude form-family views from `listViews()` + + `OBJECTSTACKDataSource.listViews(objectName)` feeds the object list-view + switcher (`ObjectView` → `ViewTabBar`), but returned **every** view bound to + the object — including form-family ones. With the backend now exposing each + view as an independent **ViewItem** carrying a `viewKind` discriminant + (ADR-0017, "Object has-many View"), a form view such as `crm_activity.default` + (expanded from `formViews.default`) leaked in as a spurious switcher tab and, + when opened, fell back to the default grid. + + `listViews()` now filters out `viewKind` `form`/`detail` items so only + list-family views reach the switcher. Bare view specs without a `viewKind` + (legacy artifacts and user-saved views) are still treated as list views. + +- Updated dependencies [c12986e] +- Updated dependencies [ddbe4a2] +- Updated dependencies [2d47e94] +- Updated dependencies [d16566f] +- Updated dependencies [300d755] +- Updated dependencies [8d1195d] + - @object-ui/core@6.3.0 + - @object-ui/types@6.3.0 + ## 6.2.3 ### Patch Changes diff --git a/packages/data-objectstack/package.json b/packages/data-objectstack/package.json index 3fd72b389..85c1a4eb9 100644 --- a/packages/data-objectstack/package.json +++ b/packages/data-objectstack/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/data-objectstack", - "version": "6.2.3", + "version": "6.3.0", "description": "ObjectStack Data Adapter for Object UI", "license": "MIT", "type": "module", diff --git a/packages/fields/CHANGELOG.md b/packages/fields/CHANGELOG.md index 19c9b6b16..69cd16851 100644 --- a/packages/fields/CHANGELOG.md +++ b/packages/fields/CHANGELOG.md @@ -1,5 +1,97 @@ # @object-ui/fields +## 6.3.0 + +### Minor Changes + +- 66ed3ad: Line-item grid: item-typeahead auto-fill from a lookup column. + + When a lookup cell's record is picked, `GridField` now copies any of the chosen record's fields whose names match a sibling column (e.g. a product's `unit_price` / `description` drop into the row), then recomputes computed columns — the catalog-typeahead behaviour of QuickBooks / Stripe / NetSuite. Opt out per column with `autofill: false`. `LookupField` gains an optional `onSelectRecord(record)` callback that surfaces the full selected record (not just its id). New pure export `lookupAutofillPatch(columns, col, record)`. + +- c6445b6: Line-item grid: inline validation, duplicate, and drag-to-reorder. + - **Inline per-cell validation** — a required, non-computed cell that's empty on a real (non-ghost) row flags red in place (`aria-invalid` + ring), so errors are visible without submitting. + - **Duplicate row** — a hover Copy action clones a line (id stripped) directly below it, for near-identical lines. + - **Drag-to-reorder** — a hover grip handle reorders rows via native drag-and-drop. Set `sort_field` on the grid config to persist order (`row[sortField] = index` stamped on every change); otherwise reorder is order-of-entry. + +- 80c133c: Spreadsheet-style line-item grid editor. + + `GridField`'s editable grid mode is reworked into an enterprise line-item editor (the QuickBooks / Stripe / NetSuite pattern), generalised across every inline grid: + - **Computed read-only columns** — a child field with an arithmetic `expression` (e.g. `amount = quantity * unit_price`) renders read-only, recomputes live as its inputs change, and writes the result back into the row so it persists and the running total reflects it. A small safe arithmetic evaluator (`+ - * / %`, parens, `record.` refs; no `eval`) powers it. + - **Trailing "ghost" row** — start-with-one + auto-append: typing in the ghost materialises a real row (index-stable, so focus/caret survive), so you keep entering lines without clicking "Add". + - **Borderless click-to-focus cells** + role-based column widths (description flexes; qty/price/amount stay narrow). + - **Keyboard navigation** — Enter / ArrowUp / ArrowDown move between rows in the same column. + - Per-row "expand to full form" is gated to grids that omit fields (no redundant expand on thin lines). + - `deriveColumns` surfaces a field `expression` as a computed column; the running-total column prefers the computed/last-currency column. Blank/ghost rows are filtered from the persisted batch (`isBlankRow`). + +- 5e1b838: Lookup cells in line-item grids. `LineItemsField` columns now support `type: 'lookup'` (with `reference` / `displayField` / `idField`), rendering a real lookup picker per cell that resolves display labels and stores the foreign-key id — so master-detail line grids can reference other objects (category, account, assignee, …) instead of only plain selects. +- 90acb7f: Master-detail subform + lightweight list primitives (SDUI). + - `MasterDetailForm` (`object-master-detail-form`): enter a parent record and its child line items together; client-orchestrated transactional create (parent → FK → bulk children → rollup → cleanup). Enterprise-convention layout (header on top, line grid, single Save bar at the bottom). + - `LineItemsField` editable child grid (line numbers, right-aligned numerics, running total) and `LineItemsPanel` (`record:line_items`) for detail-page inline edit. + - `element:definition-list` and `element:repeater` — lightweight, low-chrome list primitives for simple data. + +- 18728c1: Master-detail entry: lighter layout, compact lookup cells, persisted line order. + - **De-framed line-item section** — the subform no longer double-frames the grid in a `Card` (border + `p-6`); it renders as a light label + the grid's own bordered table, reclaiming the width the line table needs. + - **Compact lookup cells** — `LookupField` gains a `compact` mode (used by grid cells): the selected value shows inline in a borderless single-line trigger instead of a chip stacked above a separate "Select…" button. + - **Persisted drag-reorder** — `deriveMasterDetail` detects a sort field (`position`/`sort_order`/…), excludes it from the editable columns/row-form, and threads it as the grid's `sort_field` so reordering stamps `row[position] = index` and survives a reload. + +### Patch Changes + +- 2d47e94: B2 follow-ups (A): field conditional rules in inline grids + submit-time enforcement. + - **Grids**: a line-item column's `readonlyWhen` / `requiredWhen` CEL rule is now honored per row — `deriveMasterDetail` carries the props onto the `GridColumn` and `GridField` evaluates them against each row via `resolveFieldRuleState` (a `readonlyWhen`-TRUE cell locks; a `requiredWhen`-TRUE empty cell flags inline-invalid). Rules are row-scoped (`record.*`); the core helpers gained an optional `scope` (and `GridField` a `contextRecord` prop) so a future header-driven lock can bind `parent.*` — that wiring is deferred (it needs the master-detail header's re-renders isolated). + - **Submit enforcement**: `requiredWhen` already drove react-hook-form's `required` rule, so submit is blocked with a field error when the predicate is TRUE and the value is empty. Added a reactive cleanup so a stale _required_ error clears when the predicate flips FALSE (and all errors clear when a field is hidden by `visibleWhen`). + +- bd398df: Render reference/lookup cells as labels, not raw JSON + + A `lookup` / `master_detail` value can arrive as a JSON-encoded object string — + e.g. an unresolved external-id reference `{"externalId":"Website Relaunch"}`. + `LookupCellRenderer` treated the whole JSON string as an opaque id, failed to + resolve it, and fell through to `String(value)`, leaking raw JSON into the grid + cell (and detail/kanban surfaces). + - `LookupCellRenderer` now parses a JSON-object-looking string value and renders + a human label (`name` → `label` → `externalId` → `id`). + - `coerceToSafeValue` (the shared safe-render helper used by 8 cell renderers) + gains the same JSON-string parsing, and `externalId` is added to the + reference-label precedence for plain object values and arrays. + + Verified in the browser (showcase task grid: Project column shows "Website + Relaunch" instead of `{"externalId":"Website Relaunch"}`) and by unit tests. + +- 514f426: fix(master-detail): reliable submit + stable e2e hooks + + Fixes the "click Create, nothing happens" report, surfaced by a new live browser + e2e harness that drives the form with real input. + - **MasterDetailForm `handleSave`** now triggers the button-less parent form's + submit from a deferred macrotask and re-queries the live `` inside it. + Calling `requestSubmit()` synchronously inside the click handler (right after + the `setSaving` state update) intermittently dropped the nested submit event, + so react-hook-form's `onSubmit` never ran and the click appeared to do nothing + — only the occasional click got through. Deferring makes it fire every time. + - **Stable `data-testid`s** so automation/e2e can drive the widgets + deterministically (Radix Select + react-hook-form cannot be driven by + synthetic DOM events): `select-trigger-{field}` / `select-option-{value}` + (SelectField), `lookup-trigger-{field}` (LookupField), `line-items-add` + (GridField), `md-form-submit` / `md-form-cancel` (MasterDetailForm). + +- Updated dependencies [c12986e] +- Updated dependencies [ddbe4a2] +- Updated dependencies [2d47e94] +- Updated dependencies [97c6831] +- Updated dependencies [2eb3096] +- Updated dependencies [18d0339] +- Updated dependencies [d16566f] +- Updated dependencies [90acb7f] +- Updated dependencies [7913390] +- Updated dependencies [abe8ebc] +- Updated dependencies [300d755] +- Updated dependencies [2f31406] +- Updated dependencies [8d1195d] + - @object-ui/core@6.3.0 + - @object-ui/react@6.3.0 + - @object-ui/types@6.3.0 + - @object-ui/components@6.3.0 + - @object-ui/i18n@6.3.0 + - @object-ui/providers@6.3.0 + ## 6.2.3 ### Patch Changes diff --git a/packages/fields/package.json b/packages/fields/package.json index f0fe85e04..f5ae3f1a6 100644 --- a/packages/fields/package.json +++ b/packages/fields/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/fields", - "version": "6.2.3", + "version": "6.3.0", "description": "Field renderers and registry for Object UI", "license": "MIT", "type": "module", diff --git a/packages/i18n/CHANGELOG.md b/packages/i18n/CHANGELOG.md index ae91d8ad8..e21b70e4a 100644 --- a/packages/i18n/CHANGELOG.md +++ b/packages/i18n/CHANGELOG.md @@ -1,5 +1,41 @@ # @object-ui/i18n +## 6.3.0 + +### Minor Changes + +- 18d0339: Relabel metadata-driven UI on a language switch without a page refresh (#1319) + + Switching the UI language left server-resolved metadata labels (object/field/ + view labels, action-dialog text) in the old language until a hard refresh, + because renderers cache those labels by object name and never refetch on a + language change. + + **`@object-ui/auth`** — `createAuthenticatedFetch` now folds the active + `` into `Accept-Language` on API calls (never clobbering an explicit + header), so a switch carries the new locale on every subsequent request. + + **`@object-ui/app-shell`** — `ConnectedShellInner` drops the adapter's + locale-blind metadata cache in the render phase and remounts the metadata + subtree via `key={language}`, so every renderer refetches in the new locale. + The adapter and its connection sit above the key and are preserved — an in-app + relabel, not a reconnect. + + **`@object-ui/i18n`** — dev-mode missing-key warnings: `createI18n` gains + `warnMissingKeys` (default on outside production) wiring a deduped i18next + `missingKeyHandler`. `useObjectLabel`'s convention-key probes are flagged so + their intentional misses (which fall back to server metadata) stay silent. + + Pairs with the framework-side locale-aware metadata changes in + `@objectstack/client` / `@objectstack/objectql` / `@objectstack/rest`. + +### Patch Changes + +- 97c6831: Localize AI workspace, shell navigation, startup, connection, toast, and chatbot affordance text across core console screens. +- 2f31406: Refine Studio package-scoped navigation and home overview. + + Studio now treats the selected package as the home overview scope, flattens the root Overview sidebar group, hides the duplicate all-metadata sidebar entry, redirects the invalid package metadata route to package management, preserves the selected package across package-management navigation, and adds a localized package-management sidebar label. + ## 6.2.3 ## 6.2.2 diff --git a/packages/i18n/package.json b/packages/i18n/package.json index ab33ddb81..fd9c0d5e7 100644 --- a/packages/i18n/package.json +++ b/packages/i18n/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/i18n", - "version": "6.2.3", + "version": "6.3.0", "type": "module", "sideEffects": false, "license": "MIT", diff --git a/packages/layout/CHANGELOG.md b/packages/layout/CHANGELOG.md index 2c58cc5ae..9164464d1 100644 --- a/packages/layout/CHANGELOG.md +++ b/packages/layout/CHANGELOG.md @@ -1,5 +1,24 @@ # @object-ui/layout +## 6.3.0 + +### Patch Changes + +- Updated dependencies [c12986e] +- Updated dependencies [ddbe4a2] +- Updated dependencies [2d47e94] +- Updated dependencies [2eb3096] +- Updated dependencies [d16566f] +- Updated dependencies [90acb7f] +- Updated dependencies [7913390] +- Updated dependencies [abe8ebc] +- Updated dependencies [300d755] +- Updated dependencies [8d1195d] + - @object-ui/core@6.3.0 + - @object-ui/react@6.3.0 + - @object-ui/types@6.3.0 + - @object-ui/components@6.3.0 + ## 6.2.3 ### Patch Changes diff --git a/packages/layout/package.json b/packages/layout/package.json index 8dba1a530..217647624 100644 --- a/packages/layout/package.json +++ b/packages/layout/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/layout", - "version": "6.2.3", + "version": "6.3.0", "type": "module", "sideEffects": false, "main": "dist/index.umd.cjs", diff --git a/packages/mobile/CHANGELOG.md b/packages/mobile/CHANGELOG.md index 9bc65364c..24a0b4361 100644 --- a/packages/mobile/CHANGELOG.md +++ b/packages/mobile/CHANGELOG.md @@ -1,5 +1,14 @@ # @object-ui/mobile +## 6.3.0 + +### Patch Changes + +- Updated dependencies [ddbe4a2] +- Updated dependencies [d16566f] +- Updated dependencies [300d755] + - @object-ui/types@6.3.0 + ## 6.2.3 ### Patch Changes diff --git a/packages/mobile/package.json b/packages/mobile/package.json index 5aed77b97..a6a68efe9 100644 --- a/packages/mobile/package.json +++ b/packages/mobile/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/mobile", - "version": "6.2.3", + "version": "6.3.0", "type": "module", "license": "MIT", "description": "Mobile optimization for Object UI with responsive components, PWA support, and touch gesture handling.", diff --git a/packages/permissions/CHANGELOG.md b/packages/permissions/CHANGELOG.md index 623324c83..b49b4e3f8 100644 --- a/packages/permissions/CHANGELOG.md +++ b/packages/permissions/CHANGELOG.md @@ -1,5 +1,14 @@ # @object-ui/permissions +## 6.3.0 + +### Patch Changes + +- Updated dependencies [ddbe4a2] +- Updated dependencies [d16566f] +- Updated dependencies [300d755] + - @object-ui/types@6.3.0 + ## 6.2.3 ### Patch Changes diff --git a/packages/permissions/package.json b/packages/permissions/package.json index 8e34730bd..5a5748b52 100644 --- a/packages/permissions/package.json +++ b/packages/permissions/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/permissions", - "version": "6.2.3", + "version": "6.3.0", "type": "module", "license": "MIT", "description": "RBAC permission system for Object UI with object/field/row-level access control, permission guards, and hooks.", diff --git a/packages/plugin-ai/CHANGELOG.md b/packages/plugin-ai/CHANGELOG.md index c0231f0cd..82c3e0965 100644 --- a/packages/plugin-ai/CHANGELOG.md +++ b/packages/plugin-ai/CHANGELOG.md @@ -1,5 +1,24 @@ # @object-ui/plugin-ai +## 6.3.0 + +### Patch Changes + +- Updated dependencies [c12986e] +- Updated dependencies [ddbe4a2] +- Updated dependencies [2d47e94] +- Updated dependencies [2eb3096] +- Updated dependencies [d16566f] +- Updated dependencies [90acb7f] +- Updated dependencies [7913390] +- Updated dependencies [abe8ebc] +- Updated dependencies [300d755] +- Updated dependencies [8d1195d] + - @object-ui/core@6.3.0 + - @object-ui/react@6.3.0 + - @object-ui/types@6.3.0 + - @object-ui/components@6.3.0 + ## 6.2.3 ### Patch Changes diff --git a/packages/plugin-ai/package.json b/packages/plugin-ai/package.json index 98da1c346..9db5d14be 100644 --- a/packages/plugin-ai/package.json +++ b/packages/plugin-ai/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/plugin-ai", - "version": "6.2.3", + "version": "6.3.0", "type": "module", "main": "dist/index.umd.cjs", "module": "dist/index.js", diff --git a/packages/plugin-calendar/CHANGELOG.md b/packages/plugin-calendar/CHANGELOG.md index dc18a64e2..78a586dcb 100644 --- a/packages/plugin-calendar/CHANGELOG.md +++ b/packages/plugin-calendar/CHANGELOG.md @@ -1,5 +1,39 @@ # @object-ui/plugin-calendar +## 6.3.0 + +### Patch Changes + +- Updated dependencies [c12986e] +- Updated dependencies [ddbe4a2] +- Updated dependencies [2d47e94] +- Updated dependencies [97c6831] +- Updated dependencies [2eb3096] +- Updated dependencies [bd398df] +- Updated dependencies [18d0339] +- Updated dependencies [66ed3ad] +- Updated dependencies [c6445b6] +- Updated dependencies [80c133c] +- Updated dependencies [5e1b838] +- Updated dependencies [d16566f] +- Updated dependencies [90acb7f] +- Updated dependencies [7913390] +- Updated dependencies [514f426] +- Updated dependencies [abe8ebc] +- Updated dependencies [300d755] +- Updated dependencies [3cc38fe] +- Updated dependencies [2f31406] +- Updated dependencies [18728c1] +- Updated dependencies [8d1195d] + - @object-ui/core@6.3.0 + - @object-ui/react@6.3.0 + - @object-ui/types@6.3.0 + - @object-ui/components@6.3.0 + - @object-ui/fields@6.3.0 + - @object-ui/i18n@6.3.0 + - @object-ui/plugin-detail@6.3.0 + - @object-ui/mobile@6.3.0 + ## 6.2.3 ### Patch Changes diff --git a/packages/plugin-calendar/package.json b/packages/plugin-calendar/package.json index b055e43c0..76cefaca1 100644 --- a/packages/plugin-calendar/package.json +++ b/packages/plugin-calendar/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/plugin-calendar", - "version": "6.2.3", + "version": "6.3.0", "type": "module", "license": "MIT", "description": "Calendar view plugins for Object UI - includes both ObjectQL-integrated and standalone calendar components", diff --git a/packages/plugin-charts/CHANGELOG.md b/packages/plugin-charts/CHANGELOG.md index f179a1e4a..2601e2810 100644 --- a/packages/plugin-charts/CHANGELOG.md +++ b/packages/plugin-charts/CHANGELOG.md @@ -1,5 +1,28 @@ # @object-ui/plugin-charts +## 6.3.0 + +### Patch Changes + +- Updated dependencies [c12986e] +- Updated dependencies [ddbe4a2] +- Updated dependencies [2d47e94] +- Updated dependencies [97c6831] +- Updated dependencies [2eb3096] +- Updated dependencies [18d0339] +- Updated dependencies [d16566f] +- Updated dependencies [90acb7f] +- Updated dependencies [7913390] +- Updated dependencies [abe8ebc] +- Updated dependencies [300d755] +- Updated dependencies [2f31406] +- Updated dependencies [8d1195d] + - @object-ui/core@6.3.0 + - @object-ui/react@6.3.0 + - @object-ui/types@6.3.0 + - @object-ui/components@6.3.0 + - @object-ui/i18n@6.3.0 + ## 6.2.3 ### Patch Changes diff --git a/packages/plugin-charts/package.json b/packages/plugin-charts/package.json index 8209c6c3d..1ae984d92 100644 --- a/packages/plugin-charts/package.json +++ b/packages/plugin-charts/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/plugin-charts", - "version": "6.2.3", + "version": "6.3.0", "type": "module", "license": "MIT", "description": "Chart components plugin for Object UI, powered by Recharts", diff --git a/packages/plugin-chatbot/CHANGELOG.md b/packages/plugin-chatbot/CHANGELOG.md index 6d3dc497a..e3fd87c9c 100644 --- a/packages/plugin-chatbot/CHANGELOG.md +++ b/packages/plugin-chatbot/CHANGELOG.md @@ -1,5 +1,42 @@ # @object-ui/plugin-chatbot +## 6.3.0 + +### Minor Changes + +- 81c0777: feat(studio): ADR-0033 Phase B — draft review surface (chat → designer → generic diff) + + Closes the AI metadata-authoring loop in Studio. The framework (ADR-0033 Phases A + C) makes the assistant stage every change as a DRAFT; this lets a human see and review those drafts. + + **`@object-ui/plugin-chatbot`** + - `mapMessages` now detects the framework's draft envelopes — `{ status:'drafted', type, name, … }` (single) and `{ status:'drafted', drafted:[{type,name}] }` (apply_blueprint batch) — and lifts the reviewable targets onto `ChatToolInvocation.draftReview` (mirrors the existing HITL `pendingActionId` path; the Vercel `{type:'text',value}` wrapper is peeled). `blueprint_proposed` is intentionally not surfaced (no draft yet). + - `ChatbotEnhanced` renders a **"Review N change(s)"** button on drafted tool results, driven by a new `onReviewDraft` callback prop. + + **`@object-ui/app-shell`** + - `assistantBus` gains a review channel (`requestReview` / `requestAssistantReview`); `ConsoleFloatingChatbot` wires the chat button to it; a small navigator inside `AppContent` (which knows the app base) routes to `/apps/:appName/metadata/:type/:name?review=1`. + - `ResourceEditPage` honours `?review=1`: it force-reloads the pending draft (covers the case where the AI drafted the item after the page mounted) and opens the review/diff. + - New **`DraftReviewPanel`** — a generic, type-agnostic draft↔published structural diff (added / changed / removed by key), reusing `LayeredDiff`'s `computeDiffRows`. It gives **every** metadata type (view, dashboard, flow, …) a real "what will publishing change" review, surfaced as a toolbar affordance + sheet whenever a draft exists. The object designer keeps its richer per-field review. + + Nothing is published by any of this — the human still clicks Publish. + +### Patch Changes + +- 40c79df: Improve the floating chatbot flow with responsive panel bounds, safer FAB placement, inline responding and stop states, and clearer retryable error feedback. +- Updated dependencies [c12986e] +- Updated dependencies [ddbe4a2] +- Updated dependencies [2d47e94] +- Updated dependencies [2eb3096] +- Updated dependencies [d16566f] +- Updated dependencies [90acb7f] +- Updated dependencies [7913390] +- Updated dependencies [abe8ebc] +- Updated dependencies [300d755] +- Updated dependencies [8d1195d] + - @object-ui/core@6.3.0 + - @object-ui/react@6.3.0 + - @object-ui/types@6.3.0 + - @object-ui/components@6.3.0 + ## 6.2.3 ### Patch Changes diff --git a/packages/plugin-chatbot/package.json b/packages/plugin-chatbot/package.json index 62b5b567b..a6f40765c 100644 --- a/packages/plugin-chatbot/package.json +++ b/packages/plugin-chatbot/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/plugin-chatbot", - "version": "6.2.3", + "version": "6.3.0", "type": "module", "license": "MIT", "description": "Chatbot interface plugin for Object UI", diff --git a/packages/plugin-dashboard/CHANGELOG.md b/packages/plugin-dashboard/CHANGELOG.md index 290187409..710463eeb 100644 --- a/packages/plugin-dashboard/CHANGELOG.md +++ b/packages/plugin-dashboard/CHANGELOG.md @@ -1,5 +1,36 @@ # @object-ui/plugin-dashboard +## 6.3.0 + +### Patch Changes + +- Updated dependencies [c12986e] +- Updated dependencies [ddbe4a2] +- Updated dependencies [2d47e94] +- Updated dependencies [97c6831] +- Updated dependencies [2eb3096] +- Updated dependencies [bd398df] +- Updated dependencies [18d0339] +- Updated dependencies [66ed3ad] +- Updated dependencies [c6445b6] +- Updated dependencies [80c133c] +- Updated dependencies [5e1b838] +- Updated dependencies [d16566f] +- Updated dependencies [90acb7f] +- Updated dependencies [7913390] +- Updated dependencies [514f426] +- Updated dependencies [abe8ebc] +- Updated dependencies [300d755] +- Updated dependencies [2f31406] +- Updated dependencies [18728c1] +- Updated dependencies [8d1195d] + - @object-ui/core@6.3.0 + - @object-ui/react@6.3.0 + - @object-ui/types@6.3.0 + - @object-ui/components@6.3.0 + - @object-ui/fields@6.3.0 + - @object-ui/i18n@6.3.0 + ## 6.2.3 ### Patch Changes diff --git a/packages/plugin-dashboard/package.json b/packages/plugin-dashboard/package.json index aa348fa09..49ff854a4 100644 --- a/packages/plugin-dashboard/package.json +++ b/packages/plugin-dashboard/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/plugin-dashboard", - "version": "6.2.3", + "version": "6.3.0", "type": "module", "license": "MIT", "description": "Dashboard plugin for Object UI", diff --git a/packages/plugin-designer/CHANGELOG.md b/packages/plugin-designer/CHANGELOG.md index 643e07dcb..109a4e13f 100644 --- a/packages/plugin-designer/CHANGELOG.md +++ b/packages/plugin-designer/CHANGELOG.md @@ -1,5 +1,46 @@ # @object-ui/plugin-designer +## 6.3.0 + +### Patch Changes + +- Updated dependencies [c12986e] +- Updated dependencies [30ee761] +- Updated dependencies [ddbe4a2] +- Updated dependencies [2d47e94] +- Updated dependencies [97c6831] +- Updated dependencies [a58c6b8] +- Updated dependencies [f6044fa] +- Updated dependencies [2eb3096] +- Updated dependencies [bd398df] +- Updated dependencies [18d0339] +- Updated dependencies [66ed3ad] +- Updated dependencies [c6445b6] +- Updated dependencies [80c133c] +- Updated dependencies [5e1b838] +- Updated dependencies [d16566f] +- Updated dependencies [69510df] +- Updated dependencies [b148daf] +- Updated dependencies [90acb7f] +- Updated dependencies [7913390] +- Updated dependencies [514f426] +- Updated dependencies [00f8d2d] +- Updated dependencies [abe8ebc] +- Updated dependencies [300d755] +- Updated dependencies [2f31406] +- Updated dependencies [18728c1] +- Updated dependencies [8426db7] +- Updated dependencies [8d1195d] + - @object-ui/core@6.3.0 + - @object-ui/react@6.3.0 + - @object-ui/data-objectstack@6.3.0 + - @object-ui/types@6.3.0 + - @object-ui/components@6.3.0 + - @object-ui/plugin-form@6.3.0 + - @object-ui/fields@6.3.0 + - @object-ui/i18n@6.3.0 + - @object-ui/plugin-grid@6.3.0 + ## 6.2.3 ### Patch Changes diff --git a/packages/plugin-designer/package.json b/packages/plugin-designer/package.json index 5b4c305de..8361c901e 100644 --- a/packages/plugin-designer/package.json +++ b/packages/plugin-designer/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/plugin-designer", - "version": "6.2.3", + "version": "6.3.0", "type": "module", "license": "MIT", "description": "Visual designer plugin for Object UI with page, data model, process, and report designers plus collaborative editing.", diff --git a/packages/plugin-detail/CHANGELOG.md b/packages/plugin-detail/CHANGELOG.md index 9c631f076..c99016b3d 100644 --- a/packages/plugin-detail/CHANGELOG.md +++ b/packages/plugin-detail/CHANGELOG.md @@ -1,5 +1,28 @@ # @object-ui/plugin-detail +## 6.3.0 + +### Patch Changes + +- 3cc38fe: perf(detail/header): lazy + dedupe related-list fan-out, coalesce header polls + + Opening a record detail fired ~50 concurrent `/api/v1` requests that + head-of-line-blocked one another on a single control-plane container. + - `RecordDetailView` no longer eager-preloads reverse-reference children + when the reference rail renders them (that data was discarded while the + rail re-fetched the same collections). + - `record:reference_rail` now gates fetching on visibility + (`IntersectionObserver`; the rail is `hidden xl:flex`), caps concurrency + at 3, and fetches once per `(parentId + entries)` via a signature guard, + applying results through a mounted ref. + - `AppHeader` inbox/notification, approvals, and activity pollers gained + in-flight guards so bootstrap effect re-runs coalesce to one request; the + approvals poll now sends one request with all identities comma-joined + instead of one per identity. + + Measured locally: opening an environment detail dropped from ~52 to ~17 + requests, related collections from ×3–5 each to ×1, approvals from ×9 to ≤3. + ## 6.2.3 ## 6.2.2 diff --git a/packages/plugin-detail/package.json b/packages/plugin-detail/package.json index 1b7a38fa5..88dfdd98d 100644 --- a/packages/plugin-detail/package.json +++ b/packages/plugin-detail/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/plugin-detail", - "version": "6.2.3", + "version": "6.3.0", "type": "module", "license": "MIT", "description": "DetailView plugin for Object UI - comprehensive detail page with sections, tabs, and related lists", diff --git a/packages/plugin-editor/CHANGELOG.md b/packages/plugin-editor/CHANGELOG.md index 8a8d98ef6..c67c8dfa9 100644 --- a/packages/plugin-editor/CHANGELOG.md +++ b/packages/plugin-editor/CHANGELOG.md @@ -1,5 +1,24 @@ # @object-ui/plugin-editor +## 6.3.0 + +### Patch Changes + +- Updated dependencies [c12986e] +- Updated dependencies [ddbe4a2] +- Updated dependencies [2d47e94] +- Updated dependencies [2eb3096] +- Updated dependencies [d16566f] +- Updated dependencies [90acb7f] +- Updated dependencies [7913390] +- Updated dependencies [abe8ebc] +- Updated dependencies [300d755] +- Updated dependencies [8d1195d] + - @object-ui/core@6.3.0 + - @object-ui/react@6.3.0 + - @object-ui/types@6.3.0 + - @object-ui/components@6.3.0 + ## 6.2.3 ### Patch Changes diff --git a/packages/plugin-editor/package.json b/packages/plugin-editor/package.json index 8e4a33262..b8084dccd 100644 --- a/packages/plugin-editor/package.json +++ b/packages/plugin-editor/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/plugin-editor", - "version": "6.2.3", + "version": "6.3.0", "type": "module", "license": "MIT", "description": "Rich text editor plugin for Object UI, powered by Monaco Editor", diff --git a/packages/plugin-form/CHANGELOG.md b/packages/plugin-form/CHANGELOG.md index be0fbd360..b2edec3cc 100644 --- a/packages/plugin-form/CHANGELOG.md +++ b/packages/plugin-form/CHANGELOG.md @@ -1,5 +1,202 @@ # @object-ui/plugin-form +## 6.3.0 + +### Minor Changes + +- 80c133c: Spreadsheet-style line-item grid editor. + + `GridField`'s editable grid mode is reworked into an enterprise line-item editor (the QuickBooks / Stripe / NetSuite pattern), generalised across every inline grid: + - **Computed read-only columns** — a child field with an arithmetic `expression` (e.g. `amount = quantity * unit_price`) renders read-only, recomputes live as its inputs change, and writes the result back into the row so it persists and the running total reflects it. A small safe arithmetic evaluator (`+ - * / %`, parens, `record.` refs; no `eval`) powers it. + - **Trailing "ghost" row** — start-with-one + auto-append: typing in the ghost materialises a real row (index-stable, so focus/caret survive), so you keep entering lines without clicking "Add". + - **Borderless click-to-focus cells** + role-based column widths (description flexes; qty/price/amount stay narrow). + - **Keyboard navigation** — Enter / ArrowUp / ArrowDown move between rows in the same column. + - Per-row "expand to full form" is gated to grids that omit fields (no redundant expand on thin lines). + - `deriveColumns` surfaces a field `expression` as a computed column; the running-total column prefers the computed/last-currency column. Blank/ghost rows are filtered from the persisted batch (`isBlankRow`). + +- d16566f: Atomic master-detail create via the cross-object transactional batch endpoint (ObjectStack #1604). + + When the server exposes the transactional batch endpoint, a NEW parent record and its child line items are now persisted in ONE server transaction — commit all or roll back all — instead of the previous client-orchestrated "create parent → create children → best-effort cleanup on failure" sequence. + + **`@object-ui/data-objectstack` — `ObjectStackAdapter.batchTransaction(operations)`** + - New method posting `{ operations }` to `POST /api/v1/batch`. Operations run in one server transaction. A field value of `{ $ref: }` resolves to that op's generated id, so a child can reference its parent created earlier in the same batch (master-detail FK). Throws `ObjectStackError('BATCH_ERROR')` on a non-2xx response. + + **`@object-ui/plugin-form`** + - `MasterDetailForm` now detects `dataSource.batchTransaction` and, on a NEW parent, builds one atomic batch (parent at index 0, each child FK set to `{ $ref: 0 }`) via the new pure helper `buildMasterDetailBatch`. Client-side total rollups are merged into the parent payload before the batch. Edit mode and adapters without `batchTransaction` keep the existing client-orchestrated path. + - `ObjectForm` gained a `submitHandler` hook: when supplied, the form validates and hands the collected values to the host instead of calling `dataSource.create` / `dataSource.update`. `MasterDetailForm` uses it to own the atomic parent+children write while the parent fields are still rendered by `ObjectForm`. + + **`@object-ui/types`** + - `ObjectFormSchema.submitHandler?: (values) => any | Promise` — typed override for host-owned persistence. + + Pairs with the framework-side ambient-transaction fix (ObjectQL `AsyncLocalStorage` transaction propagation) and the `/api/v1/batch` endpoint added in `@objectstack/rest`. + +- 69510df: feat(master-detail): derive child columns + relationship FK from metadata + + A master-detail child collection can now be configured with **just the child + object name** — the relationship FK and the editable grid columns are derived + from the child object's schema (via `DataSource.getObjectSchema`), instead of a + hand-authored columns block. + + ```ts + // before: ~40 lines of columns + relationshipField + details: [{ childObject: 'task', relationshipField: 'project', columns: [ ...12 lines... ] }] + // after: + details: [{ childObject: 'task' }] + ``` + + - `relationshipField` is auto-detected from the child's `master_detail`/`lookup` + field that references the parent (master_detail preferred). + - `columns` are derived from the child's fields, skipping system/audit fields, + the back-reference FK, and non-editable types (formula/summary/autonumber/ + file/json/…); select options and lookup references carry through. + - `amountField` (running-total source) defaults to the first numeric/currency + column. + - Any of these can still be set explicitly to override the derived defaults. + - Save is gated until derivation resolves; new pure helpers + (`deriveDetail`/`deriveColumns`/`findRelationshipField`) are unit-tested. + +- b148daf: feat(master-detail): atomic EDIT via the cross-object batch endpoint + + Edit mode now persists the parent update together with its child line-item + create/update/delete diffs in ONE server transaction (commit all or roll back + all), matching what create already did. Previously only create used the atomic + `/api/v1/batch` path; edit fell back to client-orchestrated writes with + best-effort cleanup. + - New pure helper `buildMasterDetailEditBatch(parentObject, parentId, +parentData, details)` — emits a parent `update` op (index 0) then diffs each + child collection against its loaded snapshot into `create` / `update` / + `delete` ops (children reference the known parent id directly, no `$ref`). + - `MasterDetailForm` now treats `canBatch` as available whenever the data + source exposes `batchTransaction` (create AND edit). `submitViaBatch` builds + create-ops or edit-ops by mode; `onSuccess` → `handleSaved` ("saved" toast, + no form reset in edit). + + The server `/api/v1/batch` handler already supports `update`/`delete` actions, + and the adapter already forwards `action`/`id`, so this is a front-end change. + Unit-tested (parent update + child create/update/delete diff); the create path + remains verified by the live e2e. + +- 90acb7f: Master-detail subform + lightweight list primitives (SDUI). + - `MasterDetailForm` (`object-master-detail-form`): enter a parent record and its child line items together; client-orchestrated transactional create (parent → FK → bulk children → rollup → cleanup). Enterprise-convention layout (header on top, line grid, single Save bar at the bottom). + - `LineItemsField` editable child grid (line numbers, right-aligned numerics, running total) and `LineItemsPanel` (`record:line_items`) for detail-page inline edit. + - `element:definition-list` and `element:repeater` — lightweight, low-chrome list primitives for simple data. + +- 00f8d2d: Master-detail form: live Subtotal / Tax / Total stack. + + `MasterDetailForm` now renders a right-aligned document totals stack under the line items when the parent form has a tax-rate field (`taxRateField`, default `tax_rate`): **Subtotal** (Σ line amounts) → **Tax** (header rate %) → **Total**, recomputed live as lines and the rate change. The header rate is read via scoped event delegation on the form host (no coupling into `ObjectForm` internals). When the stack is shown, the per-grid footer total is subsumed. + +- 300d755: feat(form): inline master-detail in a plain ObjectForm via `subforms` + + `ObjectFormSchema` gains a `subforms` array. When set, a regular `object-form` + renders as a master-detail form — the object's own fields on top, an editable + grid per child collection below, persisted together in one atomic transaction — + without a bespoke `object-master-detail-form` page. + + ```ts + { type: 'object-form', objectName: 'expense_claim', + subforms: [{ childObject: 'expense_line' }] } // FK + columns auto-derived + ``` + + Each subform needs only `childObject` (relationship FK and columns are derived + from the child object's metadata; override with `relationshipField`/`columns`). + This is the config-driven, page-less way to express master-detail entry — a form + view can declare its child collections directly. + +- 18728c1: Master-detail entry: lighter layout, compact lookup cells, persisted line order. + - **De-framed line-item section** — the subform no longer double-frames the grid in a `Card` (border + `p-6`); it renders as a light label + the grid's own bordered table, reclaiming the width the line table needs. + - **Compact lookup cells** — `LookupField` gains a `compact` mode (used by grid cells): the selected value shows inline in a borderless single-line trigger instead of a chip stacked above a separate "Select…" button. + - **Persisted drag-reorder** — `deriveMasterDetail` detects a sort field (`position`/`sort_order`/…), excludes it from the editable columns/row-form, and threads it as the grid's `sort_field` so reordering stamps `row[position] = index` and survives a reload. + +- 8426db7: feat(form): standard New/Edit modal renders form-view subforms (Tier 0) + + The console's standard create/edit record modal now renders inline child + collections when the object's form view declares `subforms` — master-detail + entry with **no bespoke page**, persisted as one atomic transaction. + - `ModalForm` (and the create/edit modal in app-shell `AppContent`) detects + `subforms` and renders `MasterDetailForm` inside the dialog (it owns its Save + bar; the modal footer is suppressed); on success the modal closes + refreshes. + - `AppContent` sources `subforms` from the object's default form view + (`form.subforms` / `formViews.default.subforms`). + - `ModalFormSchema` gains `subforms`. + + With this, declaring `formViews.default.subforms: [{ childObject }]` is enough + to make an object's standard New/Edit screen a master-detail form — completing + the config-driven master-detail story (Tier 0 → derive everything from the + relationship + child metadata). + +### Patch Changes + +- ddbe4a2: B2 step 3: client-side field-level conditional rules (`visibleWhen` / `readonlyWhen` / `requiredWhen`). The form renderer now evaluates these CEL predicates reactively against the live record and gates each field's visibility, read-only state, and required-ness accordingly. Evaluation delegates to the canonical `@objectstack/formula` `ExpressionEngine` — the _same_ dialect the server enforces (`requiredWhen` in the rule-validator, `readonlyWhen` in `stripReadonlyWhenFields`) — so the UX and the persisted verdict always agree. New core helpers `evalFieldPredicate` / `resolveFieldRuleState` (zero-React, fail-open). `FormField` gains `visibleWhen` / `readonlyWhen` / `requiredWhen` (+ deprecated `conditionalRequired` alias), and `ObjectForm` carries them through from object metadata. +- 2d47e94: B2 follow-ups (A): field conditional rules in inline grids + submit-time enforcement. + - **Grids**: a line-item column's `readonlyWhen` / `requiredWhen` CEL rule is now honored per row — `deriveMasterDetail` carries the props onto the `GridColumn` and `GridField` evaluates them against each row via `resolveFieldRuleState` (a `readonlyWhen`-TRUE cell locks; a `requiredWhen`-TRUE empty cell flags inline-invalid). Rules are row-scoped (`record.*`); the core helpers gained an optional `scope` (and `GridField` a `contextRecord` prop) so a future header-driven lock can bind `parent.*` — that wiring is deferred (it needs the master-detail header's re-renders isolated). + - **Submit enforcement**: `requiredWhen` already drove react-hook-form's `required` rule, so submit is blocked with a field error when the predicate is TRUE and the value is empty. Added a reactive cleanup so a stale _required_ error clears when the predicate flips FALSE (and all errors clear when a field is hidden by `visibleWhen`). + +- f6044fa: feat(form): subforms in DrawerForm + full-page record form (Tier 0 everywhere) + + Completes config-driven master-detail across all standard create/edit entry + points (after the modal in the previous change): + - `DrawerForm` now hosts `MasterDetailForm` inside the drawer when the schema + declares `subforms` (its own Save bar; closes + refreshes on success). + - `RecordFormPage` (full-page New/Edit) sources `subforms` from the object's + form view, so the full-page form renders inline child collections too. + - `ObjectForm`'s subforms shortcut now defers to the drawer/modal variants for + those formTypes (so they keep their envelope), and only renders the + master-detail form directly for inline/simple forms. + + Declaring `formViews.default.subforms: [{ childObject }]` now yields a + master-detail experience in the modal, drawer, AND full-page form — no bespoke + page anywhere. + +- 7913390: fix(master-detail): never silent on save — feedback, reset, and a duplicate-submit guard + + `MasterDetailForm`'s "Create" submitted successfully but gave **no feedback**: no toast, no form reset, no navigation. A successful create looked broken, and re-clicking created duplicate records. + - On success: a `toast.success`, and on create the form clears (line items reset + parent `` remounts) ready for the next entry. A page-supplied `onSuccess` still runs afterwards (e.g. to navigate). + - On failure (validation / network / atomic rollback): a `toast.error` surfaces the message instead of failing silently. + - In-flight guard: the Create button shows "Saving…" and is disabled while a submit is running, preventing duplicate submissions, with a safety release if client-side validation blocks the submit. + - `@object-ui/components` now re-exports `toast` (alongside `Toaster`) from its sonner wrapper. + + Tests: two new `MasterDetailForm` tests assert success → toast + form clear, and failure → error toast. + +- 514f426: fix(master-detail): reliable submit + stable e2e hooks + + Fixes the "click Create, nothing happens" report, surfaced by a new live browser + e2e harness that drives the form with real input. + - **MasterDetailForm `handleSave`** now triggers the button-less parent form's + submit from a deferred macrotask and re-queries the live `` inside it. + Calling `requestSubmit()` synchronously inside the click handler (right after + the `setSaving` state update) intermittently dropped the nested submit event, + so react-hook-form's `onSubmit` never ran and the click appeared to do nothing + — only the occasional click got through. Deferring makes it fire every time. + - **Stable `data-testid`s** so automation/e2e can drive the widgets + deterministically (Radix Select + react-hook-form cannot be driven by + synthetic DOM events): `select-trigger-{field}` / `select-option-{value}` + (SelectField), `lookup-trigger-{field}` (LookupField), `line-items-add` + (GridField), `md-form-submit` / `md-form-cancel` (MasterDetailForm). + +- Updated dependencies [c12986e] +- Updated dependencies [ddbe4a2] +- Updated dependencies [2d47e94] +- Updated dependencies [2eb3096] +- Updated dependencies [bd398df] +- Updated dependencies [66ed3ad] +- Updated dependencies [c6445b6] +- Updated dependencies [80c133c] +- Updated dependencies [5e1b838] +- Updated dependencies [d16566f] +- Updated dependencies [90acb7f] +- Updated dependencies [7913390] +- Updated dependencies [514f426] +- Updated dependencies [abe8ebc] +- Updated dependencies [300d755] +- Updated dependencies [18728c1] +- Updated dependencies [8d1195d] + - @object-ui/core@6.3.0 + - @object-ui/react@6.3.0 + - @object-ui/types@6.3.0 + - @object-ui/components@6.3.0 + - @object-ui/fields@6.3.0 + - @object-ui/permissions@6.3.0 + ## 6.2.3 ### Patch Changes diff --git a/packages/plugin-form/package.json b/packages/plugin-form/package.json index 0aa35736b..77b800dff 100644 --- a/packages/plugin-form/package.json +++ b/packages/plugin-form/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/plugin-form", - "version": "6.2.3", + "version": "6.3.0", "type": "module", "license": "MIT", "description": "Form plugin for Object UI", diff --git a/packages/plugin-gantt/CHANGELOG.md b/packages/plugin-gantt/CHANGELOG.md index c07f347f7..9f72bf622 100644 --- a/packages/plugin-gantt/CHANGELOG.md +++ b/packages/plugin-gantt/CHANGELOG.md @@ -1,5 +1,34 @@ # @object-ui/plugin-gantt +## 6.3.0 + +### Patch Changes + +- Updated dependencies [c12986e] +- Updated dependencies [ddbe4a2] +- Updated dependencies [2d47e94] +- Updated dependencies [2eb3096] +- Updated dependencies [bd398df] +- Updated dependencies [66ed3ad] +- Updated dependencies [c6445b6] +- Updated dependencies [80c133c] +- Updated dependencies [5e1b838] +- Updated dependencies [d16566f] +- Updated dependencies [90acb7f] +- Updated dependencies [7913390] +- Updated dependencies [514f426] +- Updated dependencies [abe8ebc] +- Updated dependencies [300d755] +- Updated dependencies [3cc38fe] +- Updated dependencies [18728c1] +- Updated dependencies [8d1195d] + - @object-ui/core@6.3.0 + - @object-ui/react@6.3.0 + - @object-ui/types@6.3.0 + - @object-ui/components@6.3.0 + - @object-ui/fields@6.3.0 + - @object-ui/plugin-detail@6.3.0 + ## 6.2.3 ### Patch Changes diff --git a/packages/plugin-gantt/package.json b/packages/plugin-gantt/package.json index bedfa1075..e9d2c77f8 100644 --- a/packages/plugin-gantt/package.json +++ b/packages/plugin-gantt/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/plugin-gantt", - "version": "6.2.3", + "version": "6.3.0", "type": "module", "license": "MIT", "description": "Gantt chart plugin for Object UI", diff --git a/packages/plugin-grid/CHANGELOG.md b/packages/plugin-grid/CHANGELOG.md index f813d1806..e478c46fe 100644 --- a/packages/plugin-grid/CHANGELOG.md +++ b/packages/plugin-grid/CHANGELOG.md @@ -1,5 +1,33 @@ # @object-ui/plugin-grid +## 6.3.0 + +### Patch Changes + +- Updated dependencies [c12986e] +- Updated dependencies [ddbe4a2] +- Updated dependencies [2d47e94] +- Updated dependencies [2eb3096] +- Updated dependencies [bd398df] +- Updated dependencies [66ed3ad] +- Updated dependencies [c6445b6] +- Updated dependencies [80c133c] +- Updated dependencies [5e1b838] +- Updated dependencies [d16566f] +- Updated dependencies [90acb7f] +- Updated dependencies [7913390] +- Updated dependencies [514f426] +- Updated dependencies [abe8ebc] +- Updated dependencies [300d755] +- Updated dependencies [18728c1] +- Updated dependencies [8d1195d] + - @object-ui/core@6.3.0 + - @object-ui/react@6.3.0 + - @object-ui/types@6.3.0 + - @object-ui/components@6.3.0 + - @object-ui/fields@6.3.0 + - @object-ui/mobile@6.3.0 + ## 6.2.3 ### Patch Changes diff --git a/packages/plugin-grid/package.json b/packages/plugin-grid/package.json index 1ea67d1be..86a97c027 100644 --- a/packages/plugin-grid/package.json +++ b/packages/plugin-grid/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/plugin-grid", - "version": "6.2.3", + "version": "6.3.0", "type": "module", "license": "MIT", "description": "Grid plugin for Object UI", diff --git a/packages/plugin-kanban/CHANGELOG.md b/packages/plugin-kanban/CHANGELOG.md index 6e194b3c4..7baf73dd8 100644 --- a/packages/plugin-kanban/CHANGELOG.md +++ b/packages/plugin-kanban/CHANGELOG.md @@ -1,5 +1,38 @@ # @object-ui/plugin-kanban +## 6.3.0 + +### Patch Changes + +- Updated dependencies [c12986e] +- Updated dependencies [ddbe4a2] +- Updated dependencies [2d47e94] +- Updated dependencies [97c6831] +- Updated dependencies [2eb3096] +- Updated dependencies [bd398df] +- Updated dependencies [18d0339] +- Updated dependencies [66ed3ad] +- Updated dependencies [c6445b6] +- Updated dependencies [80c133c] +- Updated dependencies [5e1b838] +- Updated dependencies [d16566f] +- Updated dependencies [90acb7f] +- Updated dependencies [7913390] +- Updated dependencies [514f426] +- Updated dependencies [abe8ebc] +- Updated dependencies [300d755] +- Updated dependencies [3cc38fe] +- Updated dependencies [2f31406] +- Updated dependencies [18728c1] +- Updated dependencies [8d1195d] + - @object-ui/core@6.3.0 + - @object-ui/react@6.3.0 + - @object-ui/types@6.3.0 + - @object-ui/components@6.3.0 + - @object-ui/fields@6.3.0 + - @object-ui/i18n@6.3.0 + - @object-ui/plugin-detail@6.3.0 + ## 6.2.3 ### Patch Changes diff --git a/packages/plugin-kanban/package.json b/packages/plugin-kanban/package.json index d5fbdad4a..779ea24f7 100644 --- a/packages/plugin-kanban/package.json +++ b/packages/plugin-kanban/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/plugin-kanban", - "version": "6.2.3", + "version": "6.3.0", "type": "module", "license": "MIT", "description": "Kanban board plugin for Object UI, powered by dnd-kit", diff --git a/packages/plugin-list/CHANGELOG.md b/packages/plugin-list/CHANGELOG.md index 1beca6f65..da85d9788 100644 --- a/packages/plugin-list/CHANGELOG.md +++ b/packages/plugin-list/CHANGELOG.md @@ -1,5 +1,7 @@ # @object-ui/plugin-list +## 6.3.0 + ## 6.2.3 ## 6.2.2 diff --git a/packages/plugin-list/package.json b/packages/plugin-list/package.json index ab8a96d9c..6165c13b3 100644 --- a/packages/plugin-list/package.json +++ b/packages/plugin-list/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/plugin-list", - "version": "6.2.3", + "version": "6.3.0", "type": "module", "license": "MIT", "description": "ListView plugin for Object UI - unified view component with view type switching", diff --git a/packages/plugin-map/CHANGELOG.md b/packages/plugin-map/CHANGELOG.md index ab900f298..abe968a02 100644 --- a/packages/plugin-map/CHANGELOG.md +++ b/packages/plugin-map/CHANGELOG.md @@ -1,5 +1,24 @@ # @object-ui/plugin-map +## 6.3.0 + +### Patch Changes + +- Updated dependencies [c12986e] +- Updated dependencies [ddbe4a2] +- Updated dependencies [2d47e94] +- Updated dependencies [2eb3096] +- Updated dependencies [d16566f] +- Updated dependencies [90acb7f] +- Updated dependencies [7913390] +- Updated dependencies [abe8ebc] +- Updated dependencies [300d755] +- Updated dependencies [8d1195d] + - @object-ui/core@6.3.0 + - @object-ui/react@6.3.0 + - @object-ui/types@6.3.0 + - @object-ui/components@6.3.0 + ## 6.2.3 ### Patch Changes diff --git a/packages/plugin-map/package.json b/packages/plugin-map/package.json index 1df52cced..57ae68dc0 100644 --- a/packages/plugin-map/package.json +++ b/packages/plugin-map/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/plugin-map", - "version": "6.2.3", + "version": "6.3.0", "type": "module", "license": "MIT", "description": "Map visualization plugin for Object UI", diff --git a/packages/plugin-markdown/CHANGELOG.md b/packages/plugin-markdown/CHANGELOG.md index 74643a210..5fd523429 100644 --- a/packages/plugin-markdown/CHANGELOG.md +++ b/packages/plugin-markdown/CHANGELOG.md @@ -1,5 +1,24 @@ # @object-ui/plugin-markdown +## 6.3.0 + +### Patch Changes + +- Updated dependencies [c12986e] +- Updated dependencies [ddbe4a2] +- Updated dependencies [2d47e94] +- Updated dependencies [2eb3096] +- Updated dependencies [d16566f] +- Updated dependencies [90acb7f] +- Updated dependencies [7913390] +- Updated dependencies [abe8ebc] +- Updated dependencies [300d755] +- Updated dependencies [8d1195d] + - @object-ui/core@6.3.0 + - @object-ui/react@6.3.0 + - @object-ui/types@6.3.0 + - @object-ui/components@6.3.0 + ## 6.2.3 ### Patch Changes diff --git a/packages/plugin-markdown/package.json b/packages/plugin-markdown/package.json index fbf6ab60c..d81570217 100644 --- a/packages/plugin-markdown/package.json +++ b/packages/plugin-markdown/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/plugin-markdown", - "version": "6.2.3", + "version": "6.3.0", "type": "module", "license": "MIT", "description": "Markdown rendering plugin for Object UI, powered by react-markdown", diff --git a/packages/plugin-report/CHANGELOG.md b/packages/plugin-report/CHANGELOG.md index 28f4a4926..20d229277 100644 --- a/packages/plugin-report/CHANGELOG.md +++ b/packages/plugin-report/CHANGELOG.md @@ -1,5 +1,37 @@ # @object-ui/plugin-report +## 6.3.0 + +### Patch Changes + +- Updated dependencies [c12986e] +- Updated dependencies [ddbe4a2] +- Updated dependencies [2d47e94] +- Updated dependencies [97c6831] +- Updated dependencies [2eb3096] +- Updated dependencies [bd398df] +- Updated dependencies [18d0339] +- Updated dependencies [66ed3ad] +- Updated dependencies [c6445b6] +- Updated dependencies [80c133c] +- Updated dependencies [5e1b838] +- Updated dependencies [d16566f] +- Updated dependencies [90acb7f] +- Updated dependencies [7913390] +- Updated dependencies [514f426] +- Updated dependencies [abe8ebc] +- Updated dependencies [300d755] +- Updated dependencies [2f31406] +- Updated dependencies [18728c1] +- Updated dependencies [8d1195d] + - @object-ui/core@6.3.0 + - @object-ui/react@6.3.0 + - @object-ui/types@6.3.0 + - @object-ui/components@6.3.0 + - @object-ui/fields@6.3.0 + - @object-ui/i18n@6.3.0 + - @object-ui/plugin-grid@6.3.0 + ## 6.2.3 ### Patch Changes diff --git a/packages/plugin-report/package.json b/packages/plugin-report/package.json index 28486122a..bc075d260 100644 --- a/packages/plugin-report/package.json +++ b/packages/plugin-report/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/plugin-report", - "version": "6.2.3", + "version": "6.3.0", "type": "module", "main": "dist/index.umd.cjs", "module": "dist/index.js", diff --git a/packages/plugin-timeline/CHANGELOG.md b/packages/plugin-timeline/CHANGELOG.md index 33e5efc14..94b18efff 100644 --- a/packages/plugin-timeline/CHANGELOG.md +++ b/packages/plugin-timeline/CHANGELOG.md @@ -1,5 +1,25 @@ # @object-ui/plugin-timeline +## 6.3.0 + +### Patch Changes + +- Updated dependencies [c12986e] +- Updated dependencies [ddbe4a2] +- Updated dependencies [2d47e94] +- Updated dependencies [2eb3096] +- Updated dependencies [d16566f] +- Updated dependencies [90acb7f] +- Updated dependencies [7913390] +- Updated dependencies [abe8ebc] +- Updated dependencies [300d755] +- Updated dependencies [8d1195d] + - @object-ui/core@6.3.0 + - @object-ui/react@6.3.0 + - @object-ui/types@6.3.0 + - @object-ui/components@6.3.0 + - @object-ui/mobile@6.3.0 + ## 6.2.3 ### Patch Changes diff --git a/packages/plugin-timeline/package.json b/packages/plugin-timeline/package.json index 27a20c866..4af54afa8 100644 --- a/packages/plugin-timeline/package.json +++ b/packages/plugin-timeline/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/plugin-timeline", - "version": "6.2.3", + "version": "6.3.0", "type": "module", "license": "MIT", "description": "Timeline component plugin for Object UI", diff --git a/packages/plugin-view/CHANGELOG.md b/packages/plugin-view/CHANGELOG.md index cff1b32a4..cc731d5a9 100644 --- a/packages/plugin-view/CHANGELOG.md +++ b/packages/plugin-view/CHANGELOG.md @@ -1,5 +1,46 @@ # @object-ui/plugin-view +## 6.3.0 + +### Minor Changes + +- 7b71cd8: Unify the runtime ObjectView "view editor" onto the studio's spec-driven inspector. The right-rail view editor now hosts the same `ViewVariantInspector` the metadata studio uses (config fields sourced straight from `@objectstack/spec`) instead of the legacy `buildViewConfigSchema` engine, so runtime and studio share one view-editing surface. A new `view-config-adapter` bridges the runtime's flat view shape and the studio's ViewItem draft, keeping the `sys_view` persistence path untouched; field pickers read from the in-memory object definition (no extra network fetch). The legacy `buildViewConfigSchema` engine and its exports are retired; `ConfigPanelRenderer` is retained for the dashboard/report config panels. + +### Patch Changes + +- 9bef806: feat(view): pass form-view `subforms` through to ObjectForm + + `ObjectView`'s form schema now forwards `form.subforms` to `ObjectForm`, so a + form view that declares inline child collections renders as a master-detail + form (parent fields + child grids, atomic save) in ObjectView's own + create/edit form — no bespoke page. Pairs with `@objectstack/spec` + `FormViewSchema.subforms` and ObjectForm's existing `subforms` rendering. + +- Updated dependencies [c12986e] +- Updated dependencies [ddbe4a2] +- Updated dependencies [2d47e94] +- Updated dependencies [f6044fa] +- Updated dependencies [2eb3096] +- Updated dependencies [80c133c] +- Updated dependencies [d16566f] +- Updated dependencies [69510df] +- Updated dependencies [b148daf] +- Updated dependencies [90acb7f] +- Updated dependencies [7913390] +- Updated dependencies [514f426] +- Updated dependencies [00f8d2d] +- Updated dependencies [abe8ebc] +- Updated dependencies [300d755] +- Updated dependencies [18728c1] +- Updated dependencies [8426db7] +- Updated dependencies [8d1195d] + - @object-ui/core@6.3.0 + - @object-ui/react@6.3.0 + - @object-ui/types@6.3.0 + - @object-ui/components@6.3.0 + - @object-ui/plugin-form@6.3.0 + - @object-ui/plugin-grid@6.3.0 + ## 6.2.3 ### Patch Changes diff --git a/packages/plugin-view/package.json b/packages/plugin-view/package.json index 68a159210..8ae37fa3a 100644 --- a/packages/plugin-view/package.json +++ b/packages/plugin-view/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/plugin-view", - "version": "6.2.3", + "version": "6.3.0", "type": "module", "license": "MIT", "description": "Object View plugin for Object UI", diff --git a/packages/plugin-workflow/CHANGELOG.md b/packages/plugin-workflow/CHANGELOG.md index 5ba853760..142598778 100644 --- a/packages/plugin-workflow/CHANGELOG.md +++ b/packages/plugin-workflow/CHANGELOG.md @@ -1,5 +1,24 @@ # @object-ui/plugin-workflow +## 6.3.0 + +### Patch Changes + +- Updated dependencies [c12986e] +- Updated dependencies [ddbe4a2] +- Updated dependencies [2d47e94] +- Updated dependencies [2eb3096] +- Updated dependencies [d16566f] +- Updated dependencies [90acb7f] +- Updated dependencies [7913390] +- Updated dependencies [abe8ebc] +- Updated dependencies [300d755] +- Updated dependencies [8d1195d] + - @object-ui/core@6.3.0 + - @object-ui/react@6.3.0 + - @object-ui/types@6.3.0 + - @object-ui/components@6.3.0 + ## 6.2.3 ### Patch Changes diff --git a/packages/plugin-workflow/package.json b/packages/plugin-workflow/package.json index 81cccc438..a22aa1120 100644 --- a/packages/plugin-workflow/package.json +++ b/packages/plugin-workflow/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/plugin-workflow", - "version": "6.2.3", + "version": "6.3.0", "type": "module", "main": "dist/index.umd.cjs", "module": "dist/index.js", diff --git a/packages/providers/CHANGELOG.md b/packages/providers/CHANGELOG.md index a7fb11a53..c589011ee 100644 --- a/packages/providers/CHANGELOG.md +++ b/packages/providers/CHANGELOG.md @@ -1,5 +1,14 @@ # @object-ui/providers — Changelog +## 6.3.0 + +### Patch Changes + +- Updated dependencies [ddbe4a2] +- Updated dependencies [d16566f] +- Updated dependencies [300d755] + - @object-ui/types@6.3.0 + ## 6.2.3 ### Patch Changes diff --git a/packages/providers/package.json b/packages/providers/package.json index 8013c69c0..872421e9e 100644 --- a/packages/providers/package.json +++ b/packages/providers/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/providers", - "version": "6.2.3", + "version": "6.3.0", "type": "module", "license": "MIT", "description": "Reusable context providers for ObjectUI applications", diff --git a/packages/react/CHANGELOG.md b/packages/react/CHANGELOG.md index 4284843f3..6bfaef5ac 100644 --- a/packages/react/CHANGELOG.md +++ b/packages/react/CHANGELOG.md @@ -1,5 +1,102 @@ # @object-ui/react +## 6.3.0 + +### Minor Changes + +- c12986e: Add resultDialog + target interpolation for one-shot action reveals + + Some platform actions return values the user MUST copy now because the + server will not surface them again — 2FA TOTP URI + backup codes, freshly + minted OAuth client_secret, regenerated recovery codes. Previously these + had to ship as bespoke pages in `apps/account` because actions only + emitted a fire-and-forget toast. + + **`@object-ui/core` — ActionRunner** + - New `ActionDef.resultDialog: ResultDialogSpec` field. When set on a + successful action, the runner suppresses the `successMessage` toast and + awaits the registered `ResultDialogHandler` instead. Missing handler is + non-fatal (logs a warning); rejected handler is treated as acknowledged. + - New `setResultDialogHandler(handler)` setter. + - New types: `ResultDialogSpec`, `ResultDialogFieldSpec`, + `ResultDialogHandler`. + - `executeUrl` and `executeAPI` now run `${param.X}` and `${ctx.X}` + interpolation against `target` before fetching / navigating. Values are + `encodeURIComponent`'d, missing keys resolve to empty string. `ctx` + exposes `origin`, `user`, `org`, `recordId` by default; consumers can + inject more via `context.ctx`. + + **`@object-ui/react`** + - `ActionProvider` and `useActionRunner` both gained an `onResultDialog` + option that wires straight through to the runner. + + **`@object-ui/app-shell`** + - New `ActionResultDialog` component — promise-based, blocks click-outside + and Escape (the user MUST click acknowledge), renders five field + formats: `qrcode` (client-side via the `qrcode` package — never sent + off-device, so 2FA URIs stay secret), `code-list`, `secret`, `text`, + `json`. Falls back to `json` when a value's shape doesn't match its + declared format. + - `ObjectView` and `RecordDetailView` install the handler and mount the + dialog automatically, so any action with `resultDialog` declared in + metadata now works without code changes. + - New dependency: `qrcode@^1.5.x` for client-side QR rendering. + + Pairs with the framework-side `Action.resultDialog` schema added in + `@objectstack/spec` and the `sys_two_factor` / `sys_oauth_application` / + `sys_account` updates in `@objectstack/platform-objects`. + +### Patch Changes + +- abe8ebc: Repoint `useClientNotifications` to the ADR-0030 `@objectstack/client` surface + + The `useClientNotifications` bridge hook called `client.notifications.*` with + signatures that no longer exist on `@objectstack/client@7.x`: + - `registerDevice(token, platform)` → the SDK takes a single + `RegisterDeviceRequest` object (`{ token, platform }`). + - `markAsRead(id)` → there is no single-id method; the SDK exposes + `markRead(ids: string[])`. The hook keeps its friendly single-id API and + adapts to the batch call. + + These helpers are the stable transport contract for ADR-0030 (Notification + Convergence): server-side they route to the L5 `sys_inbox_message` + materialization and the `sys_notification_receipt` read-state spine — the + re-modeled `sys_notification` L2 event no longer carries recipient/read + columns. (The Console bell itself reads the inbox + receipts directly via the + generic data API; see the `@object-ui/app-shell` bell cut-over.) + + ## Cut-over sequence (operational — run in this order) + + The Console UI repoint must land together with the framework pipeline **and** + the data migration so the bell is never blank and read-state is never lost: + 1. Deploy the framework ADR-0030 change (objects + `emit()` + producers). New + notifications now land in `sys_inbox_message` + `sys_notification_receipt`. + 2. Run the data migration **once** to carry existing notifications across — + `migrateSysNotificationToEvent({ driver, data })` from + `@objectstack/metadata/migrations`. It splits each legacy `sys_notification` + inbox row into a `sys_inbox_message` + receipt, rewrites the row to the event + shape, and clears the legacy columns. It is **idempotent** and reports + `not_applicable` on fresh installs. This runs against the ObjectStack + **server/data engine** — it is not a Console (frontend) step. + 3. Deploy the objectui repoint (this change + the `@object-ui/app-shell` bell + cut-over). + +- Updated dependencies [c12986e] +- Updated dependencies [30ee761] +- Updated dependencies [ddbe4a2] +- Updated dependencies [2d47e94] +- Updated dependencies [97c6831] +- Updated dependencies [a58c6b8] +- Updated dependencies [18d0339] +- Updated dependencies [d16566f] +- Updated dependencies [300d755] +- Updated dependencies [2f31406] +- Updated dependencies [8d1195d] + - @object-ui/core@6.3.0 + - @object-ui/data-objectstack@6.3.0 + - @object-ui/types@6.3.0 + - @object-ui/i18n@6.3.0 + ## 6.2.3 ### Patch Changes diff --git a/packages/react/package.json b/packages/react/package.json index da16db09f..3787d1622 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/react", - "version": "6.2.3", + "version": "6.3.0", "type": "module", "license": "MIT", "description": "React bindings and SchemaRenderer component for Object UI", diff --git a/packages/runner/CHANGELOG.md b/packages/runner/CHANGELOG.md index 2c8250678..b463a74d6 100644 --- a/packages/runner/CHANGELOG.md +++ b/packages/runner/CHANGELOG.md @@ -1,5 +1,26 @@ # @object-ui/runner +## 6.3.0 + +### Patch Changes + +- Updated dependencies [c12986e] +- Updated dependencies [ddbe4a2] +- Updated dependencies [2d47e94] +- Updated dependencies [2eb3096] +- Updated dependencies [d16566f] +- Updated dependencies [90acb7f] +- Updated dependencies [7913390] +- Updated dependencies [abe8ebc] +- Updated dependencies [300d755] +- Updated dependencies [8d1195d] + - @object-ui/core@6.3.0 + - @object-ui/react@6.3.0 + - @object-ui/types@6.3.0 + - @object-ui/components@6.3.0 + - @object-ui/plugin-charts@6.3.0 + - @object-ui/plugin-kanban@6.3.0 + ## 6.2.3 ### Patch Changes diff --git a/packages/runner/package.json b/packages/runner/package.json index 10f950dc1..3aa8489ce 100644 --- a/packages/runner/package.json +++ b/packages/runner/package.json @@ -1,7 +1,7 @@ { "name": "@object-ui/runner", "private": false, - "version": "6.2.3", + "version": "6.3.0", "description": "Universal Object UI Application Runner", "type": "module", "homepage": "https://www.objectui.org/docs/utilities/runner", diff --git a/packages/tenant/CHANGELOG.md b/packages/tenant/CHANGELOG.md index 8780ffb05..b547048a9 100644 --- a/packages/tenant/CHANGELOG.md +++ b/packages/tenant/CHANGELOG.md @@ -1,5 +1,14 @@ # @object-ui/tenant +## 6.3.0 + +### Patch Changes + +- Updated dependencies [ddbe4a2] +- Updated dependencies [d16566f] +- Updated dependencies [300d755] + - @object-ui/types@6.3.0 + ## 6.2.3 ### Patch Changes diff --git a/packages/tenant/package.json b/packages/tenant/package.json index 7128494e2..f4abc73f3 100644 --- a/packages/tenant/package.json +++ b/packages/tenant/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/tenant", - "version": "6.2.3", + "version": "6.3.0", "type": "module", "license": "MIT", "description": "Multi-tenancy support for Object UI with tenant isolation, scoped queries, and custom branding.", diff --git a/packages/types/CHANGELOG.md b/packages/types/CHANGELOG.md index 74ee2e51e..1b708e448 100644 --- a/packages/types/CHANGELOG.md +++ b/packages/types/CHANGELOG.md @@ -1,5 +1,43 @@ # @object-ui/types +## 6.3.0 + +### Minor Changes + +- ddbe4a2: B2 step 3: client-side field-level conditional rules (`visibleWhen` / `readonlyWhen` / `requiredWhen`). The form renderer now evaluates these CEL predicates reactively against the live record and gates each field's visibility, read-only state, and required-ness accordingly. Evaluation delegates to the canonical `@objectstack/formula` `ExpressionEngine` — the _same_ dialect the server enforces (`requiredWhen` in the rule-validator, `readonlyWhen` in `stripReadonlyWhenFields`) — so the UX and the persisted verdict always agree. New core helpers `evalFieldPredicate` / `resolveFieldRuleState` (zero-React, fail-open). `FormField` gains `visibleWhen` / `readonlyWhen` / `requiredWhen` (+ deprecated `conditionalRequired` alias), and `ObjectForm` carries them through from object metadata. +- d16566f: Atomic master-detail create via the cross-object transactional batch endpoint (ObjectStack #1604). + + When the server exposes the transactional batch endpoint, a NEW parent record and its child line items are now persisted in ONE server transaction — commit all or roll back all — instead of the previous client-orchestrated "create parent → create children → best-effort cleanup on failure" sequence. + + **`@object-ui/data-objectstack` — `ObjectStackAdapter.batchTransaction(operations)`** + - New method posting `{ operations }` to `POST /api/v1/batch`. Operations run in one server transaction. A field value of `{ $ref: }` resolves to that op's generated id, so a child can reference its parent created earlier in the same batch (master-detail FK). Throws `ObjectStackError('BATCH_ERROR')` on a non-2xx response. + + **`@object-ui/plugin-form`** + - `MasterDetailForm` now detects `dataSource.batchTransaction` and, on a NEW parent, builds one atomic batch (parent at index 0, each child FK set to `{ $ref: 0 }`) via the new pure helper `buildMasterDetailBatch`. Client-side total rollups are merged into the parent payload before the batch. Edit mode and adapters without `batchTransaction` keep the existing client-orchestrated path. + - `ObjectForm` gained a `submitHandler` hook: when supplied, the form validates and hands the collected values to the host instead of calling `dataSource.create` / `dataSource.update`. `MasterDetailForm` uses it to own the atomic parent+children write while the parent fields are still rendered by `ObjectForm`. + + **`@object-ui/types`** + - `ObjectFormSchema.submitHandler?: (values) => any | Promise` — typed override for host-owned persistence. + + Pairs with the framework-side ambient-transaction fix (ObjectQL `AsyncLocalStorage` transaction propagation) and the `/api/v1/batch` endpoint added in `@objectstack/rest`. + +- 300d755: feat(form): inline master-detail in a plain ObjectForm via `subforms` + + `ObjectFormSchema` gains a `subforms` array. When set, a regular `object-form` + renders as a master-detail form — the object's own fields on top, an editable + grid per child collection below, persisted together in one atomic transaction — + without a bespoke `object-master-detail-form` page. + + ```ts + { type: 'object-form', objectName: 'expense_claim', + subforms: [{ childObject: 'expense_line' }] } // FK + columns auto-derived + ``` + + Each subform needs only `childObject` (relationship FK and columns are derived + from the child object's metadata; override with `relationshipField`/`columns`). + This is the config-driven, page-less way to express master-detail entry — a form + view can declare its child collections directly. + ## 6.2.3 ## 6.2.2 diff --git a/packages/types/package.json b/packages/types/package.json index c40c8c3dc..748ccbe21 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/types", - "version": "6.2.3", + "version": "6.3.0", "description": "Pure TypeScript type definitions for Object UI - The Protocol Layer", "type": "module", "sideEffects": false, diff --git a/packages/vscode-extension/CHANGELOG.md b/packages/vscode-extension/CHANGELOG.md index ef86010ee..7dde98406 100644 --- a/packages/vscode-extension/CHANGELOG.md +++ b/packages/vscode-extension/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 6.3.0 + +### Patch Changes + +- Updated dependencies [c12986e] +- Updated dependencies [ddbe4a2] +- Updated dependencies [2d47e94] +- Updated dependencies [d16566f] +- Updated dependencies [300d755] +- Updated dependencies [8d1195d] + - @object-ui/core@6.3.0 + - @object-ui/types@6.3.0 + ## 6.2.3 ### Patch Changes diff --git a/packages/vscode-extension/package.json b/packages/vscode-extension/package.json index fb9417af4..e7fba2901 100644 --- a/packages/vscode-extension/package.json +++ b/packages/vscode-extension/package.json @@ -2,7 +2,7 @@ "name": "object-ui", "displayName": "Object UI", "description": "VSCode extension for Object UI - Schema-driven UI development with IntelliSense, validation, and live preview", - "version": "6.2.3", + "version": "6.3.0", "publisher": "objectui", "private": true, "icon": "icon.svg",