@object-ui/app-shell 7.0.0 → 7.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (141) hide show
  1. package/CHANGELOG.md +560 -0
  2. package/dist/console/AppContent.js +23 -17
  3. package/dist/console/ConsoleShell.d.ts +16 -0
  4. package/dist/console/ConsoleShell.js +43 -2
  5. package/dist/console/ai/AiChatPage.js +47 -16
  6. package/dist/console/ai/LiveCanvas.d.ts +8 -2
  7. package/dist/console/ai/LiveCanvas.js +6 -4
  8. package/dist/console/home/HomeLayout.js +5 -7
  9. package/dist/console/home/HomePage.js +1 -9
  10. package/dist/console/organizations/CreateWorkspaceDialog.js +15 -1
  11. package/dist/console/organizations/OrganizationsPage.js +22 -3
  12. package/dist/console/organizations/provisionEnvironment.d.ts +53 -0
  13. package/dist/console/organizations/provisionEnvironment.js +64 -0
  14. package/dist/environment/EnvironmentEntitlementDialog.d.ts +34 -0
  15. package/dist/environment/EnvironmentEntitlementDialog.js +37 -0
  16. package/dist/environment/EnvironmentListToolbar.d.ts +33 -0
  17. package/dist/environment/EnvironmentListToolbar.js +59 -0
  18. package/dist/environment/entitlements.d.ts +90 -0
  19. package/dist/environment/entitlements.js +91 -0
  20. package/dist/environment/useEnvironmentEntitlements.d.ts +32 -0
  21. package/dist/environment/useEnvironmentEntitlements.js +108 -0
  22. package/dist/hooks/useActionModal.js +15 -1
  23. package/dist/hooks/useAiSurface.d.ts +59 -0
  24. package/dist/hooks/useAiSurface.js +78 -0
  25. package/dist/hooks/useChatConversation.d.ts +30 -0
  26. package/dist/hooks/useChatConversation.js +63 -0
  27. package/dist/hooks/useConsoleActionRuntime.d.ts +3 -0
  28. package/dist/hooks/useConsoleActionRuntime.js +42 -10
  29. package/dist/index.d.ts +5 -2
  30. package/dist/index.js +10 -2
  31. package/dist/layout/AppHeader.js +28 -4
  32. package/dist/layout/ConsoleFloatingChatbot.d.ts +6 -4
  33. package/dist/layout/ConsoleFloatingChatbot.js +41 -10
  34. package/dist/layout/ConsoleLayout.js +5 -6
  35. package/dist/layout/ContextSelectors.js +59 -35
  36. package/dist/layout/agentPicker.d.ts +56 -0
  37. package/dist/layout/agentPicker.js +40 -0
  38. package/dist/preview/CommitTimeline.d.ts +15 -0
  39. package/dist/preview/CommitTimeline.js +82 -0
  40. package/dist/preview/DraftPreviewBar.js +20 -7
  41. package/dist/preview/UnpublishedAppBar.js +11 -7
  42. package/dist/preview/commitHistory.d.ts +28 -0
  43. package/dist/preview/commitHistory.js +48 -0
  44. package/dist/providers/ExpressionProvider.js +9 -3
  45. package/dist/providers/MetadataProvider.js +9 -0
  46. package/dist/utils/index.d.ts +2 -2
  47. package/dist/utils/index.js +1 -1
  48. package/dist/utils/recordFormNavigation.d.ts +60 -0
  49. package/dist/utils/recordFormNavigation.js +35 -0
  50. package/dist/utils/resolvePageVarTokens.d.ts +31 -0
  51. package/dist/utils/resolvePageVarTokens.js +72 -0
  52. package/dist/views/CreateViewDialog.js +14 -1
  53. package/dist/views/FlowRunner.d.ts +2 -30
  54. package/dist/views/FlowRunner.js +18 -50
  55. package/dist/views/ObjectView.js +26 -12
  56. package/dist/views/ScreenView.d.ts +70 -0
  57. package/dist/views/ScreenView.js +73 -0
  58. package/dist/views/metadata-admin/AssignedUsersSection.d.ts +28 -0
  59. package/dist/views/metadata-admin/AssignedUsersSection.js +151 -0
  60. package/dist/views/metadata-admin/DirectoryPage.js +2 -14
  61. package/dist/views/metadata-admin/JsonSourceEditor.d.ts +3 -1
  62. package/dist/views/metadata-admin/JsonSourceEditor.js +21 -3
  63. package/dist/views/metadata-admin/PackagesPage.d.ts +5 -0
  64. package/dist/views/metadata-admin/PackagesPage.js +58 -5
  65. package/dist/views/metadata-admin/PermissionMatrixEditor.js +2 -1
  66. package/dist/views/metadata-admin/ResourceEditPage.js +83 -24
  67. package/dist/views/metadata-admin/ResourceListPage.js +28 -19
  68. package/dist/views/metadata-admin/StudioHomePage.js +6 -14
  69. package/dist/views/metadata-admin/anchors.js +20 -2
  70. package/dist/views/metadata-admin/createBody.d.ts +26 -0
  71. package/dist/views/metadata-admin/createBody.js +30 -0
  72. package/dist/views/metadata-admin/i18n.js +108 -2
  73. package/dist/views/metadata-admin/inspectors/DatasetDefaultInspector.d.ts +10 -2
  74. package/dist/views/metadata-admin/inspectors/DatasetDefaultInspector.js +136 -8
  75. package/dist/views/metadata-admin/inspectors/FlowEdgeInspector.js +99 -4
  76. package/dist/views/metadata-admin/inspectors/FlowExprIssue.d.ts +21 -0
  77. package/dist/views/metadata-admin/inspectors/FlowExprIssue.js +13 -0
  78. package/dist/views/metadata-admin/inspectors/FlowKeyValueField.d.ts +20 -2
  79. package/dist/views/metadata-admin/inspectors/FlowKeyValueField.js +71 -28
  80. package/dist/views/metadata-admin/inspectors/FlowNodeConfigField.d.ts +4 -1
  81. package/dist/views/metadata-admin/inspectors/FlowNodeConfigField.js +24 -9
  82. package/dist/views/metadata-admin/inspectors/FlowNodeInspector.js +81 -4
  83. package/dist/views/metadata-admin/inspectors/FlowObjectListField.d.ts +4 -1
  84. package/dist/views/metadata-admin/inspectors/FlowObjectListField.js +8 -3
  85. package/dist/views/metadata-admin/inspectors/ObjectDefaultInspector.js +5 -4
  86. package/dist/views/metadata-admin/inspectors/ObjectFieldInspector.js +47 -12
  87. package/dist/views/metadata-admin/inspectors/ReportDefaultInspector.d.ts +1 -1
  88. package/dist/views/metadata-admin/inspectors/ReportDefaultInspector.js +60 -2
  89. package/dist/views/metadata-admin/inspectors/VariableTextInput.d.ts +47 -0
  90. package/dist/views/metadata-admin/inspectors/VariableTextInput.js +95 -0
  91. package/dist/views/metadata-admin/inspectors/_shared.d.ts +5 -1
  92. package/dist/views/metadata-admin/inspectors/_shared.js +2 -2
  93. package/dist/views/metadata-admin/inspectors/datasetFilterCondition.d.ts +24 -0
  94. package/dist/views/metadata-admin/inspectors/datasetFilterCondition.js +102 -0
  95. package/dist/views/metadata-admin/inspectors/flow-node-config.d.ts +16 -1
  96. package/dist/views/metadata-admin/inspectors/flow-node-config.js +67 -11
  97. package/dist/views/metadata-admin/inspectors/flow-ref-check.d.ts +39 -0
  98. package/dist/views/metadata-admin/inspectors/flow-ref-check.js +114 -0
  99. package/dist/views/metadata-admin/inspectors/flow-scope.d.ts +109 -0
  100. package/dist/views/metadata-admin/inspectors/flow-scope.js +199 -0
  101. package/dist/views/metadata-admin/inspectors/useDatasetFields.d.ts +14 -3
  102. package/dist/views/metadata-admin/inspectors/useDatasetFields.js +0 -0
  103. package/dist/views/metadata-admin/inspectors/useFlowScope.d.ts +23 -0
  104. package/dist/views/metadata-admin/inspectors/useFlowScope.js +45 -0
  105. package/dist/views/metadata-admin/issuePath.d.ts +22 -0
  106. package/dist/views/metadata-admin/issuePath.js +65 -0
  107. package/dist/views/metadata-admin/package-scope.d.ts +41 -0
  108. package/dist/views/metadata-admin/package-scope.js +59 -0
  109. package/dist/views/metadata-admin/preview-registry.d.ts +12 -0
  110. package/dist/views/metadata-admin/previews/DatasetPreview.js +21 -5
  111. package/dist/views/metadata-admin/previews/FlowCanvas.d.ts +26 -1
  112. package/dist/views/metadata-admin/previews/FlowCanvas.js +143 -16
  113. package/dist/views/metadata-admin/previews/FlowPreview.d.ts +1 -1
  114. package/dist/views/metadata-admin/previews/FlowPreview.js +47 -7
  115. package/dist/views/metadata-admin/previews/FlowSimulatorPanel.js +37 -3
  116. package/dist/views/metadata-admin/previews/ObjectFormCanvas.js +9 -4
  117. package/dist/views/metadata-admin/previews/PagePreview.js +112 -3
  118. package/dist/views/metadata-admin/previews/ProblemsPanel.d.ts +18 -0
  119. package/dist/views/metadata-admin/previews/ProblemsPanel.js +27 -0
  120. package/dist/views/metadata-admin/previews/ReportPreview.d.ts +9 -8
  121. package/dist/views/metadata-admin/previews/ReportPreview.js +33 -16
  122. package/dist/views/metadata-admin/previews/ScreenPreview.d.ts +38 -0
  123. package/dist/views/metadata-admin/previews/ScreenPreview.js +61 -0
  124. package/dist/views/metadata-admin/previews/flow-canvas-layout.d.ts +14 -0
  125. package/dist/views/metadata-admin/previews/flow-canvas-layout.js +37 -0
  126. package/dist/views/metadata-admin/previews/flow-canvas-parts.d.ts +17 -1
  127. package/dist/views/metadata-admin/previews/flow-canvas-parts.js +23 -6
  128. package/dist/views/metadata-admin/previews/flow-expr-problems.d.ts +19 -0
  129. package/dist/views/metadata-admin/previews/flow-expr-problems.js +97 -0
  130. package/dist/views/metadata-admin/previews/flow-problems.d.ts +84 -0
  131. package/dist/views/metadata-admin/previews/flow-problems.js +209 -0
  132. package/dist/views/metadata-admin/previews/object-fields-io.d.ts +21 -0
  133. package/dist/views/metadata-admin/previews/object-fields-io.js +37 -2
  134. package/dist/views/metadata-admin/previews/screen-spec.d.ts +43 -0
  135. package/dist/views/metadata-admin/previews/screen-spec.js +108 -0
  136. package/dist/views/metadata-admin/previews/simulator/flow-sim-types.d.ts +20 -0
  137. package/dist/views/metadata-admin/previews/simulator/flow-sim-validate.d.ts +7 -0
  138. package/dist/views/metadata-admin/previews/simulator/flow-sim-validate.js +76 -2
  139. package/dist/views/metadata-admin/previews/simulator/flow-simulator.d.ts +32 -3
  140. package/dist/views/metadata-admin/previews/simulator/flow-simulator.js +119 -9
  141. package/package.json +38 -38
package/CHANGELOG.md CHANGED
@@ -1,5 +1,565 @@
1
1
  # @object-ui/app-shell — Changelog
2
2
 
3
+ ## 7.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 88a3e39: feat(console): born-with-env eager provisioning for multi-org workspace create
8
+
9
+ ObjectStack runs a 1-production-environment-per-organization model: a user who wants
10
+ another production space creates another organization, and each org is born with its
11
+ production environment. The self-service "create workspace" flow now delivers that
12
+ without an onboarding-wizard detour.
13
+
14
+ After `createOrganization` succeeds (which already switches the active org),
15
+ `CreateWorkspaceDialog` eagerly `POST`s `/api/v1/cloud/environments` with the new org as
16
+ target so its first environment is provisioned as a production env (allowed on every plan,
17
+ including free), then hands off to the existing switch-and-navigate-home path. The
18
+ provision is best-effort: on failure the onboarding gate provisions the env lazily on
19
+ first navigation, so multi-org still works. The `multiOrgEnabled` enable-gate is unchanged
20
+ (already wired end-to-end via the auth `/config` `features.multiOrgEnabled` flag).
21
+
22
+ Adds a gated **"Create workspace"** entry to the org switcher (avatar dropdown) that
23
+ opens the dialog directly — previously a single-org user could never reach it, because
24
+ the only path (`/organizations`) auto-skips to home when you belong to exactly one org.
25
+ The eager provision is idempotent: a control plane that auto-provisions the production
26
+ env on org create resolves it to "already provisioned" rather than erroring.
27
+
28
+ Also removes the unreferenced `apps/console` `CreateWorkspaceDialog` duplicate; the live
29
+ component is the app-shell copy used by `OrganizationsPage`.
30
+
31
+ - e301475: feat(console): hide the AI surface at runtime when the server serves no AI agent (Community Edition)
32
+
33
+ A self-host Community Edition runtime (framework + this MIT console, without the
34
+ cloud `@objectstack/service-ai-studio` package) serves no `ask`/`build` agent.
35
+ The console now hides every AI entry point via runtime, server-pushed gating —
36
+ no build-time edition flag, no tree-shake.
37
+
38
+ Crucially, gating is driven off the **agent catalog** (`GET /api/v1/ai/agents`),
39
+ not the discovery `services.ai` flag: the open-source framework keeps a headless
40
+ `@objectstack/service-ai` that still reports `services.ai` as available, so a CE
41
+ runtime can report AI "available" while serving zero agents. The catalog is the
42
+ real "is there an agent to answer?" signal.
43
+
44
+ - New `useAiSurfaceEnabled()` hook + `RequireAiSurface` route guard (exported).
45
+ - `/ai*` routes redirect to home when no agent is served; the FAB, top-bar AI
46
+ link and the metadata designers' "Ask AI" buttons hide; `AiChatPage` shows a
47
+ graceful "AI unavailable" state instead of an agent-less echo chat.
48
+ - Fully additive for cloud installs — when an agent is served, every AI surface
49
+ renders and works as before.
50
+
51
+ - 616157a: feat(studio): multi-hop relationship fields in the dataset designer (ADR-0071)
52
+
53
+ The dataset designer's field catalog and Included-relationships picker now
54
+ support multi-hop relationship paths (`account.owner.region`), matching the
55
+ framework's multi-hop join support (ADR-0071 P2):
56
+
57
+ - `useDatasetFieldCatalog` walks each included path hop-by-hop, fetching every
58
+ object along the chain, so `path.field` options surface for fields two–three
59
+ to-one hops deep (grouped under a chained `Account → Owner → User` heading).
60
+ - The Included-relationships combo offers one level deeper along each
61
+ already-included path (drill `account` → `account.owner`), capped at 3 hops.
62
+ - The author-time "relationship not in Included" warning generalizes to the full
63
+ relationship path (`account.owner`), with one-click "Add it".
64
+
65
+ Single-hop datasets are unchanged.
66
+
67
+ - 6668759: feat(console): entitlement- & state-aware environment actions
68
+
69
+ The `sys_environment` list now presents the right create affordance for the
70
+ org's state (born-with-env) instead of POST-then-error:
71
+
72
+ - **No production env** (historical orgs) → "Set up your production environment";
73
+ the create POST provisions the org's one production env — this path never errors.
74
+ - **Has prod env, free plan** → an "Add environment" button that opens a friendly
75
+ upgrade prompt (CTA to billing) instead of POSTing into a 403.
76
+ - **Has prod env, paid plan** → "Add development environment" creates a dev env.
77
+
78
+ The action runtime's `apiHandler` now also turns the cloud env-create entitlement
79
+ 403s (`DEV_ENV_PLAN_LOCKED` / `DEV_ENV_LIMIT` / `PRODUCTION_ENV_LIMIT`) into a
80
+ friendly upgrade/limit dialog with a CTA rather than a red error toast — a safety
81
+ net that covers any path. State is resolved from the new org-scoped
82
+ `GET /cloud/environment-entitlements` summary, with a row-derived `hasProductionEnv`
83
+ fallback so the production-setup path works even against an older control plane.
84
+
85
+ - 41c60c4: Flow builder: variable data-picker for expression / template config fields. Expression and template surfaces (decision Branches, edge Condition, Assignment values, Screen description, CRUD field values / filter, subflow / script inputs) now show a "{x}" picker listing the references in scope at that node — flow variables, upstream node outputs, the trigger record's fields, and any enclosing loop item — resolved graph-aware by walking the flow back from the node. Selecting a reference inserts the correctly-braced token at the cursor (bare CEL in `expression` fields, `{var}` in template fields), handling the ADR-0032 brace-in-CEL trap for the author. Free-text typing is unchanged and an empty scope degrades to a plain input.
86
+ - d23db5c: feat(detail): related-list add-by-picker (generic m2m/junction) + a generic "Assigned Users" management UI on permission sets (assign ai_seat and any role with zero bespoke CRUD; server-side cap errors surface inline).
87
+
88
+ ### Patch Changes
89
+
90
+ - 81ad9aa: feat(studio): package lifecycle UI — Duplicate base, Adopt loose items, structure-only delete (ADR-0070 D4/D5/D6)
91
+
92
+ `PackageDetailSheet` gains the user-facing affordances for the package-as-
93
+ lifecycle-unit work:
94
+ - **Duplicate** → `POST /packages/:id/duplicate` (clone a base into a new
95
+ writable package; D4).
96
+ - **Adopt loose items** → `POST /packages/:id/adopt-orphans` (migrate every
97
+ package-less orphan into this base; D5).
98
+ - **Delete** now asks whether to drop records too (`?keepData`) — structure-only
99
+ vs everything (D4 Q3).
100
+
101
+ D6 guardrail test: the scope selector never defaults to the package-less
102
+ `Local / Custom` sentinel (`writableBaseOptions` excludes it; real bases sort
103
+ first).
104
+
105
+ - 4b1cb7a: feat(studio): package-first create flow — prompt or redirect to a writable base (ADR-0070 D3)
106
+
107
+ Studio's create entry points no longer let a new metadata item land in a code
108
+ package or the package-less "Local / Custom" bucket. ResourceListPage's create
109
+ gate (`handleCreate`) now: opens the create-base dialog when no writable base
110
+ exists; redirects into the first base when the active scope is Local/none but
111
+ bases exist; otherwise proceeds normally. Adds package-scope helpers
112
+ (`isLocalScope` / `writableBaseOptions`) with tests, surfaces the kernel's
113
+ `writable_package_required` (422) as an actionable error in ResourceEditPage,
114
+ and exports `CreatePackageDialog` from PackagesPage for reuse.
115
+
116
+ - 8c2191d: fix(console): polished, localized "Assigned Users" management for permission sets — resolves users to name/email (no raw id), zh/en localized, friendly inline cap message (drops the dev `[Tag]` prefix), people-rows with visible remove + add-via-picker.
117
+ - 6028192: fix(console): gate the AI surface on the access-filtered agent catalog (per-user), not the deployment-wide service-ai capability
118
+
119
+ `useAiSurfaceEnabled` keys off `GET /api/v1/ai/agents` again (>= 1 agent → AI shows), reverting objectui#1992. The agent-catalog route is now access-filtered server-side (ADR-0049 / ADR-0068): it returns only the agents the caller may chat, so a user WITHOUT the per-user AI seat (`ai_seat`) gets an empty catalog and the whole AI surface (FAB, `/ai` routes, top-bar + designer "Ask AI") hides for them — instead of showing a control that 403s on click. The discovery `services.ai` flag is deployment-wide and cannot express per-user seating, so it is the wrong signal for the AI-seat gate. Community-Edition gating is unaffected: no service-ai → no agents → empty catalog → hidden.
120
+
121
+ - e575da0: fix(ai): stop the AI composer placeholder doubling to "Ask Ask…" for the Ask agent
122
+
123
+ The composer placeholder is `Ask {agent}…`, which reads fine for most agents
124
+ ("Ask Build…") but doubles to "Ask Ask…" for the data-query agent whose label is
125
+ literally "Ask". The Ask agent now uses its purpose-built placeholder
126
+ (`console.ai.askAnything` → "Ask anything…", already localized) instead. Found
127
+ dogfooding the AI Ask flow.
128
+
129
+ - cde7502: fix(form): create/edit record modal now honors the object's default form view
130
+
131
+ The "New <object>" modal (and the modal edit form) rendered every field from
132
+ the raw object schema, in schema order — ignoring the curated sections + field
133
+ selection/order defined in the object's default FORM VIEW. Customizing the form
134
+ view (section grouping, field selection/order) had no effect on the create
135
+ modal; only `tabbed` views were partially honored, while a `simple` view with
136
+ curated sections was dropped entirely.
137
+
138
+ New `resolveFormViewLayout(objectDef)` helper resolves the default form view
139
+ (`objectDef.form ?? formViews.default`) into the modal's layout props (curated
140
+ `sections`, `contentLayout: 'tabbed'`, and master-detail `subforms`), mirroring
141
+ the full-screen `RecordFormPage`. It is wired into:
142
+
143
+ - the global New/Edit `ModalForm` in `AppContent` (replacing the tabbed-only
144
+ inline logic so `simple` sectioned views are honored too), and
145
+ - `useActionModal` (action-opened forms), which previously passed no
146
+ `fields`/`sections` and so fell back to the whole object schema.
147
+
148
+ When the object declares no form view — or one without sections — the modal
149
+ keeps its prior flat-field behavior. Frontend-only.
150
+
151
+ - 0d8dbda: fix(metadata-admin): dataset filter builder ignores incomplete conditions
152
+
153
+ `groupToCondition` emitted a condition for any row that had a `field`, even when
154
+ its value was still blank — producing a silently-wrong filter like
155
+ `{ organization_id: { $eq: "" } }` (matches only empty → excludes everything)
156
+ instead of "no filter". Now rows with an empty/`undefined`/`[]` value are skipped
157
+ (value-less operators like is-empty / is-not-empty are still kept). Applies to both
158
+ the dataset Scope filter and per-measure filters. Found by dogfooding.
159
+
160
+ - e8c1c85: fix(metadata-admin): re-base a dataset when its base object changes
161
+
162
+ A dataset's joins (`include`), dimensions, measures, and filter all reference the
163
+ base object's fields. Changing the base object left those referencing the OLD
164
+ object — stale field refs that silently produce broken/ambiguous queries. Now a
165
+ real object change clears the object-dependent config (selecting the same object
166
+ is a no-op), and a heads-up note appears while there is config that a change would
167
+ clear. Found by dogfooding (G1).
168
+
169
+ - 0119ff4: Designer derives create defaults from the spec's create seed (/meta/types)
170
+
171
+ The metadata create flow now builds a new item's body from the server's authoritative `createSeed` (delivered per type on the `/meta/types` registry entry — the single source of truth in `@objectstack/spec`) instead of the locally hardcoded `createDefaults`, falling back to `createDefaults` when the server provides no seed (older server, or canvas-create types). This closes the drift loop behind the "designer emits a minimal shape the spec rejects → create→save 422" family (dashboard `layout`, action `body`): the structural create defaults now come from the same place the spec validates against, so they cannot diverge. Extracted as the pure, unit-tested `buildCreateModeBody`.
172
+
173
+ - 8e7c1da: fix(preview): draft-preview bar no longer demands a redundant Publish when nothing is pending
174
+
175
+ Under the auto-publish posture an AI build leaves zero pending drafts, yet opening a
176
+ draft preview still showed "Draft preview — Nothing here is live until you publish."
177
+ alongside "Changes (0)" and a Publish button — a self-contradicting, no-op call to
178
+ action. `DraftPreviewBar` now reflects the real pending-draft count: when it is
179
+ known to be zero the bar softens to a neutral preview indicator and drops the
180
+ Publish/Changes affordances; an unknown count (still loading / fetch failed) keeps
181
+ the publish path. `HomePage` (count-gated) and `RuntimeDraftBar` (draft-gated)
182
+ already behaved this way — this aligns the third surface.
183
+
184
+ - 522a54c: feat(studio): make the flow-canvas error banner clickable
185
+
186
+ The inline structural-error banner (ADR-0044 cycle surfacing) is now driven by
187
+ the unified `problems` list, and each row with a concrete target is clickable —
188
+ clicking it selects and pans-to-reveal the offending node/edge (the same reveal
189
+ the Problems panel performs). So the always-visible banner is actionable without
190
+ opening the panel. Drops the now-redundant `validationErrors` string prop: the
191
+ banner, the Problems panel, and the on-canvas badges all share one source.
192
+
193
+ - cdc6246: Flow builder (#1934): expression problems — ADR-0032 brace/shape errors and scope-aware "unknown reference" warnings — now also surface in the flow **Problems panel** and as on-canvas **node/edge badges** (#1972), not just inline in the inspector. A `{record.x}` brace-in-CEL mistake or a typo'd variable is now visible at the flow level without opening each node. The start node's bare trigger-record fields are excluded from the ref check to avoid false positives (the inline inspector check still covers them).
194
+ - 7fe2735: Flow builder data-picker (#1934): the cursor-insertion math is extracted into a pure `insertToken` helper with unit tests (alongside `formatToken`) — bare CEL vs `{var}` template insertion, append / mid-string / selection-replace, and clamping a reversed or out-of-range selection. Pure refactor, no behavior change.
195
+ - 3f529a8: refactor(studio): derive the flow red-error highlight from the unified problem list (one validateFlowDraft pass)
196
+
197
+ Follow-up to #1972 (Problems panel + badges) and #1976 (clickable banner). The
198
+ flow preview still ran `validateFlowDraft` twice per render — once in
199
+ `buildFlowProblems` (badges / banner / panel) and again in a separate memo that
200
+ derived the red node/edge ring/stroke — with the cycle-highlight logic duplicated
201
+ between them.
202
+
203
+ `buildFlowProblems` is now the single validation pass: a new
204
+ `deriveInvalidElements(problems)` produces the red error set (errors only; a
205
+ cycle paints its whole loop via a per-problem `highlight` set while its badge +
206
+ reveal stay on the closing edge). The preview drops its second `validateFlowDraft`
207
+ call. The clickable banner (#1976), badges, and panel are unchanged — all four
208
+ surfaces now derive from one list, so they cannot drift.
209
+
210
+ - 0b9c96c: Flow builder data-picker follow-ups (#1934): (1) a scope-aware "unknown reference" warning pairs the picker with inline validation — a typed reference whose root isn't in scope at the node is flagged with a nearest-match "did you mean?" hint (conservative: root-only, skips function calls / string literals / runtime globals; non-blocking amber). (2) Assignment values authored in the array form `[{ variable, value }]` now render in the key/value editor (and get the picker) instead of falling back to Advanced JSON; the editor reads both the object-map and array shapes and preserves whichever was authored. (3) A script `code` body (JS/TS, not a `{var}` template) now inserts bare references via a `refMode` field override — `{x}` is a syntax error in a script.
211
+ - 47537fe: Flow builder data-picker (#1934): inline validation now also shows on the repeater surfaces that carry the picker — decision **Branches** expressions, screen field **"visible when"**, and key/value **values** — not just single fields. Each shows the ADR-0032 brace error (red) or a scope-aware "unknown reference" warning (amber) via a shared `FlowExprIssue` line. The trigger-record picker also offers `previous.<field>` references on update / change / before-update triggers.
212
+ - 17ba30d: feat(studio): on-canvas validation badges + a Problems panel for the flow builder
213
+
214
+ Flow validation only surfaced as a top banner ("…N error(s)") that didn't point
215
+ to the offending element — in a non-trivial flow you couldn't tell _which_ node
216
+ or edge was wrong. The simulator's `validateFlowDraft` already detected the
217
+ structural problems (no resolvable entry, unreachable nodes, a decision with no
218
+ default branch, duplicate node ids, dangling edges, un-declared cycles); they
219
+ just weren't shown on the canvas. This was a surfacing gap, not a detection one.
220
+
221
+ The flow preview now:
222
+
223
+ - renders an error / warning **badge** on each offending node and edge, with the
224
+ issue message(s) as its tooltip;
225
+ - adds a **Problems panel** listing every issue (structural + the server
226
+ `_diagnostics` already attached to the layered record); clicking a row selects
227
+ and reveals (pans to) the node/edge;
228
+ - clears badges + rows as issues are resolved (everything derives from the live
229
+ draft).
230
+
231
+ `validateFlowDraft` now tags dangling-edge errors with their endpoints so they
232
+ key to the offending connection, and a new `flow-problems` module maps both
233
+ sources onto concrete canvas elements (node id / stable edge key). Server
234
+ diagnostics reach the preview through a new optional `diagnostics` prop on
235
+ `MetadataPreviewProps`.
236
+
237
+ - 104d181: fix(studio): flow wait-node inspector tolerates the loose `config` shape
238
+
239
+ The wait-node property form read only the spec-canonical
240
+ `waitEventConfig.{eventType,signalName,…}`, but the engine also accepts a looser
241
+ `config.{eventType,…}` shape — which the canonical `showcase_budget_approval`
242
+ (and AI-authored flows) use. So a showcase-shaped wait node opened in the
243
+ designer showed blank "Wait for" / "Signal name" fields.
244
+
245
+ Flow config fields gain an optional `fallbackPath`: reads fall back to it (so
246
+ loose-shape wait nodes display, and dependent fields reveal), writes target the
247
+ canonical path and prune the fallback (migrate-on-edit), and the fallback's
248
+ config key is suppressed from the Advanced block. The `wait` fields now fall
249
+ back to `config.*`, so the designer matches the engine's tolerance. Pairs with
250
+ the ADR-0044 revise-loop authoring (#1954).
251
+
252
+ - 1fa5982: fix(studio): preview joined reports in the report editor (was "design blind")
253
+
254
+ Found dogfooding report design in Studio as a business user. The report editor's
255
+ live preview only rendered single dataset-bound reports — a `joined` report
256
+ (which carries its data on `blocks`, with no top-level `dataset`) fell through to
257
+ the "Bind a dataset to preview this report" empty state, so an author building a
258
+ joined report saw nothing and designed blind.
259
+
260
+ `ReportPreview` now renders a joined report (≥1 dataset-bound block) through the
261
+ same runtime `ReportRenderer` (→ `DatasetReportRenderer`, which already stacks
262
+ the blocks), keeping the preview pixel-equal with the runtime, and shows a
263
+ joined-aware empty state ("Add a block…") when no block is bound yet.
264
+
265
+ - Updated dependencies [8e7c1da]
266
+ - Updated dependencies [cf746c9]
267
+ - Updated dependencies [d23db5c]
268
+ - @object-ui/i18n@7.2.0
269
+ - @object-ui/auth@7.2.0
270
+ - @object-ui/types@7.2.0
271
+ - @object-ui/components@7.2.0
272
+ - @object-ui/fields@7.2.0
273
+ - @object-ui/react@7.2.0
274
+ - @object-ui/collaboration@7.2.0
275
+ - @object-ui/core@7.2.0
276
+ - @object-ui/data-objectstack@7.2.0
277
+ - @object-ui/layout@7.2.0
278
+ - @object-ui/permissions@7.2.0
279
+ - @object-ui/plugin-editor@7.2.0
280
+ - @object-ui/providers@7.2.0
281
+
282
+ ## 7.1.0
283
+
284
+ ### Minor Changes
285
+
286
+ - 7b5d0f0: Build-history timeline + revert UI for AI builds (ADR-0067)
287
+
288
+ The unpublished-app banner gains a **History** button that opens a commit timeline (`GET /packages/:id/commits`): every change an AI build/edit landed, newest-first, with **Revert** per apply commit (`POST /packages/:id/commits/:cid/revert`). The history-not-confirm model — review the timeline and revert, instead of approving each publish.
289
+
290
+ - `commitHistory.ts` — `fetchCommits` / `revertCommit` helpers.
291
+ - `CommitTimeline.tsx` — slide-over panel (sibling of `DraftChangesPanel`).
292
+ - `UnpublishedAppBar` — History button + timeline mount (package-scoped).
293
+
294
+ - 7cd950e: feat(metadata-admin): dataset create opens the rich designer + dual-axis preview
295
+
296
+ - **Create → rich designer.** `dataset` joins `object` / `report` in
297
+ `CREATE_MODE_CANVAS_TYPES`, so "New dataset" opens the structured designer
298
+ (base-object picker, joins, dimension/measure editors, live preview) instead
299
+ of the degraded generic SchemaForm. `DatasetDefaultInspector` gains a
300
+ create-mode **Name** field that auto-derives a snake_case identifier from the
301
+ label until edited (mirrors `ReportDefaultInspector` / `ObjectDefaultInspector`),
302
+ so a dataset created through the canvas saves with a valid identity instead of
303
+ dead-ending.
304
+ - **Mixed-scale preview.** When a dataset preview mixes a ratio/percent measure
305
+ (e.g. `utilization`, `0.0%`) with magnitude measures (currency in the
306
+ hundred-thousands), the ratio measures now plot as a line on a secondary
307
+ (right) Y axis via the existing `combo` chart — they're no longer crushed to an
308
+ invisible sliver beside the large bars. Same-scale selections stay a plain bar
309
+ chart.
310
+
311
+ - fccebfe: feat(metadata-admin): visual filter authoring in the dataset designer
312
+
313
+ The dataset designer gains a visual filter editor (reusing the shared
314
+ `FilterBuilder`) for both the dataset-level **Scope filter** (`dataset.filter`)
315
+ and per-measure **Filter** (`measure.filter`) — previously only settable via the
316
+ raw Source/JSON tab. Both are backed by real runtime: the analytics executor ANDs
317
+ the scope filter into every query and runs measure-scoped filters as supplementary
318
+ grouped queries, so e.g. `won_amount = sum(amount) where stage = won` and an
319
+ "exclude archived" dataset scope are now authorable without hand-writing JSON.
320
+
321
+ A small, unit-tested converter bridges the builder's flat `{field, op, value}`
322
+ group ⇄ the spec `FilterCondition` (Mongo-style `$and` / `$op`). Conditions it
323
+ can't faithfully round-trip (nested groups, `$or`, multi-operator objects) are
324
+ detected and shown as "edit in Source" rather than being silently rewritten.
325
+
326
+ - 0acf0c8: feat(metadata-admin): friendlier + safer dataset measure authoring
327
+
328
+ The `dataset` designer's measure editor gets three improvements so a business
329
+ user can author measures without spec knowledge and without saving a broken
330
+ dataset:
331
+
332
+ - **Display-format picker** — replaces the raw `format` / `currency` numeral
333
+ text inputs with a structured Kind (Raw / Number / Currency / Percent) +
334
+ Decimals + Currency selection and a live sample (e.g. `US$1,234.50`). Parses
335
+ an existing format string back into the picker, so editing an existing measure
336
+ round-trips.
337
+ - **Auto-name from field** — picking a dimension/measure field when the row is
338
+ still unnamed defaults the name to the field's leaf (`account.region` →
339
+ `region`).
340
+ - **Author-time validation** — a `relationship.field` dimension/measure whose
341
+ relationship isn't in `include` now shows an inline warning with a one-click
342
+ "Add it", catching at design time the "relationship not declared in include"
343
+ error that previously only surfaced when the live preview query ran. A derived
344
+ measure with too few operands is flagged too.
345
+
346
+ - 3e1fcf5: feat(chatbot): reveal the Build/Ask switcher in the app floating assistant when AI dev is unlocked
347
+
348
+ The bottom-right FAB assistant bound each app to a single agent and hid the
349
+ agent picker unless `VITE_AI_SHOW_AGENT_PICKER` was set, so a user on an
350
+ AI-unlocked environment could not switch from `ask` (read-only data/query) to
351
+ `build` (authoring) without leaving for the full `/ai` page.
352
+
353
+ The picker now auto-reveals when AI development is unlocked for the viewer — the
354
+ live agent catalog serves BOTH an `ask` and a `build` agent (alias-aware, so
355
+ legacy `data_chat`/`metadata_assistant` count) AND authoring isn't
356
+ deployment-disabled (`aiStudio`). Pure end-user apps (only `ask`) stay clean and
357
+ never see a picker. An explicit `showAgentPicker` prop or
358
+ `VITE_AI_SHOW_AGENT_PICKER` still forces it on.
359
+
360
+ - e2b0072: Flow builder: live preview for Screen nodes (#1944)
361
+
362
+ Screen-flow nodes were authored blind — there was no way to see the form an end user would get, and the Debug simulator showed only `paused` when it reached a screen. Add a live preview that renders the screen exactly as it runs.
363
+
364
+ The runtime `FlowRunner`'s screen body (flat input fields + object-form mode) is extracted into a shared `ScreenView`, so the preview reuses the **same** renderer as runtime and can't drift (the design↔runtime divergence #1927 fixed). A new `ScreenPreview` builds a `ScreenSpec` from the node's authored `config` and feeds it to `ScreenView`.
365
+
366
+ - Reflects `title`, `description` (with `{var}` interpolation), input `fields`, and object-form mode (`objectName` / `mode` / `defaults`, rendered via `plugin-form`'s `ObjectForm`).
367
+ - Updates live as the node config changes.
368
+ - Two homes: the **flow node inspector** (interpolates against the flow's declared variable defaults) and the **Debug simulator** when paused at a screen (interpolates against the live simulated run state, replacing the bare `paused`).
369
+
370
+ - 780cabc: feat(studio): add a "Local / Custom (this env)" scope to the package selector
371
+
372
+ In a self-hosted, metadata-customizable environment (single-tenant — no org
373
+ dimension), the package selector only listed code packages, so metadata authored
374
+ at runtime (`package_id = null` / `sys_metadata` provenance) was filtered out of
375
+ every code-package view and became un-navigable — opening such an item redirected
376
+ to "new". This complements framework #2252 + objectui #1937, which stop runtime
377
+ metadata from being stamped into a loaded code package and keep it editable.
378
+
379
+ - Surface a stable, always-present "Local / Custom (this env)" entry in the
380
+ Studio package context-selector (`ContextSelectors`), mapped to the
381
+ `sys_metadata` scope the metadata list/get API already understands.
382
+ - Accept that scope in the metadata-admin pages (`StudioHomePage`,
383
+ `DirectoryPage`, `ResourceListPage`) via a shared `buildPackageScopeOptions`
384
+ helper, so it no longer redirects, and the list shows this environment's
385
+ runtime-authored items (`package_id = null`).
386
+ - On the Studio home grid, the Local scope shows every runtime-creatable type so
387
+ the user can start authoring locally even with zero items yet.
388
+
389
+ - 93cf2b1: feat(studio): preview record pages against a real sample record
390
+
391
+ The Studio page editor's Preview tab rendered a `type: 'record'` page's
392
+ `record:*` blocks (details / highlights / path / alert / quick_actions) as the
393
+ "bind a record to preview" placeholder — the metadata editor has no record
394
+ route, so the author designed blind.
395
+
396
+ The preview now fetches a handful of real records of the bound object (with
397
+ lookup / master_detail fields `$expand`ed so they show display names, not raw
398
+ foreign-key IDs), auto-binds the first one, and wraps the canvas in a
399
+ `<RecordContextProvider>` — mirroring the runtime `RecordDetailView`. A
400
+ "Preview record" dropdown lets the author switch records, so `visible` CEL
401
+ expressions (e.g. `record.status == 'in_review'`) and per-record field values
402
+ re-render live.
403
+
404
+ ### Patch Changes
405
+
406
+ - 68d82ae: New script action seeds a valid body; add create-roundtrip conformance guard
407
+
408
+ A new action defaults to `type: 'script'`, which the spec requires to carry an executable `body` or `target` — the create form seeded neither, so "New action → Save" failed validation (422). Seed a no-op L2 body in `createDefaults` so the default create round-trips. Adds a conformance guard that asserts every authorable type's default create-form output passes spec validation (catches the "designer minimal shape ≠ spec required" family before it ships).
409
+
410
+ - aae8791: Flow Screen preview: render inline master-detail subforms (follow-up to #1944)
411
+
412
+ The object-form mode of the Screen-node preview now renders inline master-detail
413
+ child grids, matching runtime. `ScreenPreview` feeds the SAME enriched object
414
+ list the runtime `FlowRunner` uses (`useMetadata().objects`, which derives
415
+ `form.subforms` from `inlineEdit` relationships via `attachInlineSubforms`), so
416
+ e.g. a `showcase_invoice` object-form step previews its **Line Items** grid
417
+ (with live Subtotal/Tax/Total) — only fetched in object-form mode.
418
+
419
+ To keep the preview non-persisting — consistent with the flat-field preview
420
+ (disabled Submit) and the simple object-form preview (no Save) — `MasterDetailForm`
421
+ now honours a `showSubmit` flag (default shown; backward-compatible) that
422
+ `ObjectForm` forwards, so the preview hides the master-detail Save bar. Also drops
423
+ a dead `e = formData` assignment in `ObjectForm` (lint `no-useless-assignment`).
424
+
425
+ - 4014bc9: Flow Screen preview: gate fields by `visibleWhen` (follow-up to #1944)
426
+
427
+ The Screen-node preview now evaluates each input field's `visibleWhen` against
428
+ the active variables — reusing the simulator's own condition evaluator
429
+ (`evalCondition`), normalising `{var}` placeholders to bare identifiers — so it
430
+ hides/shows conditional fields exactly as the runtime `screen` executor does
431
+ (which filters server-side before emitting the `ScreenSpec`).
432
+
433
+ - Debug simulator (live run state): gates faithfully, e.g. a screen whose
434
+ `opportunityName`/`opportunityAmount` are `visibleWhen: "{createOpportunity} == true"`
435
+ hides them while `createOpportunity` is false.
436
+ - Inspector (no run state): fails open — an unparseable or not-yet-decidable
437
+ condition keeps the field visible, so configured fields are never hidden on
438
+ missing data — and a footnote reports how many fields are gated out.
439
+
440
+ - d27f045: fix(metadata-admin): remove the unwired "Certified" measure toggle from the dataset designer
441
+
442
+ `measure.certified` is dead in the spec liveness ledger (declared but read by
443
+ nothing — no certifier authority, no provenance, not surfaced at point-of-use).
444
+ A self-asserted checkbox the dataset author flips on their own work isn't
445
+ certification — it's a fake trust signal. Drop the toggle (and the create
446
+ default) until real metric governance exists (separate `dataset.certify`
447
+ authority + `certifiedBy`/`certifiedAt` + a badge where reports pick measures).
448
+ The spec field stays (dormant, liveness=dead) so existing data is untouched.
449
+
450
+ - d23ed60: feat(studio): author the approval revise loop in the flow designer (ADR-0044)
451
+
452
+ The ADR-0044 send-back-for-revision loop — an approval node's `revise` out-edge to a wait point, closed by a declared `type: 'back'` edge re-entering the approval (round N+1) — was previously reachable only by hand-editing flow JSON. The flow designer now authors it visually:
453
+
454
+ - **Revise branch** — an approval out-edge offers `approve` / `reject` / `revise` via a new Approval-branch picker in the edge inspector; `maxRevisions` surfaces on the approval node's property form (from the engine's published configSchema when online, with a hardcoded fallback offline).
455
+ - **Back-edge authoring** — a new Connection-type select marks an edge as `back` (also `fault` / `conditional`). A back-edge renders distinctly on the canvas as a dashed amber return arc and is excluded from the layered auto-layout (exactly as the engine excludes it from DAG validation), so the loop reads top-to-bottom instead of dragging its target node below the wait point.
456
+ - **Client-side DAG validation** — the simulator's preflight now flags an UNmarked cycle as an error (the graph minus declared back-edges must be a DAG, mirroring `registerFlow`), while a declared revise loop passes and a self-loop is caught.
457
+ - **One-click "add revision loop"** — an amber affordance on an approval node drops the signal `wait` node + the `revise` edge + the declared `back` edge in a single gesture, reproducing the canonical `showcase_budget_approval` shape.
458
+
459
+ Refs framework#1770. Follows the flow-builder work in #1927 and #1930.
460
+
461
+ - 47c6e25: fix(studio/flow): wire decision branches to edges, expand screen config, align simulator with engine
462
+
463
+ Four fixes for the Studio Flow Builder, found dogfooding it as a business user:
464
+
465
+ - **Decision branches now route.** The "Branches" editor wrote `node.config.conditions`
466
+ but never the outgoing edges, so a decision built entirely in Studio left every
467
+ out-edge unconditional — the engine and simulator (which branch on `edge.condition`)
468
+ ran _all_ branches. Branches now mirror onto the node's out-edges (by order):
469
+ `FlowCanvas.addNode` carries the matching branch onto a newly-connected edge, and
470
+ `FlowNodeInspector` re-syncs existing edges when branches are edited (a `true`
471
+ expression marks the default/else edge).
472
+ - **Screen node config expanded.** The form exposed only `fields`; it now also edits
473
+ `title`, `description` (interpolates `{var}`), `waitForInput`, and the object-form
474
+ keys (`objectName`, `idVariable`, `mode`, `defaults`) — so a message screen or an
475
+ object-form wizard step no longer requires dropping to Advanced JSON.
476
+ - **Simulator applies assignment nodes.** Assignment was a no-op pass-through, so a
477
+ Debug run never reflected `Set variables`. It now normalizes the same shapes the
478
+ engine accepts (`assignments` map/array + flat) and interpolates `{var}`.
479
+ - **Simulator screen-pause parity.** The simulator paused on every screen; it now
480
+ pauses only when the screen collects input (`fields`) or sets `waitForInput`,
481
+ matching the engine's `shouldPause` — a field-less screen passes through.
482
+ - **Palette HTTP de-duplicated.** The base palette hardcoded the deprecated
483
+ `http_request` alias while the engine publishes the canonical `http`, showing
484
+ two HTTP entries. The base now uses `http` (merging into one), aliased to the
485
+ `http_request` config form so the inspector is unchanged.
486
+
487
+ - 4c2f910: feat(studio): surface flow validation errors inline on the canvas
488
+
489
+ The flow designer's structural validation (an un-declared cycle, missing entry node, duplicate ids, dangling edges, …) was only visible in the Debug panel. It now surfaces **inline on the canvas**: an un-declared cycle paints its offending edges + nodes red — using the same `validateFlowDraft` the simulator preflight runs — and an error banner lists the messages, so the author sees a broken graph without opening Debug. Each edge that closes the cycle carries a tooltip pointing at the fix ("mark the edge that closes the loop as a back-edge"). A declared revise loop (ADR-0044 back-edge) is excluded from cycle detection and stays un-flagged.
490
+
491
+ Follows #1954 (revise-loop authoring) and #1955 (simulating approval decisions).
492
+
493
+ - 1b3ccd1: feat(studio): simulate approval decisions in the flow debugger
494
+
495
+ The designer-time flow simulator treated an `approval` node as a pass-through that fanned out to every out-edge at once — so an ADR-0044 revise loop couldn't be debugged: it walked approve / reject / revise simultaneously and hit the step ceiling on the back-edge.
496
+
497
+ The simulator now models an approval as a durable pause (like `wait` / `screen`): it suspends at the node, and the Debug panel offers the node's out-edge labels (`approve` / `reject` / `revise`) as decision buttons. Resuming routes down ONLY the chosen branch — mirroring how the engine resumes a suspended approval by branch label — so a full revise loop is now walkable in the debugger: revise → wait → resubmit (back-edge) → round 2 → approve. An unmatched decision falls back to fanning out (mirroring the engine's label-fallback), logged so the author notices.
498
+
499
+ Follows #1954 (ADR-0044 revise-loop authoring).
500
+
501
+ - 05584aa: feat(studio/flow): context-aware Start trigger fields + explicit decision-branch binding
502
+
503
+ Two flow-builder UX improvements (follow-ups to the decision/screen/simulator fixes in #1927):
504
+
505
+ - **Start node trigger fields are now context-aware.** The Start node showed `Object`
506
+ and `Entry condition` (record-trigger config) even on screen / manual flows where
507
+ they don't apply. They're now gated by the chosen `triggerType` — shown for record /
508
+ schedule / webhook / event triggers, hidden for manual / unset (screen wizards). A
509
+ field that already holds a value is never hidden, so existing flows are unaffected.
510
+ - **Decision branches can be bound to edges explicitly.** Selecting a decision out-edge
511
+ now shows a **Branch** picker listing the source decision's branches (label · condition,
512
+ or "· default"). Picking one writes that branch's expression / label (or marks the
513
+ default) onto the edge — so routing stays correct even when edges are connected out of
514
+ branch order, instead of relying solely on the implicit by-order auto-wire. A
515
+ "— Custom —" option preserves manual editing.
516
+
517
+ Adds `flow-node-config.test.ts` covering the trigger-field gating.
518
+
519
+ - 44d4582: fix(studio): localize lookup picker config + keep published org objects editable
520
+
521
+ - The lookup field's "Picker config" sub-panel (display/description field,
522
+ selectable-records filters, depends-on, page size, quick-create) was
523
+ hard-coded English in an otherwise-Chinese designer. Routed every literal
524
+ through `t()`/`tFormat()` with new `designer.field.lookup.*` keys (en + zh).
525
+ - A freshly-published org object read back as read-only: after publish its
526
+ active version surfaces in the layered `code` slot tagged with the
527
+ `sys_metadata` provenance sentinel, and `ResourceEditPage` treated any
528
+ non-null `code` as a packaged artifact (needs `allowOrgOverride`, which the
529
+ `object` type lacks). Mirror the server's `isArtifactBacked` — which excludes
530
+ `_packageId === 'sys_metadata'` — so org-authored items stay editable.
531
+
532
+ - b419a7c: fix(studio): enable report authoring (create flow, chart render, dataset-aware inspector)
533
+
534
+ Found dogfooding report design in Studio as a business user — you could not create a report at all, plus several follow-on gaps.
535
+
536
+ - **Report create now uses the canvas + `ReportDefaultInspector`.** Only `object` was in `CREATE_MODE_CANVAS_TYPES`, so report-create fell back to a stale name-first form whose create-config (`objectName`, `columns: []`) predates the ADR-0021 dataset-bound model — saving failed server validation (_"a report needs `dataset` + `values`"_) with no field to fix it. Add `'report'` to the canvas set; the inspector exposes an auto-derived snake_case Name in create mode; fix the create-config (drop `objectName`/`columns`, seed `type: 'summary'` + `drilldown: true`).
537
+ - **Preserve `?package=` on post-create navigation** — it was dropped, so the editor reloaded a blank draft in the user's default package.
538
+ - **Render a report's embedded `chart`** in `DatasetReportRenderer` (authorable in Studio but never rendered) via the lazily-registered generic chart component; requests a non-animated render for export/background-tab safety.
539
+ - **Dedicated Chart panel in the inspector** — chart type + dataset-aware X-Axis (dimension) / Y-Axis (measure) dropdowns + title, replacing free-text axis fields and the vague "Chart: Required text value" validation.
540
+
541
+ - 15f140d: Validation messages name the offending widget + field
542
+
543
+ A nested Zod issue (e.g. `widgets.2.layout`) was shown as just its head field label — "Widgets: Invalid input" — so an author couldn't tell which widget or sub-field was at fault. `labelForIssuePath` now appends a readable trail, resolving each array index to the item's stable identity (id/name/title, incl. I18nLabel objects) from the draft: "Widgets → priority_split → layout". Single-segment paths are unchanged.
544
+
545
+ - Updated dependencies [677f7ed]
546
+ - Updated dependencies [08c47da]
547
+ - Updated dependencies [a71be60]
548
+ - Updated dependencies [cb03bc3]
549
+ - @object-ui/types@7.1.0
550
+ - @object-ui/core@7.1.0
551
+ - @object-ui/react@7.1.0
552
+ - @object-ui/auth@7.1.0
553
+ - @object-ui/collaboration@7.1.0
554
+ - @object-ui/components@7.1.0
555
+ - @object-ui/data-objectstack@7.1.0
556
+ - @object-ui/fields@7.1.0
557
+ - @object-ui/layout@7.1.0
558
+ - @object-ui/permissions@7.1.0
559
+ - @object-ui/plugin-editor@7.1.0
560
+ - @object-ui/providers@7.1.0
561
+ - @object-ui/i18n@7.1.0
562
+
3
563
  ## 7.0.0
4
564
 
5
565
  ### Minor Changes
@@ -23,7 +23,7 @@ import { usePreviewDrafts } from '../preview/PreviewModeContext';
23
23
  import { PreviewDraftEmptyState } from '../preview/PreviewDraftEmptyState';
24
24
  import { ExpressionProvider, evaluateVisibility } from '../providers/ExpressionProvider';
25
25
  import { useTrackRouteAsRecent } from '../hooks/useTrackRouteAsRecent';
26
- import { resolveRecordFormTarget, resolveNavigateCreateUrl, resolveNavigateEditUrl } from '../utils/recordFormNavigation';
26
+ import { resolveRecordFormTarget, resolveFormViewLayout, resolveNavigateCreateUrl, resolveNavigateEditUrl } from '../utils/recordFormNavigation';
27
27
  import { matchAppBySegment } from '../utils/appRoute';
28
28
  import { resolveHref } from '@object-ui/layout';
29
29
  import { ExpressionEvaluator } from '@object-ui/core';
@@ -373,8 +373,20 @@ export function AppContent({ extraRoutes, extraRoutesNoApp } = {}) {
373
373
  return (_jsx(Suspense, { fallback: _jsx(LoadingScreen, {}), children: _jsxs(Routes, { children: [_jsx(Route, { path: "create-app", element: _jsx(CreateAppPage, {}) }), _jsx(Route, { path: "system/marketplace", element: _jsx(MarketplacePage, {}) }), _jsx(Route, { path: "system/marketplace/installed", element: _jsx(MarketplaceInstalledPage, {}) }), _jsx(Route, { path: "system/marketplace/:packageId", element: _jsx(MarketplacePackagePage, {}) }), _jsx(Route, { path: "metadata", element: _jsx(MetadataDirectoryPage, {}) }), _jsx(Route, { path: "metadata/_diagnostics", element: _jsx(MetadataDiagnosticsPage, {}) }), _jsx(Route, { path: "metadata/:type", element: _jsx(MetadataResourceListPage, {}) }), _jsx(Route, { path: "metadata/:type/new", element: _jsx(MetadataResourceEditPage, { createMode: true }) }), _jsx(Route, { path: "metadata/:type/:name", element: _jsx(MetadataResourceEditPage, {}) }), _jsx(Route, { path: "metadata/:type/:name/history", element: _jsx(MetadataResourceHistoryPage, {}) }), extraRoutesNoApp] }) }));
374
374
  }
375
375
  const expressionUser = user
376
- ? { name: user.name, email: user.email, role: user.role ?? 'user' }
377
- : { name: 'Anonymous', email: '', role: 'guest' };
376
+ ? {
377
+ id: user.id,
378
+ name: user.name,
379
+ email: user.email,
380
+ role: user.role ?? 'user',
381
+ roles: user.roles,
382
+ // Surface the platform-admin flag so action `visible` CEL predicates
383
+ // gated on `ctx.user.isPlatformAdmin == true` (e.g. sys_environment
384
+ // "Change Plan (admin)") evaluate correctly. Previously only
385
+ // name/email/role were forwarded → isPlatformAdmin-gated actions were
386
+ // hidden even for platform admins.
387
+ isPlatformAdmin: user.isPlatformAdmin ?? false,
388
+ }
389
+ : { name: 'Anonymous', email: '', role: 'guest', isPlatformAdmin: false };
378
390
  return (_jsxs(ExpressionProvider, { user: expressionUser, app: activeApp, data: {}, features: features, children: [_jsx(NavigationSyncEffect, {}), _jsxs(ConsoleLayout, { activeAppName: activeApp.name, activeApp: activeApp, onAppChange: handleAppChange, objects: allObjects, connectionState: connectionState, userId: user?.id, children: [_jsx(CommandPalette, { apps: apps, activeApp: activeApp, objects: allObjects, onAppChange: handleAppChange, dataSource: dataSource }), _jsx(KeyboardShortcutsDialog, {}), _jsx(OnboardingWalkthrough, {}), _jsx(DraftReviewNavigator, { appName: appName }), _jsx(ErrorBoundary, { children: _jsx(Suspense, { fallback: _jsx(LoadingScreen, {}), children: _jsx(RouteFader, { className: "h-full", children: _jsxs(Routes, { children: [_jsx(Route, { path: "/", element: (() => {
379
391
  // When the app declares a landing target (home page or
380
392
  // first nav route) honour it; otherwise — e.g. the
@@ -389,20 +401,14 @@ export function AppContent({ extraRoutes, extraRoutesNoApp } = {}) {
389
401
  objectName: currentObjectDef.name,
390
402
  mode: editingRecord ? 'edit' : 'create',
391
403
  recordId: editingRecord?.id,
392
- // Master-detail by config: if the object's form view declares
393
- // inline child collections, the standard New/Edit modal renders
394
- // them as an atomic master-detail form (no bespoke page).
395
- subforms: currentObjectDef.form?.subforms
396
- ?? currentObjectDef.formViews?.default?.subforms,
397
- // ADR-0050 (#1890): forward the default form view's layout so the
398
- // New/Edit modal can be tabbed (not just a flat stack). `formType`
399
- // stays 'modal' (the container); `contentLayout` carries the layout.
400
- ...(() => {
401
- const fd = currentObjectDef.form ?? currentObjectDef.formViews?.default;
402
- return fd?.type === 'tabbed' && Array.isArray(fd?.sections)
403
- ? { contentLayout: 'tabbed', sections: fd.sections }
404
- : {};
405
- })(),
404
+ // Honor the object's DEFAULT FORM VIEW: curated sections (field
405
+ // selection + order + grouping), `contentLayout: 'tabbed'` when the
406
+ // view is tabbed, and inline child collections (master-detail).
407
+ // When the view declares sections they drive the modal layout and
408
+ // win over the flat `fields` list below; otherwise this resolves to
409
+ // {} and `fields` (every field, raw schema order) is used as before.
410
+ // `formType` stays 'modal' (the container). (#1890 / ADR-0050.)
411
+ ...resolveFormViewLayout(currentObjectDef),
406
412
  title: editingRecord
407
413
  ? t('form.editTitle', { object: objectLabel(currentObjectDef) })
408
414
  : t('form.createTitle', { object: objectLabel(currentObjectDef) }),