diff --git a/.changeset/adr-0057-ai-usage-indicator.md b/.changeset/adr-0057-ai-usage-indicator.md deleted file mode 100644 index 764e22fd4..000000000 --- a/.changeset/adr-0057-ai-usage-indicator.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -"@object-ui/app-shell": minor -"@object-ui/plugin-chatbot": patch -"@object-ui/i18n": patch ---- - -feat(console-ai): proactive AI usage indicator in the ChatDock (ADR-0057 #8) - -Surfaces remaining AI headroom **before** a send hits the 429 wall, instead of -only learning the limit reactively. - -- **AiUsageIndicator** — two meters (build + dataChat) as small progress rings in - the ChatDock header (desktop rail + mobile sheet). Near-full → an amber - "running low" hint and a popover with "resets tonight / next cycle" plus the - upgrade / top-up CTA (reusing the 429 deep-link). D5-safe: fractions and - qualitative words only, never a token number. Hides itself when the usage - endpoint is absent (older backend / OSS / no seat). -- **useAiUsage** — fetches the D5-safe per-meter fractions; refetches on the chat - engine's post-turn / 429 nudge and on tab re-focus; fails soft to nothing. -- **useObjectChat** emits `AI_USAGE_REFRESH_EVENT` on a rejected send (429) and on - the turn-finish edge so the ring updates right after the user's action. -- i18n: `console.ai.usage.*` in en + zh-CN. - -Consumes the cloud `GET /api/v1/ai/usage` endpoint (objectstack-ai/cloud#824). diff --git a/.changeset/adr-0085-2548-detail-ux-followups.md b/.changeset/adr-0085-2548-detail-ux-followups.md deleted file mode 100644 index 38f439501..000000000 --- a/.changeset/adr-0085-2548-detail-ux-followups.md +++ /dev/null @@ -1,47 +0,0 @@ ---- -'@object-ui/plugin-detail': patch -'@object-ui/fields': patch -'@object-ui/i18n': patch -'@object-ui/app-shell': patch ---- - -Detail-page UX follow-ups from the ADR-0085 PR4 real-backend browser pass (framework#2548): - -- **Highlight strip no longer repeats the record title.** A declared - `highlightFields` list containing the title field rendered it as the first - chip — truncated — directly under the identical page H1. `deriveHighlightFields` - now resolves the title (`primaryField` / `nameField` / deprecated - `displayNameField`, else the conventional display-field names) via the new - exported `resolveTitleField` and filters it from declared lists before the - 4-chip cap, matching what the heuristic branch always did. app-shell's - `RecordDetailView` synthParts (which pre-computes the list and bypasses the - derivation) applies the same filter. -- **Per-field currency reaches the renderers.** The spec channel - (`currencyConfig.defaultCurrency`) was dropped by the highlight-strip and - detail-section field enrichment, so a spec-authored currency field could - never show its symbol ("25,000,000" instead of "$25,000,000"); - `resolveFieldCurrency` reads it second after the designer-only bare - `currency` key. -- **app-shell approvals fetches send the Bearer token.** The header badge - poll, home-inbox count, and record-page approvals panel were cookie-only - (new shared `bearerAuthHeaders()` util) — same split-origin failure mode as - the console `approvalsApi` fix below. -- **`fieldGroups[].icon` / `description` reach detail pages.** The shared - derivation (ADR-0085 §5) already passed them through; the detail synth - dropped them. Sections now carry both, and `DetailSection` renders a real - Lucide icon for identifier-shaped names (emoji/text values keep the - historical text rendering). -- **Record meta footer stops dangling without an actor.** Seeded/system rows - with `created_by: null` rendered "Created by · 10m ago"; the footer now - falls back to actor-less labels ("Created / Updated"), with new i18n keys in - all six locales (and the zh `createdBy`/`updatedBy` mistranslation fixed: - 创建人/更新人, not 创建于/更新于). -- **Select badges ellipsize instead of clipping mid-glyph.** In bounded - containers (highlight-strip columns, grid cells) an overlong option label - used to be cut at the container edge ("Technolog…"); badges now shrink with - an inner truncate and expose the full label as a hover title. The highlight - strip's hover title also prefers the option label over the raw stored value. - -Console app (unversioned): `approvalsApi` now sends the stored Bearer token -like every other console call — cookie-only auth silently lost the approvals -surface on split-origin deployments where the SameSite cookie doesn't flow. diff --git a/.changeset/adr-0085-pr4-remove-legacy-detail-renderer.md b/.changeset/adr-0085-pr4-remove-legacy-detail-renderer.md deleted file mode 100644 index 01acb4398..000000000 --- a/.changeset/adr-0085-pr4-remove-legacy-detail-renderer.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -"@object-ui/app-shell": patch ---- - -chore(app-shell): remove the legacy monolith detail renderer + the `renderViaSchema` kill-switch (ADR-0085 PR4, #2181) - -`RecordDetailView` now always renders through the SchemaRenderer Page -pipeline (an authored `PageSchema(pageType='record')` when assigned, else -the `buildDefaultPageSchema` synthesis). The non-schema-driven monolithic -`DetailView` branch and both of its entry points are gone: - -- `objectDef.detail?.renderViaSchema === false` is no longer read (it was - the last surviving `detail.*` key — ADR-0085 removed the block from the - spec, and the key had been kept only as this path's kill-switch); -- the `?renderViaSchema=0` debug URL param is no longer honored. - -Also drops the legacy-only plumbing: the eager per-record related-lists -fan-out (`record:related_list` self-fetches lazily on the schema path) -and the intermediate `DetailViewSchema` translation layer. The -`DetailView` component itself remains in `@object-ui/plugin-detail` -(still used internally by the `record:details` renderer). diff --git a/.changeset/adr-0096-connector-origin.md b/.changeset/adr-0096-connector-origin.md deleted file mode 100644 index dcb241e1a..000000000 --- a/.changeset/adr-0096-connector-origin.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -"@object-ui/app-shell": minor ---- - -feat(flow-designer): connector picker lists dispatchable connectors + marks declarative instances (ADR-0096) - -The `connector_action` node's connector picker read `client.list('connector')` — -the declared `connectors:` metadata, which includes inert catalog descriptors and -**misses** plugin-registered connectors. It now reads the runtime registry -(`GET /api/v1/automation/connectors`), i.e. exactly the connectors a -`connector_action` can dispatch: plugin connectors and materialized declarative -instances (framework ADR-0096). Declarative instances are annotated `· declarative` -(from the descriptor's new `origin` field) so authors can tell a materialized -metadata connector apart from a plugin one. Degrades to empty on fetch failure; -the field stays free-text editable. Tolerates an older backend with no `origin`. diff --git a/.changeset/attachment-authenticated-downloads.md b/.changeset/attachment-authenticated-downloads.md deleted file mode 100644 index 5874a9f20..000000000 --- a/.changeset/attachment-authenticated-downloads.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -"@object-ui/app-shell": patch ---- - -fix(attachments): download attachments via authenticated signed URL (framework #2970) - -The framework now requires an authenticated session to download an -attachments-scope file (the stable `/storage/files/:fileId` endpoint returns -`401`/`403` for them). `RecordAttachmentsPanel`'s download control no longer -uses a bare `` (which cannot carry the console's Bearer token) — it -fetches a short-lived signed URL from `/storage/files/:fileId/url` with -`createAuthenticatedFetch`, then opens it. `403 ATTACHMENT_DOWNLOAD_DENIED` and -`401 AUTH_REQUIRED` map to friendly copy instead of a broken link. diff --git a/.changeset/attachments-2755-followups.md b/.changeset/attachments-2755-followups.md deleted file mode 100644 index 6899f63d1..000000000 --- a/.changeset/attachments-2755-followups.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -"@object-ui/app-shell": patch ---- - -fix(attachments): authenticated uploads + friendly denial copy in RecordAttachmentsPanel (framework #2755) - -The framework now gates the storage upload routes on an authenticated session -and enforces parent-derived attachment access. The panel's upload adapter -accordingly authenticates with the console's Bearer token -(`createAuthenticatedFetch` — the token console has no session cookie for -`credentials: 'include'` to carry), and the new fail-closed 403 codes -(`ATTACHMENT_DELETE_DENIED`, `ATTACHMENT_PARENT_ACCESS`, `PERMISSION_DENIED`) -map to friendly copy instead of raw server errors. The delete button still -renders for every row by design — the server is the gate, and the client -lacks the parent-edit data to pre-compute it. `uploaded_by` is still sent for -back-compat with older servers; current servers stamp it from the session. diff --git a/.changeset/authz-a4-managed-by-tristate.md b/.changeset/authz-a4-managed-by-tristate.md deleted file mode 100644 index 559152c13..000000000 --- a/.changeset/authz-a4-managed-by-tristate.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -"@object-ui/app-shell": patch ---- - -feat(app-shell): A4 — permission-provenance tri-state badge (framework#2920) - -The Studio permission-matrix editor's provenance badge was two-state -(package / custom). It is now a **tri-state — platform / package / admin(custom)**, -mirroring the unified `sys_*.managed_by` vocabulary landed in framework#2920 so -the Studio matrix and the Setup record page read the same source-of-truth -labels. - -- `PermissionMatrixEditor` — `managedBy === 'platform'` renders a **Platform** - badge; `'package'` (or an active `packageId`) renders **Package**; everything - else (including legacy `'user'`) falls through to **Custom**. -- New `perm.badge.platform` i18n key (en + zh-CN). - -The Setup record page surfaces provenance via the framework object's now-`select` -`managed_by` field (rendered by the generic record renderer), so no record-page -change is required here. diff --git a/.changeset/b3-option-predicate-guardrail.md b/.changeset/b3-option-predicate-guardrail.md deleted file mode 100644 index 4e2db7d7a..000000000 --- a/.changeset/b3-option-predicate-guardrail.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -"@object-ui/core": minor ---- - -feat(core): build-time guardrail for cascading select option predicates (#1583) - -`@object-ui/core` now exports `lintOptionPredicates(fields)` — a static, -conservative validator for the per-option `visibleWhen` CEL predicates that -drive cascading / role-gated `select` options (#2284). An option predicate fails -*closed* — a wrong one makes its option silently never appear — so this catches -the class of bug runtime fail-open can't surface: - -- `syntax` — invalid CEL, delegated to `@objectstack/formula`'s - `validateExpression` (no schema hint, so a legitimate `current_user.roles` - reference is never mistaken for an error); -- `unknown-field` — a `record.` reference to a field the form never - declares (a sibling typo); -- `option-literal-not-in-domain` — a literal compared against an *enum* sibling - that is outside its declared option values, e.g. `record.country == 'chna'` - when `country` is `cn`/`us` (the AI-authoring typo #2284 called out). - -It only flags what it can statically prove — non-`record.` roots -(`current_user.*`), open-domain fields, and unrecognized shapes are left alone, -so there are no false positives. The schema catalog runs it over every shipped -example. Design recorded in ADR-0058. diff --git a/.changeset/b3-positions-predicate-scope.md b/.changeset/b3-positions-predicate-scope.md deleted file mode 100644 index 69a6dbc75..000000000 --- a/.changeset/b3-positions-predicate-scope.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@object-ui/app-shell': patch ---- - -Forward the authenticated user's `positions` into the client predicate scope (`current_user.positions`) in the console shell and the record form page. Position-gated select options (`'admin' in current_user.positions`, ADR-0058 / objectui#2284) now hide client-side like they do everywhere else, instead of failing open as visible and only being rejected by the server on submit — `positions` is the actor shape the framework rule-validator actually binds and enforces. Docs, the schema-catalog role-gated example, the skills guide, and inline examples switch the role-gating spelling from `current_user.roles` (never bound server-side, so never enforced) to `current_user.positions`. diff --git a/.changeset/c2-beta-explain-record-grained.md b/.changeset/c2-beta-explain-record-grained.md deleted file mode 100644 index a11abf046..000000000 --- a/.changeset/c2-beta-explain-record-grained.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -"@object-ui/app-shell": minor ---- - -feat(app-shell): C2-β — AccessExplainPanel record 粒度渲染 (framework#2920) - -AccessExplainPanel 现支持记录级解释(ADR-0095): - -- **记录选择器**:选定对象后可输入或从 RecordPickerDialog 选择一条 `recordId`;请求带上 `recordId`。 -- **逐层行级归因**:每层展开该记录的 `record` 归因——outcome 徽标(准入/排除/未评估)、命中的 `rules[]`(权限集 → 岗位 → 共享 → 行规则,含 kind/grants/via/effect 三态圆点)、有效行过滤(rowFilter JSON)、matchesRecord。 -- **顶部记录判定**:`record.visible` 结论横幅 + `decidedBy` 决定性层(该记录为何可见/不可见)。 -- **posture / kernelTier**:principal 卡片显示 posture 档位徽标;每层显示 kernel tier(租户墙 vs 业务 RLS)标签。 -- i18n:en + zh-CN 全量 key。 - -**向后兼容**:不带 `recordId` 时行为与对象级完全一致。 diff --git a/.changeset/cel-editor-field-conditional-rules.md b/.changeset/cel-editor-field-conditional-rules.md deleted file mode 100644 index 6e48da5f0..000000000 --- a/.changeset/cel-editor-field-conditional-rules.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@object-ui/app-shell': minor ---- - -Studio object designer: the field inspector's conditional rules (`visibleWhen` / `readonlyWhen` / `requiredWhen`) are now edited with a proper CEL editor — live syntax/semantic validation and autocomplete (object fields after `record.` / `previous.`, the runtime-bound roots `record`/`previous`/`parent`, and the CEL stdlib), backed by the same `@objectstack/formula` validators the server uses. Bare field references are flagged with the exact `record.` fix, the deprecated `conditionalRequired` alias migrates to `requiredWhen` on first edit, and draft validation reports an invalid predicate on any field under its `fields..` path before save. (#1582) diff --git a/.changeset/cel-rls-authoring-safety.md b/.changeset/cel-rls-authoring-safety.md deleted file mode 100644 index 9c6a1cddc..000000000 --- a/.changeset/cel-rls-authoring-safety.md +++ /dev/null @@ -1,32 +0,0 @@ ---- -"@object-ui/app-shell": minor ---- - -feat(app-shell): CEL authoring safety for RLS policies — lint, field autocomplete, test-run (objectui#2413) - -The permission-set Studio editor's Row-Level Security section -(`PermissionAdvancedFacets`) let admins author `USING` (read filter) / `CHECK` -(write filter) predicates as hand-typed CEL with **no validation, no -autocomplete, and no way to test**. RLS is security-critical: a typo silently -mis-scopes rows, and some evaluation paths **fail open** — widening access with -no visible error. The `USING`/`CHECK` editors now run three author-time -safeties, all delegated to the framework's canonical CEL engine -(`@objectstack/formula`) so the GUI reaches the **same verdict as the server** -rather than maintaining a second grammar: - -- **Inline lint** (`CelPredicateField`) — `validateExpression` flags parse - faults inline (and gates Save), unknown-field near-misses as non-blocking - "did-you-mean" warnings, and a non-pushdown-able `USING` filter as a - fail-open blast-radius advisory (`isPushdownableCel`). -- **Field autocomplete** — `introspectScope` offers the target object's fields - plus scope vars (`current_user`, `record`, …) and stdlib functions as you - type, so an identifier that would silently never match is caught early. -- **Test-run** (`CelTestRunDialog`) — dry-runs a predicate against a sample - record + `current_user` and shows allow / deny / non-boolean / error before - shipping. - -The engine loads lazily (dynamic `import`, feature-detected and -error-swallowing), keeping the CEL parser out of the main bundle; a -missing/older engine degrades to "no assistance" rather than breaking the -editor. New bridge: `metadata-admin/celAuthoring.ts`. New `perm.cel.*` i18n keys -(en + zh-CN). diff --git a/.changeset/condition-builder-cel-editor.md b/.changeset/condition-builder-cel-editor.md deleted file mode 100644 index 2da59e5f5..000000000 --- a/.changeset/condition-builder-cel-editor.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -"@object-ui/app-shell": minor ---- - -Studio: CEL lint + field autocomplete for condition predicates (#1582). - -`ConditionBuilder`'s raw-expression escape hatch — a bare `