diff --git a/.changeset/action-param-upload-guard.md b/.changeset/action-param-upload-guard.md deleted file mode 100644 index 149dd0dc6..000000000 --- a/.changeset/action-param-upload-guard.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -"@object-ui/fields": patch -"@object-ui/app-shell": patch -"@object-ui/i18n": patch ---- - -fix(app-shell): block ActionParamDialog submit while a file/image param is uploading; map spec `autonumber` (ADR-0059 follow-ups) - -Two follow-ups to the shared-field-widget param rendering (ADR-0059): - -- **Upload-in-progress guard.** A `file`/`image` param's value only becomes its - fileId once the presigned upload settles, so confirming mid-upload sent an - empty/stale value. `FileField`/`ImageField` now surface their upload state via - an optional `onUploadingChange` prop (shared `useUploadingSignal` hook, - ignored by other widgets); `ActionParamDialog` wires it for `file`/`image` - params and disables Confirm (label → "Uploading…", new `actionDialog.uploading` - i18n key across all locales) plus blocks submit while any upload is in flight. -- **`autonumber` spelling.** `mapFieldTypeToFormType` now maps the spec - `FieldType` spelling `autonumber` (in addition to the widget-map key - `auto_number`) to the AutoNumber widget, so a spec-typed `autonumber` - field/param no longer falls through to the plain text input — fixes the object - form path as well as action params. diff --git a/.changeset/action-params-shared-field-widgets.md b/.changeset/action-params-shared-field-widgets.md deleted file mode 100644 index 8abd444b9..000000000 --- a/.changeset/action-params-shared-field-widgets.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -"@object-ui/fields": minor -"@object-ui/core": minor -"@object-ui/app-shell": minor ---- - -feat(app-shell): render ActionParamDialog params through the shared form field-widget renderer (ADR-0059, #2700) - -`ActionParamDialog` no longer hand-rolls a per-type ternary chain (select / -lookup / textarea / number / boolean, everything else → text input). Every -declared action param now renders through the same `fieldWidgetMap` the object -form uses, so a param of ANY form-supported field type — `file`, `image`, -`richtext`, `markdown`, `color`, `address`, `code`, `date`, … — gets its real -widget, lazily loaded behind `Suspense`. Subsumes the single `file` branch ask -in #2698: `type: 'file'` params render the real `FileField` upload control via -the ambient `UploadProvider`, honoring `multiple`/`accept`/`maxSize`. - -- `@object-ui/fields`: new exports `resolveFormWidgetType(type)` (widget-key - resolution incl. spec aliases, text fallback) and `getLazyFieldWidget(type)` - (per-type-cached `React.lazy` over the form's own widget loaders). -- `@object-ui/core`: `ActionParamDef` gains `accept`/`maxSize`; `multiple` is - now general widget config (was lookup-only). -- `@object-ui/app-shell`: new pure `paramToField()` adapter (param → field - shape) with a drift test pinning param support ⊇ form support (`FORM_FIELD_TYPES`), - mirroring the FieldEditWidget parity guard; `resolveActionParams()` inherits - `multiple`/`accept`/`maxSize` from the referenced field for every type. - `required` validation, `visible` CEL gating, helpText, error styling, and - value shapes for previously-supported types are unchanged. diff --git a/.changeset/action-result-dialog-i18n.md b/.changeset/action-result-dialog-i18n.md deleted file mode 100644 index a72ee63bf..000000000 --- a/.changeset/action-result-dialog-i18n.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -"@object-ui/i18n": minor -"@object-ui/app-shell": patch ---- - -feat(i18n): localize action result dialogs via the `_actions..resultDialog` convention - -The post-success secret-reveal dialog (create-user temporary password, 2FA -backup codes, OAuth client secrets) always rendered the hardcoded English -metadata literals — the spec bundles now carry `resultDialog` translations -(objectstack `_actions..resultDialog.*`), but nothing resolved them -client-side. - -- **@object-ui/i18n.** `useObjectLabel()` gains `actionResultDialog(objectName, - actionName, spec)`: overlays translated `title` / `description` / - `acknowledge` and per-field labels onto the metadata spec, falling back to - the literals. The `fields` node is keyed by the LITERAL result-field path - (may contain dots, e.g. `"user.email"`), so it is fetched whole with - `returnObjects` and indexed directly — never resolved through a dotted - i18next key. Built-in locale packs also translate the dialog's fallback - `defaultTitle` / `acknowledge` (previously English in all ten locales) and - add the new `actions.resultDialog.copyAll` key. -- **@object-ui/app-shell.** The result-dialog handlers in - `useConsoleActionRuntime` and `RecordDetailView` accept the action context - (already passed by `ActionRunner`) and localize the spec before opening the - dialog; `ActionResultDialog`'s hardcoded "Copy all" button now goes through - `actions.resultDialog.copyAll`. diff --git a/.changeset/align-objectstack-deps-15.md b/.changeset/align-objectstack-deps-15.md deleted file mode 100644 index 5cc9d27a6..000000000 --- a/.changeset/align-objectstack-deps-15.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -"@object-ui/core": patch -"@object-ui/app-shell": patch -"@object-ui/data-objectstack": patch -"@object-ui/console": patch ---- - -chore(deps): align `@objectstack/formula` / `lint` / `client` to `^15.1.1` - -These three were still pinned to `^14.6.0` while `@objectstack/spec` was already -`^15.1.1` — a version skew from the v15 upgrade (formula/lint/client publish in -lockstep with spec, and their own 15.0.0 entries are pure dependency bumps, so -this is alignment, not a behavioral migration). - -Practical effect: the client-side field-rule evaluation -(`visibleWhen`/`readonlyWhen`/`requiredWhen` via `fieldRules.ts`, which delegates -to `@objectstack/formula`'s `ExpressionEngine`) now tracks the 15.x engine — and -will pick up the framework's `dateField == today()` equality fix -(objectstack-ai/framework#3205) automatically at the next 15.x release via the -caret range. Renderer/action `visible`/`disabled` predicates are unaffected (they -use the home-grown JS evaluator — tracked separately in #2661). diff --git a/.changeset/align-objectstack-deps-16-rc.md b/.changeset/align-objectstack-deps-16-rc.md deleted file mode 100644 index e31efef14..000000000 --- a/.changeset/align-objectstack-deps-16-rc.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -"@object-ui/types": patch -"@object-ui/core": patch -"@object-ui/app-shell": patch -"@object-ui/data-objectstack": patch -"@object-ui/react": patch -"@object-ui/plugin-detail": patch -"@object-ui/plugin-form": patch -"@object-ui/plugin-gantt": patch -"@object-ui/plugin-map": patch -"@object-ui/plugin-timeline": patch -"@object-ui/plugin-tree": patch -"@object-ui/plugin-view": patch -"@object-ui/console": patch ---- - -chore(deps): align every `@objectstack/*` dependency to `^16.0.0-rc.0` - -Bumps `@objectstack/spec` / `client` / `formula` / `lint` from `^15.1.1` to the -`16.0.0-rc.0` pre-release across the workspace (root + `apps/console` + -`apps/site` + all consuming packages). ObjectUI's own packages are already on -major 16, so this closes the 15↔16 skew between ObjectUI and the `@objectstack` -contract libraries (which publish in lockstep with `spec`). - -This is a dependency alignment, not a behavioral migration: the full workspace -build (43/43) and the `@objectstack`-consuming package test suites -(`core` / `app-shell` / `data-objectstack` / `plugin-form` / `types`) are green -against `16.0.0-rc.0` with no source changes required. - -Practical effect: `@objectstack/client@16.0.0-rc.0` now ships -`data.batchTransaction` (framework #3271), so `ObjectStackAdapter`'s feature -detect (`typeof client.data.batchTransaction === 'function'`) routes -master-detail cross-object saves through the typed SDK method instead of the -raw `fetch('/api/v1/batch')` fallback — realizing the "verify SDK path" half of -#2694. The raw-fetch branch stays as a defensive fallback (removal tracked in -#2694). diff --git a/.changeset/api-provider-auth-fetch.md b/.changeset/api-provider-auth-fetch.md deleted file mode 100644 index 1f3ad4cf1..000000000 --- a/.changeset/api-provider-auth-fetch.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -"@object-ui/react": minor -"@object-ui/auth": minor -"@object-ui/app-shell": patch -"@object-ui/plugin-gantt": patch ---- - -feat(data): thread the host's authenticated fetch into `provider: 'api'` data sources (#2725) - -`provider: 'api'` view data sources went through a bare `globalThis.fetch`, so -custom endpoints (gantt composite trees, report aggregates) carried only -same-origin cookies while every native `/api/v1/*` request carried -`Authorization: Bearer` — the moment cookie HMAC verification failed (dev -restart rotating the fallback auth secret, cookie expiry/rotation in prod) -those views 401'd while the rest of the app kept working. - -- **`@object-ui/react`** — `SchemaRendererProvider` accepts an optional - `apiFetch`; nested providers inherit it from their parent so re-wrapped - subtrees (react pages, preview surfaces) keep the host's authentication. - `useViewData` defaults the api-provider adapter's fetch to the context - `apiFetch` (explicit `adapterOptions.fetch` still wins). -- **`@object-ui/auth`** — `createAuthenticatedFetch` gains a - `sameOriginOnly` option: cross-origin URLs pass through to the bare fetch - with no `Authorization` / `X-Tenant-ID` / `Accept-Language`, so metadata- - supplied third-party URLs never see the platform token. -- **`@object-ui/app-shell`** — the console wires - `createAuthenticatedFetch({ sameOriginOnly: true })` (settle-signal wrapped) - as `apiFetch` on the root `SchemaRendererProvider`. -- **`@object-ui/plugin-gantt`** — `ObjectGantt` resolves its api-provider - DataSource with the context `apiFetch`, covering reads and write-backs. - -Behaviour is unchanged for hosts that don't provide `apiFetch` (bare fetch + -cookies, as before). diff --git a/.changeset/approvals-composer-retire-file-params.md b/.changeset/approvals-composer-retire-file-params.md deleted file mode 100644 index bf64076a5..000000000 --- a/.changeset/approvals-composer-retire-file-params.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -"@object-ui/app-shell": minor -"@object-ui/fields": patch ---- - -feat(action-params): serialize file/image action params to storage id(s); retire the approvals composer - -Declared action params of `type: 'file'`/`'image'` now POST the portable API -contract — the storage id(s) — instead of the upload widget's rich object: - -- `FileField` surfaces the id it already receives from the upload adapter - (`meta.fileId`) as `file_id` on each emitted file object (additive; the - record file-field value shape is unchanged). -- `ActionParamDialog` maps upload-param values to their `file_id`(s) at submit - (`serializeParamValues`, pure + exported): single → string, `multiple` → - `string[]`. The api handler already forwards param values untouched, so an - action with a `file` param POSTs `attachments: string[]`. - -This lets the approvals inbox retire its last hand-wired UI — the approve/reject -composer with its bespoke attachment upload — so the drawer renders every -decision through `DeclaredActionsBar` with the declared `attachments` file param -(framework side declares it; see the paired framework change). `DeclaredActionsBar`'s -`exclude` prop stays as a general capability. diff --git a/.changeset/approvals-viewer-gating-sync.md b/.changeset/approvals-viewer-gating-sync.md deleted file mode 100644 index 98ef836d8..000000000 --- a/.changeset/approvals-viewer-gating-sync.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -"@object-ui/console": patch ---- - -fix(approvals-inbox): align participant gating with the server-computed `viewer` block - -Consume framework#3310's per-viewer capability: `ApprovalRequestRow` gains an -optional `viewer: { can_act, is_submitter }`, and the approvals inbox's -participant checks (the reply box + the "why disabled" hint) prefer it over the -client-side identity heuristic when present. This keeps the hint from ever -contradicting the declared decision buttons — whose `visible` CEL now gates on -`record.viewer.*` — and correctly recognizes position/team-addressed approvers -that the client heuristic couldn't resolve. The heuristic remains as a fallback -for a backend that predates `viewer`. diff --git a/.changeset/batch-transactional-capability-gate.md b/.changeset/batch-transactional-capability-gate.md deleted file mode 100644 index 2023e068e..000000000 --- a/.changeset/batch-transactional-capability-gate.md +++ /dev/null @@ -1,32 +0,0 @@ ---- -"@object-ui/data-objectstack": minor ---- - -feat(data-objectstack): gate the non-atomic batch fallback on the discovery `transactionalBatch` capability (#2693) - -`ObjectStackAdapter.batchTransaction` now negotiates atomic cross-object batch -**declaratively** instead of only probing at runtime. At `connect()` the adapter -reads `capabilities.transactionalBatch` from `GET /api/v1/discovery` -(framework #3298 — `declared === enforced`; the server advertises `true` only -when the `/batch` route is mounted *and* the runtime engine can honour a -transaction): - -- **Declared `true`** — the adapter TRUSTS server atomicity: it calls `/batch` - and surfaces any failure (including `404`/`405`/`501`) as a real error. No - runtime probe, no non-atomic client-side compensation. -- **Declared `false`, or absent** (backend predates #3298) — the legacy path is - unchanged: probe `/batch` and, on `404`/`405`/`501`, fall back to the - non-atomic `emulateBatchTransaction`. Keeping this avoids regressing older - backends from "saves, less safe" to "no save path" (#2679 compat constraint). - -Both the hierarchical wire shape (`{ transactionalBatch: { enabled: true } }`) -and the flat form the client SDK normalizes to (`{ transactionalBatch: true }`) -are accepted. `@object-ui/core`'s generic `emulateBatchTransaction` / -`runBatchTransaction` are untouched and remain the fallback for adapters with no -server-side transaction (`ValueDataSource`, `MockDataSource`, …). - -Docs: the adapter README and the data-source guide now document the capability -table and the minimum-backend note — atomic cross-object saves are guaranteed -only against backends advertising the capability (framework #3298 / #1604). - -Picks up #2679 acceptance item 4; unblocked by framework#3298 (merged). diff --git a/.changeset/cel-renderer-predicates.md b/.changeset/cel-renderer-predicates.md deleted file mode 100644 index e6820b068..000000000 --- a/.changeset/cel-renderer-predicates.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -"@object-ui/core": minor -"@object-ui/react": minor ---- - -feat(evaluator): route `{ dialect: 'cel' }` component/action predicates to the canonical CEL engine (#2661) - -Component and action `visible` / `disabled` / `hidden` predicates were evaluated -by the home-grown JS `ExpressionEvaluator`, while field rules -(`visibleWhen`/`readonlyWhen`/`requiredWhen`, via `fieldRules.ts`) and row/list -conditionals (via `evalRowPredicate`) already delegate to the canonical -`@objectstack/formula` engine. That split meant a `{ dialect: 'cel' }` predicate -in a renderer/action surface was executed as **JavaScript** — CEL-only forms -(`x in list`, `has()`, typed `==`, the `today()`/`daysFromNow()` catalog) behaved -differently from, or faulted against, the server's enforcement. - -This converges the remaining tier onto the same engine: - -- **`@object-ui/core`** — `ExpressionEvaluator.evaluateCondition` now detects a - `{ dialect: 'cel', source }` envelope and evaluates it on `@objectstack/formula` - (via `evalFieldPredicate`), binding the `record` namespace plus the whole - context bag as top-level scope (`record.*`, `features.*`, `user.*`, `app.*`). - Fail-soft to visible/enabled to match the legacy default; `throwOnError` - callers still fail closed on a *faulting* predicate (a genuine `false` never - throws). This fixes every `SchemaRenderer` visibility/disabled read at once. -- **`@object-ui/react`** — `toPredicateInput` preserves a CEL envelope instead of - collapsing it to a `${source}` string, and `useCondition` accepts and forwards - the envelope (keyed on a stable `(dialect, source)` so it doesn't re-evaluate - each render). Action buttons (`action-icon`/`group`/`bar`/`button`) therefore - evaluate CEL `visible`/`enabled`/`disabled` on the canonical engine. - -**Back-compat:** bare strings and `${…}` templates stay on the legacy JS path -(deprecation window); only an explicit `{ dialect: 'cel' }` envelope is rerouted. -`{ dialect: 'template' }` is unaffected. - -Together with the `^15.1.1` alignment (#2662), a renderer CEL predicate now -reaches the identical verdict as the server — including the framework's -`dateField == today()` equality fix (objectstack-ai/framework#3205) once it -lands in a published 15.x. The broader home-grown-vs-canonical divergence -motivation is #2661. diff --git a/.changeset/checkboxes-cascade-parity.md b/.changeset/checkboxes-cascade-parity.md deleted file mode 100644 index 7ae746eed..000000000 --- a/.changeset/checkboxes-cascade-parity.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -"@object-ui/fields": minor -"@object-ui/components": patch ---- - -feat(fields): CheckboxesField per-option `visibleWhen` cascading + `dependsOn` gating (completes the option-widget parity set) - -`checkboxes` was the last static-option widget still rendering `config.options` -raw — with no per-option `visibleWhen` filtering, `dependsOn` gating, or cascade -clear. It now matches `MultiSelectField` (its multi-value sibling), completing -the ADR-0058 parity across `select` / `multiselect` / `radio` / `checkboxes`. - -- **`@object-ui/fields`**: `CheckboxesField` routes through the shared - `useCascadingOptions` hook — offered boxes narrow against the live record + - `current_user`, the control gates behind a "select the parent first" hint - while a `dependsOn` field is empty, and selections no longer offered are - pruned per-element from the array. Adds `checkboxes-empty-*` / - `checkboxes-option-*` testids. -- **`@object-ui/components`**: adds `checkboxes` to the form renderer's option - field sets (`CASCADE_OPTION_FIELD_TYPES`, the cross-field cascade-clear - effect, and the option pre-filter) so a `checkboxes` field is threaded - `dependentValues` and gated identically to the other option widgets. -- Tests: `CheckboxesField.cascade.test.tsx` mirrors `MultiSelectField.cascade.test.tsx`. diff --git a/.changeset/dashboard-dataset-authoring-3251.md b/.changeset/dashboard-dataset-authoring-3251.md deleted file mode 100644 index 88497d281..000000000 --- a/.changeset/dashboard-dataset-authoring-3251.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -"@object-ui/types": minor -"@object-ui/plugin-dashboard": minor -"@object-ui/app-shell": minor ---- - -feat(dashboard): Studio authors the ADR-0021 dataset shape only (framework#3251) - -Finishes the dashboard analytics migration on the authoring side so the -framework can enable `DashboardWidgetSchema.strict()`. Both Studio surfaces now -emit only the semantic-layer shape (`dataset` + `dimensions` + `values`); no -surface authors the removed pre-ADR-0021 inline query. - -**FROM → TO** (authoring) - -- charts: `object` + `categoryField` + `valueField` + `aggregate` - → `dataset` + `dimensions` + `values` -- pivots: `object` + `rowField` + `columnField` + `valueField` + `aggregation` - → `dataset` + `dimensions` + `values` (last dimension spreads across columns) - -**Changes** - -- `@object-ui/types` — `DashboardWidgetSchema` gains `dataset` / `dimensions` / - `values`; the inline analytics keys (`object`, `categoryField`, - `categoryGranularity`, `valueField`, `aggregate`, `measures`) are marked - `@deprecated` (retained only so the renderer can still read legacy/static - metadata during the transition). -- `@object-ui/plugin-dashboard` — `WidgetConfigPanel` is rewritten as a dataset - picker (chart AND pivot). **Breaking prop change:** the unused - `availableObjects` / `availableFields` props are replaced by a new - `datasets?: WidgetDatasetCatalogEntry[]` (+ `datasetsLoading?`) catalog prop, - also forwarded by `DashboardWithConfig`. Hosts resolve the catalog (e.g. via - the metadata client's `list('dataset')`); without it the panel falls back to - free-text authoring. New exports: `WidgetDatasetCatalogEntry` and - `sanitizeDraftForType`. -- `@object-ui/app-shell` — the metadata-admin `DashboardWidgetInspector` drops - the legacy inline fields (object / value field / category field / aggregate); - the dataset section is now the primary (and only) analytics binding, and the - filter-binding field picker sources options from the bound dataset's - dimensions. The "Add widget" catalog drops `list` / `custom` — neither is a - member of `@objectstack/spec` `ChartTypeSchema`, so a widget authored with - them could never publish. - -**Not changed:** `DashboardRenderer` keeps its legacy/static read branches and -the `ObjectPivotTable` / `PivotTable` blocks (still public SDUI blocks and the -backward-compat path for stored/static widgets) — only the dashboard authoring -flow stops emitting the legacy keys. Retiring those renderer branches is a -follow-up gated on migrating stored dashboards. diff --git a/.changeset/detail-title-creator-2688.md b/.changeset/detail-title-creator-2688.md deleted file mode 100644 index 44ef67e71..000000000 --- a/.changeset/detail-title-creator-2688.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -"@object-ui/plugin-detail": patch ---- - -fix(plugin-detail): #2688 — record surfaces without a caller title no longer floor to `Record #`, and the meta footer never prints a raw audit user id - -- `DetailView` header: after every declared-identity step misses and no - `schema.title` was provided, probe name-ish record keys (`name`, `title`, - `*_name`, …) before falling to the `Record #` floor. Fixes records whose - name lives in a field the type-aware derivation deliberately skips (e.g. an - `autonumber` `name`) opened from surfaces like the gantt row drawer. -- `RecordMetaFooter`: `created_by` / `updated_by` are always user references on - ObjectStack — when the fetched schema omits the audit system fields, default - the reference target to `sys_user` so the footer renders a resolved user name - (or the muted placeholder) instead of the raw opaque id. diff --git a/.changeset/flow-designer-nested-regions.md b/.changeset/flow-designer-nested-regions.md deleted file mode 100644 index ca3b4f421..000000000 --- a/.changeset/flow-designer-nested-regions.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -"@object-ui/app-shell": minor ---- - -feat(studio): expand loop / parallel / try_catch regions inline on the flow designer canvas (#2670) - -The flow designer rendered ADR-0031 structured control-flow containers -(`loop` / `parallel` / `try_catch`) as opaque single node cards — their nested -regions (`config.body` / `config.branches[]` / `config.try`/`catch`) were only -visible, and only editable, as raw JSON in the inspector's Advanced block. - -A container card now carries an expand chevron that grows the card **in place** -to embed its region(s) as a read-only mini-canvas — the same top-to-bottom -node/edge layout as the parent graph, scaled to fit the card width — with a -header per region (a named branch or `Branch N`, and `Try` / `Catch`; a loop -body has none). The canvas layout is geometry-aware: the layers below an -expanded container are **pushed down** by its real height and its outgoing edge -leaves from its true bottom. Collapsed by default; expansion is session-only -view state (never written to the flow draft). Legacy flat loops (a `loop` with -no `config.body`) and all ordinary nodes render exactly as before — with no -expanded container the layout is identical to the previous release, locked by -invariance tests. - -Known limitation: a node pinned via a manual drag position sitting at/below an -expanded container can overlap it (manual positions are absolute); drag it -clear or collapse the container. diff --git a/.changeset/flow-designer-schedule-fix.md b/.changeset/flow-designer-schedule-fix.md deleted file mode 100644 index 6a7cccf87..000000000 --- a/.changeset/flow-designer-schedule-fix.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -"@object-ui/app-shell": patch ---- - -fix(flow-designer): author the canonical `config.schedule` a scheduled flow's runtime reads - -The start-node inspector's "Cron schedule" field wrote a flat `config.cron`, but the -automation runtime (`resolveTriggerBinding` → `normalizeSchedule`) only ever reads -`config.schedule` — so a scheduled flow authored in the designer silently never -bound and never fired. The field now writes the canonical nested -`config.schedule.expression`, and a `fallbackPath` migrates an existing flat -`config.cron` on first edit. Reading `.expression` also renders an object-shaped -`config.schedule` (e.g. `{ type: 'cron', expression }`) as its cron string instead of -"[object Object]" (the old legacy text field on `config.schedule` printed the object). -The canvas node-card summary reads the nested value too. The field is also offered for -the `time_relative` sweep cadence (optional; defaults to daily). diff --git a/.changeset/flow-nested-node-inspector.md b/.changeset/flow-nested-node-inspector.md deleted file mode 100644 index c4fd431ab..000000000 --- a/.changeset/flow-nested-node-inspector.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -"@object-ui/app-shell": minor ---- - -feat(studio): select and edit nested container nodes through the schema-driven flow inspector (#2670) - -Phase 2 (#2680) expanded a container's regions (`loop.body` / -`parallel.branches[]` / `try_catch.try`/`catch`) inline on the flow designer -canvas, but the nested nodes were read-only — changing one still meant editing -the container's Advanced JSON by hand. A nested node is now a first-class -selection: click it on the expanded canvas and it opens in the SAME -schema-driven inspector as a top-level node, with a `container › region › node` -breadcrumb. Edits (label / type / description / typed config fields / Advanced -JSON) write straight back into `config..nodes[i]` — the write rebuilds -the container with explicit spreads so the `config.branches` array stays an -array and each region's own `edges` / a branch's `name` are preserved. - -Scope resolves correctly for the region's outer context (ADR-0031): a loop -body node sees the loop's `iteratorVariable` in its data picker even though the -container's own outputs are otherwise out of scope at its id. - -This phase is edit-only by design. A nested node keeps its id read-only (rename -it in the container's Advanced JSON), has no delete, and — for a nested -decision — drops the virtual Target column, since a region sub-graph's internal -routing is not managed by the inspector yet (nested region-edge editing, -structural add/remove, and drag are follow-ups). A stale nested deep link -(the draft moved on) resolves to a harmless empty-state rather than writing to -the wrong node. - -Also fixes an expression/template validation split now that the engine -publishes a loop `configSchema`: a string property can carry an `xExpression: -'expression' | 'template'` marker so the designer renders bare-CEL vs -`interpolate()` `{var}` semantics (mono editor, data-picker brace mode, and -whether the CEL brace-trap applies) instead of guessing from the field name. A -loop / map `collection` (`{leadList}`) is a template, so it no longer -false-positives as a malformed condition inline or on the canvas badge. diff --git a/.changeset/flow-runs-region-step-logs.md b/.changeset/flow-runs-region-step-logs.md deleted file mode 100644 index d2bdb4384..000000000 --- a/.changeset/flow-runs-region-step-logs.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -"@object-ui/app-shell": minor ---- - -feat(studio): nest per-iteration / per-region step logs in the flow Runs panel (#1505) - -The run-observability `FlowRunsPanel` (Studio → flow preview → Runs) rendered a -run's step log as a flat list, so a `loop` container showed as a single step and -its body steps — one set per iteration — appeared as an undifferentiated repeat -of the same node ids, with `parallel` branches and `try`/`catch` handlers -likewise flattened. The automation engine already tags each structured-region -body step with its container (`parentNodeId`) plus an `iteration` / `regionKind` -(ADR-0031, framework #1505); the panel ignored those fields. - -`FlowRunsPanel` now reconstructs the execution tree from the flat, pre-order step -log (`buildStepTree`) and nests body steps under their container node, grouped by -a per-iteration / per-branch / handler header (`Iteration 2`, `Branch 1`, `Try`, -`Catch`). The reconstruction is robust to repeated node ids (a loop body node -runs once per iteration) and to regions nested inside regions, and degrades -safely — a body step whose container was dropped by durable-history truncation -still surfaces at the top level rather than vanishing. diff --git a/.changeset/gantt-header-open-slot-align.md b/.changeset/gantt-header-open-slot-align.md deleted file mode 100644 index 4845b5d9e..000000000 --- a/.changeset/gantt-header-open-slot-align.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -"@object-ui/plugin-gantt": patch ---- - -fix(plugin-gantt): align the task-list header with the row date columns - -Every data row reserves a trailing w-6 (+4px) slot for the 「→」 open-details -button whenever `onTaskClick` is live, but the header row didn't — so the -开始/结束 header labels sat 28px to the right of the date values they caption. -The header now mirrors the slot under the same condition. diff --git a/.changeset/gantt-hide-qr-context-menu.md b/.changeset/gantt-hide-qr-context-menu.md deleted file mode 100644 index 716574840..000000000 --- a/.changeset/gantt-hide-qr-context-menu.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -"@object-ui/plugin-gantt": patch -"@object-ui/i18n": patch ---- - -feat(plugin-gantt)!: remove the 移动端二维码 (mobile QR share) context-menu item - -The QR-share feature is removed outright: the context-menu item, the QR dialog, -the `taskUrl` prop on `GanttView`, the URL wiring in `ObjectGantt`, the -`gantt.menu.qrcode` / `gantt.qr.*` i18n keys (en/zh) and the `qrcode` -dependency are all deleted. It baked one consumer's app-specific requirement -(scan-to-open on mobile) into the generic gantt renderer, and what it encoded — -the desktop console record URL — was not even the right target for that -requirement. Apps that need scan-to-mobile flows should implement them -app-side against their own mobile surface. diff --git a/.changeset/import-wizard-auto-policy.md b/.changeset/import-wizard-auto-policy.md deleted file mode 100644 index 675bea0cb..000000000 --- a/.changeset/import-wizard-auto-policy.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -"@object-ui/app-shell": minor -"@object-ui/i18n": patch ---- - -**Console user-import wizard defaults to the `auto` password policy (tracks framework#3236).** The "Sign-in setup for imported users" selector gains an **Automatic (recommended)** option and it is now the default (was "No password"). `auto` decides per row on the server: reachable users get an invitation (email / SMS), anyone who can't be reached gets a one-time password shown once on the result screen — so it works with or without an email/SMS service, and the one-time-password reveal now surfaces only the rows that actually fell back (instead of the whole batch under `temporary`). - -The other three policies are unchanged and still selectable: `invite` (force invitations, unreachable rows fail), `temporary` (force one-time passwords for every row), `none` (identity only). New `console.identityImport.policy.auto` / `policyHint.auto` strings added for `en` and `zh`; the `none` label drops its "(recommended)" marker. diff --git a/.changeset/lint-baseline-app-shell.md b/.changeset/lint-baseline-app-shell.md deleted file mode 100644 index eff8ebb07..000000000 --- a/.changeset/lint-baseline-app-shell.md +++ /dev/null @@ -1,31 +0,0 @@ ---- -"@object-ui/app-shell": patch ---- - -chore(lint): clear the baseline lint errors in app-shell (objectui#2713 Wave 3) - -Final package of the #2713 lint-gate restoration — with this the whole workspace -is at **0 lint errors**. `@object-ui/app-shell` was red at baseline on `main`; -cleared every **error** (no behavior change; warnings out of scope): - -- **`react-hooks/rules-of-hooks` (12)** — hooks called after conditional early - returns, restructured so hook order is stable: - - `SchemaForm`: hoisted the `issuesByPath` `useMemo` above the RawJsonEditor - fallback guard, and `RecordField`'s five `useState` above its widget / - specialized-editor early returns. - - `MetadataPanel`: moved `if (!open) return null` below its three hooks. - - `LayeredDiff`: moved the `if (code == null)` guard below the two `useMemo`s - and made `rows` null-safe (`code == null ? [] : computeDiffRows(...)`). - - `ViewPreview`: hoisted the `object-view` `schema` `useMemo` above the three - render branches (the earlier branches shadow it locally). -- **`react-hooks/static-components` (12)** — icon/inspector/preview lookups - (`getIcon`, `typeIcon`, `kindIcon`, `getMetadataPreview` / `…Inspector` / - `…DefaultInspector`) are stable registry references → justified scoped disables. -- **`no-useless-assignment` (3)** — dead `= null` / `= []` initializers in - `marketplaceApi` and the two ratchet tests (the only fall-through paths - reassign first). -- **`@typescript-eslint/ban-ts-comment` (2)** — the `lucide-react/dynamic.mjs` - imports in `getIcon` / `widgets` no longer error under the build's `tsc`, so - the stale `@ts-ignore` directives are removed outright. -- **stale `eslint-disable` (1)** — removed a `@next/next/no-img-element` - directive in `AgentPreview` whose plugin isn't loaded in the flat config. diff --git a/.changeset/lint-baseline-chatbot.md b/.changeset/lint-baseline-chatbot.md deleted file mode 100644 index 2041eb2e1..000000000 --- a/.changeset/lint-baseline-chatbot.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -"@object-ui/plugin-chatbot": patch ---- - -chore(lint): clear the baseline lint errors in plugin-chatbot (objectui#2713 Wave 3) - -Wave 3 of the #2713 lint-gate restoration. `@object-ui/plugin-chatbot` was red at -baseline on `main`; cleared every **error** (no behavior change; warnings out of -scope): - -- **`react-hooks/rules-of-hooks` in `useObjectChat` (8)** — the hook called - DIFFERENT `useCallback`s in each of its two `isApiMode` return branches, so - both sets were conditional (React throws if the mode toggles between renders). - `useChat` was already called unconditionally; this destructures its result and - hoists all eight callbacks (3 API + 5 local) above the `isApiMode` branch, so - the same hooks run in the same order every render. Only the returned surface - differs by mode — the callback bodies are unchanged (the API `messages` local - is renamed `apiMessages`). Verified against the `useObjectChat.sendFailure` / - `handoffContext` / `ChatbotEnhanced.sendError` suites. -- **`react-hooks/rules-of-hooks` in `FloatingChatbotTrigger`** — - `useChatbotLabel` wrapped the provider-safe `useObjectTranslation` in - try/catch; removed the wrapper (the #2709 fix). -- **`react-hooks/static-components` in `shimmer`** — `motion.create(Component)` - genuinely builds a motion component and must key off the `as` prop, so it - can't be module-scoped. Memoized per `Component` (stable across renders, - avoids the remount) and carries a justified scoped disable at the render site. diff --git a/.changeset/lint-baseline-components.md b/.changeset/lint-baseline-components.md deleted file mode 100644 index 823e8e3a4..000000000 --- a/.changeset/lint-baseline-components.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -"@object-ui/components": patch ---- - -chore(lint): clear the baseline lint errors in components (objectui#2713 Wave 3) - -Wave 3 of the #2713 lint-gate restoration. `@object-ui/components` was red at -baseline on `main`; cleared every **error** (no behavior change; warnings out of -scope): - -- **`react-hooks/rules-of-hooks`** — `react-page` `ReactKindPage` had a - capability-gate early return *before* four hooks (incl. a `useEffect` that - `import()`s the react runtime). Hoisted the hooks above the gate **and guarded - the import** (`if (!capabilityEnabled) return` inside the effect) so a disabled - build still never loads the gated runtime; the disabled notice is returned - after the hooks. Translation helpers in `empty` / `action-bar` / `action-menu` - unwrap a try/catch around the provider-safe `useObjectTranslation` (the #2709 - fix). -- **`react-hooks/static-components`** — dynamic renderer/icon lookups - (`ComponentRegistry.get`, `resolveIcon`) in `action-bar` / `action-group` ×2 / - `action-menu`, and the five `__tests__` helpers that render a registry-resolved - component, are stable references → justified scoped disables. -- **`react-hooks/purity`** — `ui/sidebar` skeleton width uses `Math.random()` - once per mount (`useMemo([])`) for a decorative placeholder → justified scoped - disable. -- **`@typescript-eslint/no-empty-object-type`** — `ShimmerSkeletonProps` empty - extend → `type` alias. -- **`no-useless-assignment`** — `test-utils` `maxDepth` dead initializer → single - `const`. -- **`no-require-imports`** — `config-panel-renderer` test uses a top-level - `import React` instead of an in-test `require`. -- **stale `eslint-disable`** — removed a `jsx-a11y/alt-text` directive in - `elements` whose plugin is not loaded in the flat config. diff --git a/.changeset/lint-baseline-dashboard.md b/.changeset/lint-baseline-dashboard.md deleted file mode 100644 index 12f5dc4a3..000000000 --- a/.changeset/lint-baseline-dashboard.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -"@object-ui/plugin-dashboard": patch ---- - -chore(lint): clear the baseline lint errors in plugin-dashboard (objectui#2713 Wave 3) - -First package of Wave 3 in the #2713 lint-gate restoration. `@object-ui/plugin-dashboard` -was red at baseline on `main`; cleared every **error** (no behavior change; -warnings out of scope): - -- **`react-hooks/rules-of-hooks`** (`ObjectDataTable`) — `useObjectTranslation` - was wrapped in try/catch; removed the wrapper (the hook is provider-safe and - never throws — the #2709 fix). English defaults still stand until a - translation resolves. -- **`react-hooks/static-components`** (`MetricCard`, `MetricWidget`) — - `getLazyIcon(name)` returns a module-cached, stable component per name (not a - component created during render), so the render sites carry a justified scoped - disable. -- **`no-irregular-whitespace`** (`DatasetWidget`) — the literal U+FEFF BOM - prepended to the exported CSV blob (Excel UTF-8 detection) is written as the - `` escape: byte-identical at runtime, no literal irregular-whitespace char. -- **`no-useless-escape`** (`recordFields`) — dropped a needless `\$` inside a - character class (`[\$¥€£]` → `[$¥€£]`). -- **`no-sparse-arrays`** (`recordFields`) — the `|| [, '']` match fallback is - written `[undefined, '']` so index 0 is an explicit hole, not a sparse one. -- **`no-useless-assignment`** (`PivotTable`) — the `suffix` accumulator is now a - single `const` at its one assignment site instead of a dead-initialized `let`. -- **`no-require-imports`** (`DashboardRenderer.designMode` test) — the hoisted - `vi.mock` factory uses an `async` factory with `await import('react')`. diff --git a/.changeset/lint-baseline-detail.md b/.changeset/lint-baseline-detail.md deleted file mode 100644 index 07629aa42..000000000 --- a/.changeset/lint-baseline-detail.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -"@object-ui/plugin-detail": patch ---- - -chore(lint): clear the baseline lint errors in plugin-detail (objectui#2713 Wave 3) - -Wave 3 of the #2713 lint-gate restoration. `@object-ui/plugin-detail` was red at -baseline on `main`; cleared every **error** (no behavior change; warnings out of -scope). All nine are `react-hooks` errors — the record renderers called hooks -after conditional early returns, which is a real fragility (React throws when the -guard toggles between renders), so each is restructured so hooks run -unconditionally while the rendered output stays identical: - -- **`record-reference-rail`** — hoisted `useState` above the empty-entries early - return (no dependency on it). -- **`record-related-list`** — moved the `!objectName` placeholder return below - the four hooks (`usePermissions` / `useFieldPermissions` / `useRelatedRecordActions` - / `useMemo`); those hooks are pure context/memo reads, safe with an empty - object name. The object-level read gate ordering is unchanged (covered by - `RecordRelatedListRenderer.readgate.test`). -- **`record-quick-actions`** — moved the `requiredPermissions` gate below - `useActionEngine` (a pure `useContext`/`useMemo` hook). -- **`record-highlights`** — `useId` + `useRegisterHighlightFields` now run - unconditionally; the permission gate is enforced after them. Because - `useRegisterHighlightFields` has a register effect, it is passed `[]` when the - gate denies — equivalent to not registering, so no body field is ever hidden - for highlights that aren't rendered. -- **`RelatedList`** `SectionIcon` (`react-hooks/static-components`) — - `resolveIconComponent` is a stable registry lookup, not a component created - during render → justified scoped disable. diff --git a/.changeset/lint-baseline-gantt.md b/.changeset/lint-baseline-gantt.md deleted file mode 100644 index 2221a7c9d..000000000 --- a/.changeset/lint-baseline-gantt.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -"@object-ui/plugin-gantt": patch ---- - -chore(lint): clear the baseline lint errors in plugin-gantt (objectui#2713 Wave 3) - -Wave 3 of the #2713 lint-gate restoration. `@object-ui/plugin-gantt` was red at -baseline on `main`; cleared every **error** (no behavior change; warnings out of -scope). 18 of the 21 were in the demo harness: - -- **`react-hooks/static-components` (demo, ×8)** — the `Swatch` legend cell was - defined inside `ManufacturingLegend`; hoisted to module scope (purely - props-driven, so nothing from render scope is captured). -- **`react-hooks/rules-of-hooks` (demo, ×9)** — `App` had a `?quickfilter=1` - early return before ~9 hooks; moved that route below all hooks so hook order - is stable (the quick-filter branch renders `` regardless). -- **`react-hooks/purity` (demo, ×1)** — the demo render-timer necessarily reads - `performance.now()` during render (paired with an effect that measures elapsed - ms); justified scoped disable, demo-only. -- **`object-ui/no-synthetic-event-trigger`** (`GanttView.interactions.test`) — - the Escape-closes-menu test dispatched a raw `window` `KeyboardEvent`; switched - to `fireEvent.keyDown(window, { key: 'Escape' })` (the pattern already used - elsewhere in the same file). The window-level Escape listener behaves - identically. -- **`no-useless-assignment`** (`GanttView`, `ObjectGantt`) — dropped two dead - initializers (`ok`, `options`) that their exhaustive `try`/`catch` and - `if`/`else` branches overwrite before reading. diff --git a/.changeset/lint-baseline-mechanical.md b/.changeset/lint-baseline-mechanical.md deleted file mode 100644 index f71cf2b2a..000000000 --- a/.changeset/lint-baseline-mechanical.md +++ /dev/null @@ -1,38 +0,0 @@ ---- -"@object-ui/cli": patch -"@object-ui/data-objectstack": patch -"@object-ui/plugin-calendar": patch -"@object-ui/plugin-designer": patch -"@object-ui/plugin-map": patch -"@object-ui/plugin-markdown": patch -"@object-ui/plugin-timeline": patch -"@object-ui/react": patch ---- - -chore(lint): clear the mechanical baseline lint errors so these packages' lint gates protect them again - -Extends the fields/core cleanup from #2709 (objectui#2713). These eight package -lints were red at baseline on `main`, so their per-package `lint` gate could not -catch new violations of the same class. Cleared every **error** (no behavior -change; warnings are out of scope): - -- **`no-useless-catch`** (`data-objectstack`) — unwrapped five try/catch blocks - whose `catch` only re-threw; errors still propagate identically. -- **`preserve-caught-error`** (`cli`, `data-objectstack`, `react`) — the caught - error's message is inlined into the thrown `Error`; a scoped disable with a - justifying comment carries each one, because these packages target ES2020 - whose lib types the 1-arg `Error` constructor only (so `{ cause }` won't - compile) — same reasoning as the core case in #2709. -- **`prefer-const`** (`plugin-calendar`, `plugin-map`) — `let`→`const` for - never-reassigned bindings. -- **`no-empty-object-type`** (`plugin-designer`) — empty extend-only interfaces - → equivalent `type` aliases. -- **`no-useless-assignment`** (`react`) — dropped a dead initializer that both - branches overwrite before it is read. -- **`no-require-imports`** (`plugin-calendar`, `plugin-timeline` tests) — - hoisted `vi.mock` factories now use an `async` factory with - `await import('react')` instead of `require('react')`. -- **stale `eslint-disable` directive** (`plugin-markdown`) — removed a - `react/no-danger` disable whose plugin is not loaded in the flat config (an - unknown-rule reference that ESLint v10 reports as an error); the rationale is - kept as a plain comment. diff --git a/.changeset/lint-baseline-wave2.md b/.changeset/lint-baseline-wave2.md deleted file mode 100644 index 44c98c183..000000000 --- a/.changeset/lint-baseline-wave2.md +++ /dev/null @@ -1,45 +0,0 @@ ---- -"@object-ui/i18n": patch -"@object-ui/plugin-kanban": patch -"@object-ui/plugin-grid": patch -"@object-ui/plugin-view": patch -"@object-ui/plugin-list": patch -"@object-ui/plugin-charts": patch -"@object-ui/plugin-report": patch -"@object-ui/layout": patch -"@object-ui/collaboration": patch ---- - -chore(lint): clear the baseline lint errors in nine more packages (objectui#2713 Wave 2) - -Second wave of the #2713 lint-gate restoration (after #2730). These nine package -lints were red at baseline on `main`, so their per-package `lint` gate could not -catch new violations. Cleared every **error** (no behavior change; warnings out -of scope): - -- **`react-hooks/rules-of-hooks`** (`i18n`, `plugin-grid`, `plugin-view`, - `plugin-list`) — translation helpers (`useSafeFieldLabel`, - `useRowActionTranslation`, `useViewLabel`, `useViewTabLabel`, `useMoreLabel`) - wrapped a provider-safe hook (`useObjectTranslation`/`useObjectLabel`, which - never throw) in try/catch; removed the wrapper (the same fix #2709 applied in - fields). `plugin-kanban` `ObjectKanban` moved its `if (error)` early return - below the `useCallback` so hooks run unconditionally. `collaboration` - `__unsafe_usePresenceContext` keeps its deliberate danger-prefix name via a - justified scoped disable. -- **`react-hooks/static-components`** (`layout`, `plugin-list`, `plugin-report`) - — dynamic-icon / registry lookups (`resolveIcon`, `useRegistryComponent`) are - stable component references, not components created during render → scoped - disable with justification. `plugin-charts` `TreemapCell` was a *genuine* - inline component and is hoisted to module scope (it is purely props-driven). -- **`no-irregular-whitespace`** (`plugin-grid` `ImportWizard`) — the literal - U+FEFF BOM prepended to exported CSV/text blobs (so Excel detects UTF-8) is - now written as the `` escape: byte-identical at runtime, no literal - irregular-whitespace character in source. -- **`no-useless-assignment`** (`plugin-grid` `BulkActionDialog`) — dropped a - dead `= null` initializer that the exhaustive `switch` (incl. `default`) - overwrites before it is read. -- **`no-unsafe-function-type`** (`plugin-view` `ViewTabBar`) — the dnd-kit - render-prop `listeners` map is typed `Record void>` - instead of bare `Function`. -- **`no-require-imports`** (`plugin-kanban`, `plugin-view` tests) — hoisted - `vi.mock` factories use an `async` factory with `await import('react')`. diff --git a/.changeset/list-columns-owner-id.md b/.changeset/list-columns-owner-id.md deleted file mode 100644 index aa274d49d..000000000 --- a/.changeset/list-columns-owner-id.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -"@object-ui/types": patch -"@object-ui/plugin-grid": patch -"@object-ui/app-shell": patch ---- - -fix(list): keep the injected `owner_id` out of the leading auto-derived columns - -A view-less object's default list columns are derived from the object's field -order. The framework's `applySystemFields` spreads its injected -system/audit/ownership fields to the FRONT of that order and stamps them -`system: true`; `owner_id` is deliberately non-hidden and non-readonly -(ownership is reassignable), so the old name-based exclusion lists in -`ObjectGrid` and `InterfaceListPage` — which never listed `owner_id` — let it -through as column #1 on many showcase list pages (e.g. `showcase_field_zoo`). - -Default-column derivation now classifies system fields via the shared -`isSystemManagedField` helper, which branches on the spec `system` flag (the -single source of truth stamped by the registry) with a name-set fallback that -includes the ownership/tenancy FKs. `owner_id` is pushed to the end -(`ObjectGrid`) / excluded from the business columns (`InterfaceListPage`), so -auto-derived lists lead with business fields again and pick up future injected -fields without editing a name list. Also declares the `system` flag on the -`@object-ui/types` field metadata. diff --git a/.changeset/managedby-engine-owned-bucket.md b/.changeset/managedby-engine-owned-bucket.md deleted file mode 100644 index a9a90f5b6..000000000 --- a/.changeset/managedby-engine-owned-bucket.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -"@object-ui/types": minor -"@object-ui/core": minor -"@object-ui/app-shell": patch ---- - -**Add the explicit `engine-owned` lifecycle bucket (tracks framework ADR-0103 addendum / #3343).** The framework split the overloaded `managedBy: 'system'` bucket by promoting the engine-owned case to its own enum value; this mirrors it in the UI type + runtime + badge. - -- **`@object-ui/types`** — `ManagedByBucket` union and `MANAGED_BY_BUCKETS` gain `'engine-owned'` (canonical order: `platform, config, system, engine-owned, append-only, better-auth`). The union stays closed, so every consumer that missed the new value is a compile error. -- **`@object-ui/core`** — `resolveCrudAffordances` gains the `engine-owned` default row (identical all-locked matrix as `system`/`append-only`), so `isObjectInlineEditable` / the grid + form gates treat it as read-only automatically. -- **`@object-ui/app-shell`** — the `ManagedByBadge` renders `engine-owned` with the same read-only "System-managed" copy as a locked `system` object (reuses the existing `managedByBadge.system` i18n key — zero translation churn; the distinction is at the schema level, not the user-facing string), and `resolveManagedByEmptyState` reuses the `system` engine-owned empty state. - -Behaviour-preserving: `engine-owned` resolves to the same locked affordances `system` did by default, so nothing about how a locked object renders changes — the value just makes the schema self-documenting. New unit coverage for the bucket in `resolveCrudAffordances` / `isObjectInlineEditable` / `MANAGED_BY_BUCKETS` / the empty-state helper. diff --git a/.changeset/managedby-single-source-of-truth.md b/.changeset/managedby-single-source-of-truth.md deleted file mode 100644 index 54027165f..000000000 --- a/.changeset/managedby-single-source-of-truth.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -"@object-ui/types": patch -"@object-ui/core": patch -"@object-ui/app-shell": patch -"@object-ui/plugin-detail": patch ---- - -**Consolidate the `managedBy` lifecycle-bucket logic into one shared source of truth (follows framework ADR-0103).** The bucket taxonomy was hand-mirrored in several places — `crudAffordances.ts`, `ManagedByBadge.tsx` (its own `Bucket` union + `isWriteOptedIn` + the writable-system derivation), and `plugin-detail`'s `record-details.tsx` (`NON_EDITABLE_BUCKETS`, duplicated because it can't depend on app-shell) — a drift risk, and the object-schema `managedBy` type was open-ended (`(string & {})`) so unknown buckets slipped through and silently defaulted to fully-editable. - -- **`@object-ui/types`** now owns the closed `ManagedByBucket` union (+ `MANAGED_BY_BUCKETS`), and `ObjectSchema.managedBy` is tightened from `'platform' | 'better-auth' | (string & {})` to that union — unknown buckets are now a type error at authoring time. -- **`@object-ui/core`** now owns the React-free runtime logic — `resolveCrudAffordances`, `isWriteOptedIn`, `isSystemWritable`, `isObjectInlineEditable` — reachable by every UI package including `plugin-detail` (which could not import app-shell). -- **`app-shell/utils/crudAffordances.ts`** is now a thin re-export of `@object-ui/core` (existing imports keep working); `ManagedByBadge` consumes the shared `isSystemWritable`; `plugin-detail` `record-details.tsx` replaces its hand-mirrored `NON_EDITABLE_BUCKETS` with `isObjectInlineEditable`. - -Behavior-preserving — all existing affordance/edit-gate tests stay green; the shared module adds direct unit coverage (including the previously-untested `isSystemWritable` derivation). Translated copy (badge variants, empty-state messages) stays in app-shell. diff --git a/.changeset/managedby-useractions-single-parser.md b/.changeset/managedby-useractions-single-parser.md deleted file mode 100644 index 7d8c483e4..000000000 --- a/.changeset/managedby-useractions-single-parser.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -"@object-ui/core": patch -"@object-ui/app-shell": patch -"@object-ui/plugin-grid": patch -"@object-ui/plugin-form": patch -"@object-ui/plugin-detail": patch ---- - -**Finish the `managedBy` / `userActions` de-dup — one parser for the override shape (completes objectui#2712, framework#3343).** #2712 consolidated the bucket *union* + affordance *set* mirrors but left four surfaces still parsing the `userActions.{create,edit,delete}` override shape by hand. They now all route through the shared `@object-ui/core` policy, so no package re-implements the boolean / #2614-object-form parse locally. - -- **`@object-ui/core`** promotes the internal `normalizeOverride` to the exported **`normalizeUserAction(v, base)`** (the one parser) and adds **`userActionPredicates(v)`** for per-record CEL predicate extraction. -- **`app-shell/utils/managedByEmptyState.ts`** — the writable-`system` create check and its local `EmptyStateUserActions` interface are replaced by `resolveCrudAffordances({ managedBy, userActions }).create`. -- **`plugin-grid/rowCrudAffordances.ts`** — the local `isOptedOut` / `predicatesOf` helpers (and duplicated `RowCrudUserAction` / `RowCrudPredicates` types) fold into `normalizeUserAction`; the historical type names stay re-exported for compat. -- **`plugin-detail/RelatedList.tsx`** — its inline `predicatesOf` fold into `userActionPredicates`. -- **`plugin-form/ObjectForm.tsx`** — the hand-rolled `managedBy !== 'platform'` blanket lock + `userActions` unlock is replaced by the resolved affordance for the current mode (`edit` / `create`), the **same** `resolveCrudAffordances` contract the detail (`isObjectInlineEditable`) and grid surfaces use. - -Behavior-preserving for `platform` / `system` / `append-only` / `better-auth`, with one deliberate alignment: an admin-editable **`config`**-bucket object (e.g. `sys_webhook`, `sys_permission_set`) is now editable in `ObjectForm` — it was previously over-locked as "non-`platform`", while detail/grid already treated it as editable (`config` resolves `edit: true`). New unit coverage for the shared parser and the config / create-mode form gate; all existing affordance/edit-gate tests stay green. diff --git a/.changeset/managedby-writable-system-copy.md b/.changeset/managedby-writable-system-copy.md deleted file mode 100644 index 5ef156f55..000000000 --- a/.changeset/managedby-writable-system-copy.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -"@object-ui/app-shell": patch -"@object-ui/i18n": patch ---- - -**Distinguish writable `system` objects from engine-owned ones in the Console (framework ADR-0103 / #3220).** The framework split the overloaded `managedBy: 'system'` bucket: engine-owned rows stay read-only, but several `system` objects are admin/user-writable *data* (Notification Preferences/Subscriptions/Templates, delegated RBAC assignments, user preferences) and declare `userActions` opening their writes. - -The Console already surfaced the New/Edit/Delete buttons correctly for these (all affordance mirrors honour `userActions`), but the badge and empty-state *copy* still called every `system` object a "read-only monitoring surface". Now: - -- **`ManagedByBadge`** takes the object's `userActions` and, when a `system` object opens any write, renders the "Platform schema — admin-writable" variant instead of the engine-owned copy. -- **`resolveManagedByEmptyState`** returns `undefined` for a `system` object whose `userActions.create` is set, so the generic empty state (with the New button) shows instead of "entries appear automatically". -- New `managedByBadge.systemWritable.*` strings (en + zh; other locales fall back to the English default). - -Copy/UX only — no behavioural change to what a user can do. diff --git a/.changeset/master-detail-batch-transaction-adapter.md b/.changeset/master-detail-batch-transaction-adapter.md deleted file mode 100644 index 427a2e5ed..000000000 --- a/.changeset/master-detail-batch-transaction-adapter.md +++ /dev/null @@ -1,41 +0,0 @@ ---- -"@object-ui/types": minor -"@object-ui/core": minor -"@object-ui/data-objectstack": minor -"@object-ui/plugin-form": minor -"@object-ui/runner": minor ---- - -feat(data): unify master-detail saves behind `DataSource.batchTransaction`, isolate the non-atomic fallback in the adapter (#2679) - -Master-detail saves (`MasterDetailForm`, `LineItemsPanel`) now always persist -through `dataSource.batchTransaction(operations)` — one ordered cross-object -operation list, with `{ $ref: }` linking a child to a parent created -in the same batch. The form no longer contains any client-side orchestration or -best-effort compensation-delete; that atomicity anti-pattern is gone from the UI -layer (framework #1604 / framework ADR-0034 item 4). - -- **`@object-ui/types`** — `batchTransaction?` is now a first-class (optional) - method on the `DataSource` contract, typed via `BatchTransactionOperation` / - `BatchRef`. Replaces the previous `(dataSource as any).batchTransaction` - method-sniffing. -- **`@object-ui/core`** — new `emulateBatchTransaction(dataSource, operations)` - (sequential writes, `$ref` resolution, best-effort reverse-order compensation) - and `runBatchTransaction(dataSource, operations)` (prefers the adapter's method, - emulates otherwise). `ApiDataSource` / `ValueDataSource` implement - `batchTransaction` via the emulation. -- **`@object-ui/data-objectstack`** — `ObjectStackAdapter.batchTransaction` uses - the server's atomic `POST /api/v1/batch`, prefers the typed - `client.data.batchTransaction` SDK method when the installed client exposes it, - and degrades to the client-side emulation ONLY when the endpoint is missing - (404/405) or the runtime can't do transactions (501). Real errors (400/401/403/ - 409/500) still surface. This is the isolated, tested home of the non-atomic - fallback. -- **`@object-ui/plugin-form`** — removed `applyDetail` / `createMany` / - `ApplyDetailResult` from `masterDetailTx.ts`; `MasterDetailForm` and - `LineItemsPanel` build ops and call `runBatchTransaction`. `LineItemsPanel` - saves are now atomic on a capable backend, with the rollup folded into the same - batch. - -No behavior change on a current ObjectStack backend (it has `/api/v1/batch`); -older/limited backends keep a working — now clearly non-atomic — save path. diff --git a/.changeset/multiselect-cascade-2715.md b/.changeset/multiselect-cascade-2715.md deleted file mode 100644 index 58af35225..000000000 --- a/.changeset/multiselect-cascade-2715.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -"@object-ui/fields": minor ---- - -feat(fields): MultiSelectField per-option `visibleWhen` cascading + `dependsOn` gating (parity with single select, #2715) - -The multi-value chip picker now implements the same ADR-0058 option -resolution as the single `SelectField`, closing the gap #2709 opened when a -`select` + `multiple` (and the `multiselect` type) started delegating to it. - -- Extracted `useCascadingOptions` — the shared hook that resolves per-option - `visibleWhen` filtering, `dependsOn` gating, and the live `dependentValues` + - predicate-scope wiring — and routed both `SingleSelectField` and - `MultiSelectField` through it (no duplicated resolver). -- `MultiSelectField` narrows its offered chips against the live record + - `current_user`, gates behind a "select the parent first" hint while a - `dependsOn` field is empty, and surfaces a legible empty state instead of a - bare chip row. -- Cascade-clear: when the offered set changes (parent changed / predicate - flipped) the widget prunes only the now-invalid selections, keeping the - still-offered ones — the array analogue of the single select's clear. -- Tests: `MultiSelectField.cascade.test.tsx` mirrors `SelectField.cascade.test.tsx` - (gating, per-element cascade clear, role/context gating). diff --git a/.changeset/radio-cascade-parity.md b/.changeset/radio-cascade-parity.md deleted file mode 100644 index 8c123138b..000000000 --- a/.changeset/radio-cascade-parity.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -"@object-ui/core": minor -"@object-ui/fields": minor -"@object-ui/components": patch ---- - -feat(fields): RadioField per-option `visibleWhen` cascading + `dependsOn` gating; single-source the option resolver - -Brings `RadioField` to parity with `SelectField` / `MultiSelectField` for ADR-0058 -cascading & role-gated options, and collapses the three copies of the -gate-then-filter logic onto one shared resolver. - -- **`@object-ui/core`**: new pure `resolveCascadingOptions(rawOptions, record, dependsOn, scope)` - → `{ options, gated, dependsOnFields }` — the single source of truth for - `dependsOn` gating + per-option `visibleWhen` filtering. -- **`@object-ui/fields`**: `RadioField` now narrows its offered radios against - the live record + `current_user`, gates behind a "select the parent first" - hint while a `dependsOn` field is empty, and clears a value no longer offered - (scalar cascade clear). The `useCascadingOptions` hook is refactored to a thin - React wrapper over `resolveCascadingOptions`. -- **`@object-ui/components`**: the form renderer's inline option pre-filter and - cross-field cascade-clear effect now call `resolveCascadingOptions` instead of - re-deriving gating/filtering, so they can't drift from the widgets (no - behavior change). -- Tests: `RadioField.cascade.test.tsx` mirrors the select cascade tests; core - gains `resolveCascadingOptions` unit coverage. diff --git a/.changeset/related-list-default-pagination.md b/.changeset/related-list-default-pagination.md deleted file mode 100644 index f1c3e3c46..000000000 --- a/.changeset/related-list-default-pagination.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -"@object-ui/plugin-detail": minor -"@object-ui/types": patch ---- - -Related lists paginate by default and fetch server-side windows (#2711). - -`record:related_list` now applies the spec default `limit` of 5 when a node -doesn't declare one, so detail-page related lists render pages with -Previous/Next controls instead of dumping every child row. On the auto-fetch -path RelatedList requests one page at a time (`$top`/`$skip`), reads the -collection size from `QueryResult.total` (`hasMore` fallback), sends user -column sorts as a server `$orderby`, and seeds the initial order from the -node's `sort` prop (new `defaultSort` prop on RelatedList). Caller-provided -`data` keeps the historical client-side slicing. Behavior change: lists that -previously rendered all rows now show 5 per page — declare a larger `limit` -on the `record:related_list` node to widen the window. diff --git a/.changeset/report-drill-down-range-filter.md b/.changeset/report-drill-down-range-filter.md deleted file mode 100644 index 38948549d..000000000 --- a/.changeset/report-drill-down-range-filter.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -"@object-ui/core": minor -"@object-ui/app-shell": minor -"@object-ui/plugin-report": minor -"@object-ui/plugin-dashboard": minor ---- - -feat(report): drill a date-bucket cell into its time range, not a superset (#1752) - -Clicking a report/dashboard cell grouped by a `dateGranularity` date dimension -("2026-Q2") used to drill into a **superset** — the date dimension was skipped, -so the record list spanned every time bucket. It now scopes to the clicked -bucket's half-open range, consuming the framework's new `drillRanges` sidecar. - -- **`@object-ui/core`** — `buildDatasetDrillFilter` accepts the per-row - `drillRanges` and emits an ObjectQL range operator object - (`{ [field]: { $gte, $lt } }`) alongside the equality dims. -- **`@object-ui/plugin-report` / `@object-ui/plugin-dashboard`** — the report - renderer and dashboard widget forward `drillRanges`, and a **date-only** - report (no equality drill dim) is now drillable via the range alone. -- **`@object-ui/app-shell`** — the "Open in list →" escape hatch - (`useOpenRecordList`) now targets the ADR-0055 **bare data surface** - (`/:object/data`, "the URL is the view" — no baked-in view filter to - over-narrow the drill) and serializes a range to the - `filter[field][gte|lt]` operator contract. `ObjectDataPage` parses those - operators (equality shorthand unchanged), renders a range as a single chip, - and removes both bounds together. A new `drillUrlFilters` module owns the - write/read serialization so both sides can't drift (round-trip tested). - -Companion to the framework analytics change (objectstack-ai/framework#3256). diff --git a/.changeset/retire-dashboard-legacy-analytics-3320.md b/.changeset/retire-dashboard-legacy-analytics-3320.md deleted file mode 100644 index 96681d7cb..000000000 --- a/.changeset/retire-dashboard-legacy-analytics-3320.md +++ /dev/null @@ -1,31 +0,0 @@ ---- -"@object-ui/types": minor -"@object-ui/plugin-dashboard": minor -"@object-ui/plugin-designer": minor ---- - -feat(dashboard): retire the pre-ADR-0021 inline-analytics renderer branches (framework#3320) - -Follow-up to the dashboard analytics migration (framework#3251 / objectui#2703). -Authoring already emits only the semantic-layer shape (`dataset` + `dimensions` + -`values`); this removes the renderer's now-unauthored legacy read-branches. - -- **types**: drop the `@deprecated` inline-analytics keys (`object`, - `categoryField`, `categoryGranularity`, `valueField`, `aggregate`, `measures`) - from `DashboardWidgetSchema`. They were retained in #2703 only so the renderer - could read legacy/static metadata during the transition. -- **plugin-dashboard**: `DashboardRenderer` no longer emits the object-bound - metric / chart / pivot / table / list branches from the top-level `object` + - analytics keys. It keeps the renderer-internal static paths (`options.data` / - `widget.data` array and the `provider: 'object'` async config) and - `widget.component`. The dashboard renderer no longer emits `object-pivot` / - `pivot` at all — dataset pivots render through `DatasetWidget` (grouped table / - cross-tab); the `ObjectPivotTable` / `PivotTable` components stay as public - SDUI blocks for other surfaces. `DashboardGridLayout` gets the same treatment. -- **graceful fallback**: a widget that still carries the retired inline shape in - stored metadata (top-level `object`, no `dataset`, no inline `options.data`) - now renders a visible error placeholder prompting a rebind to a dataset, rather - than a blank chart/grid. -- **plugin-designer**: `DashboardEditor` drops its inline object / value-field / - aggregate fields (analytics binding is authored via the dataset picker in - app-shell's `DashboardWidgetInspector` / plugin-dashboard's `WidgetConfigPanel`). diff --git a/.changeset/schema-fields-keyvalue.md b/.changeset/schema-fields-keyvalue.md deleted file mode 100644 index 41f51fdff..000000000 --- a/.changeset/schema-fields-keyvalue.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -"@object-ui/app-shell": minor ---- - -feat(flow-designer): map free-form object maps → keyValue (and numeric arrays → numberList) in the schema-driven inspector (#3304) - -The server-first flow-designer form generator (`jsonSchemaToFlowFields`, ADR-0018) -had no way to render the flat `{ var: value }` **keyValue** editor from a JSON -Schema, so any node whose config uses a free-form map — a CRUD node's `fields` / -`filter`, an `assignment`'s `assignments`, a connector's `input`, a screen's -`defaults` — could not be driven from its published `configSchema` without -dropping that editor to raw Advanced JSON. - -The adapter now maps: - -- an object with **`additionalProperties`** (a value schema, or `true`) and **no - fixed `properties`** → a `keyValue` field (the object-with-`properties` case - still flattens to sub-fields; an opaque object or `additionalProperties: false` - still falls through to the Advanced block); -- an array of **number / integer** → `numberList` (the sibling of the existing - array-of-string → `stringList`). - -This is a pure capability addition — inert until a node publishes such a schema, -so no existing form changes. It unblocks giving the previously schema-less flow -nodes (assignment, the CRUD quartet, script, subflow, screen) a server-driven -config form that matches their hardcoded one, the objectui half of framework -#3304 (the descriptor-side counterpart to #2670 Phase 3). diff --git a/.changeset/select-multiple-multiselect-and-lint.md b/.changeset/select-multiple-multiselect-and-lint.md deleted file mode 100644 index f2697b6f0..000000000 --- a/.changeset/select-multiple-multiselect-and-lint.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -"@object-ui/fields": minor -"@object-ui/core": patch ---- - -feat(fields): render `select` + `multiple` through the multi-value chip picker; restore fields/core lint gates - -- **Multi-value select** — a `select` field/param declared `multiple: true` - now renders the multi-value chip picker (the `multiselect` widget) and stores - a `string[]`, instead of collapsing to a single-value dropdown that could - hold only one value. The delegation lives inside `SelectField`, so the object - form, the inline grid editor, and the app-shell `ActionParamDialog` all - inherit it from the one `select` widget with no per-surface drift. Single - selects keep the cascading dropdown (multi + per-option `visibleWhen` - cascading is not a combination in use today). -- **`autonumber` mapping is unchanged** here; this change is orthogonal. -- **Lint gates restored** — fixed the pre-existing baseline lint errors that - had left the `@object-ui/fields` and `@object-ui/core` package lints red (so - the gate could not catch new violations): `react-hooks/rules-of-hooks` in - `ImageField` / `TextAreaField` / `index.tsx` (hooks hoisted above early - returns; the `useFieldTranslate` hook no longer wrapped in try/catch), plus - `no-useless-assignment` / `no-useless-escape` / `no-control-regex` / - `prefer-const` / `preserve-caught-error` in the core evaluator and utils. No - behavior change from the lint fixes. diff --git a/.changeset/summary-filter-editor.md b/.changeset/summary-filter-editor.md deleted file mode 100644 index b56f153d7..000000000 --- a/.changeset/summary-filter-editor.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -"@object-ui/app-shell": minor ---- - -feat(studio): filter editor for roll-up `summary` fields (framework#1868) - -The object-designer field inspector now edits `summaryOperations.filter` on a -`summary` field. Backing the framework's new filtered roll-ups — where one child -object feeds several parent totals, each aggregating only the child rows a -predicate matches (an approved-only sum vs the grand total) — the inspector adds -a structured field/operator/value row editor under Rollup Options (mirroring the -lookupFilters editor), reading and writing the spec's FilterCondition object. - -- Values are coerced to the child field's stored type, so a `boolean` field emits - `{ billable: true }` (not the string `"true"`) and a numeric operator emits - `{ amount: { $gte: 500 } }` — the FilterCondition then matches the real column. -- Rows map to/from the flat FilterCondition (and a top-level `$and`); a filter - using logic the rows can't represent (`$or` / nested) is shown read-only with a - note instead of being clobbered on edit. -- New `designer.field.summary.filter*` i18n keys (en + zh-CN). diff --git a/.changeset/system-field-classifier-consolidation.md b/.changeset/system-field-classifier-consolidation.md deleted file mode 100644 index f579fef15..000000000 --- a/.changeset/system-field-classifier-consolidation.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -"@object-ui/plugin-grid": patch -"@object-ui/fields": patch -"@object-ui/plugin-detail": patch ---- - -fix(list): route remaining system-field groupings through the shared classifier - -Follow-up to the `owner_id` default-column fix: consolidate the display-oriented -system-field exclusions onto the shared `isSystemManagedField` / -`SYSTEM_MANAGED_FIELD_NAMES` (from `@object-ui/types`) so the framework-injected -`owner_id` is treated consistently across the grid, record picker, and detail -drawer. - -- `ObjectGrid` record-detail drawer: the business-fields vs. muted meta-section - split now uses the shared classifier, so `owner_id` (and other injected system - fields) land in the meta section instead of the business body. -- `deriveLookupColumns` (record picker): drops its local name set for the shared - classifier — now flag-aware (`field.system`), not just name-based. -- `RecordDetailDrawer`: its default `systemFields` set is derived from the shared - `SYSTEM_MANAGED_FIELD_NAMES`; the `systemFields` prop override is preserved. - -`deriveRelatedLists`' narrow "audit FK on every object" set and plugin-detail's -inline-edit "never editable" set are intentionally left distinct — different -semantics (the latter deliberately keeps `owner_id` editable). diff --git a/.changeset/time-relative-trigger-designer.md b/.changeset/time-relative-trigger-designer.md deleted file mode 100644 index 72a70a203..000000000 --- a/.changeset/time-relative-trigger-designer.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -"@object-ui/app-shell": minor ---- - -feat(flow-designer): first-class panel for the time-relative trigger (#1874) - -The flow designer's start-node inspector now offers a **Time-relative (date sweep)** -trigger option alongside record / schedule triggers. Picking it reveals typed -fields for the backend's `config.timeRelative` descriptor — Sweep object, Date -field, Within days (range mode), Offset days (T-minus mode), an Extra filter, and -Max records — instead of hand-writing the block in the Advanced JSON editor. The -per-record Entry condition is available too. - -Adds a `numberList` config-field kind (a string-list editor that commits -`number[]`), so **Offset days** authors emit numbers rather than strings — keeping -the backend schema (`z.array(z.number())`) strict rather than coercing on the -consumer side. All fields live under the nested `config.timeRelative` block, which -the group fully owns, so it never double-renders in Advanced JSON. diff --git a/apps/console/CHANGELOG.md b/apps/console/CHANGELOG.md index 34cd71b66..2e7f7c36d 100644 --- a/apps/console/CHANGELOG.md +++ b/apps/console/CHANGELOG.md @@ -1,5 +1,58 @@ # @object-ui/console +## 16.1.0 + +### Patch Changes + +- 8b8b744: chore(deps): align `@objectstack/formula` / `lint` / `client` to `^15.1.1` + + These three were still pinned to `^14.6.0` while `@objectstack/spec` was already + `^15.1.1` — a version skew from the v15 upgrade (formula/lint/client publish in + lockstep with spec, and their own 15.0.0 entries are pure dependency bumps, so + this is alignment, not a behavioral migration). + + Practical effect: the client-side field-rule evaluation + (`visibleWhen`/`readonlyWhen`/`requiredWhen` via `fieldRules.ts`, which delegates + to `@objectstack/formula`'s `ExpressionEngine`) now tracks the 15.x engine — and + will pick up the framework's `dateField == today()` equality fix + (objectstack-ai/framework#3205) automatically at the next 15.x release via the + caret range. Renderer/action `visible`/`disabled` predicates are unaffected (they + use the home-grown JS evaluator — tracked separately in #2661). + +- 7cf4051: chore(deps): align every `@objectstack/*` dependency to `^16.0.0-rc.0` + + Bumps `@objectstack/spec` / `client` / `formula` / `lint` from `^15.1.1` to the + `16.0.0-rc.0` pre-release across the workspace (root + `apps/console` + + `apps/site` + all consuming packages). ObjectUI's own packages are already on + major 16, so this closes the 15↔16 skew between ObjectUI and the `@objectstack` + contract libraries (which publish in lockstep with `spec`). + + This is a dependency alignment, not a behavioral migration: the full workspace + build (43/43) and the `@objectstack`-consuming package test suites + (`core` / `app-shell` / `data-objectstack` / `plugin-form` / `types`) are green + against `16.0.0-rc.0` with no source changes required. + + Practical effect: `@objectstack/client@16.0.0-rc.0` now ships + `data.batchTransaction` (framework #3271), so `ObjectStackAdapter`'s feature + detect (`typeof client.data.batchTransaction === 'function'`) routes + master-detail cross-object saves through the typed SDK method instead of the + raw `fetch('/api/v1/batch')` fallback — realizing the "verify SDK path" half of + #2694. The raw-fetch branch stays as a defensive fallback (removal tracked in + #2694). + +- 6b114a1: fix(approvals-inbox): align participant gating with the server-computed `viewer` block + + Consume framework#3310's per-viewer capability: `ApprovalRequestRow` gains an + optional `viewer: { can_act, is_submitter }`, and the approvals inbox's + participant checks (the reply box + the "why disabled" hint) prefer it over the + client-side identity heuristic when present. This keeps the hint from ever + contradicting the declared decision buttons — whose `visible` CEL now gates on + `record.viewer.*` — and correctly recognizes position/team-addressed approvers + that the client heuristic couldn't resolve. The heuristic remains as a fallback + for a backend that predates `viewer`. + - @object-ui/react-runtime@16.1.0 + - @object-ui/sdui-parser@16.1.0 + ## 16.0.0 ### Patch Changes diff --git a/apps/console/package.json b/apps/console/package.json index d4a5d7147..10d4811d8 100644 --- a/apps/console/package.json +++ b/apps/console/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/console", - "version": "16.0.0", + "version": "16.1.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 004c84961..2e97ad88b 100644 --- a/packages/app-shell/CHANGELOG.md +++ b/packages/app-shell/CHANGELOG.md @@ -1,5 +1,496 @@ # @object-ui/app-shell — Changelog +## 16.1.0 + +### Minor Changes + +- 1c8935a: feat(app-shell): render ActionParamDialog params through the shared form field-widget renderer (ADR-0059, #2700) + + `ActionParamDialog` no longer hand-rolls a per-type ternary chain (select / + lookup / textarea / number / boolean, everything else → text input). Every + declared action param now renders through the same `fieldWidgetMap` the object + form uses, so a param of ANY form-supported field type — `file`, `image`, + `richtext`, `markdown`, `color`, `address`, `code`, `date`, … — gets its real + widget, lazily loaded behind `Suspense`. Subsumes the single `file` branch ask + in #2698: `type: 'file'` params render the real `FileField` upload control via + the ambient `UploadProvider`, honoring `multiple`/`accept`/`maxSize`. + + - `@object-ui/fields`: new exports `resolveFormWidgetType(type)` (widget-key + resolution incl. spec aliases, text fallback) and `getLazyFieldWidget(type)` + (per-type-cached `React.lazy` over the form's own widget loaders). + - `@object-ui/core`: `ActionParamDef` gains `accept`/`maxSize`; `multiple` is + now general widget config (was lookup-only). + - `@object-ui/app-shell`: new pure `paramToField()` adapter (param → field + shape) with a drift test pinning param support ⊇ form support (`FORM_FIELD_TYPES`), + mirroring the FieldEditWidget parity guard; `resolveActionParams()` inherits + `multiple`/`accept`/`maxSize` from the referenced field for every type. + `required` validation, `visible` CEL gating, helpText, error styling, and + value shapes for previously-supported types are unchanged. + +- aefcf39: feat(action-params): serialize file/image action params to storage id(s); retire the approvals composer + + Declared action params of `type: 'file'`/`'image'` now POST the portable API + contract — the storage id(s) — instead of the upload widget's rich object: + + - `FileField` surfaces the id it already receives from the upload adapter + (`meta.fileId`) as `file_id` on each emitted file object (additive; the + record file-field value shape is unchanged). + - `ActionParamDialog` maps upload-param values to their `file_id`(s) at submit + (`serializeParamValues`, pure + exported): single → string, `multiple` → + `string[]`. The api handler already forwards param values untouched, so an + action with a `file` param POSTs `attachments: string[]`. + + This lets the approvals inbox retire its last hand-wired UI — the approve/reject + composer with its bespoke attachment upload — so the drawer renders every + decision through `DeclaredActionsBar` with the declared `attachments` file param + (framework side declares it; see the paired framework change). `DeclaredActionsBar`'s + `exclude` prop stays as a general capability. + +- 94d4876: feat(dashboard): Studio authors the ADR-0021 dataset shape only (framework#3251) + + Finishes the dashboard analytics migration on the authoring side so the + framework can enable `DashboardWidgetSchema.strict()`. Both Studio surfaces now + emit only the semantic-layer shape (`dataset` + `dimensions` + `values`); no + surface authors the removed pre-ADR-0021 inline query. + + **FROM → TO** (authoring) + + - charts: `object` + `categoryField` + `valueField` + `aggregate` + → `dataset` + `dimensions` + `values` + - pivots: `object` + `rowField` + `columnField` + `valueField` + `aggregation` + → `dataset` + `dimensions` + `values` (last dimension spreads across columns) + + **Changes** + + - `@object-ui/types` — `DashboardWidgetSchema` gains `dataset` / `dimensions` / + `values`; the inline analytics keys (`object`, `categoryField`, + `categoryGranularity`, `valueField`, `aggregate`, `measures`) are marked + `@deprecated` (retained only so the renderer can still read legacy/static + metadata during the transition). + - `@object-ui/plugin-dashboard` — `WidgetConfigPanel` is rewritten as a dataset + picker (chart AND pivot). **Breaking prop change:** the unused + `availableObjects` / `availableFields` props are replaced by a new + `datasets?: WidgetDatasetCatalogEntry[]` (+ `datasetsLoading?`) catalog prop, + also forwarded by `DashboardWithConfig`. Hosts resolve the catalog (e.g. via + the metadata client's `list('dataset')`); without it the panel falls back to + free-text authoring. New exports: `WidgetDatasetCatalogEntry` and + `sanitizeDraftForType`. + - `@object-ui/app-shell` — the metadata-admin `DashboardWidgetInspector` drops + the legacy inline fields (object / value field / category field / aggregate); + the dataset section is now the primary (and only) analytics binding, and the + filter-binding field picker sources options from the bound dataset's + dimensions. The "Add widget" catalog drops `list` / `custom` — neither is a + member of `@objectstack/spec` `ChartTypeSchema`, so a widget authored with + them could never publish. + + **Not changed:** `DashboardRenderer` keeps its legacy/static read branches and + the `ObjectPivotTable` / `PivotTable` blocks (still public SDUI blocks and the + backward-compat path for stored/static widgets) — only the dashboard authoring + flow stops emitting the legacy keys. Retiring those renderer branches is a + follow-up gated on migrating stored dashboards. + +- a4acca7: feat(studio): expand loop / parallel / try_catch regions inline on the flow designer canvas (#2670) + + The flow designer rendered ADR-0031 structured control-flow containers + (`loop` / `parallel` / `try_catch`) as opaque single node cards — their nested + regions (`config.body` / `config.branches[]` / `config.try`/`catch`) were only + visible, and only editable, as raw JSON in the inspector's Advanced block. + + A container card now carries an expand chevron that grows the card **in place** + to embed its region(s) as a read-only mini-canvas — the same top-to-bottom + node/edge layout as the parent graph, scaled to fit the card width — with a + header per region (a named branch or `Branch N`, and `Try` / `Catch`; a loop + body has none). The canvas layout is geometry-aware: the layers below an + expanded container are **pushed down** by its real height and its outgoing edge + leaves from its true bottom. Collapsed by default; expansion is session-only + view state (never written to the flow draft). Legacy flat loops (a `loop` with + no `config.body`) and all ordinary nodes render exactly as before — with no + expanded container the layout is identical to the previous release, locked by + invariance tests. + + Known limitation: a node pinned via a manual drag position sitting at/below an + expanded container can overlap it (manual positions are absolute); drag it + clear or collapse the container. + +- 5a89ee5: feat(studio): select and edit nested container nodes through the schema-driven flow inspector (#2670) + + Phase 2 (#2680) expanded a container's regions (`loop.body` / + `parallel.branches[]` / `try_catch.try`/`catch`) inline on the flow designer + canvas, but the nested nodes were read-only — changing one still meant editing + the container's Advanced JSON by hand. A nested node is now a first-class + selection: click it on the expanded canvas and it opens in the SAME + schema-driven inspector as a top-level node, with a `container › region › node` + breadcrumb. Edits (label / type / description / typed config fields / Advanced + JSON) write straight back into `config..nodes[i]` — the write rebuilds + the container with explicit spreads so the `config.branches` array stays an + array and each region's own `edges` / a branch's `name` are preserved. + + Scope resolves correctly for the region's outer context (ADR-0031): a loop + body node sees the loop's `iteratorVariable` in its data picker even though the + container's own outputs are otherwise out of scope at its id. + + This phase is edit-only by design. A nested node keeps its id read-only (rename + it in the container's Advanced JSON), has no delete, and — for a nested + decision — drops the virtual Target column, since a region sub-graph's internal + routing is not managed by the inspector yet (nested region-edge editing, + structural add/remove, and drag are follow-ups). A stale nested deep link + (the draft moved on) resolves to a harmless empty-state rather than writing to + the wrong node. + + Also fixes an expression/template validation split now that the engine + publishes a loop `configSchema`: a string property can carry an `xExpression: +'expression' | 'template'` marker so the designer renders bare-CEL vs + `interpolate()` `{var}` semantics (mono editor, data-picker brace mode, and + whether the CEL brace-trap applies) instead of guessing from the field name. A + loop / map `collection` (`{leadList}`) is a template, so it no longer + false-positives as a malformed condition inline or on the canvas badge. + +- 12390de: feat(studio): nest per-iteration / per-region step logs in the flow Runs panel (#1505) + + The run-observability `FlowRunsPanel` (Studio → flow preview → Runs) rendered a + run's step log as a flat list, so a `loop` container showed as a single step and + its body steps — one set per iteration — appeared as an undifferentiated repeat + of the same node ids, with `parallel` branches and `try`/`catch` handlers + likewise flattened. The automation engine already tags each structured-region + body step with its container (`parentNodeId`) plus an `iteration` / `regionKind` + (ADR-0031, framework #1505); the panel ignored those fields. + + `FlowRunsPanel` now reconstructs the execution tree from the flat, pre-order step + log (`buildStepTree`) and nests body steps under their container node, grouped by + a per-iteration / per-branch / handler header (`Iteration 2`, `Branch 1`, `Try`, + `Catch`). The reconstruction is robust to repeated node ids (a loop body node + runs once per iteration) and to regions nested inside regions, and degrades + safely — a body step whose container was dropped by durable-history truncation + still surfaces at the top level rather than vanishing. + +- 7abe4cd: **Console user-import wizard defaults to the `auto` password policy (tracks framework#3236).** The "Sign-in setup for imported users" selector gains an **Automatic (recommended)** option and it is now the default (was "No password"). `auto` decides per row on the server: reachable users get an invitation (email / SMS), anyone who can't be reached gets a one-time password shown once on the result screen — so it works with or without an email/SMS service, and the one-time-password reveal now surfaces only the rows that actually fell back (instead of the whole batch under `temporary`). + + The other three policies are unchanged and still selectable: `invite` (force invitations, unreachable rows fail), `temporary` (force one-time passwords for every row), `none` (identity only). New `console.identityImport.policy.auto` / `policyHint.auto` strings added for `en` and `zh`; the `none` label drops its "(recommended)" marker. + +- 2331ac9: feat(report): drill a date-bucket cell into its time range, not a superset (#1752) + + Clicking a report/dashboard cell grouped by a `dateGranularity` date dimension + ("2026-Q2") used to drill into a **superset** — the date dimension was skipped, + so the record list spanned every time bucket. It now scopes to the clicked + bucket's half-open range, consuming the framework's new `drillRanges` sidecar. + + - **`@object-ui/core`** — `buildDatasetDrillFilter` accepts the per-row + `drillRanges` and emits an ObjectQL range operator object + (`{ [field]: { $gte, $lt } }`) alongside the equality dims. + - **`@object-ui/plugin-report` / `@object-ui/plugin-dashboard`** — the report + renderer and dashboard widget forward `drillRanges`, and a **date-only** + report (no equality drill dim) is now drillable via the range alone. + - **`@object-ui/app-shell`** — the "Open in list →" escape hatch + (`useOpenRecordList`) now targets the ADR-0055 **bare data surface** + (`/:object/data`, "the URL is the view" — no baked-in view filter to + over-narrow the drill) and serializes a range to the + `filter[field][gte|lt]` operator contract. `ObjectDataPage` parses those + operators (equality shorthand unchanged), renders a range as a single chip, + and removes both bounds together. A new `drillUrlFilters` module owns the + write/read serialization so both sides can't drift (round-trip tested). + + Companion to the framework analytics change (objectstack-ai/framework#3256). + +- e7a8de7: feat(flow-designer): map free-form object maps → keyValue (and numeric arrays → numberList) in the schema-driven inspector (#3304) + + The server-first flow-designer form generator (`jsonSchemaToFlowFields`, ADR-0018) + had no way to render the flat `{ var: value }` **keyValue** editor from a JSON + Schema, so any node whose config uses a free-form map — a CRUD node's `fields` / + `filter`, an `assignment`'s `assignments`, a connector's `input`, a screen's + `defaults` — could not be driven from its published `configSchema` without + dropping that editor to raw Advanced JSON. + + The adapter now maps: + + - an object with **`additionalProperties`** (a value schema, or `true`) and **no + fixed `properties`** → a `keyValue` field (the object-with-`properties` case + still flattens to sub-fields; an opaque object or `additionalProperties: false` + still falls through to the Advanced block); + - an array of **number / integer** → `numberList` (the sibling of the existing + array-of-string → `stringList`). + + This is a pure capability addition — inert until a node publishes such a schema, + so no existing form changes. It unblocks giving the previously schema-less flow + nodes (assignment, the CRUD quartet, script, subflow, screen) a server-driven + config form that matches their hardcoded one, the objectui half of framework + #3304 (the descriptor-side counterpart to #2670 Phase 3). + +- 7938b60: feat(studio): filter editor for roll-up `summary` fields (framework#1868) + + The object-designer field inspector now edits `summaryOperations.filter` on a + `summary` field. Backing the framework's new filtered roll-ups — where one child + object feeds several parent totals, each aggregating only the child rows a + predicate matches (an approved-only sum vs the grand total) — the inspector adds + a structured field/operator/value row editor under Rollup Options (mirroring the + lookupFilters editor), reading and writing the spec's FilterCondition object. + + - Values are coerced to the child field's stored type, so a `boolean` field emits + `{ billable: true }` (not the string `"true"`) and a numeric operator emits + `{ amount: { $gte: 500 } }` — the FilterCondition then matches the real column. + - Rows map to/from the flat FilterCondition (and a top-level `$and`); a filter + using logic the rows can't represent (`$or` / nested) is shown read-only with a + note instead of being clobbered on edit. + - New `designer.field.summary.filter*` i18n keys (en + zh-CN). + +- 276c6ba: feat(flow-designer): first-class panel for the time-relative trigger (#1874) + + The flow designer's start-node inspector now offers a **Time-relative (date sweep)** + trigger option alongside record / schedule triggers. Picking it reveals typed + fields for the backend's `config.timeRelative` descriptor — Sweep object, Date + field, Within days (range mode), Offset days (T-minus mode), an Extra filter, and + Max records — instead of hand-writing the block in the Advanced JSON editor. The + per-record Entry condition is available too. + + Adds a `numberList` config-field kind (a string-list editor that commits + `number[]`), so **Offset days** authors emit numbers rather than strings — keeping + the backend schema (`z.array(z.number())`) strict rather than coercing on the + consumer side. All fields live under the nested `config.timeRelative` block, which + the group fully owns, so it never double-renders in Advanced JSON. + +### Patch Changes + +- 0318118: fix(app-shell): block ActionParamDialog submit while a file/image param is uploading; map spec `autonumber` (ADR-0059 follow-ups) + + Two follow-ups to the shared-field-widget param rendering (ADR-0059): + + - **Upload-in-progress guard.** A `file`/`image` param's value only becomes its + fileId once the presigned upload settles, so confirming mid-upload sent an + empty/stale value. `FileField`/`ImageField` now surface their upload state via + an optional `onUploadingChange` prop (shared `useUploadingSignal` hook, + ignored by other widgets); `ActionParamDialog` wires it for `file`/`image` + params and disables Confirm (label → "Uploading…", new `actionDialog.uploading` + i18n key across all locales) plus blocks submit while any upload is in flight. + - **`autonumber` spelling.** `mapFieldTypeToFormType` now maps the spec + `FieldType` spelling `autonumber` (in addition to the widget-map key + `auto_number`) to the AutoNumber widget, so a spec-typed `autonumber` + field/param no longer falls through to the plain text input — fixes the object + form path as well as action params. + +- af1b0db: feat(i18n): localize action result dialogs via the `_actions..resultDialog` convention + + The post-success secret-reveal dialog (create-user temporary password, 2FA + backup codes, OAuth client secrets) always rendered the hardcoded English + metadata literals — the spec bundles now carry `resultDialog` translations + (objectstack `_actions..resultDialog.*`), but nothing resolved them + client-side. + + - **@object-ui/i18n.** `useObjectLabel()` gains `actionResultDialog(objectName, +actionName, spec)`: overlays translated `title` / `description` / + `acknowledge` and per-field labels onto the metadata spec, falling back to + the literals. The `fields` node is keyed by the LITERAL result-field path + (may contain dots, e.g. `"user.email"`), so it is fetched whole with + `returnObjects` and indexed directly — never resolved through a dotted + i18next key. Built-in locale packs also translate the dialog's fallback + `defaultTitle` / `acknowledge` (previously English in all ten locales) and + add the new `actions.resultDialog.copyAll` key. + - **@object-ui/app-shell.** The result-dialog handlers in + `useConsoleActionRuntime` and `RecordDetailView` accept the action context + (already passed by `ActionRunner`) and localize the spec before opening the + dialog; `ActionResultDialog`'s hardcoded "Copy all" button now goes through + `actions.resultDialog.copyAll`. + +- 8b8b744: chore(deps): align `@objectstack/formula` / `lint` / `client` to `^15.1.1` + + These three were still pinned to `^14.6.0` while `@objectstack/spec` was already + `^15.1.1` — a version skew from the v15 upgrade (formula/lint/client publish in + lockstep with spec, and their own 15.0.0 entries are pure dependency bumps, so + this is alignment, not a behavioral migration). + + Practical effect: the client-side field-rule evaluation + (`visibleWhen`/`readonlyWhen`/`requiredWhen` via `fieldRules.ts`, which delegates + to `@objectstack/formula`'s `ExpressionEngine`) now tracks the 15.x engine — and + will pick up the framework's `dateField == today()` equality fix + (objectstack-ai/framework#3205) automatically at the next 15.x release via the + caret range. Renderer/action `visible`/`disabled` predicates are unaffected (they + use the home-grown JS evaluator — tracked separately in #2661). + +- 7cf4051: chore(deps): align every `@objectstack/*` dependency to `^16.0.0-rc.0` + + Bumps `@objectstack/spec` / `client` / `formula` / `lint` from `^15.1.1` to the + `16.0.0-rc.0` pre-release across the workspace (root + `apps/console` + + `apps/site` + all consuming packages). ObjectUI's own packages are already on + major 16, so this closes the 15↔16 skew between ObjectUI and the `@objectstack` + contract libraries (which publish in lockstep with `spec`). + + This is a dependency alignment, not a behavioral migration: the full workspace + build (43/43) and the `@objectstack`-consuming package test suites + (`core` / `app-shell` / `data-objectstack` / `plugin-form` / `types`) are green + against `16.0.0-rc.0` with no source changes required. + + Practical effect: `@objectstack/client@16.0.0-rc.0` now ships + `data.batchTransaction` (framework #3271), so `ObjectStackAdapter`'s feature + detect (`typeof client.data.batchTransaction === 'function'`) routes + master-detail cross-object saves through the typed SDK method instead of the + raw `fetch('/api/v1/batch')` fallback — realizing the "verify SDK path" half of + #2694. The raw-fetch branch stays as a defensive fallback (removal tracked in + #2694). + +- 803558e: feat(data): thread the host's authenticated fetch into `provider: 'api'` data sources (#2725) + + `provider: 'api'` view data sources went through a bare `globalThis.fetch`, so + custom endpoints (gantt composite trees, report aggregates) carried only + same-origin cookies while every native `/api/v1/*` request carried + `Authorization: Bearer` — the moment cookie HMAC verification failed (dev + restart rotating the fallback auth secret, cookie expiry/rotation in prod) + those views 401'd while the rest of the app kept working. + + - **`@object-ui/react`** — `SchemaRendererProvider` accepts an optional + `apiFetch`; nested providers inherit it from their parent so re-wrapped + subtrees (react pages, preview surfaces) keep the host's authentication. + `useViewData` defaults the api-provider adapter's fetch to the context + `apiFetch` (explicit `adapterOptions.fetch` still wins). + - **`@object-ui/auth`** — `createAuthenticatedFetch` gains a + `sameOriginOnly` option: cross-origin URLs pass through to the bare fetch + with no `Authorization` / `X-Tenant-ID` / `Accept-Language`, so metadata- + supplied third-party URLs never see the platform token. + - **`@object-ui/app-shell`** — the console wires + `createAuthenticatedFetch({ sameOriginOnly: true })` (settle-signal wrapped) + as `apiFetch` on the root `SchemaRendererProvider`. + - **`@object-ui/plugin-gantt`** — `ObjectGantt` resolves its api-provider + DataSource with the context `apiFetch`, covering reads and write-backs. + + Behaviour is unchanged for hosts that don't provide `apiFetch` (bare fetch + + cookies, as before). + +- ce5e3fc: fix(flow-designer): author the canonical `config.schedule` a scheduled flow's runtime reads + + The start-node inspector's "Cron schedule" field wrote a flat `config.cron`, but the + automation runtime (`resolveTriggerBinding` → `normalizeSchedule`) only ever reads + `config.schedule` — so a scheduled flow authored in the designer silently never + bound and never fired. The field now writes the canonical nested + `config.schedule.expression`, and a `fallbackPath` migrates an existing flat + `config.cron` on first edit. Reading `.expression` also renders an object-shaped + `config.schedule` (e.g. `{ type: 'cron', expression }`) as its cron string instead of + "[object Object]" (the old legacy text field on `config.schedule` printed the object). + The canvas node-card summary reads the nested value too. The field is also offered for + the `time_relative` sweep cadence (optional; defaults to daily). + +- d9c304d: chore(lint): clear the baseline lint errors in app-shell (objectui#2713 Wave 3) + + Final package of the #2713 lint-gate restoration — with this the whole workspace + is at **0 lint errors**. `@object-ui/app-shell` was red at baseline on `main`; + cleared every **error** (no behavior change; warnings out of scope): + + - **`react-hooks/rules-of-hooks` (12)** — hooks called after conditional early + returns, restructured so hook order is stable: + - `SchemaForm`: hoisted the `issuesByPath` `useMemo` above the RawJsonEditor + fallback guard, and `RecordField`'s five `useState` above its widget / + specialized-editor early returns. + - `MetadataPanel`: moved `if (!open) return null` below its three hooks. + - `LayeredDiff`: moved the `if (code == null)` guard below the two `useMemo`s + and made `rows` null-safe (`code == null ? [] : computeDiffRows(...)`). + - `ViewPreview`: hoisted the `object-view` `schema` `useMemo` above the three + render branches (the earlier branches shadow it locally). + - **`react-hooks/static-components` (12)** — icon/inspector/preview lookups + (`getIcon`, `typeIcon`, `kindIcon`, `getMetadataPreview` / `…Inspector` / + `…DefaultInspector`) are stable registry references → justified scoped disables. + - **`no-useless-assignment` (3)** — dead `= null` / `= []` initializers in + `marketplaceApi` and the two ratchet tests (the only fall-through paths + reassign first). + - **`@typescript-eslint/ban-ts-comment` (2)** — the `lucide-react/dynamic.mjs` + imports in `getIcon` / `widgets` no longer error under the build's `tsc`, so + the stale `@ts-ignore` directives are removed outright. + - **stale `eslint-disable` (1)** — removed a `@next/next/no-img-element` + directive in `AgentPreview` whose plugin isn't loaded in the flat config. + +- 2b17339: fix(list): keep the injected `owner_id` out of the leading auto-derived columns + + A view-less object's default list columns are derived from the object's field + order. The framework's `applySystemFields` spreads its injected + system/audit/ownership fields to the FRONT of that order and stamps them + `system: true`; `owner_id` is deliberately non-hidden and non-readonly + (ownership is reassignable), so the old name-based exclusion lists in + `ObjectGrid` and `InterfaceListPage` — which never listed `owner_id` — let it + through as column #1 on many showcase list pages (e.g. `showcase_field_zoo`). + + Default-column derivation now classifies system fields via the shared + `isSystemManagedField` helper, which branches on the spec `system` flag (the + single source of truth stamped by the registry) with a name-set fallback that + includes the ownership/tenancy FKs. `owner_id` is pushed to the end + (`ObjectGrid`) / excluded from the business columns (`InterfaceListPage`), so + auto-derived lists lead with business fields again and pick up future injected + fields without editing a name list. Also declares the `system` flag on the + `@object-ui/types` field metadata. + +- 31b77d4: **Add the explicit `engine-owned` lifecycle bucket (tracks framework ADR-0103 addendum / #3343).** The framework split the overloaded `managedBy: 'system'` bucket by promoting the engine-owned case to its own enum value; this mirrors it in the UI type + runtime + badge. + + - **`@object-ui/types`** — `ManagedByBucket` union and `MANAGED_BY_BUCKETS` gain `'engine-owned'` (canonical order: `platform, config, system, engine-owned, append-only, better-auth`). The union stays closed, so every consumer that missed the new value is a compile error. + - **`@object-ui/core`** — `resolveCrudAffordances` gains the `engine-owned` default row (identical all-locked matrix as `system`/`append-only`), so `isObjectInlineEditable` / the grid + form gates treat it as read-only automatically. + - **`@object-ui/app-shell`** — the `ManagedByBadge` renders `engine-owned` with the same read-only "System-managed" copy as a locked `system` object (reuses the existing `managedByBadge.system` i18n key — zero translation churn; the distinction is at the schema level, not the user-facing string), and `resolveManagedByEmptyState` reuses the `system` engine-owned empty state. + + Behaviour-preserving: `engine-owned` resolves to the same locked affordances `system` did by default, so nothing about how a locked object renders changes — the value just makes the schema self-documenting. New unit coverage for the bucket in `resolveCrudAffordances` / `isObjectInlineEditable` / `MANAGED_BY_BUCKETS` / the empty-state helper. + +- 6d4fbe6: **Consolidate the `managedBy` lifecycle-bucket logic into one shared source of truth (follows framework ADR-0103).** The bucket taxonomy was hand-mirrored in several places — `crudAffordances.ts`, `ManagedByBadge.tsx` (its own `Bucket` union + `isWriteOptedIn` + the writable-system derivation), and `plugin-detail`'s `record-details.tsx` (`NON_EDITABLE_BUCKETS`, duplicated because it can't depend on app-shell) — a drift risk, and the object-schema `managedBy` type was open-ended (`(string & {})`) so unknown buckets slipped through and silently defaulted to fully-editable. + + - **`@object-ui/types`** now owns the closed `ManagedByBucket` union (+ `MANAGED_BY_BUCKETS`), and `ObjectSchema.managedBy` is tightened from `'platform' | 'better-auth' | (string & {})` to that union — unknown buckets are now a type error at authoring time. + - **`@object-ui/core`** now owns the React-free runtime logic — `resolveCrudAffordances`, `isWriteOptedIn`, `isSystemWritable`, `isObjectInlineEditable` — reachable by every UI package including `plugin-detail` (which could not import app-shell). + - **`app-shell/utils/crudAffordances.ts`** is now a thin re-export of `@object-ui/core` (existing imports keep working); `ManagedByBadge` consumes the shared `isSystemWritable`; `plugin-detail` `record-details.tsx` replaces its hand-mirrored `NON_EDITABLE_BUCKETS` with `isObjectInlineEditable`. + + Behavior-preserving — all existing affordance/edit-gate tests stay green; the shared module adds direct unit coverage (including the previously-untested `isSystemWritable` derivation). Translated copy (badge variants, empty-state messages) stays in app-shell. + +- 0a3710b: **Finish the `managedBy` / `userActions` de-dup — one parser for the override shape (completes objectui#2712, framework#3343).** #2712 consolidated the bucket _union_ + affordance _set_ mirrors but left four surfaces still parsing the `userActions.{create,edit,delete}` override shape by hand. They now all route through the shared `@object-ui/core` policy, so no package re-implements the boolean / #2614-object-form parse locally. + + - **`@object-ui/core`** promotes the internal `normalizeOverride` to the exported **`normalizeUserAction(v, base)`** (the one parser) and adds **`userActionPredicates(v)`** for per-record CEL predicate extraction. + - **`app-shell/utils/managedByEmptyState.ts`** — the writable-`system` create check and its local `EmptyStateUserActions` interface are replaced by `resolveCrudAffordances({ managedBy, userActions }).create`. + - **`plugin-grid/rowCrudAffordances.ts`** — the local `isOptedOut` / `predicatesOf` helpers (and duplicated `RowCrudUserAction` / `RowCrudPredicates` types) fold into `normalizeUserAction`; the historical type names stay re-exported for compat. + - **`plugin-detail/RelatedList.tsx`** — its inline `predicatesOf` fold into `userActionPredicates`. + - **`plugin-form/ObjectForm.tsx`** — the hand-rolled `managedBy !== 'platform'` blanket lock + `userActions` unlock is replaced by the resolved affordance for the current mode (`edit` / `create`), the **same** `resolveCrudAffordances` contract the detail (`isObjectInlineEditable`) and grid surfaces use. + + Behavior-preserving for `platform` / `system` / `append-only` / `better-auth`, with one deliberate alignment: an admin-editable **`config`**-bucket object (e.g. `sys_webhook`, `sys_permission_set`) is now editable in `ObjectForm` — it was previously over-locked as "non-`platform`", while detail/grid already treated it as editable (`config` resolves `edit: true`). New unit coverage for the shared parser and the config / create-mode form gate; all existing affordance/edit-gate tests stay green. + +- f80aaf2: **Distinguish writable `system` objects from engine-owned ones in the Console (framework ADR-0103 / #3220).** The framework split the overloaded `managedBy: 'system'` bucket: engine-owned rows stay read-only, but several `system` objects are admin/user-writable _data_ (Notification Preferences/Subscriptions/Templates, delegated RBAC assignments, user preferences) and declare `userActions` opening their writes. + + The Console already surfaced the New/Edit/Delete buttons correctly for these (all affordance mirrors honour `userActions`), but the badge and empty-state _copy_ still called every `system` object a "read-only monitoring surface". Now: + + - **`ManagedByBadge`** takes the object's `userActions` and, when a `system` object opens any write, renders the "Platform schema — admin-writable" variant instead of the engine-owned copy. + - **`resolveManagedByEmptyState`** returns `undefined` for a `system` object whose `userActions.create` is set, so the generic empty state (with the New button) shows instead of "entries appear automatically". + - New `managedByBadge.systemWritable.*` strings (en + zh; other locales fall back to the English default). + + Copy/UX only — no behavioural change to what a user can do. + +- Updated dependencies [0318118] +- Updated dependencies [1c8935a] +- Updated dependencies [af1b0db] +- Updated dependencies [8b8b744] +- Updated dependencies [7cf4051] +- Updated dependencies [803558e] +- Updated dependencies [aefcf39] +- Updated dependencies [8c1e415] +- Updated dependencies [2e7d7f0] +- Updated dependencies [ef14f69] +- Updated dependencies [94d4876] +- Updated dependencies [1100a8b] +- Updated dependencies [7abe4cd] +- Updated dependencies [69fa5d1] +- Updated dependencies [549c67d] +- Updated dependencies [ebe6494] +- Updated dependencies [2b17339] +- Updated dependencies [31b77d4] +- Updated dependencies [6d4fbe6] +- Updated dependencies [0a3710b] +- Updated dependencies [f80aaf2] +- Updated dependencies [62b9ab5] +- Updated dependencies [14cb729] +- Updated dependencies [1629313] +- Updated dependencies [faebac3] +- Updated dependencies [2331ac9] +- Updated dependencies [199fa83] +- Updated dependencies [eee4ded] +- Updated dependencies [3b2e4d9] + - @object-ui/fields@16.1.0 + - @object-ui/i18n@16.1.0 + - @object-ui/core@16.1.0 + - @object-ui/data-objectstack@16.1.0 + - @object-ui/types@16.1.0 + - @object-ui/react@16.1.0 + - @object-ui/auth@16.1.0 + - @object-ui/components@16.1.0 + - @object-ui/layout@16.1.0 + - @object-ui/collaboration@16.1.0 + - @object-ui/plugin-editor@16.1.0 + - @object-ui/permissions@16.1.0 + - @object-ui/providers@16.1.0 + ## 16.0.0 ### Minor Changes diff --git a/packages/app-shell/package.json b/packages/app-shell/package.json index 1d15e2e8f..10687593b 100644 --- a/packages/app-shell/package.json +++ b/packages/app-shell/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/app-shell", - "version": "16.0.0", + "version": "16.1.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 88af5f164..c0734b52c 100644 --- a/packages/auth/CHANGELOG.md +++ b/packages/auth/CHANGELOG.md @@ -1,5 +1,48 @@ # @object-ui/auth +## 16.1.0 + +### Minor Changes + +- 803558e: feat(data): thread the host's authenticated fetch into `provider: 'api'` data sources (#2725) + + `provider: 'api'` view data sources went through a bare `globalThis.fetch`, so + custom endpoints (gantt composite trees, report aggregates) carried only + same-origin cookies while every native `/api/v1/*` request carried + `Authorization: Bearer` — the moment cookie HMAC verification failed (dev + restart rotating the fallback auth secret, cookie expiry/rotation in prod) + those views 401'd while the rest of the app kept working. + + - **`@object-ui/react`** — `SchemaRendererProvider` accepts an optional + `apiFetch`; nested providers inherit it from their parent so re-wrapped + subtrees (react pages, preview surfaces) keep the host's authentication. + `useViewData` defaults the api-provider adapter's fetch to the context + `apiFetch` (explicit `adapterOptions.fetch` still wins). + - **`@object-ui/auth`** — `createAuthenticatedFetch` gains a + `sameOriginOnly` option: cross-origin URLs pass through to the bare fetch + with no `Authorization` / `X-Tenant-ID` / `Accept-Language`, so metadata- + supplied third-party URLs never see the platform token. + - **`@object-ui/app-shell`** — the console wires + `createAuthenticatedFetch({ sameOriginOnly: true })` (settle-signal wrapped) + as `apiFetch` on the root `SchemaRendererProvider`. + - **`@object-ui/plugin-gantt`** — `ObjectGantt` resolves its api-provider + DataSource with the context `apiFetch`, covering reads and write-backs. + + Behaviour is unchanged for hosts that don't provide `apiFetch` (bare fetch + + cookies, as before). + +### Patch Changes + +- Updated dependencies [7cf4051] +- Updated dependencies [94d4876] +- Updated dependencies [2b17339] +- Updated dependencies [31b77d4] +- Updated dependencies [6d4fbe6] +- Updated dependencies [62b9ab5] +- Updated dependencies [faebac3] +- Updated dependencies [199fa83] + - @object-ui/types@16.1.0 + ## 16.0.0 ### Patch Changes diff --git a/packages/auth/package.json b/packages/auth/package.json index f50949929..6e1857011 100644 --- a/packages/auth/package.json +++ b/packages/auth/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/auth", - "version": "16.0.0", + "version": "16.1.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 d78d19bcf..760b688a8 100644 --- a/packages/cli/CHANGELOG.md +++ b/packages/cli/CHANGELOG.md @@ -1,5 +1,55 @@ # @object-ui/cli +## 16.1.0 + +### Patch Changes + +- 549c67d: chore(lint): clear the mechanical baseline lint errors so these packages' lint gates protect them again + + Extends the fields/core cleanup from #2709 (objectui#2713). These eight package + lints were red at baseline on `main`, so their per-package `lint` gate could not + catch new violations of the same class. Cleared every **error** (no behavior + change; warnings are out of scope): + + - **`no-useless-catch`** (`data-objectstack`) — unwrapped five try/catch blocks + whose `catch` only re-threw; errors still propagate identically. + - **`preserve-caught-error`** (`cli`, `data-objectstack`, `react`) — the caught + error's message is inlined into the thrown `Error`; a scoped disable with a + justifying comment carries each one, because these packages target ES2020 + whose lib types the 1-arg `Error` constructor only (so `{ cause }` won't + compile) — same reasoning as the core case in #2709. + - **`prefer-const`** (`plugin-calendar`, `plugin-map`) — `let`→`const` for + never-reassigned bindings. + - **`no-empty-object-type`** (`plugin-designer`) — empty extend-only interfaces + → equivalent `type` aliases. + - **`no-useless-assignment`** (`react`) — dropped a dead initializer that both + branches overwrite before it is read. + - **`no-require-imports`** (`plugin-calendar`, `plugin-timeline` tests) — + hoisted `vi.mock` factories now use an `async` factory with + `await import('react')` instead of `require('react')`. + - **stale `eslint-disable` directive** (`plugin-markdown`) — removed a + `react/no-danger` disable whose plugin is not loaded in the flat config (an + unknown-rule reference that ESLint v10 reports as an error); the rationale is + kept as a plain comment. + +- Updated dependencies [7cf4051] +- Updated dependencies [803558e] +- Updated dependencies [2e7d7f0] +- Updated dependencies [ef14f69] +- Updated dependencies [94d4876] +- Updated dependencies [69fa5d1] +- Updated dependencies [549c67d] +- Updated dependencies [2b17339] +- Updated dependencies [31b77d4] +- Updated dependencies [6d4fbe6] +- Updated dependencies [62b9ab5] +- Updated dependencies [1629313] +- Updated dependencies [faebac3] +- Updated dependencies [199fa83] + - @object-ui/types@16.1.0 + - @object-ui/react@16.1.0 + - @object-ui/components@16.1.0 + ## 16.0.0 ### Patch Changes diff --git a/packages/cli/package.json b/packages/cli/package.json index 31a510387..2b3b96a4b 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/cli", - "version": "16.0.0", + "version": "16.1.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 a469accbb..74880e005 100644 --- a/packages/collaboration/CHANGELOG.md +++ b/packages/collaboration/CHANGELOG.md @@ -1,5 +1,53 @@ # @object-ui/collaboration +## 16.1.0 + +### Patch Changes + +- ebe6494: chore(lint): clear the baseline lint errors in nine more packages (objectui#2713 Wave 2) + + Second wave of the #2713 lint-gate restoration (after #2730). These nine package + lints were red at baseline on `main`, so their per-package `lint` gate could not + catch new violations. Cleared every **error** (no behavior change; warnings out + of scope): + + - **`react-hooks/rules-of-hooks`** (`i18n`, `plugin-grid`, `plugin-view`, + `plugin-list`) — translation helpers (`useSafeFieldLabel`, + `useRowActionTranslation`, `useViewLabel`, `useViewTabLabel`, `useMoreLabel`) + wrapped a provider-safe hook (`useObjectTranslation`/`useObjectLabel`, which + never throw) in try/catch; removed the wrapper (the same fix #2709 applied in + fields). `plugin-kanban` `ObjectKanban` moved its `if (error)` early return + below the `useCallback` so hooks run unconditionally. `collaboration` + `__unsafe_usePresenceContext` keeps its deliberate danger-prefix name via a + justified scoped disable. + - **`react-hooks/static-components`** (`layout`, `plugin-list`, `plugin-report`) + — dynamic-icon / registry lookups (`resolveIcon`, `useRegistryComponent`) are + stable component references, not components created during render → scoped + disable with justification. `plugin-charts` `TreemapCell` was a _genuine_ + inline component and is hoisted to module scope (it is purely props-driven). + - **`no-irregular-whitespace`** (`plugin-grid` `ImportWizard`) — the literal + U+FEFF BOM prepended to exported CSV/text blobs (so Excel detects UTF-8) is + now written as the `` escape: byte-identical at runtime, no literal + irregular-whitespace character in source. + - **`no-useless-assignment`** (`plugin-grid` `BulkActionDialog`) — dropped a + dead `= null` initializer that the exhaustive `switch` (incl. `default`) + overwrites before it is read. + - **`no-unsafe-function-type`** (`plugin-view` `ViewTabBar`) — the dnd-kit + render-prop `listeners` map is typed `Record void>` + instead of bare `Function`. + - **`no-require-imports`** (`plugin-kanban`, `plugin-view` tests) — hoisted + `vi.mock` factories use an `async` factory with `await import('react')`. + +- Updated dependencies [7cf4051] +- Updated dependencies [94d4876] +- Updated dependencies [2b17339] +- Updated dependencies [31b77d4] +- Updated dependencies [6d4fbe6] +- Updated dependencies [62b9ab5] +- Updated dependencies [faebac3] +- Updated dependencies [199fa83] + - @object-ui/types@16.1.0 + ## 16.0.0 ### Patch Changes diff --git a/packages/collaboration/package.json b/packages/collaboration/package.json index 763c33695..1ad8d9c68 100644 --- a/packages/collaboration/package.json +++ b/packages/collaboration/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/collaboration", - "version": "16.0.0", + "version": "16.1.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 76850dd57..2fa50d666 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -1,5 +1,109 @@ # @object-ui/components +## 16.1.0 + +### Patch Changes + +- ef14f69: feat(fields): CheckboxesField per-option `visibleWhen` cascading + `dependsOn` gating (completes the option-widget parity set) + + `checkboxes` was the last static-option widget still rendering `config.options` + raw — with no per-option `visibleWhen` filtering, `dependsOn` gating, or cascade + clear. It now matches `MultiSelectField` (its multi-value sibling), completing + the ADR-0058 parity across `select` / `multiselect` / `radio` / `checkboxes`. + + - **`@object-ui/fields`**: `CheckboxesField` routes through the shared + `useCascadingOptions` hook — offered boxes narrow against the live record + + `current_user`, the control gates behind a "select the parent first" hint + while a `dependsOn` field is empty, and selections no longer offered are + pruned per-element from the array. Adds `checkboxes-empty-*` / + `checkboxes-option-*` testids. + - **`@object-ui/components`**: adds `checkboxes` to the form renderer's option + field sets (`CASCADE_OPTION_FIELD_TYPES`, the cross-field cascade-clear + effect, and the option pre-filter) so a `checkboxes` field is threaded + `dependentValues` and gated identically to the other option widgets. + - Tests: `CheckboxesField.cascade.test.tsx` mirrors `MultiSelectField.cascade.test.tsx`. + +- 69fa5d1: chore(lint): clear the baseline lint errors in components (objectui#2713 Wave 3) + + Wave 3 of the #2713 lint-gate restoration. `@object-ui/components` was red at + baseline on `main`; cleared every **error** (no behavior change; warnings out of + scope): + + - **`react-hooks/rules-of-hooks`** — `react-page` `ReactKindPage` had a + capability-gate early return _before_ four hooks (incl. a `useEffect` that + `import()`s the react runtime). Hoisted the hooks above the gate **and guarded + the import** (`if (!capabilityEnabled) return` inside the effect) so a disabled + build still never loads the gated runtime; the disabled notice is returned + after the hooks. Translation helpers in `empty` / `action-bar` / `action-menu` + unwrap a try/catch around the provider-safe `useObjectTranslation` (the #2709 + fix). + - **`react-hooks/static-components`** — dynamic renderer/icon lookups + (`ComponentRegistry.get`, `resolveIcon`) in `action-bar` / `action-group` ×2 / + `action-menu`, and the five `__tests__` helpers that render a registry-resolved + component, are stable references → justified scoped disables. + - **`react-hooks/purity`** — `ui/sidebar` skeleton width uses `Math.random()` + once per mount (`useMemo([])`) for a decorative placeholder → justified scoped + disable. + - **`@typescript-eslint/no-empty-object-type`** — `ShimmerSkeletonProps` empty + extend → `type` alias. + - **`no-useless-assignment`** — `test-utils` `maxDepth` dead initializer → single + `const`. + - **`no-require-imports`** — `config-panel-renderer` test uses a top-level + `import React` instead of an in-test `require`. + - **stale `eslint-disable`** — removed a `jsx-a11y/alt-text` directive in + `elements` whose plugin is not loaded in the flat config. + +- 1629313: feat(fields): RadioField per-option `visibleWhen` cascading + `dependsOn` gating; single-source the option resolver + + Brings `RadioField` to parity with `SelectField` / `MultiSelectField` for ADR-0058 + cascading & role-gated options, and collapses the three copies of the + gate-then-filter logic onto one shared resolver. + + - **`@object-ui/core`**: new pure `resolveCascadingOptions(rawOptions, record, dependsOn, scope)` + → `{ options, gated, dependsOnFields }` — the single source of truth for + `dependsOn` gating + per-option `visibleWhen` filtering. + - **`@object-ui/fields`**: `RadioField` now narrows its offered radios against + the live record + `current_user`, gates behind a "select the parent first" + hint while a `dependsOn` field is empty, and clears a value no longer offered + (scalar cascade clear). The `useCascadingOptions` hook is refactored to a thin + React wrapper over `resolveCascadingOptions`. + - **`@object-ui/components`**: the form renderer's inline option pre-filter and + cross-field cascade-clear effect now call `resolveCascadingOptions` instead of + re-deriving gating/filtering, so they can't drift from the widgets (no + behavior change). + - Tests: `RadioField.cascade.test.tsx` mirrors the select cascade tests; core + gains `resolveCascadingOptions` unit coverage. + +- Updated dependencies [0318118] +- Updated dependencies [1c8935a] +- Updated dependencies [af1b0db] +- Updated dependencies [8b8b744] +- Updated dependencies [7cf4051] +- Updated dependencies [803558e] +- Updated dependencies [2e7d7f0] +- Updated dependencies [94d4876] +- Updated dependencies [1100a8b] +- Updated dependencies [7abe4cd] +- Updated dependencies [549c67d] +- Updated dependencies [ebe6494] +- Updated dependencies [2b17339] +- Updated dependencies [31b77d4] +- Updated dependencies [6d4fbe6] +- Updated dependencies [0a3710b] +- Updated dependencies [f80aaf2] +- Updated dependencies [62b9ab5] +- Updated dependencies [1629313] +- Updated dependencies [faebac3] +- Updated dependencies [2331ac9] +- Updated dependencies [199fa83] +- Updated dependencies [eee4ded] + - @object-ui/i18n@16.1.0 + - @object-ui/core@16.1.0 + - @object-ui/types@16.1.0 + - @object-ui/react@16.1.0 + - @object-ui/react-runtime@16.1.0 + - @object-ui/sdui-parser@16.1.0 + ## 16.0.0 ### Minor Changes diff --git a/packages/components/package.json b/packages/components/package.json index 955d5caa3..a8a39a6dd 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/components", - "version": "16.0.0", + "version": "16.1.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 a8fbc5078..54c55d20a 100644 --- a/packages/core/CHANGELOG.md +++ b/packages/core/CHANGELOG.md @@ -1,5 +1,241 @@ # @object-ui/core +## 16.1.0 + +### Minor Changes + +- 1c8935a: feat(app-shell): render ActionParamDialog params through the shared form field-widget renderer (ADR-0059, #2700) + + `ActionParamDialog` no longer hand-rolls a per-type ternary chain (select / + lookup / textarea / number / boolean, everything else → text input). Every + declared action param now renders through the same `fieldWidgetMap` the object + form uses, so a param of ANY form-supported field type — `file`, `image`, + `richtext`, `markdown`, `color`, `address`, `code`, `date`, … — gets its real + widget, lazily loaded behind `Suspense`. Subsumes the single `file` branch ask + in #2698: `type: 'file'` params render the real `FileField` upload control via + the ambient `UploadProvider`, honoring `multiple`/`accept`/`maxSize`. + + - `@object-ui/fields`: new exports `resolveFormWidgetType(type)` (widget-key + resolution incl. spec aliases, text fallback) and `getLazyFieldWidget(type)` + (per-type-cached `React.lazy` over the form's own widget loaders). + - `@object-ui/core`: `ActionParamDef` gains `accept`/`maxSize`; `multiple` is + now general widget config (was lookup-only). + - `@object-ui/app-shell`: new pure `paramToField()` adapter (param → field + shape) with a drift test pinning param support ⊇ form support (`FORM_FIELD_TYPES`), + mirroring the FieldEditWidget parity guard; `resolveActionParams()` inherits + `multiple`/`accept`/`maxSize` from the referenced field for every type. + `required` validation, `visible` CEL gating, helpText, error styling, and + value shapes for previously-supported types are unchanged. + +- 2e7d7f0: feat(evaluator): route `{ dialect: 'cel' }` component/action predicates to the canonical CEL engine (#2661) + + Component and action `visible` / `disabled` / `hidden` predicates were evaluated + by the home-grown JS `ExpressionEvaluator`, while field rules + (`visibleWhen`/`readonlyWhen`/`requiredWhen`, via `fieldRules.ts`) and row/list + conditionals (via `evalRowPredicate`) already delegate to the canonical + `@objectstack/formula` engine. That split meant a `{ dialect: 'cel' }` predicate + in a renderer/action surface was executed as **JavaScript** — CEL-only forms + (`x in list`, `has()`, typed `==`, the `today()`/`daysFromNow()` catalog) behaved + differently from, or faulted against, the server's enforcement. + + This converges the remaining tier onto the same engine: + + - **`@object-ui/core`** — `ExpressionEvaluator.evaluateCondition` now detects a + `{ dialect: 'cel', source }` envelope and evaluates it on `@objectstack/formula` + (via `evalFieldPredicate`), binding the `record` namespace plus the whole + context bag as top-level scope (`record.*`, `features.*`, `user.*`, `app.*`). + Fail-soft to visible/enabled to match the legacy default; `throwOnError` + callers still fail closed on a _faulting_ predicate (a genuine `false` never + throws). This fixes every `SchemaRenderer` visibility/disabled read at once. + - **`@object-ui/react`** — `toPredicateInput` preserves a CEL envelope instead of + collapsing it to a `${source}` string, and `useCondition` accepts and forwards + the envelope (keyed on a stable `(dialect, source)` so it doesn't re-evaluate + each render). Action buttons (`action-icon`/`group`/`bar`/`button`) therefore + evaluate CEL `visible`/`enabled`/`disabled` on the canonical engine. + + **Back-compat:** bare strings and `${…}` templates stay on the legacy JS path + (deprecation window); only an explicit `{ dialect: 'cel' }` envelope is rerouted. + `{ dialect: 'template' }` is unaffected. + + Together with the `^15.1.1` alignment (#2662), a renderer CEL predicate now + reaches the identical verdict as the server — including the framework's + `dateField == today()` equality fix (objectstack-ai/framework#3205) once it + lands in a published 15.x. The broader home-grown-vs-canonical divergence + motivation is #2661. + +- 31b77d4: **Add the explicit `engine-owned` lifecycle bucket (tracks framework ADR-0103 addendum / #3343).** The framework split the overloaded `managedBy: 'system'` bucket by promoting the engine-owned case to its own enum value; this mirrors it in the UI type + runtime + badge. + + - **`@object-ui/types`** — `ManagedByBucket` union and `MANAGED_BY_BUCKETS` gain `'engine-owned'` (canonical order: `platform, config, system, engine-owned, append-only, better-auth`). The union stays closed, so every consumer that missed the new value is a compile error. + - **`@object-ui/core`** — `resolveCrudAffordances` gains the `engine-owned` default row (identical all-locked matrix as `system`/`append-only`), so `isObjectInlineEditable` / the grid + form gates treat it as read-only automatically. + - **`@object-ui/app-shell`** — the `ManagedByBadge` renders `engine-owned` with the same read-only "System-managed" copy as a locked `system` object (reuses the existing `managedByBadge.system` i18n key — zero translation churn; the distinction is at the schema level, not the user-facing string), and `resolveManagedByEmptyState` reuses the `system` engine-owned empty state. + + Behaviour-preserving: `engine-owned` resolves to the same locked affordances `system` did by default, so nothing about how a locked object renders changes — the value just makes the schema self-documenting. New unit coverage for the bucket in `resolveCrudAffordances` / `isObjectInlineEditable` / `MANAGED_BY_BUCKETS` / the empty-state helper. + +- 62b9ab5: feat(data): unify master-detail saves behind `DataSource.batchTransaction`, isolate the non-atomic fallback in the adapter (#2679) + + Master-detail saves (`MasterDetailForm`, `LineItemsPanel`) now always persist + through `dataSource.batchTransaction(operations)` — one ordered cross-object + operation list, with `{ $ref: }` linking a child to a parent created + in the same batch. The form no longer contains any client-side orchestration or + best-effort compensation-delete; that atomicity anti-pattern is gone from the UI + layer (framework #1604 / framework ADR-0034 item 4). + + - **`@object-ui/types`** — `batchTransaction?` is now a first-class (optional) + method on the `DataSource` contract, typed via `BatchTransactionOperation` / + `BatchRef`. Replaces the previous `(dataSource as any).batchTransaction` + method-sniffing. + - **`@object-ui/core`** — new `emulateBatchTransaction(dataSource, operations)` + (sequential writes, `$ref` resolution, best-effort reverse-order compensation) + and `runBatchTransaction(dataSource, operations)` (prefers the adapter's method, + emulates otherwise). `ApiDataSource` / `ValueDataSource` implement + `batchTransaction` via the emulation. + - **`@object-ui/data-objectstack`** — `ObjectStackAdapter.batchTransaction` uses + the server's atomic `POST /api/v1/batch`, prefers the typed + `client.data.batchTransaction` SDK method when the installed client exposes it, + and degrades to the client-side emulation ONLY when the endpoint is missing + (404/405) or the runtime can't do transactions (501). Real errors (400/401/403/ + 409/500) still surface. This is the isolated, tested home of the non-atomic + fallback. + - **`@object-ui/plugin-form`** — removed `applyDetail` / `createMany` / + `ApplyDetailResult` from `masterDetailTx.ts`; `MasterDetailForm` and + `LineItemsPanel` build ops and call `runBatchTransaction`. `LineItemsPanel` + saves are now atomic on a capable backend, with the rollup folded into the same + batch. + + No behavior change on a current ObjectStack backend (it has `/api/v1/batch`); + older/limited backends keep a working — now clearly non-atomic — save path. + +- 1629313: feat(fields): RadioField per-option `visibleWhen` cascading + `dependsOn` gating; single-source the option resolver + + Brings `RadioField` to parity with `SelectField` / `MultiSelectField` for ADR-0058 + cascading & role-gated options, and collapses the three copies of the + gate-then-filter logic onto one shared resolver. + + - **`@object-ui/core`**: new pure `resolveCascadingOptions(rawOptions, record, dependsOn, scope)` + → `{ options, gated, dependsOnFields }` — the single source of truth for + `dependsOn` gating + per-option `visibleWhen` filtering. + - **`@object-ui/fields`**: `RadioField` now narrows its offered radios against + the live record + `current_user`, gates behind a "select the parent first" + hint while a `dependsOn` field is empty, and clears a value no longer offered + (scalar cascade clear). The `useCascadingOptions` hook is refactored to a thin + React wrapper over `resolveCascadingOptions`. + - **`@object-ui/components`**: the form renderer's inline option pre-filter and + cross-field cascade-clear effect now call `resolveCascadingOptions` instead of + re-deriving gating/filtering, so they can't drift from the widgets (no + behavior change). + - Tests: `RadioField.cascade.test.tsx` mirrors the select cascade tests; core + gains `resolveCascadingOptions` unit coverage. + +- 2331ac9: feat(report): drill a date-bucket cell into its time range, not a superset (#1752) + + Clicking a report/dashboard cell grouped by a `dateGranularity` date dimension + ("2026-Q2") used to drill into a **superset** — the date dimension was skipped, + so the record list spanned every time bucket. It now scopes to the clicked + bucket's half-open range, consuming the framework's new `drillRanges` sidecar. + + - **`@object-ui/core`** — `buildDatasetDrillFilter` accepts the per-row + `drillRanges` and emits an ObjectQL range operator object + (`{ [field]: { $gte, $lt } }`) alongside the equality dims. + - **`@object-ui/plugin-report` / `@object-ui/plugin-dashboard`** — the report + renderer and dashboard widget forward `drillRanges`, and a **date-only** + report (no equality drill dim) is now drillable via the range alone. + - **`@object-ui/app-shell`** — the "Open in list →" escape hatch + (`useOpenRecordList`) now targets the ADR-0055 **bare data surface** + (`/:object/data`, "the URL is the view" — no baked-in view filter to + over-narrow the drill) and serializes a range to the + `filter[field][gte|lt]` operator contract. `ObjectDataPage` parses those + operators (equality shorthand unchanged), renders a range as a single chip, + and removes both bounds together. A new `drillUrlFilters` module owns the + write/read serialization so both sides can't drift (round-trip tested). + + Companion to the framework analytics change (objectstack-ai/framework#3256). + +### Patch Changes + +- 8b8b744: chore(deps): align `@objectstack/formula` / `lint` / `client` to `^15.1.1` + + These three were still pinned to `^14.6.0` while `@objectstack/spec` was already + `^15.1.1` — a version skew from the v15 upgrade (formula/lint/client publish in + lockstep with spec, and their own 15.0.0 entries are pure dependency bumps, so + this is alignment, not a behavioral migration). + + Practical effect: the client-side field-rule evaluation + (`visibleWhen`/`readonlyWhen`/`requiredWhen` via `fieldRules.ts`, which delegates + to `@objectstack/formula`'s `ExpressionEngine`) now tracks the 15.x engine — and + will pick up the framework's `dateField == today()` equality fix + (objectstack-ai/framework#3205) automatically at the next 15.x release via the + caret range. Renderer/action `visible`/`disabled` predicates are unaffected (they + use the home-grown JS evaluator — tracked separately in #2661). + +- 7cf4051: chore(deps): align every `@objectstack/*` dependency to `^16.0.0-rc.0` + + Bumps `@objectstack/spec` / `client` / `formula` / `lint` from `^15.1.1` to the + `16.0.0-rc.0` pre-release across the workspace (root + `apps/console` + + `apps/site` + all consuming packages). ObjectUI's own packages are already on + major 16, so this closes the 15↔16 skew between ObjectUI and the `@objectstack` + contract libraries (which publish in lockstep with `spec`). + + This is a dependency alignment, not a behavioral migration: the full workspace + build (43/43) and the `@objectstack`-consuming package test suites + (`core` / `app-shell` / `data-objectstack` / `plugin-form` / `types`) are green + against `16.0.0-rc.0` with no source changes required. + + Practical effect: `@objectstack/client@16.0.0-rc.0` now ships + `data.batchTransaction` (framework #3271), so `ObjectStackAdapter`'s feature + detect (`typeof client.data.batchTransaction === 'function'`) routes + master-detail cross-object saves through the typed SDK method instead of the + raw `fetch('/api/v1/batch')` fallback — realizing the "verify SDK path" half of + #2694. The raw-fetch branch stays as a defensive fallback (removal tracked in + #2694). + +- 6d4fbe6: **Consolidate the `managedBy` lifecycle-bucket logic into one shared source of truth (follows framework ADR-0103).** The bucket taxonomy was hand-mirrored in several places — `crudAffordances.ts`, `ManagedByBadge.tsx` (its own `Bucket` union + `isWriteOptedIn` + the writable-system derivation), and `plugin-detail`'s `record-details.tsx` (`NON_EDITABLE_BUCKETS`, duplicated because it can't depend on app-shell) — a drift risk, and the object-schema `managedBy` type was open-ended (`(string & {})`) so unknown buckets slipped through and silently defaulted to fully-editable. + + - **`@object-ui/types`** now owns the closed `ManagedByBucket` union (+ `MANAGED_BY_BUCKETS`), and `ObjectSchema.managedBy` is tightened from `'platform' | 'better-auth' | (string & {})` to that union — unknown buckets are now a type error at authoring time. + - **`@object-ui/core`** now owns the React-free runtime logic — `resolveCrudAffordances`, `isWriteOptedIn`, `isSystemWritable`, `isObjectInlineEditable` — reachable by every UI package including `plugin-detail` (which could not import app-shell). + - **`app-shell/utils/crudAffordances.ts`** is now a thin re-export of `@object-ui/core` (existing imports keep working); `ManagedByBadge` consumes the shared `isSystemWritable`; `plugin-detail` `record-details.tsx` replaces its hand-mirrored `NON_EDITABLE_BUCKETS` with `isObjectInlineEditable`. + + Behavior-preserving — all existing affordance/edit-gate tests stay green; the shared module adds direct unit coverage (including the previously-untested `isSystemWritable` derivation). Translated copy (badge variants, empty-state messages) stays in app-shell. + +- 0a3710b: **Finish the `managedBy` / `userActions` de-dup — one parser for the override shape (completes objectui#2712, framework#3343).** #2712 consolidated the bucket _union_ + affordance _set_ mirrors but left four surfaces still parsing the `userActions.{create,edit,delete}` override shape by hand. They now all route through the shared `@object-ui/core` policy, so no package re-implements the boolean / #2614-object-form parse locally. + + - **`@object-ui/core`** promotes the internal `normalizeOverride` to the exported **`normalizeUserAction(v, base)`** (the one parser) and adds **`userActionPredicates(v)`** for per-record CEL predicate extraction. + - **`app-shell/utils/managedByEmptyState.ts`** — the writable-`system` create check and its local `EmptyStateUserActions` interface are replaced by `resolveCrudAffordances({ managedBy, userActions }).create`. + - **`plugin-grid/rowCrudAffordances.ts`** — the local `isOptedOut` / `predicatesOf` helpers (and duplicated `RowCrudUserAction` / `RowCrudPredicates` types) fold into `normalizeUserAction`; the historical type names stay re-exported for compat. + - **`plugin-detail/RelatedList.tsx`** — its inline `predicatesOf` fold into `userActionPredicates`. + - **`plugin-form/ObjectForm.tsx`** — the hand-rolled `managedBy !== 'platform'` blanket lock + `userActions` unlock is replaced by the resolved affordance for the current mode (`edit` / `create`), the **same** `resolveCrudAffordances` contract the detail (`isObjectInlineEditable`) and grid surfaces use. + + Behavior-preserving for `platform` / `system` / `append-only` / `better-auth`, with one deliberate alignment: an admin-editable **`config`**-bucket object (e.g. `sys_webhook`, `sys_permission_set`) is now editable in `ObjectForm` — it was previously over-locked as "non-`platform`", while detail/grid already treated it as editable (`config` resolves `edit: true`). New unit coverage for the shared parser and the config / create-mode form gate; all existing affordance/edit-gate tests stay green. + +- eee4ded: feat(fields): render `select` + `multiple` through the multi-value chip picker; restore fields/core lint gates + + - **Multi-value select** — a `select` field/param declared `multiple: true` + now renders the multi-value chip picker (the `multiselect` widget) and stores + a `string[]`, instead of collapsing to a single-value dropdown that could + hold only one value. The delegation lives inside `SelectField`, so the object + form, the inline grid editor, and the app-shell `ActionParamDialog` all + inherit it from the one `select` widget with no per-surface drift. Single + selects keep the cascading dropdown (multi + per-option `visibleWhen` + cascading is not a combination in use today). + - **`autonumber` mapping is unchanged** here; this change is orthogonal. + - **Lint gates restored** — fixed the pre-existing baseline lint errors that + had left the `@object-ui/fields` and `@object-ui/core` package lints red (so + the gate could not catch new violations): `react-hooks/rules-of-hooks` in + `ImageField` / `TextAreaField` / `index.tsx` (hooks hoisted above early + returns; the `useFieldTranslate` hook no longer wrapped in try/catch), plus + `no-useless-assignment` / `no-useless-escape` / `no-control-regex` / + `prefer-const` / `preserve-caught-error` in the core evaluator and utils. No + behavior change from the lint fixes. + +- Updated dependencies [7cf4051] +- Updated dependencies [94d4876] +- Updated dependencies [2b17339] +- Updated dependencies [31b77d4] +- Updated dependencies [6d4fbe6] +- Updated dependencies [62b9ab5] +- Updated dependencies [faebac3] +- Updated dependencies [199fa83] + - @object-ui/types@16.1.0 + ## 16.0.0 ### Patch Changes diff --git a/packages/core/package.json b/packages/core/package.json index 5165e7e9e..8b0bdc5d6 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/core", - "version": "16.0.0", + "version": "16.1.0", "type": "module", "sideEffects": false, "license": "MIT", diff --git a/packages/create-plugin/CHANGELOG.md b/packages/create-plugin/CHANGELOG.md index b8c4c5338..b4a55c815 100644 --- a/packages/create-plugin/CHANGELOG.md +++ b/packages/create-plugin/CHANGELOG.md @@ -1,5 +1,7 @@ # @object-ui/create-plugin +## 16.1.0 + ## 16.0.0 ## 15.0.0 diff --git a/packages/create-plugin/package.json b/packages/create-plugin/package.json index db125b272..d2a50f7c5 100644 --- a/packages/create-plugin/package.json +++ b/packages/create-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/create-plugin", - "version": "16.0.0", + "version": "16.1.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 da3089e3b..4331aa0fd 100644 --- a/packages/data-objectstack/CHANGELOG.md +++ b/packages/data-objectstack/CHANGELOG.md @@ -1,5 +1,156 @@ # @object-ui/data-objectstack +## 16.1.0 + +### Minor Changes + +- 8c1e415: feat(data-objectstack): gate the non-atomic batch fallback on the discovery `transactionalBatch` capability (#2693) + + `ObjectStackAdapter.batchTransaction` now negotiates atomic cross-object batch + **declaratively** instead of only probing at runtime. At `connect()` the adapter + reads `capabilities.transactionalBatch` from `GET /api/v1/discovery` + (framework #3298 — `declared === enforced`; the server advertises `true` only + when the `/batch` route is mounted _and_ the runtime engine can honour a + transaction): + + - **Declared `true`** — the adapter TRUSTS server atomicity: it calls `/batch` + and surfaces any failure (including `404`/`405`/`501`) as a real error. No + runtime probe, no non-atomic client-side compensation. + - **Declared `false`, or absent** (backend predates #3298) — the legacy path is + unchanged: probe `/batch` and, on `404`/`405`/`501`, fall back to the + non-atomic `emulateBatchTransaction`. Keeping this avoids regressing older + backends from "saves, less safe" to "no save path" (#2679 compat constraint). + + Both the hierarchical wire shape (`{ transactionalBatch: { enabled: true } }`) + and the flat form the client SDK normalizes to (`{ transactionalBatch: true }`) + are accepted. `@object-ui/core`'s generic `emulateBatchTransaction` / + `runBatchTransaction` are untouched and remain the fallback for adapters with no + server-side transaction (`ValueDataSource`, `MockDataSource`, …). + + Docs: the adapter README and the data-source guide now document the capability + table and the minimum-backend note — atomic cross-object saves are guaranteed + only against backends advertising the capability (framework #3298 / #1604). + + Picks up #2679 acceptance item 4; unblocked by framework#3298 (merged). + +- 62b9ab5: feat(data): unify master-detail saves behind `DataSource.batchTransaction`, isolate the non-atomic fallback in the adapter (#2679) + + Master-detail saves (`MasterDetailForm`, `LineItemsPanel`) now always persist + through `dataSource.batchTransaction(operations)` — one ordered cross-object + operation list, with `{ $ref: }` linking a child to a parent created + in the same batch. The form no longer contains any client-side orchestration or + best-effort compensation-delete; that atomicity anti-pattern is gone from the UI + layer (framework #1604 / framework ADR-0034 item 4). + + - **`@object-ui/types`** — `batchTransaction?` is now a first-class (optional) + method on the `DataSource` contract, typed via `BatchTransactionOperation` / + `BatchRef`. Replaces the previous `(dataSource as any).batchTransaction` + method-sniffing. + - **`@object-ui/core`** — new `emulateBatchTransaction(dataSource, operations)` + (sequential writes, `$ref` resolution, best-effort reverse-order compensation) + and `runBatchTransaction(dataSource, operations)` (prefers the adapter's method, + emulates otherwise). `ApiDataSource` / `ValueDataSource` implement + `batchTransaction` via the emulation. + - **`@object-ui/data-objectstack`** — `ObjectStackAdapter.batchTransaction` uses + the server's atomic `POST /api/v1/batch`, prefers the typed + `client.data.batchTransaction` SDK method when the installed client exposes it, + and degrades to the client-side emulation ONLY when the endpoint is missing + (404/405) or the runtime can't do transactions (501). Real errors (400/401/403/ + 409/500) still surface. This is the isolated, tested home of the non-atomic + fallback. + - **`@object-ui/plugin-form`** — removed `applyDetail` / `createMany` / + `ApplyDetailResult` from `masterDetailTx.ts`; `MasterDetailForm` and + `LineItemsPanel` build ops and call `runBatchTransaction`. `LineItemsPanel` + saves are now atomic on a capable backend, with the rollup folded into the same + batch. + + No behavior change on a current ObjectStack backend (it has `/api/v1/batch`); + older/limited backends keep a working — now clearly non-atomic — save path. + +### Patch Changes + +- 8b8b744: chore(deps): align `@objectstack/formula` / `lint` / `client` to `^15.1.1` + + These three were still pinned to `^14.6.0` while `@objectstack/spec` was already + `^15.1.1` — a version skew from the v15 upgrade (formula/lint/client publish in + lockstep with spec, and their own 15.0.0 entries are pure dependency bumps, so + this is alignment, not a behavioral migration). + + Practical effect: the client-side field-rule evaluation + (`visibleWhen`/`readonlyWhen`/`requiredWhen` via `fieldRules.ts`, which delegates + to `@objectstack/formula`'s `ExpressionEngine`) now tracks the 15.x engine — and + will pick up the framework's `dateField == today()` equality fix + (objectstack-ai/framework#3205) automatically at the next 15.x release via the + caret range. Renderer/action `visible`/`disabled` predicates are unaffected (they + use the home-grown JS evaluator — tracked separately in #2661). + +- 7cf4051: chore(deps): align every `@objectstack/*` dependency to `^16.0.0-rc.0` + + Bumps `@objectstack/spec` / `client` / `formula` / `lint` from `^15.1.1` to the + `16.0.0-rc.0` pre-release across the workspace (root + `apps/console` + + `apps/site` + all consuming packages). ObjectUI's own packages are already on + major 16, so this closes the 15↔16 skew between ObjectUI and the `@objectstack` + contract libraries (which publish in lockstep with `spec`). + + This is a dependency alignment, not a behavioral migration: the full workspace + build (43/43) and the `@objectstack`-consuming package test suites + (`core` / `app-shell` / `data-objectstack` / `plugin-form` / `types`) are green + against `16.0.0-rc.0` with no source changes required. + + Practical effect: `@objectstack/client@16.0.0-rc.0` now ships + `data.batchTransaction` (framework #3271), so `ObjectStackAdapter`'s feature + detect (`typeof client.data.batchTransaction === 'function'`) routes + master-detail cross-object saves through the typed SDK method instead of the + raw `fetch('/api/v1/batch')` fallback — realizing the "verify SDK path" half of + #2694. The raw-fetch branch stays as a defensive fallback (removal tracked in + #2694). + +- 549c67d: chore(lint): clear the mechanical baseline lint errors so these packages' lint gates protect them again + + Extends the fields/core cleanup from #2709 (objectui#2713). These eight package + lints were red at baseline on `main`, so their per-package `lint` gate could not + catch new violations of the same class. Cleared every **error** (no behavior + change; warnings are out of scope): + + - **`no-useless-catch`** (`data-objectstack`) — unwrapped five try/catch blocks + whose `catch` only re-threw; errors still propagate identically. + - **`preserve-caught-error`** (`cli`, `data-objectstack`, `react`) — the caught + error's message is inlined into the thrown `Error`; a scoped disable with a + justifying comment carries each one, because these packages target ES2020 + whose lib types the 1-arg `Error` constructor only (so `{ cause }` won't + compile) — same reasoning as the core case in #2709. + - **`prefer-const`** (`plugin-calendar`, `plugin-map`) — `let`→`const` for + never-reassigned bindings. + - **`no-empty-object-type`** (`plugin-designer`) — empty extend-only interfaces + → equivalent `type` aliases. + - **`no-useless-assignment`** (`react`) — dropped a dead initializer that both + branches overwrite before it is read. + - **`no-require-imports`** (`plugin-calendar`, `plugin-timeline` tests) — + hoisted `vi.mock` factories now use an `async` factory with + `await import('react')` instead of `require('react')`. + - **stale `eslint-disable` directive** (`plugin-markdown`) — removed a + `react/no-danger` disable whose plugin is not loaded in the flat config (an + unknown-rule reference that ESLint v10 reports as an error); the rationale is + kept as a plain comment. + +- Updated dependencies [1c8935a] +- Updated dependencies [8b8b744] +- Updated dependencies [7cf4051] +- Updated dependencies [2e7d7f0] +- Updated dependencies [94d4876] +- Updated dependencies [2b17339] +- Updated dependencies [31b77d4] +- Updated dependencies [6d4fbe6] +- Updated dependencies [0a3710b] +- Updated dependencies [62b9ab5] +- Updated dependencies [1629313] +- Updated dependencies [faebac3] +- Updated dependencies [2331ac9] +- Updated dependencies [199fa83] +- Updated dependencies [eee4ded] + - @object-ui/core@16.1.0 + - @object-ui/types@16.1.0 + ## 16.0.0 ### Patch Changes diff --git a/packages/data-objectstack/package.json b/packages/data-objectstack/package.json index cbc30f716..9950ded8e 100644 --- a/packages/data-objectstack/package.json +++ b/packages/data-objectstack/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/data-objectstack", - "version": "16.0.0", + "version": "16.1.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 09e094d68..7cee38944 100644 --- a/packages/fields/CHANGELOG.md +++ b/packages/fields/CHANGELOG.md @@ -1,5 +1,202 @@ # @object-ui/fields +## 16.1.0 + +### Minor Changes + +- 1c8935a: feat(app-shell): render ActionParamDialog params through the shared form field-widget renderer (ADR-0059, #2700) + + `ActionParamDialog` no longer hand-rolls a per-type ternary chain (select / + lookup / textarea / number / boolean, everything else → text input). Every + declared action param now renders through the same `fieldWidgetMap` the object + form uses, so a param of ANY form-supported field type — `file`, `image`, + `richtext`, `markdown`, `color`, `address`, `code`, `date`, … — gets its real + widget, lazily loaded behind `Suspense`. Subsumes the single `file` branch ask + in #2698: `type: 'file'` params render the real `FileField` upload control via + the ambient `UploadProvider`, honoring `multiple`/`accept`/`maxSize`. + + - `@object-ui/fields`: new exports `resolveFormWidgetType(type)` (widget-key + resolution incl. spec aliases, text fallback) and `getLazyFieldWidget(type)` + (per-type-cached `React.lazy` over the form's own widget loaders). + - `@object-ui/core`: `ActionParamDef` gains `accept`/`maxSize`; `multiple` is + now general widget config (was lookup-only). + - `@object-ui/app-shell`: new pure `paramToField()` adapter (param → field + shape) with a drift test pinning param support ⊇ form support (`FORM_FIELD_TYPES`), + mirroring the FieldEditWidget parity guard; `resolveActionParams()` inherits + `multiple`/`accept`/`maxSize` from the referenced field for every type. + `required` validation, `visible` CEL gating, helpText, error styling, and + value shapes for previously-supported types are unchanged. + +- ef14f69: feat(fields): CheckboxesField per-option `visibleWhen` cascading + `dependsOn` gating (completes the option-widget parity set) + + `checkboxes` was the last static-option widget still rendering `config.options` + raw — with no per-option `visibleWhen` filtering, `dependsOn` gating, or cascade + clear. It now matches `MultiSelectField` (its multi-value sibling), completing + the ADR-0058 parity across `select` / `multiselect` / `radio` / `checkboxes`. + + - **`@object-ui/fields`**: `CheckboxesField` routes through the shared + `useCascadingOptions` hook — offered boxes narrow against the live record + + `current_user`, the control gates behind a "select the parent first" hint + while a `dependsOn` field is empty, and selections no longer offered are + pruned per-element from the array. Adds `checkboxes-empty-*` / + `checkboxes-option-*` testids. + - **`@object-ui/components`**: adds `checkboxes` to the form renderer's option + field sets (`CASCADE_OPTION_FIELD_TYPES`, the cross-field cascade-clear + effect, and the option pre-filter) so a `checkboxes` field is threaded + `dependentValues` and gated identically to the other option widgets. + - Tests: `CheckboxesField.cascade.test.tsx` mirrors `MultiSelectField.cascade.test.tsx`. + +- 14cb729: feat(fields): MultiSelectField per-option `visibleWhen` cascading + `dependsOn` gating (parity with single select, #2715) + + The multi-value chip picker now implements the same ADR-0058 option + resolution as the single `SelectField`, closing the gap #2709 opened when a + `select` + `multiple` (and the `multiselect` type) started delegating to it. + + - Extracted `useCascadingOptions` — the shared hook that resolves per-option + `visibleWhen` filtering, `dependsOn` gating, and the live `dependentValues` + + predicate-scope wiring — and routed both `SingleSelectField` and + `MultiSelectField` through it (no duplicated resolver). + - `MultiSelectField` narrows its offered chips against the live record + + `current_user`, gates behind a "select the parent first" hint while a + `dependsOn` field is empty, and surfaces a legible empty state instead of a + bare chip row. + - Cascade-clear: when the offered set changes (parent changed / predicate + flipped) the widget prunes only the now-invalid selections, keeping the + still-offered ones — the array analogue of the single select's clear. + - Tests: `MultiSelectField.cascade.test.tsx` mirrors `SelectField.cascade.test.tsx` + (gating, per-element cascade clear, role/context gating). + +- 1629313: feat(fields): RadioField per-option `visibleWhen` cascading + `dependsOn` gating; single-source the option resolver + + Brings `RadioField` to parity with `SelectField` / `MultiSelectField` for ADR-0058 + cascading & role-gated options, and collapses the three copies of the + gate-then-filter logic onto one shared resolver. + + - **`@object-ui/core`**: new pure `resolveCascadingOptions(rawOptions, record, dependsOn, scope)` + → `{ options, gated, dependsOnFields }` — the single source of truth for + `dependsOn` gating + per-option `visibleWhen` filtering. + - **`@object-ui/fields`**: `RadioField` now narrows its offered radios against + the live record + `current_user`, gates behind a "select the parent first" + hint while a `dependsOn` field is empty, and clears a value no longer offered + (scalar cascade clear). The `useCascadingOptions` hook is refactored to a thin + React wrapper over `resolveCascadingOptions`. + - **`@object-ui/components`**: the form renderer's inline option pre-filter and + cross-field cascade-clear effect now call `resolveCascadingOptions` instead of + re-deriving gating/filtering, so they can't drift from the widgets (no + behavior change). + - Tests: `RadioField.cascade.test.tsx` mirrors the select cascade tests; core + gains `resolveCascadingOptions` unit coverage. + +- eee4ded: feat(fields): render `select` + `multiple` through the multi-value chip picker; restore fields/core lint gates + + - **Multi-value select** — a `select` field/param declared `multiple: true` + now renders the multi-value chip picker (the `multiselect` widget) and stores + a `string[]`, instead of collapsing to a single-value dropdown that could + hold only one value. The delegation lives inside `SelectField`, so the object + form, the inline grid editor, and the app-shell `ActionParamDialog` all + inherit it from the one `select` widget with no per-surface drift. Single + selects keep the cascading dropdown (multi + per-option `visibleWhen` + cascading is not a combination in use today). + - **`autonumber` mapping is unchanged** here; this change is orthogonal. + - **Lint gates restored** — fixed the pre-existing baseline lint errors that + had left the `@object-ui/fields` and `@object-ui/core` package lints red (so + the gate could not catch new violations): `react-hooks/rules-of-hooks` in + `ImageField` / `TextAreaField` / `index.tsx` (hooks hoisted above early + returns; the `useFieldTranslate` hook no longer wrapped in try/catch), plus + `no-useless-assignment` / `no-useless-escape` / `no-control-regex` / + `prefer-const` / `preserve-caught-error` in the core evaluator and utils. No + behavior change from the lint fixes. + +### Patch Changes + +- 0318118: fix(app-shell): block ActionParamDialog submit while a file/image param is uploading; map spec `autonumber` (ADR-0059 follow-ups) + + Two follow-ups to the shared-field-widget param rendering (ADR-0059): + + - **Upload-in-progress guard.** A `file`/`image` param's value only becomes its + fileId once the presigned upload settles, so confirming mid-upload sent an + empty/stale value. `FileField`/`ImageField` now surface their upload state via + an optional `onUploadingChange` prop (shared `useUploadingSignal` hook, + ignored by other widgets); `ActionParamDialog` wires it for `file`/`image` + params and disables Confirm (label → "Uploading…", new `actionDialog.uploading` + i18n key across all locales) plus blocks submit while any upload is in flight. + - **`autonumber` spelling.** `mapFieldTypeToFormType` now maps the spec + `FieldType` spelling `autonumber` (in addition to the widget-map key + `auto_number`) to the AutoNumber widget, so a spec-typed `autonumber` + field/param no longer falls through to the plain text input — fixes the object + form path as well as action params. + +- aefcf39: feat(action-params): serialize file/image action params to storage id(s); retire the approvals composer + + Declared action params of `type: 'file'`/`'image'` now POST the portable API + contract — the storage id(s) — instead of the upload widget's rich object: + + - `FileField` surfaces the id it already receives from the upload adapter + (`meta.fileId`) as `file_id` on each emitted file object (additive; the + record file-field value shape is unchanged). + - `ActionParamDialog` maps upload-param values to their `file_id`(s) at submit + (`serializeParamValues`, pure + exported): single → string, `multiple` → + `string[]`. The api handler already forwards param values untouched, so an + action with a `file` param POSTs `attachments: string[]`. + + This lets the approvals inbox retire its last hand-wired UI — the approve/reject + composer with its bespoke attachment upload — so the drawer renders every + decision through `DeclaredActionsBar` with the declared `attachments` file param + (framework side declares it; see the paired framework change). `DeclaredActionsBar`'s + `exclude` prop stays as a general capability. + +- 3b2e4d9: fix(list): route remaining system-field groupings through the shared classifier + + Follow-up to the `owner_id` default-column fix: consolidate the display-oriented + system-field exclusions onto the shared `isSystemManagedField` / + `SYSTEM_MANAGED_FIELD_NAMES` (from `@object-ui/types`) so the framework-injected + `owner_id` is treated consistently across the grid, record picker, and detail + drawer. + + - `ObjectGrid` record-detail drawer: the business-fields vs. muted meta-section + split now uses the shared classifier, so `owner_id` (and other injected system + fields) land in the meta section instead of the business body. + - `deriveLookupColumns` (record picker): drops its local name set for the shared + classifier — now flag-aware (`field.system`), not just name-based. + - `RecordDetailDrawer`: its default `systemFields` set is derived from the shared + `SYSTEM_MANAGED_FIELD_NAMES`; the `systemFields` prop override is preserved. + + `deriveRelatedLists`' narrow "audit FK on every object" set and plugin-detail's + inline-edit "never editable" set are intentionally left distinct — different + semantics (the latter deliberately keeps `owner_id` editable). + +- Updated dependencies [0318118] +- Updated dependencies [1c8935a] +- Updated dependencies [af1b0db] +- Updated dependencies [8b8b744] +- Updated dependencies [7cf4051] +- Updated dependencies [803558e] +- Updated dependencies [2e7d7f0] +- Updated dependencies [ef14f69] +- Updated dependencies [94d4876] +- Updated dependencies [1100a8b] +- Updated dependencies [7abe4cd] +- Updated dependencies [69fa5d1] +- Updated dependencies [549c67d] +- Updated dependencies [ebe6494] +- Updated dependencies [2b17339] +- Updated dependencies [31b77d4] +- Updated dependencies [6d4fbe6] +- Updated dependencies [0a3710b] +- Updated dependencies [f80aaf2] +- Updated dependencies [62b9ab5] +- Updated dependencies [1629313] +- Updated dependencies [faebac3] +- Updated dependencies [2331ac9] +- Updated dependencies [199fa83] +- Updated dependencies [eee4ded] + - @object-ui/i18n@16.1.0 + - @object-ui/core@16.1.0 + - @object-ui/types@16.1.0 + - @object-ui/react@16.1.0 + - @object-ui/components@16.1.0 + - @object-ui/providers@16.1.0 + ## 16.0.0 ### Patch Changes diff --git a/packages/fields/package.json b/packages/fields/package.json index 254de5c48..6021a8efb 100644 --- a/packages/fields/package.json +++ b/packages/fields/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/fields", - "version": "16.0.0", + "version": "16.1.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 070d71d2c..9c5718cb7 100644 --- a/packages/i18n/CHANGELOG.md +++ b/packages/i18n/CHANGELOG.md @@ -1,5 +1,110 @@ # @object-ui/i18n +## 16.1.0 + +### Minor Changes + +- af1b0db: feat(i18n): localize action result dialogs via the `_actions..resultDialog` convention + + The post-success secret-reveal dialog (create-user temporary password, 2FA + backup codes, OAuth client secrets) always rendered the hardcoded English + metadata literals — the spec bundles now carry `resultDialog` translations + (objectstack `_actions..resultDialog.*`), but nothing resolved them + client-side. + + - **@object-ui/i18n.** `useObjectLabel()` gains `actionResultDialog(objectName, +actionName, spec)`: overlays translated `title` / `description` / + `acknowledge` and per-field labels onto the metadata spec, falling back to + the literals. The `fields` node is keyed by the LITERAL result-field path + (may contain dots, e.g. `"user.email"`), so it is fetched whole with + `returnObjects` and indexed directly — never resolved through a dotted + i18next key. Built-in locale packs also translate the dialog's fallback + `defaultTitle` / `acknowledge` (previously English in all ten locales) and + add the new `actions.resultDialog.copyAll` key. + - **@object-ui/app-shell.** The result-dialog handlers in + `useConsoleActionRuntime` and `RecordDetailView` accept the action context + (already passed by `ActionRunner`) and localize the spec before opening the + dialog; `ActionResultDialog`'s hardcoded "Copy all" button now goes through + `actions.resultDialog.copyAll`. + +### Patch Changes + +- 0318118: fix(app-shell): block ActionParamDialog submit while a file/image param is uploading; map spec `autonumber` (ADR-0059 follow-ups) + + Two follow-ups to the shared-field-widget param rendering (ADR-0059): + + - **Upload-in-progress guard.** A `file`/`image` param's value only becomes its + fileId once the presigned upload settles, so confirming mid-upload sent an + empty/stale value. `FileField`/`ImageField` now surface their upload state via + an optional `onUploadingChange` prop (shared `useUploadingSignal` hook, + ignored by other widgets); `ActionParamDialog` wires it for `file`/`image` + params and disables Confirm (label → "Uploading…", new `actionDialog.uploading` + i18n key across all locales) plus blocks submit while any upload is in flight. + - **`autonumber` spelling.** `mapFieldTypeToFormType` now maps the spec + `FieldType` spelling `autonumber` (in addition to the widget-map key + `auto_number`) to the AutoNumber widget, so a spec-typed `autonumber` + field/param no longer falls through to the plain text input — fixes the object + form path as well as action params. + +- 1100a8b: feat(plugin-gantt)!: remove the 移动端二维码 (mobile QR share) context-menu item + + The QR-share feature is removed outright: the context-menu item, the QR dialog, + the `taskUrl` prop on `GanttView`, the URL wiring in `ObjectGantt`, the + `gantt.menu.qrcode` / `gantt.qr.*` i18n keys (en/zh) and the `qrcode` + dependency are all deleted. It baked one consumer's app-specific requirement + (scan-to-open on mobile) into the generic gantt renderer, and what it encoded — + the desktop console record URL — was not even the right target for that + requirement. Apps that need scan-to-mobile flows should implement them + app-side against their own mobile surface. + +- 7abe4cd: **Console user-import wizard defaults to the `auto` password policy (tracks framework#3236).** The "Sign-in setup for imported users" selector gains an **Automatic (recommended)** option and it is now the default (was "No password"). `auto` decides per row on the server: reachable users get an invitation (email / SMS), anyone who can't be reached gets a one-time password shown once on the result screen — so it works with or without an email/SMS service, and the one-time-password reveal now surfaces only the rows that actually fell back (instead of the whole batch under `temporary`). + + The other three policies are unchanged and still selectable: `invite` (force invitations, unreachable rows fail), `temporary` (force one-time passwords for every row), `none` (identity only). New `console.identityImport.policy.auto` / `policyHint.auto` strings added for `en` and `zh`; the `none` label drops its "(recommended)" marker. + +- ebe6494: chore(lint): clear the baseline lint errors in nine more packages (objectui#2713 Wave 2) + + Second wave of the #2713 lint-gate restoration (after #2730). These nine package + lints were red at baseline on `main`, so their per-package `lint` gate could not + catch new violations. Cleared every **error** (no behavior change; warnings out + of scope): + + - **`react-hooks/rules-of-hooks`** (`i18n`, `plugin-grid`, `plugin-view`, + `plugin-list`) — translation helpers (`useSafeFieldLabel`, + `useRowActionTranslation`, `useViewLabel`, `useViewTabLabel`, `useMoreLabel`) + wrapped a provider-safe hook (`useObjectTranslation`/`useObjectLabel`, which + never throw) in try/catch; removed the wrapper (the same fix #2709 applied in + fields). `plugin-kanban` `ObjectKanban` moved its `if (error)` early return + below the `useCallback` so hooks run unconditionally. `collaboration` + `__unsafe_usePresenceContext` keeps its deliberate danger-prefix name via a + justified scoped disable. + - **`react-hooks/static-components`** (`layout`, `plugin-list`, `plugin-report`) + — dynamic-icon / registry lookups (`resolveIcon`, `useRegistryComponent`) are + stable component references, not components created during render → scoped + disable with justification. `plugin-charts` `TreemapCell` was a _genuine_ + inline component and is hoisted to module scope (it is purely props-driven). + - **`no-irregular-whitespace`** (`plugin-grid` `ImportWizard`) — the literal + U+FEFF BOM prepended to exported CSV/text blobs (so Excel detects UTF-8) is + now written as the `` escape: byte-identical at runtime, no literal + irregular-whitespace character in source. + - **`no-useless-assignment`** (`plugin-grid` `BulkActionDialog`) — dropped a + dead `= null` initializer that the exhaustive `switch` (incl. `default`) + overwrites before it is read. + - **`no-unsafe-function-type`** (`plugin-view` `ViewTabBar`) — the dnd-kit + render-prop `listeners` map is typed `Record void>` + instead of bare `Function`. + - **`no-require-imports`** (`plugin-kanban`, `plugin-view` tests) — hoisted + `vi.mock` factories use an `async` factory with `await import('react')`. + +- f80aaf2: **Distinguish writable `system` objects from engine-owned ones in the Console (framework ADR-0103 / #3220).** The framework split the overloaded `managedBy: 'system'` bucket: engine-owned rows stay read-only, but several `system` objects are admin/user-writable _data_ (Notification Preferences/Subscriptions/Templates, delegated RBAC assignments, user preferences) and declare `userActions` opening their writes. + + The Console already surfaced the New/Edit/Delete buttons correctly for these (all affordance mirrors honour `userActions`), but the badge and empty-state _copy_ still called every `system` object a "read-only monitoring surface". Now: + + - **`ManagedByBadge`** takes the object's `userActions` and, when a `system` object opens any write, renders the "Platform schema — admin-writable" variant instead of the engine-owned copy. + - **`resolveManagedByEmptyState`** returns `undefined` for a `system` object whose `userActions.create` is set, so the generic empty state (with the New button) shows instead of "entries appear automatically". + - New `managedByBadge.systemWritable.*` strings (en + zh; other locales fall back to the English default). + + Copy/UX only — no behavioural change to what a user can do. + ## 16.0.0 ### Patch Changes diff --git a/packages/i18n/package.json b/packages/i18n/package.json index 606a2432b..f54dc222e 100644 --- a/packages/i18n/package.json +++ b/packages/i18n/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/i18n", - "version": "16.0.0", + "version": "16.1.0", "type": "module", "sideEffects": false, "license": "MIT", diff --git a/packages/layout/CHANGELOG.md b/packages/layout/CHANGELOG.md index 735baa002..27d42327b 100644 --- a/packages/layout/CHANGELOG.md +++ b/packages/layout/CHANGELOG.md @@ -1,5 +1,67 @@ # @object-ui/layout +## 16.1.0 + +### Patch Changes + +- ebe6494: chore(lint): clear the baseline lint errors in nine more packages (objectui#2713 Wave 2) + + Second wave of the #2713 lint-gate restoration (after #2730). These nine package + lints were red at baseline on `main`, so their per-package `lint` gate could not + catch new violations. Cleared every **error** (no behavior change; warnings out + of scope): + + - **`react-hooks/rules-of-hooks`** (`i18n`, `plugin-grid`, `plugin-view`, + `plugin-list`) — translation helpers (`useSafeFieldLabel`, + `useRowActionTranslation`, `useViewLabel`, `useViewTabLabel`, `useMoreLabel`) + wrapped a provider-safe hook (`useObjectTranslation`/`useObjectLabel`, which + never throw) in try/catch; removed the wrapper (the same fix #2709 applied in + fields). `plugin-kanban` `ObjectKanban` moved its `if (error)` early return + below the `useCallback` so hooks run unconditionally. `collaboration` + `__unsafe_usePresenceContext` keeps its deliberate danger-prefix name via a + justified scoped disable. + - **`react-hooks/static-components`** (`layout`, `plugin-list`, `plugin-report`) + — dynamic-icon / registry lookups (`resolveIcon`, `useRegistryComponent`) are + stable component references, not components created during render → scoped + disable with justification. `plugin-charts` `TreemapCell` was a _genuine_ + inline component and is hoisted to module scope (it is purely props-driven). + - **`no-irregular-whitespace`** (`plugin-grid` `ImportWizard`) — the literal + U+FEFF BOM prepended to exported CSV/text blobs (so Excel detects UTF-8) is + now written as the `` escape: byte-identical at runtime, no literal + irregular-whitespace character in source. + - **`no-useless-assignment`** (`plugin-grid` `BulkActionDialog`) — dropped a + dead `= null` initializer that the exhaustive `switch` (incl. `default`) + overwrites before it is read. + - **`no-unsafe-function-type`** (`plugin-view` `ViewTabBar`) — the dnd-kit + render-prop `listeners` map is typed `Record void>` + instead of bare `Function`. + - **`no-require-imports`** (`plugin-kanban`, `plugin-view` tests) — hoisted + `vi.mock` factories use an `async` factory with `await import('react')`. + +- Updated dependencies [1c8935a] +- Updated dependencies [8b8b744] +- Updated dependencies [7cf4051] +- Updated dependencies [803558e] +- Updated dependencies [2e7d7f0] +- Updated dependencies [ef14f69] +- Updated dependencies [94d4876] +- Updated dependencies [69fa5d1] +- Updated dependencies [549c67d] +- Updated dependencies [2b17339] +- Updated dependencies [31b77d4] +- Updated dependencies [6d4fbe6] +- Updated dependencies [0a3710b] +- Updated dependencies [62b9ab5] +- Updated dependencies [1629313] +- Updated dependencies [faebac3] +- Updated dependencies [2331ac9] +- Updated dependencies [199fa83] +- Updated dependencies [eee4ded] + - @object-ui/core@16.1.0 + - @object-ui/types@16.1.0 + - @object-ui/react@16.1.0 + - @object-ui/components@16.1.0 + ## 16.0.0 ### Patch Changes diff --git a/packages/layout/package.json b/packages/layout/package.json index 5fd7a2efd..d96b12e1f 100644 --- a/packages/layout/package.json +++ b/packages/layout/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/layout", - "version": "16.0.0", + "version": "16.1.0", "type": "module", "sideEffects": false, "main": "dist/index.umd.cjs", diff --git a/packages/mobile/CHANGELOG.md b/packages/mobile/CHANGELOG.md index 10011f1ee..e0beb4795 100644 --- a/packages/mobile/CHANGELOG.md +++ b/packages/mobile/CHANGELOG.md @@ -1,5 +1,19 @@ # @object-ui/mobile +## 16.1.0 + +### Patch Changes + +- Updated dependencies [7cf4051] +- Updated dependencies [94d4876] +- Updated dependencies [2b17339] +- Updated dependencies [31b77d4] +- Updated dependencies [6d4fbe6] +- Updated dependencies [62b9ab5] +- Updated dependencies [faebac3] +- Updated dependencies [199fa83] + - @object-ui/types@16.1.0 + ## 16.0.0 ### Patch Changes diff --git a/packages/mobile/package.json b/packages/mobile/package.json index 2d3131131..126504d31 100644 --- a/packages/mobile/package.json +++ b/packages/mobile/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/mobile", - "version": "16.0.0", + "version": "16.1.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 9deaf879b..9caaf4730 100644 --- a/packages/permissions/CHANGELOG.md +++ b/packages/permissions/CHANGELOG.md @@ -1,5 +1,19 @@ # @object-ui/permissions +## 16.1.0 + +### Patch Changes + +- Updated dependencies [7cf4051] +- Updated dependencies [94d4876] +- Updated dependencies [2b17339] +- Updated dependencies [31b77d4] +- Updated dependencies [6d4fbe6] +- Updated dependencies [62b9ab5] +- Updated dependencies [faebac3] +- Updated dependencies [199fa83] + - @object-ui/types@16.1.0 + ## 16.0.0 ### Patch Changes diff --git a/packages/permissions/package.json b/packages/permissions/package.json index f6b8069b4..bf78f1b39 100644 --- a/packages/permissions/package.json +++ b/packages/permissions/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/permissions", - "version": "16.0.0", + "version": "16.1.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 7870645ec..d12519dff 100644 --- a/packages/plugin-ai/CHANGELOG.md +++ b/packages/plugin-ai/CHANGELOG.md @@ -1,5 +1,33 @@ # @object-ui/plugin-ai +## 16.1.0 + +### Patch Changes + +- Updated dependencies [1c8935a] +- Updated dependencies [8b8b744] +- Updated dependencies [7cf4051] +- Updated dependencies [803558e] +- Updated dependencies [2e7d7f0] +- Updated dependencies [ef14f69] +- Updated dependencies [94d4876] +- Updated dependencies [69fa5d1] +- Updated dependencies [549c67d] +- Updated dependencies [2b17339] +- Updated dependencies [31b77d4] +- Updated dependencies [6d4fbe6] +- Updated dependencies [0a3710b] +- Updated dependencies [62b9ab5] +- Updated dependencies [1629313] +- Updated dependencies [faebac3] +- Updated dependencies [2331ac9] +- Updated dependencies [199fa83] +- Updated dependencies [eee4ded] + - @object-ui/core@16.1.0 + - @object-ui/types@16.1.0 + - @object-ui/react@16.1.0 + - @object-ui/components@16.1.0 + ## 16.0.0 ### Patch Changes diff --git a/packages/plugin-ai/package.json b/packages/plugin-ai/package.json index 9ad9e6d63..6836a2b25 100644 --- a/packages/plugin-ai/package.json +++ b/packages/plugin-ai/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/plugin-ai", - "version": "16.0.0", + "version": "16.1.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 2cbad68d0..5016440f0 100644 --- a/packages/plugin-calendar/CHANGELOG.md +++ b/packages/plugin-calendar/CHANGELOG.md @@ -1,5 +1,76 @@ # @object-ui/plugin-calendar +## 16.1.0 + +### Patch Changes + +- 549c67d: chore(lint): clear the mechanical baseline lint errors so these packages' lint gates protect them again + + Extends the fields/core cleanup from #2709 (objectui#2713). These eight package + lints were red at baseline on `main`, so their per-package `lint` gate could not + catch new violations of the same class. Cleared every **error** (no behavior + change; warnings are out of scope): + + - **`no-useless-catch`** (`data-objectstack`) — unwrapped five try/catch blocks + whose `catch` only re-threw; errors still propagate identically. + - **`preserve-caught-error`** (`cli`, `data-objectstack`, `react`) — the caught + error's message is inlined into the thrown `Error`; a scoped disable with a + justifying comment carries each one, because these packages target ES2020 + whose lib types the 1-arg `Error` constructor only (so `{ cause }` won't + compile) — same reasoning as the core case in #2709. + - **`prefer-const`** (`plugin-calendar`, `plugin-map`) — `let`→`const` for + never-reassigned bindings. + - **`no-empty-object-type`** (`plugin-designer`) — empty extend-only interfaces + → equivalent `type` aliases. + - **`no-useless-assignment`** (`react`) — dropped a dead initializer that both + branches overwrite before it is read. + - **`no-require-imports`** (`plugin-calendar`, `plugin-timeline` tests) — + hoisted `vi.mock` factories now use an `async` factory with + `await import('react')` instead of `require('react')`. + - **stale `eslint-disable` directive** (`plugin-markdown`) — removed a + `react/no-danger` disable whose plugin is not loaded in the flat config (an + unknown-rule reference that ESLint v10 reports as an error); the rationale is + kept as a plain comment. + +- Updated dependencies [0318118] +- Updated dependencies [1c8935a] +- Updated dependencies [af1b0db] +- Updated dependencies [8b8b744] +- Updated dependencies [7cf4051] +- Updated dependencies [803558e] +- Updated dependencies [aefcf39] +- Updated dependencies [2e7d7f0] +- Updated dependencies [ef14f69] +- Updated dependencies [94d4876] +- Updated dependencies [53513a4] +- Updated dependencies [1100a8b] +- Updated dependencies [7abe4cd] +- Updated dependencies [69fa5d1] +- Updated dependencies [f329ec5] +- Updated dependencies [549c67d] +- Updated dependencies [ebe6494] +- Updated dependencies [2b17339] +- Updated dependencies [31b77d4] +- Updated dependencies [6d4fbe6] +- Updated dependencies [0a3710b] +- Updated dependencies [f80aaf2] +- Updated dependencies [62b9ab5] +- Updated dependencies [14cb729] +- Updated dependencies [1629313] +- Updated dependencies [faebac3] +- Updated dependencies [2331ac9] +- Updated dependencies [199fa83] +- Updated dependencies [eee4ded] +- Updated dependencies [3b2e4d9] + - @object-ui/fields@16.1.0 + - @object-ui/i18n@16.1.0 + - @object-ui/core@16.1.0 + - @object-ui/types@16.1.0 + - @object-ui/react@16.1.0 + - @object-ui/plugin-detail@16.1.0 + - @object-ui/components@16.1.0 + - @object-ui/mobile@16.1.0 + ## 16.0.0 ### Patch Changes diff --git a/packages/plugin-calendar/package.json b/packages/plugin-calendar/package.json index 00c34e9aa..0c32f13d6 100644 --- a/packages/plugin-calendar/package.json +++ b/packages/plugin-calendar/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/plugin-calendar", - "version": "16.0.0", + "version": "16.1.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 3fdf9e3b7..43750e040 100644 --- a/packages/plugin-charts/CHANGELOG.md +++ b/packages/plugin-charts/CHANGELOG.md @@ -1,5 +1,74 @@ # @object-ui/plugin-charts +## 16.1.0 + +### Patch Changes + +- ebe6494: chore(lint): clear the baseline lint errors in nine more packages (objectui#2713 Wave 2) + + Second wave of the #2713 lint-gate restoration (after #2730). These nine package + lints were red at baseline on `main`, so their per-package `lint` gate could not + catch new violations. Cleared every **error** (no behavior change; warnings out + of scope): + + - **`react-hooks/rules-of-hooks`** (`i18n`, `plugin-grid`, `plugin-view`, + `plugin-list`) — translation helpers (`useSafeFieldLabel`, + `useRowActionTranslation`, `useViewLabel`, `useViewTabLabel`, `useMoreLabel`) + wrapped a provider-safe hook (`useObjectTranslation`/`useObjectLabel`, which + never throw) in try/catch; removed the wrapper (the same fix #2709 applied in + fields). `plugin-kanban` `ObjectKanban` moved its `if (error)` early return + below the `useCallback` so hooks run unconditionally. `collaboration` + `__unsafe_usePresenceContext` keeps its deliberate danger-prefix name via a + justified scoped disable. + - **`react-hooks/static-components`** (`layout`, `plugin-list`, `plugin-report`) + — dynamic-icon / registry lookups (`resolveIcon`, `useRegistryComponent`) are + stable component references, not components created during render → scoped + disable with justification. `plugin-charts` `TreemapCell` was a _genuine_ + inline component and is hoisted to module scope (it is purely props-driven). + - **`no-irregular-whitespace`** (`plugin-grid` `ImportWizard`) — the literal + U+FEFF BOM prepended to exported CSV/text blobs (so Excel detects UTF-8) is + now written as the `` escape: byte-identical at runtime, no literal + irregular-whitespace character in source. + - **`no-useless-assignment`** (`plugin-grid` `BulkActionDialog`) — dropped a + dead `= null` initializer that the exhaustive `switch` (incl. `default`) + overwrites before it is read. + - **`no-unsafe-function-type`** (`plugin-view` `ViewTabBar`) — the dnd-kit + render-prop `listeners` map is typed `Record void>` + instead of bare `Function`. + - **`no-require-imports`** (`plugin-kanban`, `plugin-view` tests) — hoisted + `vi.mock` factories use an `async` factory with `await import('react')`. + +- Updated dependencies [0318118] +- Updated dependencies [1c8935a] +- Updated dependencies [af1b0db] +- Updated dependencies [8b8b744] +- Updated dependencies [7cf4051] +- Updated dependencies [803558e] +- Updated dependencies [2e7d7f0] +- Updated dependencies [ef14f69] +- Updated dependencies [94d4876] +- Updated dependencies [1100a8b] +- Updated dependencies [7abe4cd] +- Updated dependencies [69fa5d1] +- Updated dependencies [549c67d] +- Updated dependencies [ebe6494] +- Updated dependencies [2b17339] +- Updated dependencies [31b77d4] +- Updated dependencies [6d4fbe6] +- Updated dependencies [0a3710b] +- Updated dependencies [f80aaf2] +- Updated dependencies [62b9ab5] +- Updated dependencies [1629313] +- Updated dependencies [faebac3] +- Updated dependencies [2331ac9] +- Updated dependencies [199fa83] +- Updated dependencies [eee4ded] + - @object-ui/i18n@16.1.0 + - @object-ui/core@16.1.0 + - @object-ui/types@16.1.0 + - @object-ui/react@16.1.0 + - @object-ui/components@16.1.0 + ## 16.0.0 ### Patch Changes diff --git a/packages/plugin-charts/package.json b/packages/plugin-charts/package.json index 8d6083b70..513ef9f6f 100644 --- a/packages/plugin-charts/package.json +++ b/packages/plugin-charts/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/plugin-charts", - "version": "16.0.0", + "version": "16.1.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 aee2513cf..e92ea431a 100644 --- a/packages/plugin-chatbot/CHANGELOG.md +++ b/packages/plugin-chatbot/CHANGELOG.md @@ -1,5 +1,56 @@ # @object-ui/plugin-chatbot +## 16.1.0 + +### Patch Changes + +- 59db1f9: chore(lint): clear the baseline lint errors in plugin-chatbot (objectui#2713 Wave 3) + + Wave 3 of the #2713 lint-gate restoration. `@object-ui/plugin-chatbot` was red at + baseline on `main`; cleared every **error** (no behavior change; warnings out of + scope): + + - **`react-hooks/rules-of-hooks` in `useObjectChat` (8)** — the hook called + DIFFERENT `useCallback`s in each of its two `isApiMode` return branches, so + both sets were conditional (React throws if the mode toggles between renders). + `useChat` was already called unconditionally; this destructures its result and + hoists all eight callbacks (3 API + 5 local) above the `isApiMode` branch, so + the same hooks run in the same order every render. Only the returned surface + differs by mode — the callback bodies are unchanged (the API `messages` local + is renamed `apiMessages`). Verified against the `useObjectChat.sendFailure` / + `handoffContext` / `ChatbotEnhanced.sendError` suites. + - **`react-hooks/rules-of-hooks` in `FloatingChatbotTrigger`** — + `useChatbotLabel` wrapped the provider-safe `useObjectTranslation` in + try/catch; removed the wrapper (the #2709 fix). + - **`react-hooks/static-components` in `shimmer`** — `motion.create(Component)` + genuinely builds a motion component and must key off the `as` prop, so it + can't be module-scoped. Memoized per `Component` (stable across renders, + avoids the remount) and carries a justified scoped disable at the render site. + +- Updated dependencies [1c8935a] +- Updated dependencies [8b8b744] +- Updated dependencies [7cf4051] +- Updated dependencies [803558e] +- Updated dependencies [2e7d7f0] +- Updated dependencies [ef14f69] +- Updated dependencies [94d4876] +- Updated dependencies [69fa5d1] +- Updated dependencies [549c67d] +- Updated dependencies [2b17339] +- Updated dependencies [31b77d4] +- Updated dependencies [6d4fbe6] +- Updated dependencies [0a3710b] +- Updated dependencies [62b9ab5] +- Updated dependencies [1629313] +- Updated dependencies [faebac3] +- Updated dependencies [2331ac9] +- Updated dependencies [199fa83] +- Updated dependencies [eee4ded] + - @object-ui/core@16.1.0 + - @object-ui/types@16.1.0 + - @object-ui/react@16.1.0 + - @object-ui/components@16.1.0 + ## 16.0.0 ### Patch Changes diff --git a/packages/plugin-chatbot/package.json b/packages/plugin-chatbot/package.json index 1bb91e30b..71c023726 100644 --- a/packages/plugin-chatbot/package.json +++ b/packages/plugin-chatbot/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/plugin-chatbot", - "version": "16.0.0", + "version": "16.1.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 7bf1e25ef..3b0407a68 100644 --- a/packages/plugin-dashboard/CHANGELOG.md +++ b/packages/plugin-dashboard/CHANGELOG.md @@ -1,5 +1,165 @@ # @object-ui/plugin-dashboard +## 16.1.0 + +### Minor Changes + +- 94d4876: feat(dashboard): Studio authors the ADR-0021 dataset shape only (framework#3251) + + Finishes the dashboard analytics migration on the authoring side so the + framework can enable `DashboardWidgetSchema.strict()`. Both Studio surfaces now + emit only the semantic-layer shape (`dataset` + `dimensions` + `values`); no + surface authors the removed pre-ADR-0021 inline query. + + **FROM → TO** (authoring) + + - charts: `object` + `categoryField` + `valueField` + `aggregate` + → `dataset` + `dimensions` + `values` + - pivots: `object` + `rowField` + `columnField` + `valueField` + `aggregation` + → `dataset` + `dimensions` + `values` (last dimension spreads across columns) + + **Changes** + + - `@object-ui/types` — `DashboardWidgetSchema` gains `dataset` / `dimensions` / + `values`; the inline analytics keys (`object`, `categoryField`, + `categoryGranularity`, `valueField`, `aggregate`, `measures`) are marked + `@deprecated` (retained only so the renderer can still read legacy/static + metadata during the transition). + - `@object-ui/plugin-dashboard` — `WidgetConfigPanel` is rewritten as a dataset + picker (chart AND pivot). **Breaking prop change:** the unused + `availableObjects` / `availableFields` props are replaced by a new + `datasets?: WidgetDatasetCatalogEntry[]` (+ `datasetsLoading?`) catalog prop, + also forwarded by `DashboardWithConfig`. Hosts resolve the catalog (e.g. via + the metadata client's `list('dataset')`); without it the panel falls back to + free-text authoring. New exports: `WidgetDatasetCatalogEntry` and + `sanitizeDraftForType`. + - `@object-ui/app-shell` — the metadata-admin `DashboardWidgetInspector` drops + the legacy inline fields (object / value field / category field / aggregate); + the dataset section is now the primary (and only) analytics binding, and the + filter-binding field picker sources options from the bound dataset's + dimensions. The "Add widget" catalog drops `list` / `custom` — neither is a + member of `@objectstack/spec` `ChartTypeSchema`, so a widget authored with + them could never publish. + + **Not changed:** `DashboardRenderer` keeps its legacy/static read branches and + the `ObjectPivotTable` / `PivotTable` blocks (still public SDUI blocks and the + backward-compat path for stored/static widgets) — only the dashboard authoring + flow stops emitting the legacy keys. Retiring those renderer branches is a + follow-up gated on migrating stored dashboards. + +- 2331ac9: feat(report): drill a date-bucket cell into its time range, not a superset (#1752) + + Clicking a report/dashboard cell grouped by a `dateGranularity` date dimension + ("2026-Q2") used to drill into a **superset** — the date dimension was skipped, + so the record list spanned every time bucket. It now scopes to the clicked + bucket's half-open range, consuming the framework's new `drillRanges` sidecar. + + - **`@object-ui/core`** — `buildDatasetDrillFilter` accepts the per-row + `drillRanges` and emits an ObjectQL range operator object + (`{ [field]: { $gte, $lt } }`) alongside the equality dims. + - **`@object-ui/plugin-report` / `@object-ui/plugin-dashboard`** — the report + renderer and dashboard widget forward `drillRanges`, and a **date-only** + report (no equality drill dim) is now drillable via the range alone. + - **`@object-ui/app-shell`** — the "Open in list →" escape hatch + (`useOpenRecordList`) now targets the ADR-0055 **bare data surface** + (`/:object/data`, "the URL is the view" — no baked-in view filter to + over-narrow the drill) and serializes a range to the + `filter[field][gte|lt]` operator contract. `ObjectDataPage` parses those + operators (equality shorthand unchanged), renders a range as a single chip, + and removes both bounds together. A new `drillUrlFilters` module owns the + write/read serialization so both sides can't drift (round-trip tested). + + Companion to the framework analytics change (objectstack-ai/framework#3256). + +- 199fa83: feat(dashboard): retire the pre-ADR-0021 inline-analytics renderer branches (framework#3320) + + Follow-up to the dashboard analytics migration (framework#3251 / objectui#2703). + Authoring already emits only the semantic-layer shape (`dataset` + `dimensions` + + `values`); this removes the renderer's now-unauthored legacy read-branches. + + - **types**: drop the `@deprecated` inline-analytics keys (`object`, + `categoryField`, `categoryGranularity`, `valueField`, `aggregate`, `measures`) + from `DashboardWidgetSchema`. They were retained in #2703 only so the renderer + could read legacy/static metadata during the transition. + - **plugin-dashboard**: `DashboardRenderer` no longer emits the object-bound + metric / chart / pivot / table / list branches from the top-level `object` + + analytics keys. It keeps the renderer-internal static paths (`options.data` / + `widget.data` array and the `provider: 'object'` async config) and + `widget.component`. The dashboard renderer no longer emits `object-pivot` / + `pivot` at all — dataset pivots render through `DatasetWidget` (grouped table / + cross-tab); the `ObjectPivotTable` / `PivotTable` components stay as public + SDUI blocks for other surfaces. `DashboardGridLayout` gets the same treatment. + - **graceful fallback**: a widget that still carries the retired inline shape in + stored metadata (top-level `object`, no `dataset`, no inline `options.data`) + now renders a visible error placeholder prompting a rebind to a dataset, rather + than a blank chart/grid. + - **plugin-designer**: `DashboardEditor` drops its inline object / value-field / + aggregate fields (analytics binding is authored via the dataset picker in + app-shell's `DashboardWidgetInspector` / plugin-dashboard's `WidgetConfigPanel`). + +### Patch Changes + +- 0c3209a: chore(lint): clear the baseline lint errors in plugin-dashboard (objectui#2713 Wave 3) + + First package of Wave 3 in the #2713 lint-gate restoration. `@object-ui/plugin-dashboard` + was red at baseline on `main`; cleared every **error** (no behavior change; + warnings out of scope): + + - **`react-hooks/rules-of-hooks`** (`ObjectDataTable`) — `useObjectTranslation` + was wrapped in try/catch; removed the wrapper (the hook is provider-safe and + never throws — the #2709 fix). English defaults still stand until a + translation resolves. + - **`react-hooks/static-components`** (`MetricCard`, `MetricWidget`) — + `getLazyIcon(name)` returns a module-cached, stable component per name (not a + component created during render), so the render sites carry a justified scoped + disable. + - **`no-irregular-whitespace`** (`DatasetWidget`) — the literal U+FEFF BOM + prepended to the exported CSV blob (Excel UTF-8 detection) is written as the + `` escape: byte-identical at runtime, no literal irregular-whitespace char. + - **`no-useless-escape`** (`recordFields`) — dropped a needless `\$` inside a + character class (`[\$¥€£]` → `[$¥€£]`). + - **`no-sparse-arrays`** (`recordFields`) — the `|| [, '']` match fallback is + written `[undefined, '']` so index 0 is an explicit hole, not a sparse one. + - **`no-useless-assignment`** (`PivotTable`) — the `suffix` accumulator is now a + single `const` at its one assignment site instead of a dead-initialized `let`. + - **`no-require-imports`** (`DashboardRenderer.designMode` test) — the hoisted + `vi.mock` factory uses an `async` factory with `await import('react')`. + +- Updated dependencies [0318118] +- Updated dependencies [1c8935a] +- Updated dependencies [af1b0db] +- Updated dependencies [8b8b744] +- Updated dependencies [7cf4051] +- Updated dependencies [803558e] +- Updated dependencies [aefcf39] +- Updated dependencies [2e7d7f0] +- Updated dependencies [ef14f69] +- Updated dependencies [94d4876] +- Updated dependencies [1100a8b] +- Updated dependencies [7abe4cd] +- Updated dependencies [69fa5d1] +- Updated dependencies [549c67d] +- Updated dependencies [ebe6494] +- Updated dependencies [2b17339] +- Updated dependencies [31b77d4] +- Updated dependencies [6d4fbe6] +- Updated dependencies [0a3710b] +- Updated dependencies [f80aaf2] +- Updated dependencies [62b9ab5] +- Updated dependencies [14cb729] +- Updated dependencies [1629313] +- Updated dependencies [faebac3] +- Updated dependencies [2331ac9] +- Updated dependencies [199fa83] +- Updated dependencies [eee4ded] +- Updated dependencies [3b2e4d9] + - @object-ui/fields@16.1.0 + - @object-ui/i18n@16.1.0 + - @object-ui/core@16.1.0 + - @object-ui/types@16.1.0 + - @object-ui/react@16.1.0 + - @object-ui/components@16.1.0 + ## 16.0.0 ### Patch Changes diff --git a/packages/plugin-dashboard/package.json b/packages/plugin-dashboard/package.json index 6efbc403b..db78f3a00 100644 --- a/packages/plugin-dashboard/package.json +++ b/packages/plugin-dashboard/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/plugin-dashboard", - "version": "16.0.0", + "version": "16.1.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 8f83dc2b8..da8abc245 100644 --- a/packages/plugin-designer/CHANGELOG.md +++ b/packages/plugin-designer/CHANGELOG.md @@ -1,5 +1,104 @@ # @object-ui/plugin-designer +## 16.1.0 + +### Minor Changes + +- 199fa83: feat(dashboard): retire the pre-ADR-0021 inline-analytics renderer branches (framework#3320) + + Follow-up to the dashboard analytics migration (framework#3251 / objectui#2703). + Authoring already emits only the semantic-layer shape (`dataset` + `dimensions` + + `values`); this removes the renderer's now-unauthored legacy read-branches. + + - **types**: drop the `@deprecated` inline-analytics keys (`object`, + `categoryField`, `categoryGranularity`, `valueField`, `aggregate`, `measures`) + from `DashboardWidgetSchema`. They were retained in #2703 only so the renderer + could read legacy/static metadata during the transition. + - **plugin-dashboard**: `DashboardRenderer` no longer emits the object-bound + metric / chart / pivot / table / list branches from the top-level `object` + + analytics keys. It keeps the renderer-internal static paths (`options.data` / + `widget.data` array and the `provider: 'object'` async config) and + `widget.component`. The dashboard renderer no longer emits `object-pivot` / + `pivot` at all — dataset pivots render through `DatasetWidget` (grouped table / + cross-tab); the `ObjectPivotTable` / `PivotTable` components stay as public + SDUI blocks for other surfaces. `DashboardGridLayout` gets the same treatment. + - **graceful fallback**: a widget that still carries the retired inline shape in + stored metadata (top-level `object`, no `dataset`, no inline `options.data`) + now renders a visible error placeholder prompting a rebind to a dataset, rather + than a blank chart/grid. + - **plugin-designer**: `DashboardEditor` drops its inline object / value-field / + aggregate fields (analytics binding is authored via the dataset picker in + app-shell's `DashboardWidgetInspector` / plugin-dashboard's `WidgetConfigPanel`). + +### Patch Changes + +- 549c67d: chore(lint): clear the mechanical baseline lint errors so these packages' lint gates protect them again + + Extends the fields/core cleanup from #2709 (objectui#2713). These eight package + lints were red at baseline on `main`, so their per-package `lint` gate could not + catch new violations of the same class. Cleared every **error** (no behavior + change; warnings are out of scope): + + - **`no-useless-catch`** (`data-objectstack`) — unwrapped five try/catch blocks + whose `catch` only re-threw; errors still propagate identically. + - **`preserve-caught-error`** (`cli`, `data-objectstack`, `react`) — the caught + error's message is inlined into the thrown `Error`; a scoped disable with a + justifying comment carries each one, because these packages target ES2020 + whose lib types the 1-arg `Error` constructor only (so `{ cause }` won't + compile) — same reasoning as the core case in #2709. + - **`prefer-const`** (`plugin-calendar`, `plugin-map`) — `let`→`const` for + never-reassigned bindings. + - **`no-empty-object-type`** (`plugin-designer`) — empty extend-only interfaces + → equivalent `type` aliases. + - **`no-useless-assignment`** (`react`) — dropped a dead initializer that both + branches overwrite before it is read. + - **`no-require-imports`** (`plugin-calendar`, `plugin-timeline` tests) — + hoisted `vi.mock` factories now use an `async` factory with + `await import('react')` instead of `require('react')`. + - **stale `eslint-disable` directive** (`plugin-markdown`) — removed a + `react/no-danger` disable whose plugin is not loaded in the flat config (an + unknown-rule reference that ESLint v10 reports as an error); the rationale is + kept as a plain comment. + +- Updated dependencies [0318118] +- Updated dependencies [1c8935a] +- Updated dependencies [af1b0db] +- Updated dependencies [8b8b744] +- Updated dependencies [7cf4051] +- Updated dependencies [803558e] +- Updated dependencies [aefcf39] +- Updated dependencies [8c1e415] +- Updated dependencies [2e7d7f0] +- Updated dependencies [ef14f69] +- Updated dependencies [94d4876] +- Updated dependencies [1100a8b] +- Updated dependencies [7abe4cd] +- Updated dependencies [69fa5d1] +- Updated dependencies [549c67d] +- Updated dependencies [ebe6494] +- Updated dependencies [2b17339] +- Updated dependencies [31b77d4] +- Updated dependencies [6d4fbe6] +- Updated dependencies [0a3710b] +- Updated dependencies [f80aaf2] +- Updated dependencies [62b9ab5] +- Updated dependencies [14cb729] +- Updated dependencies [1629313] +- Updated dependencies [faebac3] +- Updated dependencies [2331ac9] +- Updated dependencies [199fa83] +- Updated dependencies [eee4ded] +- Updated dependencies [3b2e4d9] + - @object-ui/fields@16.1.0 + - @object-ui/i18n@16.1.0 + - @object-ui/core@16.1.0 + - @object-ui/data-objectstack@16.1.0 + - @object-ui/types@16.1.0 + - @object-ui/react@16.1.0 + - @object-ui/plugin-form@16.1.0 + - @object-ui/components@16.1.0 + - @object-ui/plugin-grid@16.1.0 + ## 16.0.0 ### Patch Changes diff --git a/packages/plugin-designer/package.json b/packages/plugin-designer/package.json index d5f14e840..ab794b4e6 100644 --- a/packages/plugin-designer/package.json +++ b/packages/plugin-designer/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/plugin-designer", - "version": "16.0.0", + "version": "16.1.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 ce66ddfd5..ffef8208f 100644 --- a/packages/plugin-detail/CHANGELOG.md +++ b/packages/plugin-detail/CHANGELOG.md @@ -1,5 +1,130 @@ # @object-ui/plugin-detail +## 16.1.0 + +### Minor Changes + +- faebac3: Related lists paginate by default and fetch server-side windows (#2711). + + `record:related_list` now applies the spec default `limit` of 5 when a node + doesn't declare one, so detail-page related lists render pages with + Previous/Next controls instead of dumping every child row. On the auto-fetch + path RelatedList requests one page at a time (`$top`/`$skip`), reads the + collection size from `QueryResult.total` (`hasMore` fallback), sends user + column sorts as a server `$orderby`, and seeds the initial order from the + node's `sort` prop (new `defaultSort` prop on RelatedList). Caller-provided + `data` keeps the historical client-side slicing. Behavior change: lists that + previously rendered all rows now show 5 per page — declare a larger `limit` + on the `record:related_list` node to widen the window. + +### Patch Changes + +- 7cf4051: chore(deps): align every `@objectstack/*` dependency to `^16.0.0-rc.0` + + Bumps `@objectstack/spec` / `client` / `formula` / `lint` from `^15.1.1` to the + `16.0.0-rc.0` pre-release across the workspace (root + `apps/console` + + `apps/site` + all consuming packages). ObjectUI's own packages are already on + major 16, so this closes the 15↔16 skew between ObjectUI and the `@objectstack` + contract libraries (which publish in lockstep with `spec`). + + This is a dependency alignment, not a behavioral migration: the full workspace + build (43/43) and the `@objectstack`-consuming package test suites + (`core` / `app-shell` / `data-objectstack` / `plugin-form` / `types`) are green + against `16.0.0-rc.0` with no source changes required. + + Practical effect: `@objectstack/client@16.0.0-rc.0` now ships + `data.batchTransaction` (framework #3271), so `ObjectStackAdapter`'s feature + detect (`typeof client.data.batchTransaction === 'function'`) routes + master-detail cross-object saves through the typed SDK method instead of the + raw `fetch('/api/v1/batch')` fallback — realizing the "verify SDK path" half of + #2694. The raw-fetch branch stays as a defensive fallback (removal tracked in + #2694). + +- 53513a4: fix(plugin-detail): #2688 — record surfaces without a caller title no longer floor to `Record #`, and the meta footer never prints a raw audit user id + + - `DetailView` header: after every declared-identity step misses and no + `schema.title` was provided, probe name-ish record keys (`name`, `title`, + `*_name`, …) before falling to the `Record #` floor. Fixes records whose + name lives in a field the type-aware derivation deliberately skips (e.g. an + `autonumber` `name`) opened from surfaces like the gantt row drawer. + - `RecordMetaFooter`: `created_by` / `updated_by` are always user references on + ObjectStack — when the fetched schema omits the audit system fields, default + the reference target to `sys_user` so the footer renders a resolved user name + (or the muted placeholder) instead of the raw opaque id. + +- f329ec5: chore(lint): clear the baseline lint errors in plugin-detail (objectui#2713 Wave 3) + + Wave 3 of the #2713 lint-gate restoration. `@object-ui/plugin-detail` was red at + baseline on `main`; cleared every **error** (no behavior change; warnings out of + scope). All nine are `react-hooks` errors — the record renderers called hooks + after conditional early returns, which is a real fragility (React throws when the + guard toggles between renders), so each is restructured so hooks run + unconditionally while the rendered output stays identical: + + - **`record-reference-rail`** — hoisted `useState` above the empty-entries early + return (no dependency on it). + - **`record-related-list`** — moved the `!objectName` placeholder return below + the four hooks (`usePermissions` / `useFieldPermissions` / `useRelatedRecordActions` + / `useMemo`); those hooks are pure context/memo reads, safe with an empty + object name. The object-level read gate ordering is unchanged (covered by + `RecordRelatedListRenderer.readgate.test`). + - **`record-quick-actions`** — moved the `requiredPermissions` gate below + `useActionEngine` (a pure `useContext`/`useMemo` hook). + - **`record-highlights`** — `useId` + `useRegisterHighlightFields` now run + unconditionally; the permission gate is enforced after them. Because + `useRegisterHighlightFields` has a register effect, it is passed `[]` when the + gate denies — equivalent to not registering, so no body field is ever hidden + for highlights that aren't rendered. + - **`RelatedList`** `SectionIcon` (`react-hooks/static-components`) — + `resolveIconComponent` is a stable registry lookup, not a component created + during render → justified scoped disable. + +- 6d4fbe6: **Consolidate the `managedBy` lifecycle-bucket logic into one shared source of truth (follows framework ADR-0103).** The bucket taxonomy was hand-mirrored in several places — `crudAffordances.ts`, `ManagedByBadge.tsx` (its own `Bucket` union + `isWriteOptedIn` + the writable-system derivation), and `plugin-detail`'s `record-details.tsx` (`NON_EDITABLE_BUCKETS`, duplicated because it can't depend on app-shell) — a drift risk, and the object-schema `managedBy` type was open-ended (`(string & {})`) so unknown buckets slipped through and silently defaulted to fully-editable. + + - **`@object-ui/types`** now owns the closed `ManagedByBucket` union (+ `MANAGED_BY_BUCKETS`), and `ObjectSchema.managedBy` is tightened from `'platform' | 'better-auth' | (string & {})` to that union — unknown buckets are now a type error at authoring time. + - **`@object-ui/core`** now owns the React-free runtime logic — `resolveCrudAffordances`, `isWriteOptedIn`, `isSystemWritable`, `isObjectInlineEditable` — reachable by every UI package including `plugin-detail` (which could not import app-shell). + - **`app-shell/utils/crudAffordances.ts`** is now a thin re-export of `@object-ui/core` (existing imports keep working); `ManagedByBadge` consumes the shared `isSystemWritable`; `plugin-detail` `record-details.tsx` replaces its hand-mirrored `NON_EDITABLE_BUCKETS` with `isObjectInlineEditable`. + + Behavior-preserving — all existing affordance/edit-gate tests stay green; the shared module adds direct unit coverage (including the previously-untested `isSystemWritable` derivation). Translated copy (badge variants, empty-state messages) stays in app-shell. + +- 0a3710b: **Finish the `managedBy` / `userActions` de-dup — one parser for the override shape (completes objectui#2712, framework#3343).** #2712 consolidated the bucket _union_ + affordance _set_ mirrors but left four surfaces still parsing the `userActions.{create,edit,delete}` override shape by hand. They now all route through the shared `@object-ui/core` policy, so no package re-implements the boolean / #2614-object-form parse locally. + + - **`@object-ui/core`** promotes the internal `normalizeOverride` to the exported **`normalizeUserAction(v, base)`** (the one parser) and adds **`userActionPredicates(v)`** for per-record CEL predicate extraction. + - **`app-shell/utils/managedByEmptyState.ts`** — the writable-`system` create check and its local `EmptyStateUserActions` interface are replaced by `resolveCrudAffordances({ managedBy, userActions }).create`. + - **`plugin-grid/rowCrudAffordances.ts`** — the local `isOptedOut` / `predicatesOf` helpers (and duplicated `RowCrudUserAction` / `RowCrudPredicates` types) fold into `normalizeUserAction`; the historical type names stay re-exported for compat. + - **`plugin-detail/RelatedList.tsx`** — its inline `predicatesOf` fold into `userActionPredicates`. + - **`plugin-form/ObjectForm.tsx`** — the hand-rolled `managedBy !== 'platform'` blanket lock + `userActions` unlock is replaced by the resolved affordance for the current mode (`edit` / `create`), the **same** `resolveCrudAffordances` contract the detail (`isObjectInlineEditable`) and grid surfaces use. + + Behavior-preserving for `platform` / `system` / `append-only` / `better-auth`, with one deliberate alignment: an admin-editable **`config`**-bucket object (e.g. `sys_webhook`, `sys_permission_set`) is now editable in `ObjectForm` — it was previously over-locked as "non-`platform`", while detail/grid already treated it as editable (`config` resolves `edit: true`). New unit coverage for the shared parser and the config / create-mode form gate; all existing affordance/edit-gate tests stay green. + +- 3b2e4d9: fix(list): route remaining system-field groupings through the shared classifier + + Follow-up to the `owner_id` default-column fix: consolidate the display-oriented + system-field exclusions onto the shared `isSystemManagedField` / + `SYSTEM_MANAGED_FIELD_NAMES` (from `@object-ui/types`) so the framework-injected + `owner_id` is treated consistently across the grid, record picker, and detail + drawer. + + - `ObjectGrid` record-detail drawer: the business-fields vs. muted meta-section + split now uses the shared classifier, so `owner_id` (and other injected system + fields) land in the meta section instead of the business body. + - `deriveLookupColumns` (record picker): drops its local name set for the shared + classifier — now flag-aware (`field.system`), not just name-based. + - `RecordDetailDrawer`: its default `systemFields` set is derived from the shared + `SYSTEM_MANAGED_FIELD_NAMES`; the `systemFields` prop override is preserved. + + `deriveRelatedLists`' narrow "audit FK on every object" set and plugin-detail's + inline-edit "never editable" set are intentionally left distinct — different + semantics (the latter deliberately keeps `owner_id` editable). + +- Updated dependencies [0318118] +- Updated dependencies [af1b0db] +- Updated dependencies [1100a8b] +- Updated dependencies [7abe4cd] +- Updated dependencies [ebe6494] +- Updated dependencies [f80aaf2] + - @object-ui/i18n@16.1.0 + ## 16.0.0 ### Minor Changes diff --git a/packages/plugin-detail/package.json b/packages/plugin-detail/package.json index c6b1301c9..a4a199a0e 100644 --- a/packages/plugin-detail/package.json +++ b/packages/plugin-detail/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/plugin-detail", - "version": "16.0.0", + "version": "16.1.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 0500cb62f..4d00e3a7c 100644 --- a/packages/plugin-editor/CHANGELOG.md +++ b/packages/plugin-editor/CHANGELOG.md @@ -1,5 +1,33 @@ # @object-ui/plugin-editor +## 16.1.0 + +### Patch Changes + +- Updated dependencies [1c8935a] +- Updated dependencies [8b8b744] +- Updated dependencies [7cf4051] +- Updated dependencies [803558e] +- Updated dependencies [2e7d7f0] +- Updated dependencies [ef14f69] +- Updated dependencies [94d4876] +- Updated dependencies [69fa5d1] +- Updated dependencies [549c67d] +- Updated dependencies [2b17339] +- Updated dependencies [31b77d4] +- Updated dependencies [6d4fbe6] +- Updated dependencies [0a3710b] +- Updated dependencies [62b9ab5] +- Updated dependencies [1629313] +- Updated dependencies [faebac3] +- Updated dependencies [2331ac9] +- Updated dependencies [199fa83] +- Updated dependencies [eee4ded] + - @object-ui/core@16.1.0 + - @object-ui/types@16.1.0 + - @object-ui/react@16.1.0 + - @object-ui/components@16.1.0 + ## 16.0.0 ### Patch Changes diff --git a/packages/plugin-editor/package.json b/packages/plugin-editor/package.json index 2d52ee9aa..a4294fdd9 100644 --- a/packages/plugin-editor/package.json +++ b/packages/plugin-editor/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/plugin-editor", - "version": "16.0.0", + "version": "16.1.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 0d64ab11b..0b9760c9a 100644 --- a/packages/plugin-form/CHANGELOG.md +++ b/packages/plugin-form/CHANGELOG.md @@ -1,5 +1,112 @@ # @object-ui/plugin-form +## 16.1.0 + +### Minor Changes + +- 62b9ab5: feat(data): unify master-detail saves behind `DataSource.batchTransaction`, isolate the non-atomic fallback in the adapter (#2679) + + Master-detail saves (`MasterDetailForm`, `LineItemsPanel`) now always persist + through `dataSource.batchTransaction(operations)` — one ordered cross-object + operation list, with `{ $ref: }` linking a child to a parent created + in the same batch. The form no longer contains any client-side orchestration or + best-effort compensation-delete; that atomicity anti-pattern is gone from the UI + layer (framework #1604 / framework ADR-0034 item 4). + + - **`@object-ui/types`** — `batchTransaction?` is now a first-class (optional) + method on the `DataSource` contract, typed via `BatchTransactionOperation` / + `BatchRef`. Replaces the previous `(dataSource as any).batchTransaction` + method-sniffing. + - **`@object-ui/core`** — new `emulateBatchTransaction(dataSource, operations)` + (sequential writes, `$ref` resolution, best-effort reverse-order compensation) + and `runBatchTransaction(dataSource, operations)` (prefers the adapter's method, + emulates otherwise). `ApiDataSource` / `ValueDataSource` implement + `batchTransaction` via the emulation. + - **`@object-ui/data-objectstack`** — `ObjectStackAdapter.batchTransaction` uses + the server's atomic `POST /api/v1/batch`, prefers the typed + `client.data.batchTransaction` SDK method when the installed client exposes it, + and degrades to the client-side emulation ONLY when the endpoint is missing + (404/405) or the runtime can't do transactions (501). Real errors (400/401/403/ + 409/500) still surface. This is the isolated, tested home of the non-atomic + fallback. + - **`@object-ui/plugin-form`** — removed `applyDetail` / `createMany` / + `ApplyDetailResult` from `masterDetailTx.ts`; `MasterDetailForm` and + `LineItemsPanel` build ops and call `runBatchTransaction`. `LineItemsPanel` + saves are now atomic on a capable backend, with the rollup folded into the same + batch. + + No behavior change on a current ObjectStack backend (it has `/api/v1/batch`); + older/limited backends keep a working — now clearly non-atomic — save path. + +### Patch Changes + +- 7cf4051: chore(deps): align every `@objectstack/*` dependency to `^16.0.0-rc.0` + + Bumps `@objectstack/spec` / `client` / `formula` / `lint` from `^15.1.1` to the + `16.0.0-rc.0` pre-release across the workspace (root + `apps/console` + + `apps/site` + all consuming packages). ObjectUI's own packages are already on + major 16, so this closes the 15↔16 skew between ObjectUI and the `@objectstack` + contract libraries (which publish in lockstep with `spec`). + + This is a dependency alignment, not a behavioral migration: the full workspace + build (43/43) and the `@objectstack`-consuming package test suites + (`core` / `app-shell` / `data-objectstack` / `plugin-form` / `types`) are green + against `16.0.0-rc.0` with no source changes required. + + Practical effect: `@objectstack/client@16.0.0-rc.0` now ships + `data.batchTransaction` (framework #3271), so `ObjectStackAdapter`'s feature + detect (`typeof client.data.batchTransaction === 'function'`) routes + master-detail cross-object saves through the typed SDK method instead of the + raw `fetch('/api/v1/batch')` fallback — realizing the "verify SDK path" half of + #2694. The raw-fetch branch stays as a defensive fallback (removal tracked in + #2694). + +- 0a3710b: **Finish the `managedBy` / `userActions` de-dup — one parser for the override shape (completes objectui#2712, framework#3343).** #2712 consolidated the bucket _union_ + affordance _set_ mirrors but left four surfaces still parsing the `userActions.{create,edit,delete}` override shape by hand. They now all route through the shared `@object-ui/core` policy, so no package re-implements the boolean / #2614-object-form parse locally. + + - **`@object-ui/core`** promotes the internal `normalizeOverride` to the exported **`normalizeUserAction(v, base)`** (the one parser) and adds **`userActionPredicates(v)`** for per-record CEL predicate extraction. + - **`app-shell/utils/managedByEmptyState.ts`** — the writable-`system` create check and its local `EmptyStateUserActions` interface are replaced by `resolveCrudAffordances({ managedBy, userActions }).create`. + - **`plugin-grid/rowCrudAffordances.ts`** — the local `isOptedOut` / `predicatesOf` helpers (and duplicated `RowCrudUserAction` / `RowCrudPredicates` types) fold into `normalizeUserAction`; the historical type names stay re-exported for compat. + - **`plugin-detail/RelatedList.tsx`** — its inline `predicatesOf` fold into `userActionPredicates`. + - **`plugin-form/ObjectForm.tsx`** — the hand-rolled `managedBy !== 'platform'` blanket lock + `userActions` unlock is replaced by the resolved affordance for the current mode (`edit` / `create`), the **same** `resolveCrudAffordances` contract the detail (`isObjectInlineEditable`) and grid surfaces use. + + Behavior-preserving for `platform` / `system` / `append-only` / `better-auth`, with one deliberate alignment: an admin-editable **`config`**-bucket object (e.g. `sys_webhook`, `sys_permission_set`) is now editable in `ObjectForm` — it was previously over-locked as "non-`platform`", while detail/grid already treated it as editable (`config` resolves `edit: true`). New unit coverage for the shared parser and the config / create-mode form gate; all existing affordance/edit-gate tests stay green. + +- Updated dependencies [0318118] +- Updated dependencies [1c8935a] +- Updated dependencies [af1b0db] +- Updated dependencies [8b8b744] +- Updated dependencies [7cf4051] +- Updated dependencies [803558e] +- Updated dependencies [aefcf39] +- Updated dependencies [2e7d7f0] +- Updated dependencies [ef14f69] +- Updated dependencies [94d4876] +- Updated dependencies [1100a8b] +- Updated dependencies [7abe4cd] +- Updated dependencies [69fa5d1] +- Updated dependencies [549c67d] +- Updated dependencies [ebe6494] +- Updated dependencies [2b17339] +- Updated dependencies [31b77d4] +- Updated dependencies [6d4fbe6] +- Updated dependencies [0a3710b] +- Updated dependencies [f80aaf2] +- Updated dependencies [62b9ab5] +- Updated dependencies [14cb729] +- Updated dependencies [1629313] +- Updated dependencies [faebac3] +- Updated dependencies [2331ac9] +- Updated dependencies [199fa83] +- Updated dependencies [eee4ded] +- Updated dependencies [3b2e4d9] + - @object-ui/fields@16.1.0 + - @object-ui/i18n@16.1.0 + - @object-ui/core@16.1.0 + - @object-ui/types@16.1.0 + - @object-ui/react@16.1.0 + - @object-ui/components@16.1.0 + - @object-ui/permissions@16.1.0 + ## 16.0.0 ### Minor Changes diff --git a/packages/plugin-form/package.json b/packages/plugin-form/package.json index b9eb05e59..c561983c4 100644 --- a/packages/plugin-form/package.json +++ b/packages/plugin-form/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/plugin-form", - "version": "16.0.0", + "version": "16.1.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 e59591947..ba7761d16 100644 --- a/packages/plugin-gantt/CHANGELOG.md +++ b/packages/plugin-gantt/CHANGELOG.md @@ -1,5 +1,137 @@ # @object-ui/plugin-gantt +## 16.1.0 + +### Patch Changes + +- 7cf4051: chore(deps): align every `@objectstack/*` dependency to `^16.0.0-rc.0` + + Bumps `@objectstack/spec` / `client` / `formula` / `lint` from `^15.1.1` to the + `16.0.0-rc.0` pre-release across the workspace (root + `apps/console` + + `apps/site` + all consuming packages). ObjectUI's own packages are already on + major 16, so this closes the 15↔16 skew between ObjectUI and the `@objectstack` + contract libraries (which publish in lockstep with `spec`). + + This is a dependency alignment, not a behavioral migration: the full workspace + build (43/43) and the `@objectstack`-consuming package test suites + (`core` / `app-shell` / `data-objectstack` / `plugin-form` / `types`) are green + against `16.0.0-rc.0` with no source changes required. + + Practical effect: `@objectstack/client@16.0.0-rc.0` now ships + `data.batchTransaction` (framework #3271), so `ObjectStackAdapter`'s feature + detect (`typeof client.data.batchTransaction === 'function'`) routes + master-detail cross-object saves through the typed SDK method instead of the + raw `fetch('/api/v1/batch')` fallback — realizing the "verify SDK path" half of + #2694. The raw-fetch branch stays as a defensive fallback (removal tracked in + #2694). + +- 803558e: feat(data): thread the host's authenticated fetch into `provider: 'api'` data sources (#2725) + + `provider: 'api'` view data sources went through a bare `globalThis.fetch`, so + custom endpoints (gantt composite trees, report aggregates) carried only + same-origin cookies while every native `/api/v1/*` request carried + `Authorization: Bearer` — the moment cookie HMAC verification failed (dev + restart rotating the fallback auth secret, cookie expiry/rotation in prod) + those views 401'd while the rest of the app kept working. + + - **`@object-ui/react`** — `SchemaRendererProvider` accepts an optional + `apiFetch`; nested providers inherit it from their parent so re-wrapped + subtrees (react pages, preview surfaces) keep the host's authentication. + `useViewData` defaults the api-provider adapter's fetch to the context + `apiFetch` (explicit `adapterOptions.fetch` still wins). + - **`@object-ui/auth`** — `createAuthenticatedFetch` gains a + `sameOriginOnly` option: cross-origin URLs pass through to the bare fetch + with no `Authorization` / `X-Tenant-ID` / `Accept-Language`, so metadata- + supplied third-party URLs never see the platform token. + - **`@object-ui/app-shell`** — the console wires + `createAuthenticatedFetch({ sameOriginOnly: true })` (settle-signal wrapped) + as `apiFetch` on the root `SchemaRendererProvider`. + - **`@object-ui/plugin-gantt`** — `ObjectGantt` resolves its api-provider + DataSource with the context `apiFetch`, covering reads and write-backs. + + Behaviour is unchanged for hosts that don't provide `apiFetch` (bare fetch + + cookies, as before). + +- 5606ca8: fix(plugin-gantt): align the task-list header with the row date columns + + Every data row reserves a trailing w-6 (+4px) slot for the 「→」 open-details + button whenever `onTaskClick` is live, but the header row didn't — so the + 开始/结束 header labels sat 28px to the right of the date values they caption. + The header now mirrors the slot under the same condition. + +- 1100a8b: feat(plugin-gantt)!: remove the 移动端二维码 (mobile QR share) context-menu item + + The QR-share feature is removed outright: the context-menu item, the QR dialog, + the `taskUrl` prop on `GanttView`, the URL wiring in `ObjectGantt`, the + `gantt.menu.qrcode` / `gantt.qr.*` i18n keys (en/zh) and the `qrcode` + dependency are all deleted. It baked one consumer's app-specific requirement + (scan-to-open on mobile) into the generic gantt renderer, and what it encoded — + the desktop console record URL — was not even the right target for that + requirement. Apps that need scan-to-mobile flows should implement them + app-side against their own mobile surface. + +- 7a5750e: chore(lint): clear the baseline lint errors in plugin-gantt (objectui#2713 Wave 3) + + Wave 3 of the #2713 lint-gate restoration. `@object-ui/plugin-gantt` was red at + baseline on `main`; cleared every **error** (no behavior change; warnings out of + scope). 18 of the 21 were in the demo harness: + + - **`react-hooks/static-components` (demo, ×8)** — the `Swatch` legend cell was + defined inside `ManufacturingLegend`; hoisted to module scope (purely + props-driven, so nothing from render scope is captured). + - **`react-hooks/rules-of-hooks` (demo, ×9)** — `App` had a `?quickfilter=1` + early return before ~9 hooks; moved that route below all hooks so hook order + is stable (the quick-filter branch renders `` regardless). + - **`react-hooks/purity` (demo, ×1)** — the demo render-timer necessarily reads + `performance.now()` during render (paired with an effect that measures elapsed + ms); justified scoped disable, demo-only. + - **`object-ui/no-synthetic-event-trigger`** (`GanttView.interactions.test`) — + the Escape-closes-menu test dispatched a raw `window` `KeyboardEvent`; switched + to `fireEvent.keyDown(window, { key: 'Escape' })` (the pattern already used + elsewhere in the same file). The window-level Escape listener behaves + identically. + - **`no-useless-assignment`** (`GanttView`, `ObjectGantt`) — dropped two dead + initializers (`ok`, `options`) that their exhaustive `try`/`catch` and + `if`/`else` branches overwrite before reading. + +- Updated dependencies [0318118] +- Updated dependencies [1c8935a] +- Updated dependencies [af1b0db] +- Updated dependencies [8b8b744] +- Updated dependencies [7cf4051] +- Updated dependencies [803558e] +- Updated dependencies [aefcf39] +- Updated dependencies [2e7d7f0] +- Updated dependencies [ef14f69] +- Updated dependencies [94d4876] +- Updated dependencies [53513a4] +- Updated dependencies [1100a8b] +- Updated dependencies [7abe4cd] +- Updated dependencies [69fa5d1] +- Updated dependencies [f329ec5] +- Updated dependencies [549c67d] +- Updated dependencies [ebe6494] +- Updated dependencies [2b17339] +- Updated dependencies [31b77d4] +- Updated dependencies [6d4fbe6] +- Updated dependencies [0a3710b] +- Updated dependencies [f80aaf2] +- Updated dependencies [62b9ab5] +- Updated dependencies [14cb729] +- Updated dependencies [1629313] +- Updated dependencies [faebac3] +- Updated dependencies [2331ac9] +- Updated dependencies [199fa83] +- Updated dependencies [eee4ded] +- Updated dependencies [3b2e4d9] + - @object-ui/fields@16.1.0 + - @object-ui/i18n@16.1.0 + - @object-ui/core@16.1.0 + - @object-ui/types@16.1.0 + - @object-ui/react@16.1.0 + - @object-ui/plugin-detail@16.1.0 + - @object-ui/components@16.1.0 + ## 16.0.0 ### Patch Changes diff --git a/packages/plugin-gantt/package.json b/packages/plugin-gantt/package.json index b95b9793b..d48ddb234 100644 --- a/packages/plugin-gantt/package.json +++ b/packages/plugin-gantt/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/plugin-gantt", - "version": "16.0.0", + "version": "16.1.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 588308012..179a27497 100644 --- a/packages/plugin-grid/CHANGELOG.md +++ b/packages/plugin-grid/CHANGELOG.md @@ -1,5 +1,128 @@ # @object-ui/plugin-grid +## 16.1.0 + +### Patch Changes + +- ebe6494: chore(lint): clear the baseline lint errors in nine more packages (objectui#2713 Wave 2) + + Second wave of the #2713 lint-gate restoration (after #2730). These nine package + lints were red at baseline on `main`, so their per-package `lint` gate could not + catch new violations. Cleared every **error** (no behavior change; warnings out + of scope): + + - **`react-hooks/rules-of-hooks`** (`i18n`, `plugin-grid`, `plugin-view`, + `plugin-list`) — translation helpers (`useSafeFieldLabel`, + `useRowActionTranslation`, `useViewLabel`, `useViewTabLabel`, `useMoreLabel`) + wrapped a provider-safe hook (`useObjectTranslation`/`useObjectLabel`, which + never throw) in try/catch; removed the wrapper (the same fix #2709 applied in + fields). `plugin-kanban` `ObjectKanban` moved its `if (error)` early return + below the `useCallback` so hooks run unconditionally. `collaboration` + `__unsafe_usePresenceContext` keeps its deliberate danger-prefix name via a + justified scoped disable. + - **`react-hooks/static-components`** (`layout`, `plugin-list`, `plugin-report`) + — dynamic-icon / registry lookups (`resolveIcon`, `useRegistryComponent`) are + stable component references, not components created during render → scoped + disable with justification. `plugin-charts` `TreemapCell` was a _genuine_ + inline component and is hoisted to module scope (it is purely props-driven). + - **`no-irregular-whitespace`** (`plugin-grid` `ImportWizard`) — the literal + U+FEFF BOM prepended to exported CSV/text blobs (so Excel detects UTF-8) is + now written as the `` escape: byte-identical at runtime, no literal + irregular-whitespace character in source. + - **`no-useless-assignment`** (`plugin-grid` `BulkActionDialog`) — dropped a + dead `= null` initializer that the exhaustive `switch` (incl. `default`) + overwrites before it is read. + - **`no-unsafe-function-type`** (`plugin-view` `ViewTabBar`) — the dnd-kit + render-prop `listeners` map is typed `Record void>` + instead of bare `Function`. + - **`no-require-imports`** (`plugin-kanban`, `plugin-view` tests) — hoisted + `vi.mock` factories use an `async` factory with `await import('react')`. + +- 2b17339: fix(list): keep the injected `owner_id` out of the leading auto-derived columns + + A view-less object's default list columns are derived from the object's field + order. The framework's `applySystemFields` spreads its injected + system/audit/ownership fields to the FRONT of that order and stamps them + `system: true`; `owner_id` is deliberately non-hidden and non-readonly + (ownership is reassignable), so the old name-based exclusion lists in + `ObjectGrid` and `InterfaceListPage` — which never listed `owner_id` — let it + through as column #1 on many showcase list pages (e.g. `showcase_field_zoo`). + + Default-column derivation now classifies system fields via the shared + `isSystemManagedField` helper, which branches on the spec `system` flag (the + single source of truth stamped by the registry) with a name-set fallback that + includes the ownership/tenancy FKs. `owner_id` is pushed to the end + (`ObjectGrid`) / excluded from the business columns (`InterfaceListPage`), so + auto-derived lists lead with business fields again and pick up future injected + fields without editing a name list. Also declares the `system` flag on the + `@object-ui/types` field metadata. + +- 0a3710b: **Finish the `managedBy` / `userActions` de-dup — one parser for the override shape (completes objectui#2712, framework#3343).** #2712 consolidated the bucket _union_ + affordance _set_ mirrors but left four surfaces still parsing the `userActions.{create,edit,delete}` override shape by hand. They now all route through the shared `@object-ui/core` policy, so no package re-implements the boolean / #2614-object-form parse locally. + + - **`@object-ui/core`** promotes the internal `normalizeOverride` to the exported **`normalizeUserAction(v, base)`** (the one parser) and adds **`userActionPredicates(v)`** for per-record CEL predicate extraction. + - **`app-shell/utils/managedByEmptyState.ts`** — the writable-`system` create check and its local `EmptyStateUserActions` interface are replaced by `resolveCrudAffordances({ managedBy, userActions }).create`. + - **`plugin-grid/rowCrudAffordances.ts`** — the local `isOptedOut` / `predicatesOf` helpers (and duplicated `RowCrudUserAction` / `RowCrudPredicates` types) fold into `normalizeUserAction`; the historical type names stay re-exported for compat. + - **`plugin-detail/RelatedList.tsx`** — its inline `predicatesOf` fold into `userActionPredicates`. + - **`plugin-form/ObjectForm.tsx`** — the hand-rolled `managedBy !== 'platform'` blanket lock + `userActions` unlock is replaced by the resolved affordance for the current mode (`edit` / `create`), the **same** `resolveCrudAffordances` contract the detail (`isObjectInlineEditable`) and grid surfaces use. + + Behavior-preserving for `platform` / `system` / `append-only` / `better-auth`, with one deliberate alignment: an admin-editable **`config`**-bucket object (e.g. `sys_webhook`, `sys_permission_set`) is now editable in `ObjectForm` — it was previously over-locked as "non-`platform`", while detail/grid already treated it as editable (`config` resolves `edit: true`). New unit coverage for the shared parser and the config / create-mode form gate; all existing affordance/edit-gate tests stay green. + +- 3b2e4d9: fix(list): route remaining system-field groupings through the shared classifier + + Follow-up to the `owner_id` default-column fix: consolidate the display-oriented + system-field exclusions onto the shared `isSystemManagedField` / + `SYSTEM_MANAGED_FIELD_NAMES` (from `@object-ui/types`) so the framework-injected + `owner_id` is treated consistently across the grid, record picker, and detail + drawer. + + - `ObjectGrid` record-detail drawer: the business-fields vs. muted meta-section + split now uses the shared classifier, so `owner_id` (and other injected system + fields) land in the meta section instead of the business body. + - `deriveLookupColumns` (record picker): drops its local name set for the shared + classifier — now flag-aware (`field.system`), not just name-based. + - `RecordDetailDrawer`: its default `systemFields` set is derived from the shared + `SYSTEM_MANAGED_FIELD_NAMES`; the `systemFields` prop override is preserved. + + `deriveRelatedLists`' narrow "audit FK on every object" set and plugin-detail's + inline-edit "never editable" set are intentionally left distinct — different + semantics (the latter deliberately keeps `owner_id` editable). + +- Updated dependencies [0318118] +- Updated dependencies [1c8935a] +- Updated dependencies [af1b0db] +- Updated dependencies [8b8b744] +- Updated dependencies [7cf4051] +- Updated dependencies [803558e] +- Updated dependencies [aefcf39] +- Updated dependencies [2e7d7f0] +- Updated dependencies [ef14f69] +- Updated dependencies [94d4876] +- Updated dependencies [1100a8b] +- Updated dependencies [7abe4cd] +- Updated dependencies [69fa5d1] +- Updated dependencies [549c67d] +- Updated dependencies [ebe6494] +- Updated dependencies [2b17339] +- Updated dependencies [31b77d4] +- Updated dependencies [6d4fbe6] +- Updated dependencies [0a3710b] +- Updated dependencies [f80aaf2] +- Updated dependencies [62b9ab5] +- Updated dependencies [14cb729] +- Updated dependencies [1629313] +- Updated dependencies [faebac3] +- Updated dependencies [2331ac9] +- Updated dependencies [199fa83] +- Updated dependencies [eee4ded] +- Updated dependencies [3b2e4d9] + - @object-ui/fields@16.1.0 + - @object-ui/i18n@16.1.0 + - @object-ui/core@16.1.0 + - @object-ui/types@16.1.0 + - @object-ui/react@16.1.0 + - @object-ui/components@16.1.0 + - @object-ui/mobile@16.1.0 + ## 16.0.0 ### Minor Changes diff --git a/packages/plugin-grid/package.json b/packages/plugin-grid/package.json index 35edb0640..0e1dc4cce 100644 --- a/packages/plugin-grid/package.json +++ b/packages/plugin-grid/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/plugin-grid", - "version": "16.0.0", + "version": "16.1.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 c5236da5f..a51e3ca9e 100644 --- a/packages/plugin-kanban/CHANGELOG.md +++ b/packages/plugin-kanban/CHANGELOG.md @@ -1,5 +1,81 @@ # @object-ui/plugin-kanban +## 16.1.0 + +### Patch Changes + +- ebe6494: chore(lint): clear the baseline lint errors in nine more packages (objectui#2713 Wave 2) + + Second wave of the #2713 lint-gate restoration (after #2730). These nine package + lints were red at baseline on `main`, so their per-package `lint` gate could not + catch new violations. Cleared every **error** (no behavior change; warnings out + of scope): + + - **`react-hooks/rules-of-hooks`** (`i18n`, `plugin-grid`, `plugin-view`, + `plugin-list`) — translation helpers (`useSafeFieldLabel`, + `useRowActionTranslation`, `useViewLabel`, `useViewTabLabel`, `useMoreLabel`) + wrapped a provider-safe hook (`useObjectTranslation`/`useObjectLabel`, which + never throw) in try/catch; removed the wrapper (the same fix #2709 applied in + fields). `plugin-kanban` `ObjectKanban` moved its `if (error)` early return + below the `useCallback` so hooks run unconditionally. `collaboration` + `__unsafe_usePresenceContext` keeps its deliberate danger-prefix name via a + justified scoped disable. + - **`react-hooks/static-components`** (`layout`, `plugin-list`, `plugin-report`) + — dynamic-icon / registry lookups (`resolveIcon`, `useRegistryComponent`) are + stable component references, not components created during render → scoped + disable with justification. `plugin-charts` `TreemapCell` was a _genuine_ + inline component and is hoisted to module scope (it is purely props-driven). + - **`no-irregular-whitespace`** (`plugin-grid` `ImportWizard`) — the literal + U+FEFF BOM prepended to exported CSV/text blobs (so Excel detects UTF-8) is + now written as the `` escape: byte-identical at runtime, no literal + irregular-whitespace character in source. + - **`no-useless-assignment`** (`plugin-grid` `BulkActionDialog`) — dropped a + dead `= null` initializer that the exhaustive `switch` (incl. `default`) + overwrites before it is read. + - **`no-unsafe-function-type`** (`plugin-view` `ViewTabBar`) — the dnd-kit + render-prop `listeners` map is typed `Record void>` + instead of bare `Function`. + - **`no-require-imports`** (`plugin-kanban`, `plugin-view` tests) — hoisted + `vi.mock` factories use an `async` factory with `await import('react')`. + +- Updated dependencies [0318118] +- Updated dependencies [1c8935a] +- Updated dependencies [af1b0db] +- Updated dependencies [8b8b744] +- Updated dependencies [7cf4051] +- Updated dependencies [803558e] +- Updated dependencies [aefcf39] +- Updated dependencies [2e7d7f0] +- Updated dependencies [ef14f69] +- Updated dependencies [94d4876] +- Updated dependencies [53513a4] +- Updated dependencies [1100a8b] +- Updated dependencies [7abe4cd] +- Updated dependencies [69fa5d1] +- Updated dependencies [f329ec5] +- Updated dependencies [549c67d] +- Updated dependencies [ebe6494] +- Updated dependencies [2b17339] +- Updated dependencies [31b77d4] +- Updated dependencies [6d4fbe6] +- Updated dependencies [0a3710b] +- Updated dependencies [f80aaf2] +- Updated dependencies [62b9ab5] +- Updated dependencies [14cb729] +- Updated dependencies [1629313] +- Updated dependencies [faebac3] +- Updated dependencies [2331ac9] +- Updated dependencies [199fa83] +- Updated dependencies [eee4ded] +- Updated dependencies [3b2e4d9] + - @object-ui/fields@16.1.0 + - @object-ui/i18n@16.1.0 + - @object-ui/core@16.1.0 + - @object-ui/types@16.1.0 + - @object-ui/react@16.1.0 + - @object-ui/plugin-detail@16.1.0 + - @object-ui/components@16.1.0 + ## 16.0.0 ### Patch Changes diff --git a/packages/plugin-kanban/package.json b/packages/plugin-kanban/package.json index 760e59ed3..ce5040f1a 100644 --- a/packages/plugin-kanban/package.json +++ b/packages/plugin-kanban/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/plugin-kanban", - "version": "16.0.0", + "version": "16.1.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 3a79d279e..9a241414e 100644 --- a/packages/plugin-list/CHANGELOG.md +++ b/packages/plugin-list/CHANGELOG.md @@ -1,5 +1,43 @@ # @object-ui/plugin-list +## 16.1.0 + +### Patch Changes + +- ebe6494: chore(lint): clear the baseline lint errors in nine more packages (objectui#2713 Wave 2) + + Second wave of the #2713 lint-gate restoration (after #2730). These nine package + lints were red at baseline on `main`, so their per-package `lint` gate could not + catch new violations. Cleared every **error** (no behavior change; warnings out + of scope): + + - **`react-hooks/rules-of-hooks`** (`i18n`, `plugin-grid`, `plugin-view`, + `plugin-list`) — translation helpers (`useSafeFieldLabel`, + `useRowActionTranslation`, `useViewLabel`, `useViewTabLabel`, `useMoreLabel`) + wrapped a provider-safe hook (`useObjectTranslation`/`useObjectLabel`, which + never throw) in try/catch; removed the wrapper (the same fix #2709 applied in + fields). `plugin-kanban` `ObjectKanban` moved its `if (error)` early return + below the `useCallback` so hooks run unconditionally. `collaboration` + `__unsafe_usePresenceContext` keeps its deliberate danger-prefix name via a + justified scoped disable. + - **`react-hooks/static-components`** (`layout`, `plugin-list`, `plugin-report`) + — dynamic-icon / registry lookups (`resolveIcon`, `useRegistryComponent`) are + stable component references, not components created during render → scoped + disable with justification. `plugin-charts` `TreemapCell` was a _genuine_ + inline component and is hoisted to module scope (it is purely props-driven). + - **`no-irregular-whitespace`** (`plugin-grid` `ImportWizard`) — the literal + U+FEFF BOM prepended to exported CSV/text blobs (so Excel detects UTF-8) is + now written as the `` escape: byte-identical at runtime, no literal + irregular-whitespace character in source. + - **`no-useless-assignment`** (`plugin-grid` `BulkActionDialog`) — dropped a + dead `= null` initializer that the exhaustive `switch` (incl. `default`) + overwrites before it is read. + - **`no-unsafe-function-type`** (`plugin-view` `ViewTabBar`) — the dnd-kit + render-prop `listeners` map is typed `Record void>` + instead of bare `Function`. + - **`no-require-imports`** (`plugin-kanban`, `plugin-view` tests) — hoisted + `vi.mock` factories use an `async` factory with `await import('react')`. + ## 16.0.0 ### Patch Changes diff --git a/packages/plugin-list/package.json b/packages/plugin-list/package.json index 9bb9c285e..6c0b779ef 100644 --- a/packages/plugin-list/package.json +++ b/packages/plugin-list/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/plugin-list", - "version": "16.0.0", + "version": "16.1.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 8af2c3c4b..eaf140acf 100644 --- a/packages/plugin-map/CHANGELOG.md +++ b/packages/plugin-map/CHANGELOG.md @@ -1,5 +1,82 @@ # @object-ui/plugin-map +## 16.1.0 + +### Patch Changes + +- 7cf4051: chore(deps): align every `@objectstack/*` dependency to `^16.0.0-rc.0` + + Bumps `@objectstack/spec` / `client` / `formula` / `lint` from `^15.1.1` to the + `16.0.0-rc.0` pre-release across the workspace (root + `apps/console` + + `apps/site` + all consuming packages). ObjectUI's own packages are already on + major 16, so this closes the 15↔16 skew between ObjectUI and the `@objectstack` + contract libraries (which publish in lockstep with `spec`). + + This is a dependency alignment, not a behavioral migration: the full workspace + build (43/43) and the `@objectstack`-consuming package test suites + (`core` / `app-shell` / `data-objectstack` / `plugin-form` / `types`) are green + against `16.0.0-rc.0` with no source changes required. + + Practical effect: `@objectstack/client@16.0.0-rc.0` now ships + `data.batchTransaction` (framework #3271), so `ObjectStackAdapter`'s feature + detect (`typeof client.data.batchTransaction === 'function'`) routes + master-detail cross-object saves through the typed SDK method instead of the + raw `fetch('/api/v1/batch')` fallback — realizing the "verify SDK path" half of + #2694. The raw-fetch branch stays as a defensive fallback (removal tracked in + #2694). + +- 549c67d: chore(lint): clear the mechanical baseline lint errors so these packages' lint gates protect them again + + Extends the fields/core cleanup from #2709 (objectui#2713). These eight package + lints were red at baseline on `main`, so their per-package `lint` gate could not + catch new violations of the same class. Cleared every **error** (no behavior + change; warnings are out of scope): + + - **`no-useless-catch`** (`data-objectstack`) — unwrapped five try/catch blocks + whose `catch` only re-threw; errors still propagate identically. + - **`preserve-caught-error`** (`cli`, `data-objectstack`, `react`) — the caught + error's message is inlined into the thrown `Error`; a scoped disable with a + justifying comment carries each one, because these packages target ES2020 + whose lib types the 1-arg `Error` constructor only (so `{ cause }` won't + compile) — same reasoning as the core case in #2709. + - **`prefer-const`** (`plugin-calendar`, `plugin-map`) — `let`→`const` for + never-reassigned bindings. + - **`no-empty-object-type`** (`plugin-designer`) — empty extend-only interfaces + → equivalent `type` aliases. + - **`no-useless-assignment`** (`react`) — dropped a dead initializer that both + branches overwrite before it is read. + - **`no-require-imports`** (`plugin-calendar`, `plugin-timeline` tests) — + hoisted `vi.mock` factories now use an `async` factory with + `await import('react')` instead of `require('react')`. + - **stale `eslint-disable` directive** (`plugin-markdown`) — removed a + `react/no-danger` disable whose plugin is not loaded in the flat config (an + unknown-rule reference that ESLint v10 reports as an error); the rationale is + kept as a plain comment. + +- Updated dependencies [1c8935a] +- Updated dependencies [8b8b744] +- Updated dependencies [7cf4051] +- Updated dependencies [803558e] +- Updated dependencies [2e7d7f0] +- Updated dependencies [ef14f69] +- Updated dependencies [94d4876] +- Updated dependencies [69fa5d1] +- Updated dependencies [549c67d] +- Updated dependencies [2b17339] +- Updated dependencies [31b77d4] +- Updated dependencies [6d4fbe6] +- Updated dependencies [0a3710b] +- Updated dependencies [62b9ab5] +- Updated dependencies [1629313] +- Updated dependencies [faebac3] +- Updated dependencies [2331ac9] +- Updated dependencies [199fa83] +- Updated dependencies [eee4ded] + - @object-ui/core@16.1.0 + - @object-ui/types@16.1.0 + - @object-ui/react@16.1.0 + - @object-ui/components@16.1.0 + ## 16.0.0 ### Patch Changes diff --git a/packages/plugin-map/package.json b/packages/plugin-map/package.json index c2ccdb65d..3058f9a2d 100644 --- a/packages/plugin-map/package.json +++ b/packages/plugin-map/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/plugin-map", - "version": "16.0.0", + "version": "16.1.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 1a3c3a641..e3e1ea682 100644 --- a/packages/plugin-markdown/CHANGELOG.md +++ b/packages/plugin-markdown/CHANGELOG.md @@ -1,5 +1,61 @@ # @object-ui/plugin-markdown +## 16.1.0 + +### Patch Changes + +- 549c67d: chore(lint): clear the mechanical baseline lint errors so these packages' lint gates protect them again + + Extends the fields/core cleanup from #2709 (objectui#2713). These eight package + lints were red at baseline on `main`, so their per-package `lint` gate could not + catch new violations of the same class. Cleared every **error** (no behavior + change; warnings are out of scope): + + - **`no-useless-catch`** (`data-objectstack`) — unwrapped five try/catch blocks + whose `catch` only re-threw; errors still propagate identically. + - **`preserve-caught-error`** (`cli`, `data-objectstack`, `react`) — the caught + error's message is inlined into the thrown `Error`; a scoped disable with a + justifying comment carries each one, because these packages target ES2020 + whose lib types the 1-arg `Error` constructor only (so `{ cause }` won't + compile) — same reasoning as the core case in #2709. + - **`prefer-const`** (`plugin-calendar`, `plugin-map`) — `let`→`const` for + never-reassigned bindings. + - **`no-empty-object-type`** (`plugin-designer`) — empty extend-only interfaces + → equivalent `type` aliases. + - **`no-useless-assignment`** (`react`) — dropped a dead initializer that both + branches overwrite before it is read. + - **`no-require-imports`** (`plugin-calendar`, `plugin-timeline` tests) — + hoisted `vi.mock` factories now use an `async` factory with + `await import('react')` instead of `require('react')`. + - **stale `eslint-disable` directive** (`plugin-markdown`) — removed a + `react/no-danger` disable whose plugin is not loaded in the flat config (an + unknown-rule reference that ESLint v10 reports as an error); the rationale is + kept as a plain comment. + +- Updated dependencies [1c8935a] +- Updated dependencies [8b8b744] +- Updated dependencies [7cf4051] +- Updated dependencies [803558e] +- Updated dependencies [2e7d7f0] +- Updated dependencies [ef14f69] +- Updated dependencies [94d4876] +- Updated dependencies [69fa5d1] +- Updated dependencies [549c67d] +- Updated dependencies [2b17339] +- Updated dependencies [31b77d4] +- Updated dependencies [6d4fbe6] +- Updated dependencies [0a3710b] +- Updated dependencies [62b9ab5] +- Updated dependencies [1629313] +- Updated dependencies [faebac3] +- Updated dependencies [2331ac9] +- Updated dependencies [199fa83] +- Updated dependencies [eee4ded] + - @object-ui/core@16.1.0 + - @object-ui/types@16.1.0 + - @object-ui/react@16.1.0 + - @object-ui/components@16.1.0 + ## 16.0.0 ### Patch Changes diff --git a/packages/plugin-markdown/package.json b/packages/plugin-markdown/package.json index 1b14d3bf4..a1669aded 100644 --- a/packages/plugin-markdown/package.json +++ b/packages/plugin-markdown/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/plugin-markdown", - "version": "16.0.0", + "version": "16.1.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 f91e9c2a8..88fccd4ea 100644 --- a/packages/plugin-report/CHANGELOG.md +++ b/packages/plugin-report/CHANGELOG.md @@ -1,5 +1,105 @@ # @object-ui/plugin-report +## 16.1.0 + +### Minor Changes + +- 2331ac9: feat(report): drill a date-bucket cell into its time range, not a superset (#1752) + + Clicking a report/dashboard cell grouped by a `dateGranularity` date dimension + ("2026-Q2") used to drill into a **superset** — the date dimension was skipped, + so the record list spanned every time bucket. It now scopes to the clicked + bucket's half-open range, consuming the framework's new `drillRanges` sidecar. + + - **`@object-ui/core`** — `buildDatasetDrillFilter` accepts the per-row + `drillRanges` and emits an ObjectQL range operator object + (`{ [field]: { $gte, $lt } }`) alongside the equality dims. + - **`@object-ui/plugin-report` / `@object-ui/plugin-dashboard`** — the report + renderer and dashboard widget forward `drillRanges`, and a **date-only** + report (no equality drill dim) is now drillable via the range alone. + - **`@object-ui/app-shell`** — the "Open in list →" escape hatch + (`useOpenRecordList`) now targets the ADR-0055 **bare data surface** + (`/:object/data`, "the URL is the view" — no baked-in view filter to + over-narrow the drill) and serializes a range to the + `filter[field][gte|lt]` operator contract. `ObjectDataPage` parses those + operators (equality shorthand unchanged), renders a range as a single chip, + and removes both bounds together. A new `drillUrlFilters` module owns the + write/read serialization so both sides can't drift (round-trip tested). + + Companion to the framework analytics change (objectstack-ai/framework#3256). + +### Patch Changes + +- ebe6494: chore(lint): clear the baseline lint errors in nine more packages (objectui#2713 Wave 2) + + Second wave of the #2713 lint-gate restoration (after #2730). These nine package + lints were red at baseline on `main`, so their per-package `lint` gate could not + catch new violations. Cleared every **error** (no behavior change; warnings out + of scope): + + - **`react-hooks/rules-of-hooks`** (`i18n`, `plugin-grid`, `plugin-view`, + `plugin-list`) — translation helpers (`useSafeFieldLabel`, + `useRowActionTranslation`, `useViewLabel`, `useViewTabLabel`, `useMoreLabel`) + wrapped a provider-safe hook (`useObjectTranslation`/`useObjectLabel`, which + never throw) in try/catch; removed the wrapper (the same fix #2709 applied in + fields). `plugin-kanban` `ObjectKanban` moved its `if (error)` early return + below the `useCallback` so hooks run unconditionally. `collaboration` + `__unsafe_usePresenceContext` keeps its deliberate danger-prefix name via a + justified scoped disable. + - **`react-hooks/static-components`** (`layout`, `plugin-list`, `plugin-report`) + — dynamic-icon / registry lookups (`resolveIcon`, `useRegistryComponent`) are + stable component references, not components created during render → scoped + disable with justification. `plugin-charts` `TreemapCell` was a _genuine_ + inline component and is hoisted to module scope (it is purely props-driven). + - **`no-irregular-whitespace`** (`plugin-grid` `ImportWizard`) — the literal + U+FEFF BOM prepended to exported CSV/text blobs (so Excel detects UTF-8) is + now written as the `` escape: byte-identical at runtime, no literal + irregular-whitespace character in source. + - **`no-useless-assignment`** (`plugin-grid` `BulkActionDialog`) — dropped a + dead `= null` initializer that the exhaustive `switch` (incl. `default`) + overwrites before it is read. + - **`no-unsafe-function-type`** (`plugin-view` `ViewTabBar`) — the dnd-kit + render-prop `listeners` map is typed `Record void>` + instead of bare `Function`. + - **`no-require-imports`** (`plugin-kanban`, `plugin-view` tests) — hoisted + `vi.mock` factories use an `async` factory with `await import('react')`. + +- Updated dependencies [0318118] +- Updated dependencies [1c8935a] +- Updated dependencies [af1b0db] +- Updated dependencies [8b8b744] +- Updated dependencies [7cf4051] +- Updated dependencies [803558e] +- Updated dependencies [aefcf39] +- Updated dependencies [2e7d7f0] +- Updated dependencies [ef14f69] +- Updated dependencies [94d4876] +- Updated dependencies [1100a8b] +- Updated dependencies [7abe4cd] +- Updated dependencies [69fa5d1] +- Updated dependencies [549c67d] +- Updated dependencies [ebe6494] +- Updated dependencies [2b17339] +- Updated dependencies [31b77d4] +- Updated dependencies [6d4fbe6] +- Updated dependencies [0a3710b] +- Updated dependencies [f80aaf2] +- Updated dependencies [62b9ab5] +- Updated dependencies [14cb729] +- Updated dependencies [1629313] +- Updated dependencies [faebac3] +- Updated dependencies [2331ac9] +- Updated dependencies [199fa83] +- Updated dependencies [eee4ded] +- Updated dependencies [3b2e4d9] + - @object-ui/fields@16.1.0 + - @object-ui/i18n@16.1.0 + - @object-ui/core@16.1.0 + - @object-ui/types@16.1.0 + - @object-ui/react@16.1.0 + - @object-ui/components@16.1.0 + - @object-ui/plugin-grid@16.1.0 + ## 16.0.0 ### Patch Changes diff --git a/packages/plugin-report/package.json b/packages/plugin-report/package.json index 0c64da790..b0e2609ce 100644 --- a/packages/plugin-report/package.json +++ b/packages/plugin-report/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/plugin-report", - "version": "16.0.0", + "version": "16.1.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 791e5701f..471e2a013 100644 --- a/packages/plugin-timeline/CHANGELOG.md +++ b/packages/plugin-timeline/CHANGELOG.md @@ -1,5 +1,83 @@ # @object-ui/plugin-timeline +## 16.1.0 + +### Patch Changes + +- 7cf4051: chore(deps): align every `@objectstack/*` dependency to `^16.0.0-rc.0` + + Bumps `@objectstack/spec` / `client` / `formula` / `lint` from `^15.1.1` to the + `16.0.0-rc.0` pre-release across the workspace (root + `apps/console` + + `apps/site` + all consuming packages). ObjectUI's own packages are already on + major 16, so this closes the 15↔16 skew between ObjectUI and the `@objectstack` + contract libraries (which publish in lockstep with `spec`). + + This is a dependency alignment, not a behavioral migration: the full workspace + build (43/43) and the `@objectstack`-consuming package test suites + (`core` / `app-shell` / `data-objectstack` / `plugin-form` / `types`) are green + against `16.0.0-rc.0` with no source changes required. + + Practical effect: `@objectstack/client@16.0.0-rc.0` now ships + `data.batchTransaction` (framework #3271), so `ObjectStackAdapter`'s feature + detect (`typeof client.data.batchTransaction === 'function'`) routes + master-detail cross-object saves through the typed SDK method instead of the + raw `fetch('/api/v1/batch')` fallback — realizing the "verify SDK path" half of + #2694. The raw-fetch branch stays as a defensive fallback (removal tracked in + #2694). + +- 549c67d: chore(lint): clear the mechanical baseline lint errors so these packages' lint gates protect them again + + Extends the fields/core cleanup from #2709 (objectui#2713). These eight package + lints were red at baseline on `main`, so their per-package `lint` gate could not + catch new violations of the same class. Cleared every **error** (no behavior + change; warnings are out of scope): + + - **`no-useless-catch`** (`data-objectstack`) — unwrapped five try/catch blocks + whose `catch` only re-threw; errors still propagate identically. + - **`preserve-caught-error`** (`cli`, `data-objectstack`, `react`) — the caught + error's message is inlined into the thrown `Error`; a scoped disable with a + justifying comment carries each one, because these packages target ES2020 + whose lib types the 1-arg `Error` constructor only (so `{ cause }` won't + compile) — same reasoning as the core case in #2709. + - **`prefer-const`** (`plugin-calendar`, `plugin-map`) — `let`→`const` for + never-reassigned bindings. + - **`no-empty-object-type`** (`plugin-designer`) — empty extend-only interfaces + → equivalent `type` aliases. + - **`no-useless-assignment`** (`react`) — dropped a dead initializer that both + branches overwrite before it is read. + - **`no-require-imports`** (`plugin-calendar`, `plugin-timeline` tests) — + hoisted `vi.mock` factories now use an `async` factory with + `await import('react')` instead of `require('react')`. + - **stale `eslint-disable` directive** (`plugin-markdown`) — removed a + `react/no-danger` disable whose plugin is not loaded in the flat config (an + unknown-rule reference that ESLint v10 reports as an error); the rationale is + kept as a plain comment. + +- Updated dependencies [1c8935a] +- Updated dependencies [8b8b744] +- Updated dependencies [7cf4051] +- Updated dependencies [803558e] +- Updated dependencies [2e7d7f0] +- Updated dependencies [ef14f69] +- Updated dependencies [94d4876] +- Updated dependencies [69fa5d1] +- Updated dependencies [549c67d] +- Updated dependencies [2b17339] +- Updated dependencies [31b77d4] +- Updated dependencies [6d4fbe6] +- Updated dependencies [0a3710b] +- Updated dependencies [62b9ab5] +- Updated dependencies [1629313] +- Updated dependencies [faebac3] +- Updated dependencies [2331ac9] +- Updated dependencies [199fa83] +- Updated dependencies [eee4ded] + - @object-ui/core@16.1.0 + - @object-ui/types@16.1.0 + - @object-ui/react@16.1.0 + - @object-ui/components@16.1.0 + - @object-ui/mobile@16.1.0 + ## 16.0.0 ### Patch Changes diff --git a/packages/plugin-timeline/package.json b/packages/plugin-timeline/package.json index 2f0aabaf8..d14cc2d3c 100644 --- a/packages/plugin-timeline/package.json +++ b/packages/plugin-timeline/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/plugin-timeline", - "version": "16.0.0", + "version": "16.1.0", "type": "module", "license": "MIT", "description": "Timeline component plugin for Object UI", diff --git a/packages/plugin-tree/CHANGELOG.md b/packages/plugin-tree/CHANGELOG.md index 258e013dd..a73bdfc93 100644 --- a/packages/plugin-tree/CHANGELOG.md +++ b/packages/plugin-tree/CHANGELOG.md @@ -1,5 +1,54 @@ # @object-ui/plugin-tree +## 16.1.0 + +### Patch Changes + +- 7cf4051: chore(deps): align every `@objectstack/*` dependency to `^16.0.0-rc.0` + + Bumps `@objectstack/spec` / `client` / `formula` / `lint` from `^15.1.1` to the + `16.0.0-rc.0` pre-release across the workspace (root + `apps/console` + + `apps/site` + all consuming packages). ObjectUI's own packages are already on + major 16, so this closes the 15↔16 skew between ObjectUI and the `@objectstack` + contract libraries (which publish in lockstep with `spec`). + + This is a dependency alignment, not a behavioral migration: the full workspace + build (43/43) and the `@objectstack`-consuming package test suites + (`core` / `app-shell` / `data-objectstack` / `plugin-form` / `types`) are green + against `16.0.0-rc.0` with no source changes required. + + Practical effect: `@objectstack/client@16.0.0-rc.0` now ships + `data.batchTransaction` (framework #3271), so `ObjectStackAdapter`'s feature + detect (`typeof client.data.batchTransaction === 'function'`) routes + master-detail cross-object saves through the typed SDK method instead of the + raw `fetch('/api/v1/batch')` fallback — realizing the "verify SDK path" half of + #2694. The raw-fetch branch stays as a defensive fallback (removal tracked in + #2694). + +- Updated dependencies [1c8935a] +- Updated dependencies [8b8b744] +- Updated dependencies [7cf4051] +- Updated dependencies [803558e] +- Updated dependencies [2e7d7f0] +- Updated dependencies [ef14f69] +- Updated dependencies [94d4876] +- Updated dependencies [69fa5d1] +- Updated dependencies [549c67d] +- Updated dependencies [2b17339] +- Updated dependencies [31b77d4] +- Updated dependencies [6d4fbe6] +- Updated dependencies [0a3710b] +- Updated dependencies [62b9ab5] +- Updated dependencies [1629313] +- Updated dependencies [faebac3] +- Updated dependencies [2331ac9] +- Updated dependencies [199fa83] +- Updated dependencies [eee4ded] + - @object-ui/core@16.1.0 + - @object-ui/types@16.1.0 + - @object-ui/react@16.1.0 + - @object-ui/components@16.1.0 + ## 16.0.0 ### Patch Changes diff --git a/packages/plugin-tree/package.json b/packages/plugin-tree/package.json index ae28699d0..ae09185a5 100644 --- a/packages/plugin-tree/package.json +++ b/packages/plugin-tree/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/plugin-tree", - "version": "16.0.0", + "version": "16.1.0", "type": "module", "license": "MIT", "description": "Tree / tree-grid visualization plugin for Object UI", diff --git a/packages/plugin-view/CHANGELOG.md b/packages/plugin-view/CHANGELOG.md index cfd8144b0..2b7bd46a4 100644 --- a/packages/plugin-view/CHANGELOG.md +++ b/packages/plugin-view/CHANGELOG.md @@ -1,5 +1,98 @@ # @object-ui/plugin-view +## 16.1.0 + +### Patch Changes + +- 7cf4051: chore(deps): align every `@objectstack/*` dependency to `^16.0.0-rc.0` + + Bumps `@objectstack/spec` / `client` / `formula` / `lint` from `^15.1.1` to the + `16.0.0-rc.0` pre-release across the workspace (root + `apps/console` + + `apps/site` + all consuming packages). ObjectUI's own packages are already on + major 16, so this closes the 15↔16 skew between ObjectUI and the `@objectstack` + contract libraries (which publish in lockstep with `spec`). + + This is a dependency alignment, not a behavioral migration: the full workspace + build (43/43) and the `@objectstack`-consuming package test suites + (`core` / `app-shell` / `data-objectstack` / `plugin-form` / `types`) are green + against `16.0.0-rc.0` with no source changes required. + + Practical effect: `@objectstack/client@16.0.0-rc.0` now ships + `data.batchTransaction` (framework #3271), so `ObjectStackAdapter`'s feature + detect (`typeof client.data.batchTransaction === 'function'`) routes + master-detail cross-object saves through the typed SDK method instead of the + raw `fetch('/api/v1/batch')` fallback — realizing the "verify SDK path" half of + #2694. The raw-fetch branch stays as a defensive fallback (removal tracked in + #2694). + +- ebe6494: chore(lint): clear the baseline lint errors in nine more packages (objectui#2713 Wave 2) + + Second wave of the #2713 lint-gate restoration (after #2730). These nine package + lints were red at baseline on `main`, so their per-package `lint` gate could not + catch new violations. Cleared every **error** (no behavior change; warnings out + of scope): + + - **`react-hooks/rules-of-hooks`** (`i18n`, `plugin-grid`, `plugin-view`, + `plugin-list`) — translation helpers (`useSafeFieldLabel`, + `useRowActionTranslation`, `useViewLabel`, `useViewTabLabel`, `useMoreLabel`) + wrapped a provider-safe hook (`useObjectTranslation`/`useObjectLabel`, which + never throw) in try/catch; removed the wrapper (the same fix #2709 applied in + fields). `plugin-kanban` `ObjectKanban` moved its `if (error)` early return + below the `useCallback` so hooks run unconditionally. `collaboration` + `__unsafe_usePresenceContext` keeps its deliberate danger-prefix name via a + justified scoped disable. + - **`react-hooks/static-components`** (`layout`, `plugin-list`, `plugin-report`) + — dynamic-icon / registry lookups (`resolveIcon`, `useRegistryComponent`) are + stable component references, not components created during render → scoped + disable with justification. `plugin-charts` `TreemapCell` was a _genuine_ + inline component and is hoisted to module scope (it is purely props-driven). + - **`no-irregular-whitespace`** (`plugin-grid` `ImportWizard`) — the literal + U+FEFF BOM prepended to exported CSV/text blobs (so Excel detects UTF-8) is + now written as the `` escape: byte-identical at runtime, no literal + irregular-whitespace character in source. + - **`no-useless-assignment`** (`plugin-grid` `BulkActionDialog`) — dropped a + dead `= null` initializer that the exhaustive `switch` (incl. `default`) + overwrites before it is read. + - **`no-unsafe-function-type`** (`plugin-view` `ViewTabBar`) — the dnd-kit + render-prop `listeners` map is typed `Record void>` + instead of bare `Function`. + - **`no-require-imports`** (`plugin-kanban`, `plugin-view` tests) — hoisted + `vi.mock` factories use an `async` factory with `await import('react')`. + +- Updated dependencies [0318118] +- Updated dependencies [1c8935a] +- Updated dependencies [af1b0db] +- Updated dependencies [8b8b744] +- Updated dependencies [7cf4051] +- Updated dependencies [803558e] +- Updated dependencies [2e7d7f0] +- Updated dependencies [ef14f69] +- Updated dependencies [94d4876] +- Updated dependencies [1100a8b] +- Updated dependencies [7abe4cd] +- Updated dependencies [69fa5d1] +- Updated dependencies [549c67d] +- Updated dependencies [ebe6494] +- Updated dependencies [2b17339] +- Updated dependencies [31b77d4] +- Updated dependencies [6d4fbe6] +- Updated dependencies [0a3710b] +- Updated dependencies [f80aaf2] +- Updated dependencies [62b9ab5] +- Updated dependencies [1629313] +- Updated dependencies [faebac3] +- Updated dependencies [2331ac9] +- Updated dependencies [199fa83] +- Updated dependencies [eee4ded] +- Updated dependencies [3b2e4d9] + - @object-ui/i18n@16.1.0 + - @object-ui/core@16.1.0 + - @object-ui/types@16.1.0 + - @object-ui/react@16.1.0 + - @object-ui/plugin-form@16.1.0 + - @object-ui/components@16.1.0 + - @object-ui/plugin-grid@16.1.0 + ## 16.0.0 ### Patch Changes diff --git a/packages/plugin-view/package.json b/packages/plugin-view/package.json index 185de93b6..c36083d35 100644 --- a/packages/plugin-view/package.json +++ b/packages/plugin-view/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/plugin-view", - "version": "16.0.0", + "version": "16.1.0", "type": "module", "license": "MIT", "description": "Object View plugin for Object UI", diff --git a/packages/providers/CHANGELOG.md b/packages/providers/CHANGELOG.md index 63d5a9b4d..4734d8c16 100644 --- a/packages/providers/CHANGELOG.md +++ b/packages/providers/CHANGELOG.md @@ -1,5 +1,19 @@ # @object-ui/providers — Changelog +## 16.1.0 + +### Patch Changes + +- Updated dependencies [7cf4051] +- Updated dependencies [94d4876] +- Updated dependencies [2b17339] +- Updated dependencies [31b77d4] +- Updated dependencies [6d4fbe6] +- Updated dependencies [62b9ab5] +- Updated dependencies [faebac3] +- Updated dependencies [199fa83] + - @object-ui/types@16.1.0 + ## 16.0.0 ### Patch Changes diff --git a/packages/providers/package.json b/packages/providers/package.json index 32bf22756..f4788d67f 100644 --- a/packages/providers/package.json +++ b/packages/providers/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/providers", - "version": "16.0.0", + "version": "16.1.0", "type": "module", "license": "MIT", "description": "Reusable context providers for ObjectUI applications", diff --git a/packages/react-runtime/CHANGELOG.md b/packages/react-runtime/CHANGELOG.md index 9d59847c9..228be0958 100644 --- a/packages/react-runtime/CHANGELOG.md +++ b/packages/react-runtime/CHANGELOG.md @@ -1,5 +1,7 @@ # @object-ui/react-runtime +## 16.1.0 + ## 16.0.0 ## 15.0.0 diff --git a/packages/react-runtime/package.json b/packages/react-runtime/package.json index 45c4c1e1d..afc95c635 100644 --- a/packages/react-runtime/package.json +++ b/packages/react-runtime/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/react-runtime", - "version": "16.0.0", + "version": "16.1.0", "type": "module", "sideEffects": false, "license": "MIT", diff --git a/packages/react/CHANGELOG.md b/packages/react/CHANGELOG.md index fa77d227b..a4719db21 100644 --- a/packages/react/CHANGELOG.md +++ b/packages/react/CHANGELOG.md @@ -1,5 +1,151 @@ # @object-ui/react +## 16.1.0 + +### Minor Changes + +- 803558e: feat(data): thread the host's authenticated fetch into `provider: 'api'` data sources (#2725) + + `provider: 'api'` view data sources went through a bare `globalThis.fetch`, so + custom endpoints (gantt composite trees, report aggregates) carried only + same-origin cookies while every native `/api/v1/*` request carried + `Authorization: Bearer` — the moment cookie HMAC verification failed (dev + restart rotating the fallback auth secret, cookie expiry/rotation in prod) + those views 401'd while the rest of the app kept working. + + - **`@object-ui/react`** — `SchemaRendererProvider` accepts an optional + `apiFetch`; nested providers inherit it from their parent so re-wrapped + subtrees (react pages, preview surfaces) keep the host's authentication. + `useViewData` defaults the api-provider adapter's fetch to the context + `apiFetch` (explicit `adapterOptions.fetch` still wins). + - **`@object-ui/auth`** — `createAuthenticatedFetch` gains a + `sameOriginOnly` option: cross-origin URLs pass through to the bare fetch + with no `Authorization` / `X-Tenant-ID` / `Accept-Language`, so metadata- + supplied third-party URLs never see the platform token. + - **`@object-ui/app-shell`** — the console wires + `createAuthenticatedFetch({ sameOriginOnly: true })` (settle-signal wrapped) + as `apiFetch` on the root `SchemaRendererProvider`. + - **`@object-ui/plugin-gantt`** — `ObjectGantt` resolves its api-provider + DataSource with the context `apiFetch`, covering reads and write-backs. + + Behaviour is unchanged for hosts that don't provide `apiFetch` (bare fetch + + cookies, as before). + +- 2e7d7f0: feat(evaluator): route `{ dialect: 'cel' }` component/action predicates to the canonical CEL engine (#2661) + + Component and action `visible` / `disabled` / `hidden` predicates were evaluated + by the home-grown JS `ExpressionEvaluator`, while field rules + (`visibleWhen`/`readonlyWhen`/`requiredWhen`, via `fieldRules.ts`) and row/list + conditionals (via `evalRowPredicate`) already delegate to the canonical + `@objectstack/formula` engine. That split meant a `{ dialect: 'cel' }` predicate + in a renderer/action surface was executed as **JavaScript** — CEL-only forms + (`x in list`, `has()`, typed `==`, the `today()`/`daysFromNow()` catalog) behaved + differently from, or faulted against, the server's enforcement. + + This converges the remaining tier onto the same engine: + + - **`@object-ui/core`** — `ExpressionEvaluator.evaluateCondition` now detects a + `{ dialect: 'cel', source }` envelope and evaluates it on `@objectstack/formula` + (via `evalFieldPredicate`), binding the `record` namespace plus the whole + context bag as top-level scope (`record.*`, `features.*`, `user.*`, `app.*`). + Fail-soft to visible/enabled to match the legacy default; `throwOnError` + callers still fail closed on a _faulting_ predicate (a genuine `false` never + throws). This fixes every `SchemaRenderer` visibility/disabled read at once. + - **`@object-ui/react`** — `toPredicateInput` preserves a CEL envelope instead of + collapsing it to a `${source}` string, and `useCondition` accepts and forwards + the envelope (keyed on a stable `(dialect, source)` so it doesn't re-evaluate + each render). Action buttons (`action-icon`/`group`/`bar`/`button`) therefore + evaluate CEL `visible`/`enabled`/`disabled` on the canonical engine. + + **Back-compat:** bare strings and `${…}` templates stay on the legacy JS path + (deprecation window); only an explicit `{ dialect: 'cel' }` envelope is rerouted. + `{ dialect: 'template' }` is unaffected. + + Together with the `^15.1.1` alignment (#2662), a renderer CEL predicate now + reaches the identical verdict as the server — including the framework's + `dateField == today()` equality fix (objectstack-ai/framework#3205) once it + lands in a published 15.x. The broader home-grown-vs-canonical divergence + motivation is #2661. + +### Patch Changes + +- 7cf4051: chore(deps): align every `@objectstack/*` dependency to `^16.0.0-rc.0` + + Bumps `@objectstack/spec` / `client` / `formula` / `lint` from `^15.1.1` to the + `16.0.0-rc.0` pre-release across the workspace (root + `apps/console` + + `apps/site` + all consuming packages). ObjectUI's own packages are already on + major 16, so this closes the 15↔16 skew between ObjectUI and the `@objectstack` + contract libraries (which publish in lockstep with `spec`). + + This is a dependency alignment, not a behavioral migration: the full workspace + build (43/43) and the `@objectstack`-consuming package test suites + (`core` / `app-shell` / `data-objectstack` / `plugin-form` / `types`) are green + against `16.0.0-rc.0` with no source changes required. + + Practical effect: `@objectstack/client@16.0.0-rc.0` now ships + `data.batchTransaction` (framework #3271), so `ObjectStackAdapter`'s feature + detect (`typeof client.data.batchTransaction === 'function'`) routes + master-detail cross-object saves through the typed SDK method instead of the + raw `fetch('/api/v1/batch')` fallback — realizing the "verify SDK path" half of + #2694. The raw-fetch branch stays as a defensive fallback (removal tracked in + #2694). + +- 549c67d: chore(lint): clear the mechanical baseline lint errors so these packages' lint gates protect them again + + Extends the fields/core cleanup from #2709 (objectui#2713). These eight package + lints were red at baseline on `main`, so their per-package `lint` gate could not + catch new violations of the same class. Cleared every **error** (no behavior + change; warnings are out of scope): + + - **`no-useless-catch`** (`data-objectstack`) — unwrapped five try/catch blocks + whose `catch` only re-threw; errors still propagate identically. + - **`preserve-caught-error`** (`cli`, `data-objectstack`, `react`) — the caught + error's message is inlined into the thrown `Error`; a scoped disable with a + justifying comment carries each one, because these packages target ES2020 + whose lib types the 1-arg `Error` constructor only (so `{ cause }` won't + compile) — same reasoning as the core case in #2709. + - **`prefer-const`** (`plugin-calendar`, `plugin-map`) — `let`→`const` for + never-reassigned bindings. + - **`no-empty-object-type`** (`plugin-designer`) — empty extend-only interfaces + → equivalent `type` aliases. + - **`no-useless-assignment`** (`react`) — dropped a dead initializer that both + branches overwrite before it is read. + - **`no-require-imports`** (`plugin-calendar`, `plugin-timeline` tests) — + hoisted `vi.mock` factories now use an `async` factory with + `await import('react')` instead of `require('react')`. + - **stale `eslint-disable` directive** (`plugin-markdown`) — removed a + `react/no-danger` disable whose plugin is not loaded in the flat config (an + unknown-rule reference that ESLint v10 reports as an error); the rationale is + kept as a plain comment. + +- Updated dependencies [0318118] +- Updated dependencies [1c8935a] +- Updated dependencies [af1b0db] +- Updated dependencies [8b8b744] +- Updated dependencies [7cf4051] +- Updated dependencies [8c1e415] +- Updated dependencies [2e7d7f0] +- Updated dependencies [94d4876] +- Updated dependencies [1100a8b] +- Updated dependencies [7abe4cd] +- Updated dependencies [549c67d] +- Updated dependencies [ebe6494] +- Updated dependencies [2b17339] +- Updated dependencies [31b77d4] +- Updated dependencies [6d4fbe6] +- Updated dependencies [0a3710b] +- Updated dependencies [f80aaf2] +- Updated dependencies [62b9ab5] +- Updated dependencies [1629313] +- Updated dependencies [faebac3] +- Updated dependencies [2331ac9] +- Updated dependencies [199fa83] +- Updated dependencies [eee4ded] + - @object-ui/i18n@16.1.0 + - @object-ui/core@16.1.0 + - @object-ui/data-objectstack@16.1.0 + - @object-ui/types@16.1.0 + ## 16.0.0 ### Minor Changes diff --git a/packages/react/package.json b/packages/react/package.json index b6b6b3159..e85c98f9f 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/react", - "version": "16.0.0", + "version": "16.1.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 f2b26746e..d5639ee40 100644 --- a/packages/runner/CHANGELOG.md +++ b/packages/runner/CHANGELOG.md @@ -1,5 +1,72 @@ # @object-ui/runner +## 16.1.0 + +### Minor Changes + +- 62b9ab5: feat(data): unify master-detail saves behind `DataSource.batchTransaction`, isolate the non-atomic fallback in the adapter (#2679) + + Master-detail saves (`MasterDetailForm`, `LineItemsPanel`) now always persist + through `dataSource.batchTransaction(operations)` — one ordered cross-object + operation list, with `{ $ref: }` linking a child to a parent created + in the same batch. The form no longer contains any client-side orchestration or + best-effort compensation-delete; that atomicity anti-pattern is gone from the UI + layer (framework #1604 / framework ADR-0034 item 4). + + - **`@object-ui/types`** — `batchTransaction?` is now a first-class (optional) + method on the `DataSource` contract, typed via `BatchTransactionOperation` / + `BatchRef`. Replaces the previous `(dataSource as any).batchTransaction` + method-sniffing. + - **`@object-ui/core`** — new `emulateBatchTransaction(dataSource, operations)` + (sequential writes, `$ref` resolution, best-effort reverse-order compensation) + and `runBatchTransaction(dataSource, operations)` (prefers the adapter's method, + emulates otherwise). `ApiDataSource` / `ValueDataSource` implement + `batchTransaction` via the emulation. + - **`@object-ui/data-objectstack`** — `ObjectStackAdapter.batchTransaction` uses + the server's atomic `POST /api/v1/batch`, prefers the typed + `client.data.batchTransaction` SDK method when the installed client exposes it, + and degrades to the client-side emulation ONLY when the endpoint is missing + (404/405) or the runtime can't do transactions (501). Real errors (400/401/403/ + 409/500) still surface. This is the isolated, tested home of the non-atomic + fallback. + - **`@object-ui/plugin-form`** — removed `applyDetail` / `createMany` / + `ApplyDetailResult` from `masterDetailTx.ts`; `MasterDetailForm` and + `LineItemsPanel` build ops and call `runBatchTransaction`. `LineItemsPanel` + saves are now atomic on a capable backend, with the rollup folded into the same + batch. + + No behavior change on a current ObjectStack backend (it has `/api/v1/batch`); + older/limited backends keep a working — now clearly non-atomic — save path. + +### Patch Changes + +- Updated dependencies [1c8935a] +- Updated dependencies [8b8b744] +- Updated dependencies [7cf4051] +- Updated dependencies [803558e] +- Updated dependencies [2e7d7f0] +- Updated dependencies [ef14f69] +- Updated dependencies [94d4876] +- Updated dependencies [69fa5d1] +- Updated dependencies [549c67d] +- Updated dependencies [ebe6494] +- Updated dependencies [2b17339] +- Updated dependencies [31b77d4] +- Updated dependencies [6d4fbe6] +- Updated dependencies [0a3710b] +- Updated dependencies [62b9ab5] +- Updated dependencies [1629313] +- Updated dependencies [faebac3] +- Updated dependencies [2331ac9] +- Updated dependencies [199fa83] +- Updated dependencies [eee4ded] + - @object-ui/core@16.1.0 + - @object-ui/types@16.1.0 + - @object-ui/react@16.1.0 + - @object-ui/components@16.1.0 + - @object-ui/plugin-kanban@16.1.0 + - @object-ui/plugin-charts@16.1.0 + ## 16.0.0 ### Patch Changes diff --git a/packages/runner/package.json b/packages/runner/package.json index 58f0e4169..f4e1e3517 100644 --- a/packages/runner/package.json +++ b/packages/runner/package.json @@ -1,7 +1,7 @@ { "name": "@object-ui/runner", "private": false, - "version": "16.0.0", + "version": "16.1.0", "description": "Universal Object UI Application Runner", "type": "module", "homepage": "https://www.objectui.org/docs/utilities/runner", diff --git a/packages/sdui-parser/CHANGELOG.md b/packages/sdui-parser/CHANGELOG.md index bd3748717..491672488 100644 --- a/packages/sdui-parser/CHANGELOG.md +++ b/packages/sdui-parser/CHANGELOG.md @@ -1,5 +1,7 @@ # @object-ui/sdui-parser +## 16.1.0 + ## 16.0.0 ## 15.0.0 diff --git a/packages/sdui-parser/package.json b/packages/sdui-parser/package.json index 34a385d96..1a83bb20a 100644 --- a/packages/sdui-parser/package.json +++ b/packages/sdui-parser/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/sdui-parser", - "version": "16.0.0", + "version": "16.1.0", "type": "module", "sideEffects": false, "license": "MIT", diff --git a/packages/types/CHANGELOG.md b/packages/types/CHANGELOG.md index 7618c7ff7..be49c83db 100644 --- a/packages/types/CHANGELOG.md +++ b/packages/types/CHANGELOG.md @@ -1,5 +1,183 @@ # @object-ui/types +## 16.1.0 + +### Minor Changes + +- 94d4876: feat(dashboard): Studio authors the ADR-0021 dataset shape only (framework#3251) + + Finishes the dashboard analytics migration on the authoring side so the + framework can enable `DashboardWidgetSchema.strict()`. Both Studio surfaces now + emit only the semantic-layer shape (`dataset` + `dimensions` + `values`); no + surface authors the removed pre-ADR-0021 inline query. + + **FROM → TO** (authoring) + + - charts: `object` + `categoryField` + `valueField` + `aggregate` + → `dataset` + `dimensions` + `values` + - pivots: `object` + `rowField` + `columnField` + `valueField` + `aggregation` + → `dataset` + `dimensions` + `values` (last dimension spreads across columns) + + **Changes** + + - `@object-ui/types` — `DashboardWidgetSchema` gains `dataset` / `dimensions` / + `values`; the inline analytics keys (`object`, `categoryField`, + `categoryGranularity`, `valueField`, `aggregate`, `measures`) are marked + `@deprecated` (retained only so the renderer can still read legacy/static + metadata during the transition). + - `@object-ui/plugin-dashboard` — `WidgetConfigPanel` is rewritten as a dataset + picker (chart AND pivot). **Breaking prop change:** the unused + `availableObjects` / `availableFields` props are replaced by a new + `datasets?: WidgetDatasetCatalogEntry[]` (+ `datasetsLoading?`) catalog prop, + also forwarded by `DashboardWithConfig`. Hosts resolve the catalog (e.g. via + the metadata client's `list('dataset')`); without it the panel falls back to + free-text authoring. New exports: `WidgetDatasetCatalogEntry` and + `sanitizeDraftForType`. + - `@object-ui/app-shell` — the metadata-admin `DashboardWidgetInspector` drops + the legacy inline fields (object / value field / category field / aggregate); + the dataset section is now the primary (and only) analytics binding, and the + filter-binding field picker sources options from the bound dataset's + dimensions. The "Add widget" catalog drops `list` / `custom` — neither is a + member of `@objectstack/spec` `ChartTypeSchema`, so a widget authored with + them could never publish. + + **Not changed:** `DashboardRenderer` keeps its legacy/static read branches and + the `ObjectPivotTable` / `PivotTable` blocks (still public SDUI blocks and the + backward-compat path for stored/static widgets) — only the dashboard authoring + flow stops emitting the legacy keys. Retiring those renderer branches is a + follow-up gated on migrating stored dashboards. + +- 31b77d4: **Add the explicit `engine-owned` lifecycle bucket (tracks framework ADR-0103 addendum / #3343).** The framework split the overloaded `managedBy: 'system'` bucket by promoting the engine-owned case to its own enum value; this mirrors it in the UI type + runtime + badge. + + - **`@object-ui/types`** — `ManagedByBucket` union and `MANAGED_BY_BUCKETS` gain `'engine-owned'` (canonical order: `platform, config, system, engine-owned, append-only, better-auth`). The union stays closed, so every consumer that missed the new value is a compile error. + - **`@object-ui/core`** — `resolveCrudAffordances` gains the `engine-owned` default row (identical all-locked matrix as `system`/`append-only`), so `isObjectInlineEditable` / the grid + form gates treat it as read-only automatically. + - **`@object-ui/app-shell`** — the `ManagedByBadge` renders `engine-owned` with the same read-only "System-managed" copy as a locked `system` object (reuses the existing `managedByBadge.system` i18n key — zero translation churn; the distinction is at the schema level, not the user-facing string), and `resolveManagedByEmptyState` reuses the `system` engine-owned empty state. + + Behaviour-preserving: `engine-owned` resolves to the same locked affordances `system` did by default, so nothing about how a locked object renders changes — the value just makes the schema self-documenting. New unit coverage for the bucket in `resolveCrudAffordances` / `isObjectInlineEditable` / `MANAGED_BY_BUCKETS` / the empty-state helper. + +- 62b9ab5: feat(data): unify master-detail saves behind `DataSource.batchTransaction`, isolate the non-atomic fallback in the adapter (#2679) + + Master-detail saves (`MasterDetailForm`, `LineItemsPanel`) now always persist + through `dataSource.batchTransaction(operations)` — one ordered cross-object + operation list, with `{ $ref: }` linking a child to a parent created + in the same batch. The form no longer contains any client-side orchestration or + best-effort compensation-delete; that atomicity anti-pattern is gone from the UI + layer (framework #1604 / framework ADR-0034 item 4). + + - **`@object-ui/types`** — `batchTransaction?` is now a first-class (optional) + method on the `DataSource` contract, typed via `BatchTransactionOperation` / + `BatchRef`. Replaces the previous `(dataSource as any).batchTransaction` + method-sniffing. + - **`@object-ui/core`** — new `emulateBatchTransaction(dataSource, operations)` + (sequential writes, `$ref` resolution, best-effort reverse-order compensation) + and `runBatchTransaction(dataSource, operations)` (prefers the adapter's method, + emulates otherwise). `ApiDataSource` / `ValueDataSource` implement + `batchTransaction` via the emulation. + - **`@object-ui/data-objectstack`** — `ObjectStackAdapter.batchTransaction` uses + the server's atomic `POST /api/v1/batch`, prefers the typed + `client.data.batchTransaction` SDK method when the installed client exposes it, + and degrades to the client-side emulation ONLY when the endpoint is missing + (404/405) or the runtime can't do transactions (501). Real errors (400/401/403/ + 409/500) still surface. This is the isolated, tested home of the non-atomic + fallback. + - **`@object-ui/plugin-form`** — removed `applyDetail` / `createMany` / + `ApplyDetailResult` from `masterDetailTx.ts`; `MasterDetailForm` and + `LineItemsPanel` build ops and call `runBatchTransaction`. `LineItemsPanel` + saves are now atomic on a capable backend, with the rollup folded into the same + batch. + + No behavior change on a current ObjectStack backend (it has `/api/v1/batch`); + older/limited backends keep a working — now clearly non-atomic — save path. + +- 199fa83: feat(dashboard): retire the pre-ADR-0021 inline-analytics renderer branches (framework#3320) + + Follow-up to the dashboard analytics migration (framework#3251 / objectui#2703). + Authoring already emits only the semantic-layer shape (`dataset` + `dimensions` + + `values`); this removes the renderer's now-unauthored legacy read-branches. + + - **types**: drop the `@deprecated` inline-analytics keys (`object`, + `categoryField`, `categoryGranularity`, `valueField`, `aggregate`, `measures`) + from `DashboardWidgetSchema`. They were retained in #2703 only so the renderer + could read legacy/static metadata during the transition. + - **plugin-dashboard**: `DashboardRenderer` no longer emits the object-bound + metric / chart / pivot / table / list branches from the top-level `object` + + analytics keys. It keeps the renderer-internal static paths (`options.data` / + `widget.data` array and the `provider: 'object'` async config) and + `widget.component`. The dashboard renderer no longer emits `object-pivot` / + `pivot` at all — dataset pivots render through `DatasetWidget` (grouped table / + cross-tab); the `ObjectPivotTable` / `PivotTable` components stay as public + SDUI blocks for other surfaces. `DashboardGridLayout` gets the same treatment. + - **graceful fallback**: a widget that still carries the retired inline shape in + stored metadata (top-level `object`, no `dataset`, no inline `options.data`) + now renders a visible error placeholder prompting a rebind to a dataset, rather + than a blank chart/grid. + - **plugin-designer**: `DashboardEditor` drops its inline object / value-field / + aggregate fields (analytics binding is authored via the dataset picker in + app-shell's `DashboardWidgetInspector` / plugin-dashboard's `WidgetConfigPanel`). + +### Patch Changes + +- 7cf4051: chore(deps): align every `@objectstack/*` dependency to `^16.0.0-rc.0` + + Bumps `@objectstack/spec` / `client` / `formula` / `lint` from `^15.1.1` to the + `16.0.0-rc.0` pre-release across the workspace (root + `apps/console` + + `apps/site` + all consuming packages). ObjectUI's own packages are already on + major 16, so this closes the 15↔16 skew between ObjectUI and the `@objectstack` + contract libraries (which publish in lockstep with `spec`). + + This is a dependency alignment, not a behavioral migration: the full workspace + build (43/43) and the `@objectstack`-consuming package test suites + (`core` / `app-shell` / `data-objectstack` / `plugin-form` / `types`) are green + against `16.0.0-rc.0` with no source changes required. + + Practical effect: `@objectstack/client@16.0.0-rc.0` now ships + `data.batchTransaction` (framework #3271), so `ObjectStackAdapter`'s feature + detect (`typeof client.data.batchTransaction === 'function'`) routes + master-detail cross-object saves through the typed SDK method instead of the + raw `fetch('/api/v1/batch')` fallback — realizing the "verify SDK path" half of + #2694. The raw-fetch branch stays as a defensive fallback (removal tracked in + #2694). + +- 2b17339: fix(list): keep the injected `owner_id` out of the leading auto-derived columns + + A view-less object's default list columns are derived from the object's field + order. The framework's `applySystemFields` spreads its injected + system/audit/ownership fields to the FRONT of that order and stamps them + `system: true`; `owner_id` is deliberately non-hidden and non-readonly + (ownership is reassignable), so the old name-based exclusion lists in + `ObjectGrid` and `InterfaceListPage` — which never listed `owner_id` — let it + through as column #1 on many showcase list pages (e.g. `showcase_field_zoo`). + + Default-column derivation now classifies system fields via the shared + `isSystemManagedField` helper, which branches on the spec `system` flag (the + single source of truth stamped by the registry) with a name-set fallback that + includes the ownership/tenancy FKs. `owner_id` is pushed to the end + (`ObjectGrid`) / excluded from the business columns (`InterfaceListPage`), so + auto-derived lists lead with business fields again and pick up future injected + fields without editing a name list. Also declares the `system` flag on the + `@object-ui/types` field metadata. + +- 6d4fbe6: **Consolidate the `managedBy` lifecycle-bucket logic into one shared source of truth (follows framework ADR-0103).** The bucket taxonomy was hand-mirrored in several places — `crudAffordances.ts`, `ManagedByBadge.tsx` (its own `Bucket` union + `isWriteOptedIn` + the writable-system derivation), and `plugin-detail`'s `record-details.tsx` (`NON_EDITABLE_BUCKETS`, duplicated because it can't depend on app-shell) — a drift risk, and the object-schema `managedBy` type was open-ended (`(string & {})`) so unknown buckets slipped through and silently defaulted to fully-editable. + + - **`@object-ui/types`** now owns the closed `ManagedByBucket` union (+ `MANAGED_BY_BUCKETS`), and `ObjectSchema.managedBy` is tightened from `'platform' | 'better-auth' | (string & {})` to that union — unknown buckets are now a type error at authoring time. + - **`@object-ui/core`** now owns the React-free runtime logic — `resolveCrudAffordances`, `isWriteOptedIn`, `isSystemWritable`, `isObjectInlineEditable` — reachable by every UI package including `plugin-detail` (which could not import app-shell). + - **`app-shell/utils/crudAffordances.ts`** is now a thin re-export of `@object-ui/core` (existing imports keep working); `ManagedByBadge` consumes the shared `isSystemWritable`; `plugin-detail` `record-details.tsx` replaces its hand-mirrored `NON_EDITABLE_BUCKETS` with `isObjectInlineEditable`. + + Behavior-preserving — all existing affordance/edit-gate tests stay green; the shared module adds direct unit coverage (including the previously-untested `isSystemWritable` derivation). Translated copy (badge variants, empty-state messages) stays in app-shell. + +- faebac3: Related lists paginate by default and fetch server-side windows (#2711). + + `record:related_list` now applies the spec default `limit` of 5 when a node + doesn't declare one, so detail-page related lists render pages with + Previous/Next controls instead of dumping every child row. On the auto-fetch + path RelatedList requests one page at a time (`$top`/`$skip`), reads the + collection size from `QueryResult.total` (`hasMore` fallback), sends user + column sorts as a server `$orderby`, and seeds the initial order from the + node's `sort` prop (new `defaultSort` prop on RelatedList). Caller-provided + `data` keeps the historical client-side slicing. Behavior change: lists that + previously rendered all rows now show 5 per page — declare a larger `limit` + on the `record:related_list` node to widen the window. + ## 16.0.0 ### Major Changes diff --git a/packages/types/package.json b/packages/types/package.json index 7b4c5b7a7..5ee500caf 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@object-ui/types", - "version": "16.0.0", + "version": "16.1.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 ba75dc360..1b3b4e0cb 100644 --- a/packages/vscode-extension/CHANGELOG.md +++ b/packages/vscode-extension/CHANGELOG.md @@ -1,5 +1,27 @@ # Changelog +## 16.1.0 + +### Patch Changes + +- Updated dependencies [1c8935a] +- Updated dependencies [8b8b744] +- Updated dependencies [7cf4051] +- Updated dependencies [2e7d7f0] +- Updated dependencies [94d4876] +- Updated dependencies [2b17339] +- Updated dependencies [31b77d4] +- Updated dependencies [6d4fbe6] +- Updated dependencies [0a3710b] +- Updated dependencies [62b9ab5] +- Updated dependencies [1629313] +- Updated dependencies [faebac3] +- Updated dependencies [2331ac9] +- Updated dependencies [199fa83] +- Updated dependencies [eee4ded] + - @object-ui/core@16.1.0 + - @object-ui/types@16.1.0 + ## 16.0.0 ### Patch Changes diff --git a/packages/vscode-extension/package.json b/packages/vscode-extension/package.json index 792737ac1..64b21e738 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": "16.0.0", + "version": "16.1.0", "publisher": "objectui", "private": true, "icon": "icon.svg",