@object-ui/app-shell 6.2.3 → 7.1.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 (486) hide show
  1. package/CHANGELOG.md +1229 -0
  2. package/README.md +292 -0
  3. package/dist/assistant/assistantBus.d.ts +72 -0
  4. package/dist/assistant/assistantBus.js +133 -0
  5. package/dist/chrome/CommandPalette.d.ts +1 -1
  6. package/dist/chrome/CommandPalette.js +26 -22
  7. package/dist/chrome/ConditionalAuthWrapper.d.ts +1 -1
  8. package/dist/chrome/ConsoleToaster.d.ts +1 -1
  9. package/dist/chrome/ConsoleToaster.js +3 -1
  10. package/dist/chrome/ErrorBoundary.d.ts +1 -1
  11. package/dist/chrome/KeyboardShortcutsDialog.d.ts +1 -1
  12. package/dist/chrome/KeyboardShortcutsDialog.js +16 -5
  13. package/dist/chrome/LoadingScreen.d.ts +1 -1
  14. package/dist/chrome/LoadingScreen.js +22 -26
  15. package/dist/chrome/RouteFader.d.ts +1 -1
  16. package/dist/chrome/ThemeProvider.d.ts +1 -1
  17. package/dist/components/ManagedByBadge.d.ts +1 -1
  18. package/dist/console/AppContent.d.ts +1 -1
  19. package/dist/console/AppContent.js +184 -39
  20. package/dist/console/ConsoleShell.d.ts +7 -7
  21. package/dist/console/ConsoleShell.js +32 -3
  22. package/dist/console/ai/AiChatPage.d.ts +88 -1
  23. package/dist/console/ai/AiChatPage.js +747 -66
  24. package/dist/console/ai/ConversationsSidebar.d.ts +26 -1
  25. package/dist/console/ai/ConversationsSidebar.js +149 -34
  26. package/dist/console/ai/LiveCanvas.d.ts +28 -0
  27. package/dist/console/ai/LiveCanvas.js +80 -0
  28. package/dist/console/ai/reconcileTurn.d.ts +8 -0
  29. package/dist/console/ai/reconcileTurn.js +20 -0
  30. package/dist/console/auth/AuthPageLayout.d.ts +1 -1
  31. package/dist/console/auth/ForgotPasswordPage.d.ts +1 -1
  32. package/dist/console/auth/LoginPage.d.ts +1 -1
  33. package/dist/console/auth/RegisterPage.d.ts +1 -1
  34. package/dist/console/auth/RegisterPage.js +23 -3
  35. package/dist/console/cloud-connection/CloudConnectionPanel.d.ts +1 -0
  36. package/dist/console/cloud-connection/CloudConnectionPanel.js +169 -0
  37. package/dist/console/home/AppCard.d.ts +1 -1
  38. package/dist/console/home/AppCard.js +6 -12
  39. package/dist/console/home/HomeAppsStrip.d.ts +8 -0
  40. package/dist/console/home/HomeAppsStrip.js +61 -0
  41. package/dist/console/home/HomeLayout.d.ts +1 -1
  42. package/dist/console/home/HomeLayout.js +3 -1
  43. package/dist/console/home/HomePage.d.ts +1 -2
  44. package/dist/console/home/HomePage.js +149 -21
  45. package/dist/console/home/HomeRail.d.ts +22 -0
  46. package/dist/console/home/HomeRail.js +62 -0
  47. package/dist/console/home/QuickActions.d.ts +1 -1
  48. package/dist/console/home/QuickActions.js +3 -11
  49. package/dist/console/home/RecentApps.d.ts +1 -1
  50. package/dist/console/home/RecentApps.js +2 -2
  51. package/dist/console/home/StarredApps.d.ts +1 -1
  52. package/dist/console/home/StarredApps.js +2 -2
  53. package/dist/console/marketplace/InstalledListWidget.d.ts +1 -0
  54. package/dist/console/marketplace/InstalledListWidget.js +93 -0
  55. package/dist/console/marketplace/MarkdownText.d.ts +1 -1
  56. package/dist/console/marketplace/MarketplaceAccessDenied.d.ts +1 -1
  57. package/dist/console/marketplace/MarketplaceInstalledPage.d.ts +8 -14
  58. package/dist/console/marketplace/MarketplaceInstalledPage.js +14 -66
  59. package/dist/console/marketplace/MarketplacePackagePage.d.ts +1 -1
  60. package/dist/console/marketplace/MarketplacePackagePage.js +249 -8
  61. package/dist/console/marketplace/MarketplacePage.d.ts +1 -1
  62. package/dist/console/marketplace/MarketplacePage.js +60 -3
  63. package/dist/console/marketplace/PackageIcon.d.ts +1 -1
  64. package/dist/console/marketplace/PluginDisclosure.d.ts +14 -0
  65. package/dist/console/marketplace/PluginDisclosure.js +38 -0
  66. package/dist/console/marketplace/marketplaceApi.d.ts +123 -0
  67. package/dist/console/marketplace/marketplaceApi.js +254 -1
  68. package/dist/console/organizations/CreateWorkspaceDialog.d.ts +1 -1
  69. package/dist/console/organizations/OrganizationsLayout.d.ts +1 -1
  70. package/dist/console/organizations/OrganizationsPage.d.ts +1 -1
  71. package/dist/console/organizations/manage/AcceptInvitationPage.d.ts +1 -1
  72. package/dist/console/organizations/manage/InvitationsPage.d.ts +1 -1
  73. package/dist/console/organizations/manage/InviteMemberDialog.d.ts +1 -1
  74. package/dist/console/organizations/manage/MembersPage.d.ts +1 -1
  75. package/dist/console/organizations/manage/OrganizationLayout.d.ts +1 -1
  76. package/dist/console/organizations/manage/SettingsPage.d.ts +1 -1
  77. package/dist/context/CommandPaletteProvider.d.ts +44 -0
  78. package/dist/context/CommandPaletteProvider.js +71 -0
  79. package/dist/context/FavoritesProvider.d.ts +1 -1
  80. package/dist/context/NavigationContext.d.ts +1 -1
  81. package/dist/context/RecentItemsProvider.d.ts +2 -2
  82. package/dist/context/UserStateAdapters.d.ts +1 -1
  83. package/dist/context/index.d.ts +2 -0
  84. package/dist/context/index.js +1 -0
  85. package/dist/hooks/index.d.ts +5 -2
  86. package/dist/hooks/index.js +4 -1
  87. package/dist/hooks/useActionModal.d.ts +53 -0
  88. package/dist/hooks/useActionModal.js +111 -0
  89. package/dist/hooks/useChatConversation.d.ts +137 -4
  90. package/dist/hooks/useChatConversation.js +316 -25
  91. package/dist/hooks/useConsoleActionRuntime.d.ts +70 -0
  92. package/dist/hooks/useConsoleActionRuntime.js +564 -0
  93. package/dist/hooks/useConversationList.js +61 -3
  94. package/dist/hooks/useHomeInbox.d.ts +13 -0
  95. package/dist/hooks/useHomeInbox.js +142 -0
  96. package/dist/hooks/useNavPins.js +17 -23
  97. package/dist/hooks/useNavigationSync.d.ts +33 -0
  98. package/dist/hooks/useNavigationSync.js +98 -12
  99. package/dist/hooks/useReconcileOnError.d.ts +40 -0
  100. package/dist/hooks/useReconcileOnError.js +37 -0
  101. package/dist/hooks/useRecordApprovals.d.ts +18 -19
  102. package/dist/hooks/useRecordApprovals.js +24 -40
  103. package/dist/hooks/useResponsiveSidebar.js +14 -5
  104. package/dist/hooks/useSettleSignal.d.ts +19 -0
  105. package/dist/hooks/useSettleSignal.js +20 -0
  106. package/dist/hooks/useTrackRouteAsRecent.js +35 -0
  107. package/dist/hooks/useUrlOverlay.d.ts +62 -0
  108. package/dist/hooks/useUrlOverlay.js +88 -0
  109. package/dist/index.d.ts +18 -8
  110. package/dist/index.js +17 -5
  111. package/dist/layout/ActivityFeed.d.ts +1 -1
  112. package/dist/layout/AppHeader.d.ts +3 -2
  113. package/dist/layout/AppHeader.js +237 -72
  114. package/dist/layout/AppSidebar.d.ts +2 -1
  115. package/dist/layout/AppSidebar.js +26 -46
  116. package/dist/layout/AppSwitcher.d.ts +2 -1
  117. package/dist/layout/AppSwitcher.js +9 -5
  118. package/dist/layout/AuthPageLayout.d.ts +1 -1
  119. package/dist/layout/ConnectionStatus.d.ts +1 -1
  120. package/dist/layout/ConnectionStatus.js +9 -6
  121. package/dist/layout/ConsoleChatbotFab.d.ts +19 -1
  122. package/dist/layout/ConsoleChatbotFab.js +16 -2
  123. package/dist/layout/ConsoleFloatingChatbot.d.ts +34 -2
  124. package/dist/layout/ConsoleFloatingChatbot.js +391 -41
  125. package/dist/layout/ConsoleLayout.d.ts +1 -1
  126. package/dist/layout/ConsoleLayout.js +27 -11
  127. package/dist/layout/ContextSelectors.d.ts +44 -0
  128. package/dist/layout/ContextSelectors.js +242 -0
  129. package/dist/layout/InboxPopover.d.ts +6 -1
  130. package/dist/layout/InboxPopover.js +25 -6
  131. package/dist/layout/LocaleSwitcher.d.ts +1 -1
  132. package/dist/layout/LocalizedSidebarTrigger.d.ts +2 -0
  133. package/dist/layout/LocalizedSidebarTrigger.js +15 -0
  134. package/dist/layout/MobileViewSwitcherContext.d.ts +1 -1
  135. package/dist/layout/ModeToggle.d.ts +1 -1
  136. package/dist/layout/PageHeader.d.ts +1 -1
  137. package/dist/layout/UnifiedSidebar.d.ts +2 -1
  138. package/dist/layout/UnifiedSidebar.js +116 -15
  139. package/dist/layout/agentPicker.d.ts +56 -0
  140. package/dist/layout/agentPicker.js +40 -0
  141. package/dist/observability/index.d.ts +1 -0
  142. package/dist/observability/index.js +1 -0
  143. package/dist/observability/settleSignal.d.ts +64 -0
  144. package/dist/observability/settleSignal.js +131 -0
  145. package/dist/preview/CommitTimeline.d.ts +15 -0
  146. package/dist/preview/CommitTimeline.js +82 -0
  147. package/dist/preview/DraftChangesPanel.d.ts +19 -0
  148. package/dist/preview/DraftChangesPanel.js +114 -0
  149. package/dist/preview/DraftPreviewBar.d.ts +8 -0
  150. package/dist/preview/DraftPreviewBar.js +86 -0
  151. package/dist/preview/PreviewDraftEmptyState.d.ts +16 -0
  152. package/dist/preview/PreviewDraftEmptyState.js +47 -0
  153. package/dist/preview/PreviewModeContext.d.ts +57 -0
  154. package/dist/preview/PreviewModeContext.js +99 -0
  155. package/dist/preview/UnpublishedAppBar.d.ts +8 -0
  156. package/dist/preview/UnpublishedAppBar.js +83 -0
  157. package/dist/preview/commitHistory.d.ts +28 -0
  158. package/dist/preview/commitHistory.js +48 -0
  159. package/dist/preview/draftStatus.d.ts +20 -0
  160. package/dist/preview/draftStatus.js +27 -0
  161. package/dist/preview/usePublishAllDrafts.d.ts +18 -0
  162. package/dist/preview/usePublishAllDrafts.js +106 -0
  163. package/dist/providers/AdapterProvider.d.ts +1 -1
  164. package/dist/providers/AdapterProvider.js +6 -1
  165. package/dist/providers/ExpressionProvider.d.ts +1 -1
  166. package/dist/providers/MetadataProvider.d.ts +17 -2
  167. package/dist/providers/MetadataProvider.js +192 -12
  168. package/dist/runtime-config.d.ts +46 -2
  169. package/dist/runtime-config.js +39 -2
  170. package/dist/services/builtinComponents.js +68 -59
  171. package/dist/skeletons/SkeletonDashboard.d.ts +1 -1
  172. package/dist/skeletons/SkeletonDetail.d.ts +1 -1
  173. package/dist/skeletons/SkeletonGrid.d.ts +1 -1
  174. package/dist/utils/appRoute.d.ts +21 -0
  175. package/dist/utils/appRoute.js +25 -0
  176. package/dist/utils/deriveRelatedLists.d.ts +54 -0
  177. package/dist/utils/deriveRelatedLists.js +91 -0
  178. package/dist/utils/index.d.ts +4 -0
  179. package/dist/utils/index.js +3 -0
  180. package/dist/utils/managedByEmptyState.d.ts +8 -1
  181. package/dist/utils/managedByEmptyState.js +13 -7
  182. package/dist/utils/preferLocal.d.ts +18 -0
  183. package/dist/utils/preferLocal.js +24 -0
  184. package/dist/views/ActionConfirmDialog.d.ts +1 -1
  185. package/dist/views/ActionConfirmDialog.js +3 -1
  186. package/dist/views/ActionParamDialog.d.ts +6 -1
  187. package/dist/views/ActionParamDialog.js +9 -3
  188. package/dist/views/ActionResultDialog.d.ts +13 -0
  189. package/dist/views/ActionResultDialog.js +134 -0
  190. package/dist/views/ComponentNavView.d.ts +14 -1
  191. package/dist/views/CreateViewDialog.d.ts +1 -1
  192. package/dist/views/DashboardConfigPanel.d.ts +28 -0
  193. package/dist/views/DashboardConfigPanel.js +81 -0
  194. package/dist/views/DashboardView.d.ts +4 -3
  195. package/dist/views/DashboardView.js +38 -239
  196. package/dist/views/FlowRunner.d.ts +31 -0
  197. package/dist/views/FlowRunner.js +121 -0
  198. package/dist/views/InterfaceListPage.d.ts +49 -0
  199. package/dist/views/InterfaceListPage.js +347 -0
  200. package/dist/views/MetadataInspector.d.ts +2 -2
  201. package/dist/views/ObjectView.d.ts +1 -1
  202. package/dist/views/ObjectView.js +209 -532
  203. package/dist/views/PageView.d.ts +8 -3
  204. package/dist/views/PageView.js +45 -32
  205. package/dist/views/RecordDetailView.d.ts +1 -1
  206. package/dist/views/RecordDetailView.js +363 -148
  207. package/dist/views/RecordFormPage.d.ts +1 -1
  208. package/dist/views/RecordFormPage.js +26 -1
  209. package/dist/views/ReportConfigPanel.d.ts +37 -0
  210. package/dist/views/ReportConfigPanel.js +85 -0
  211. package/dist/views/ReportView.d.ts +1 -1
  212. package/dist/views/ReportView.js +116 -7
  213. package/dist/views/RuntimeDraftBar.d.ts +30 -0
  214. package/dist/views/RuntimeDraftBar.js +112 -0
  215. package/dist/views/ScreenView.d.ts +70 -0
  216. package/dist/views/ScreenView.js +73 -0
  217. package/dist/views/SearchResultsPage.d.ts +1 -1
  218. package/dist/views/SearchResultsPage.js +8 -18
  219. package/dist/views/ViewConfigPanel.d.ts +24 -17
  220. package/dist/views/ViewConfigPanel.js +121 -77
  221. package/dist/views/index.d.ts +1 -1
  222. package/dist/views/index.js +1 -1
  223. package/dist/views/metadata-admin/AuditPanel.d.ts +28 -0
  224. package/dist/views/metadata-admin/AuditPanel.js +79 -0
  225. package/dist/views/metadata-admin/DiagnosticsPage.d.ts +20 -0
  226. package/dist/views/metadata-admin/DiagnosticsPage.js +69 -0
  227. package/dist/views/metadata-admin/DirectoryPage.d.ts +16 -1
  228. package/dist/views/metadata-admin/DirectoryPage.js +101 -24
  229. package/dist/views/metadata-admin/DraftReviewPanel.d.ts +33 -0
  230. package/dist/views/metadata-admin/DraftReviewPanel.js +77 -0
  231. package/dist/views/metadata-admin/EmbeddedItemEditor.d.ts +17 -1
  232. package/dist/views/metadata-admin/EmbeddedItemEditor.js +15 -8
  233. package/dist/views/metadata-admin/JsonSourceEditor.d.ts +39 -0
  234. package/dist/views/metadata-admin/JsonSourceEditor.js +196 -0
  235. package/dist/views/metadata-admin/LayeredDiff.d.ts +39 -1
  236. package/dist/views/metadata-admin/LayeredDiff.js +171 -5
  237. package/dist/views/metadata-admin/MetadataDetailDrawer.d.ts +15 -1
  238. package/dist/views/metadata-admin/MetadataTypeActions.d.ts +48 -0
  239. package/dist/views/metadata-admin/MetadataTypeActions.js +165 -0
  240. package/dist/views/metadata-admin/PackagesPage.d.ts +18 -0
  241. package/dist/views/metadata-admin/PackagesPage.js +403 -0
  242. package/dist/views/metadata-admin/PageShell.d.ts +1 -1
  243. package/dist/views/metadata-admin/PageShell.js +9 -4
  244. package/dist/views/metadata-admin/PermissionMatrixEditor.d.ts +35 -1
  245. package/dist/views/metadata-admin/QuickFind.d.ts +21 -1
  246. package/dist/views/metadata-admin/QuickFind.js +6 -3
  247. package/dist/views/metadata-admin/RelatedPanel.d.ts +24 -1
  248. package/dist/views/metadata-admin/RelatedPanel.js +20 -18
  249. package/dist/views/metadata-admin/ResourceEditPage.d.ts +40 -1
  250. package/dist/views/metadata-admin/ResourceEditPage.js +1250 -60
  251. package/dist/views/metadata-admin/ResourceHistoryPage.d.ts +39 -1
  252. package/dist/views/metadata-admin/ResourceHistoryPage.js +66 -16
  253. package/dist/views/metadata-admin/ResourceListPage.d.ts +13 -1
  254. package/dist/views/metadata-admin/ResourceListPage.js +258 -30
  255. package/dist/views/metadata-admin/ResourceRouter.d.ts +23 -1
  256. package/dist/views/metadata-admin/SchemaForm.d.ts +34 -1
  257. package/dist/views/metadata-admin/SchemaForm.js +559 -49
  258. package/dist/views/metadata-admin/StudioHomePage.d.ts +22 -0
  259. package/dist/views/metadata-admin/StudioHomePage.js +205 -0
  260. package/dist/views/metadata-admin/anchors.js +255 -24
  261. package/dist/views/metadata-admin/clientValidation.d.ts +50 -0
  262. package/dist/views/metadata-admin/clientValidation.js +169 -0
  263. package/dist/views/metadata-admin/color-variant-field.d.ts +30 -0
  264. package/dist/views/metadata-admin/color-variant-field.js +38 -0
  265. package/dist/views/metadata-admin/createDerive.d.ts +75 -0
  266. package/dist/views/metadata-admin/createDerive.js +179 -0
  267. package/dist/views/metadata-admin/dashboard-schema.d.ts +12 -0
  268. package/dist/views/metadata-admin/dashboard-schema.js +80 -0
  269. package/dist/views/metadata-admin/datasource/DatasourceResourcePage.d.ts +35 -0
  270. package/dist/views/metadata-admin/datasource/DatasourceResourcePage.js +327 -0
  271. package/dist/views/metadata-admin/datasource/register.d.ts +1 -0
  272. package/dist/views/metadata-admin/datasource/register.js +24 -0
  273. package/dist/views/metadata-admin/default-inspector-registry.d.ts +49 -0
  274. package/dist/views/metadata-admin/default-inspector-registry.js +8 -0
  275. package/dist/views/metadata-admin/default-schemas.js +115 -10
  276. package/dist/views/metadata-admin/external/ExternalDatasourcePanel.d.ts +27 -0
  277. package/dist/views/metadata-admin/external/ExternalDatasourcePanel.js +69 -0
  278. package/dist/views/metadata-admin/external/ImportObjectDialog.d.ts +27 -0
  279. package/dist/views/metadata-admin/external/ImportObjectDialog.js +77 -0
  280. package/dist/views/metadata-admin/external/SchemaBrowser.d.ts +16 -0
  281. package/dist/views/metadata-admin/external/SchemaBrowser.js +74 -0
  282. package/dist/views/metadata-admin/external/ValidationPanel.d.ts +16 -0
  283. package/dist/views/metadata-admin/external/ValidationPanel.js +68 -0
  284. package/dist/views/metadata-admin/external/api.d.ts +100 -0
  285. package/dist/views/metadata-admin/external/api.js +124 -0
  286. package/dist/views/metadata-admin/i18n.d.ts +1 -0
  287. package/dist/views/metadata-admin/i18n.js +1252 -2
  288. package/dist/views/metadata-admin/index.d.ts +8 -5
  289. package/dist/views/metadata-admin/index.js +12 -2
  290. package/dist/views/metadata-admin/inspector-registry.d.ts +51 -0
  291. package/dist/views/metadata-admin/inspector-registry.js +11 -0
  292. package/dist/views/metadata-admin/inspectors/ActionDefaultInspector.d.ts +30 -0
  293. package/dist/views/metadata-admin/inspectors/ActionDefaultInspector.js +180 -0
  294. package/dist/views/metadata-admin/inspectors/AppNavInspector.d.ts +16 -0
  295. package/dist/views/metadata-admin/inspectors/AppNavInspector.js +110 -0
  296. package/dist/views/metadata-admin/inspectors/ConditionBuilder.d.ts +29 -0
  297. package/dist/views/metadata-admin/inspectors/ConditionBuilder.js +154 -0
  298. package/dist/views/metadata-admin/inspectors/DashboardDefaultInspector.d.ts +28 -0
  299. package/dist/views/metadata-admin/inspectors/DashboardDefaultInspector.js +110 -0
  300. package/dist/views/metadata-admin/inspectors/DashboardWidgetInspector.d.ts +18 -0
  301. package/dist/views/metadata-admin/inspectors/DashboardWidgetInspector.js +139 -0
  302. package/dist/views/metadata-admin/inspectors/DatasetDefaultInspector.d.ts +21 -0
  303. package/dist/views/metadata-admin/inspectors/DatasetDefaultInspector.js +221 -0
  304. package/dist/views/metadata-admin/inspectors/FlowEdgeInspector.d.ts +16 -0
  305. package/dist/views/metadata-admin/inspectors/FlowEdgeInspector.js +126 -0
  306. package/dist/views/metadata-admin/inspectors/FlowInspector.d.ts +12 -0
  307. package/dist/views/metadata-admin/inspectors/FlowInspector.js +9 -0
  308. package/dist/views/metadata-admin/inspectors/FlowKeyValueField.d.ts +30 -0
  309. package/dist/views/metadata-admin/inspectors/FlowKeyValueField.js +125 -0
  310. package/dist/views/metadata-admin/inspectors/FlowNodeConfigField.d.ts +18 -0
  311. package/dist/views/metadata-admin/inspectors/FlowNodeConfigField.js +40 -0
  312. package/dist/views/metadata-admin/inspectors/FlowNodeInspector.d.ts +14 -0
  313. package/dist/views/metadata-admin/inspectors/FlowNodeInspector.js +205 -0
  314. package/dist/views/metadata-admin/inspectors/FlowObjectListField.d.ts +26 -0
  315. package/dist/views/metadata-admin/inspectors/FlowObjectListField.js +105 -0
  316. package/dist/views/metadata-admin/inspectors/FlowReferenceField.d.ts +83 -0
  317. package/dist/views/metadata-admin/inspectors/FlowReferenceField.js +181 -0
  318. package/dist/views/metadata-admin/inspectors/FlowStringListField.d.ts +21 -0
  319. package/dist/views/metadata-admin/inspectors/FlowStringListField.js +60 -0
  320. package/dist/views/metadata-admin/inspectors/InspectorComboField.d.ts +40 -0
  321. package/dist/views/metadata-admin/inspectors/InspectorComboField.js +61 -0
  322. package/dist/views/metadata-admin/inspectors/ObjectDefaultInspector.d.ts +21 -0
  323. package/dist/views/metadata-admin/inspectors/ObjectDefaultInspector.js +55 -0
  324. package/dist/views/metadata-admin/inspectors/ObjectFieldInspector.d.ts +23 -0
  325. package/dist/views/metadata-admin/inspectors/ObjectFieldInspector.js +365 -0
  326. package/dist/views/metadata-admin/inspectors/PageBlockInspector.d.ts +48 -0
  327. package/dist/views/metadata-admin/inspectors/PageBlockInspector.js +332 -0
  328. package/dist/views/metadata-admin/inspectors/ReportDefaultInspector.d.ts +58 -0
  329. package/dist/views/metadata-admin/inspectors/ReportDefaultInspector.js +218 -0
  330. package/dist/views/metadata-admin/inspectors/ViewColumnInspector.d.ts +19 -0
  331. package/dist/views/metadata-admin/inspectors/ViewColumnInspector.js +144 -0
  332. package/dist/views/metadata-admin/inspectors/ViewInspector.d.ts +19 -0
  333. package/dist/views/metadata-admin/inspectors/ViewInspector.js +21 -0
  334. package/dist/views/metadata-admin/inspectors/ViewVariantInspector.d.ts +54 -0
  335. package/dist/views/metadata-admin/inspectors/ViewVariantInspector.js +191 -0
  336. package/dist/views/metadata-admin/inspectors/_shared.d.ts +128 -0
  337. package/dist/views/metadata-admin/inspectors/_shared.js +113 -0
  338. package/dist/views/metadata-admin/inspectors/datasetFilterCondition.d.ts +24 -0
  339. package/dist/views/metadata-admin/inspectors/datasetFilterCondition.js +97 -0
  340. package/dist/views/metadata-admin/inspectors/expression-validate.d.ts +26 -0
  341. package/dist/views/metadata-admin/inspectors/expression-validate.js +66 -0
  342. package/dist/views/metadata-admin/inspectors/flow-node-config.d.ts +143 -0
  343. package/dist/views/metadata-admin/inspectors/flow-node-config.js +506 -0
  344. package/dist/views/metadata-admin/inspectors/index.d.ts +1 -0
  345. package/dist/views/metadata-admin/inspectors/index.js +45 -0
  346. package/dist/views/metadata-admin/inspectors/json-schema-to-fields.d.ts +40 -0
  347. package/dist/views/metadata-admin/inspectors/json-schema-to-fields.js +227 -0
  348. package/dist/views/metadata-admin/inspectors/useDatasetFields.d.ts +72 -0
  349. package/dist/views/metadata-admin/inspectors/useDatasetFields.js +0 -0
  350. package/dist/views/metadata-admin/issuePath.d.ts +22 -0
  351. package/dist/views/metadata-admin/issuePath.js +65 -0
  352. package/dist/views/metadata-admin/mergeServerFields.d.ts +65 -0
  353. package/dist/views/metadata-admin/mergeServerFields.js +56 -0
  354. package/dist/views/metadata-admin/package-scope.d.ts +26 -0
  355. package/dist/views/metadata-admin/package-scope.js +43 -0
  356. package/dist/views/metadata-admin/preview-registry.d.ts +55 -0
  357. package/dist/views/metadata-admin/previews/ActionPreview.d.ts +25 -0
  358. package/dist/views/metadata-admin/previews/ActionPreview.js +238 -0
  359. package/dist/views/metadata-admin/previews/AddWidgetPicker.d.ts +12 -0
  360. package/dist/views/metadata-admin/previews/AddWidgetPicker.js +56 -0
  361. package/dist/views/metadata-admin/previews/AgentPreview.d.ts +24 -0
  362. package/dist/views/metadata-admin/previews/AgentPreview.js +100 -0
  363. package/dist/views/metadata-admin/previews/AppNavCanvas.d.ts +31 -0
  364. package/dist/views/metadata-admin/previews/AppNavCanvas.js +260 -0
  365. package/dist/views/metadata-admin/previews/AppPreview.d.ts +16 -1
  366. package/dist/views/metadata-admin/previews/AppPreview.js +23 -14
  367. package/dist/views/metadata-admin/previews/BookPreview.d.ts +20 -0
  368. package/dist/views/metadata-admin/previews/BookPreview.js +132 -0
  369. package/dist/views/metadata-admin/previews/DashboardPreview.d.ts +16 -1
  370. package/dist/views/metadata-admin/previews/DashboardPreview.js +110 -8
  371. package/dist/views/metadata-admin/previews/DatasetPreview.d.ts +18 -0
  372. package/dist/views/metadata-admin/previews/DatasetPreview.js +105 -0
  373. package/dist/views/metadata-admin/previews/DatasourcePreview.d.ts +23 -0
  374. package/dist/views/metadata-admin/previews/DatasourcePreview.js +68 -0
  375. package/dist/views/metadata-admin/previews/EmailTemplatePreview.d.ts +14 -1
  376. package/dist/views/metadata-admin/previews/FieldStub.d.ts +30 -0
  377. package/dist/views/metadata-admin/previews/FieldStub.js +104 -0
  378. package/dist/views/metadata-admin/previews/FieldsListEditor.d.ts +50 -0
  379. package/dist/views/metadata-admin/previews/FieldsListEditor.js +97 -0
  380. package/dist/views/metadata-admin/previews/FlowCanvas.d.ts +49 -0
  381. package/dist/views/metadata-admin/previews/FlowCanvas.js +416 -0
  382. package/dist/views/metadata-admin/previews/FlowPreview.d.ts +20 -0
  383. package/dist/views/metadata-admin/previews/FlowPreview.js +120 -0
  384. package/dist/views/metadata-admin/previews/FlowRunsPanel.d.ts +46 -0
  385. package/dist/views/metadata-admin/previews/FlowRunsPanel.js +97 -0
  386. package/dist/views/metadata-admin/previews/FlowSimulatorPanel.d.ts +25 -0
  387. package/dist/views/metadata-admin/previews/FlowSimulatorPanel.js +204 -0
  388. package/dist/views/metadata-admin/previews/JobPreview.d.ts +28 -0
  389. package/dist/views/metadata-admin/previews/JobPreview.js +290 -0
  390. package/dist/views/metadata-admin/previews/ObjectFormCanvas.d.ts +30 -0
  391. package/dist/views/metadata-admin/previews/ObjectFormCanvas.js +547 -0
  392. package/dist/views/metadata-admin/previews/ObjectPreview.d.ts +14 -1
  393. package/dist/views/metadata-admin/previews/ObjectPreview.js +5 -30
  394. package/dist/views/metadata-admin/previews/OutlineStrip.d.ts +32 -0
  395. package/dist/views/metadata-admin/previews/OutlineStrip.js +8 -0
  396. package/dist/views/metadata-admin/previews/PageBlockCanvas.d.ts +49 -0
  397. package/dist/views/metadata-admin/previews/PageBlockCanvas.js +510 -0
  398. package/dist/views/metadata-admin/previews/PagePreview.d.ts +10 -1
  399. package/dist/views/metadata-admin/previews/PagePreview.js +200 -5
  400. package/dist/views/metadata-admin/previews/PermissionPreview.d.ts +27 -0
  401. package/dist/views/metadata-admin/previews/PermissionPreview.js +115 -0
  402. package/dist/views/metadata-admin/previews/PreviewShell.d.ts +29 -6
  403. package/dist/views/metadata-admin/previews/PreviewShell.js +16 -3
  404. package/dist/views/metadata-admin/previews/ReportPreview.d.ts +18 -1
  405. package/dist/views/metadata-admin/previews/ReportPreview.js +23 -15
  406. package/dist/views/metadata-admin/previews/RolePreview.d.ts +19 -0
  407. package/dist/views/metadata-admin/previews/RolePreview.js +14 -0
  408. package/dist/views/metadata-admin/previews/ScreenPreview.d.ts +38 -0
  409. package/dist/views/metadata-admin/previews/ScreenPreview.js +61 -0
  410. package/dist/views/metadata-admin/previews/SkillPreview.d.ts +22 -0
  411. package/dist/views/metadata-admin/previews/SkillPreview.js +34 -0
  412. package/dist/views/metadata-admin/previews/ToolPreview.d.ts +25 -0
  413. package/dist/views/metadata-admin/previews/ToolPreview.js +122 -0
  414. package/dist/views/metadata-admin/previews/TranslationPreview.d.ts +25 -0
  415. package/dist/views/metadata-admin/previews/TranslationPreview.js +52 -0
  416. package/dist/views/metadata-admin/previews/ValidationPreview.d.ts +27 -0
  417. package/dist/views/metadata-admin/previews/ValidationPreview.js +110 -0
  418. package/dist/views/metadata-admin/previews/ViewColumnPanes.d.ts +62 -0
  419. package/dist/views/metadata-admin/previews/ViewColumnPanes.js +140 -0
  420. package/dist/views/metadata-admin/previews/ViewPreview.d.ts +23 -1
  421. package/dist/views/metadata-admin/previews/ViewPreview.js +101 -73
  422. package/dist/views/metadata-admin/previews/block-config.d.ts +82 -0
  423. package/dist/views/metadata-admin/previews/block-config.js +324 -0
  424. package/dist/views/metadata-admin/previews/block-types.d.ts +40 -0
  425. package/dist/views/metadata-admin/previews/block-types.js +110 -0
  426. package/dist/views/metadata-admin/previews/field-types.d.ts +53 -0
  427. package/dist/views/metadata-admin/previews/field-types.js +97 -0
  428. package/dist/views/metadata-admin/previews/flow-canvas-layout.d.ts +102 -0
  429. package/dist/views/metadata-admin/previews/flow-canvas-layout.js +227 -0
  430. package/dist/views/metadata-admin/previews/flow-canvas-parts.d.ts +96 -0
  431. package/dist/views/metadata-admin/previews/flow-canvas-parts.js +373 -0
  432. package/dist/views/metadata-admin/previews/form-preview.d.ts +24 -0
  433. package/dist/views/metadata-admin/previews/form-preview.js +29 -0
  434. package/dist/views/metadata-admin/previews/index.js +43 -0
  435. package/dist/views/metadata-admin/previews/object-fields-bridge.d.ts +66 -0
  436. package/dist/views/metadata-admin/previews/object-fields-bridge.js +171 -0
  437. package/dist/views/metadata-admin/previews/object-fields-io.d.ts +130 -0
  438. package/dist/views/metadata-admin/previews/object-fields-io.js +243 -0
  439. package/dist/views/metadata-admin/previews/screen-spec.d.ts +43 -0
  440. package/dist/views/metadata-admin/previews/screen-spec.js +108 -0
  441. package/dist/views/metadata-admin/previews/simulator/flow-sim-types.d.ts +102 -0
  442. package/dist/views/metadata-admin/previews/simulator/flow-sim-types.js +2 -0
  443. package/dist/views/metadata-admin/previews/simulator/flow-sim-validate.d.ts +15 -0
  444. package/dist/views/metadata-admin/previews/simulator/flow-sim-validate.js +185 -0
  445. package/dist/views/metadata-admin/previews/simulator/flow-simulator.d.ts +73 -0
  446. package/dist/views/metadata-admin/previews/simulator/flow-simulator.js +426 -0
  447. package/dist/views/metadata-admin/previews/useDatasetCatalog.d.ts +47 -0
  448. package/dist/views/metadata-admin/previews/useDatasetCatalog.js +133 -0
  449. package/dist/views/metadata-admin/previews/useFlowNodePalette.d.ts +44 -0
  450. package/dist/views/metadata-admin/previews/useFlowNodePalette.js +124 -0
  451. package/dist/views/metadata-admin/previews/useMetaOptions.d.ts +8 -0
  452. package/dist/views/metadata-admin/previews/useMetaOptions.js +50 -0
  453. package/dist/views/metadata-admin/previews/useObjectFields.d.ts +23 -0
  454. package/dist/views/metadata-admin/previews/useObjectFields.js +79 -0
  455. package/dist/views/metadata-admin/previews/useObjectOptions.d.ts +8 -0
  456. package/dist/views/metadata-admin/previews/useObjectOptions.js +43 -0
  457. package/dist/views/metadata-admin/previews/view-column-io.d.ts +42 -0
  458. package/dist/views/metadata-admin/previews/view-column-io.js +73 -0
  459. package/dist/views/metadata-admin/previews/widget-types.d.ts +24 -0
  460. package/dist/views/metadata-admin/previews/widget-types.js +40 -0
  461. package/dist/views/metadata-admin/registry.d.ts +140 -19
  462. package/dist/views/metadata-admin/report-schema.d.ts +26 -0
  463. package/dist/views/metadata-admin/report-schema.js +121 -0
  464. package/dist/views/metadata-admin/useMetadata.d.ts +100 -2
  465. package/dist/views/metadata-admin/useMetadata.js +155 -4
  466. package/dist/views/metadata-admin/view-item-normalize.d.ts +20 -0
  467. package/dist/views/metadata-admin/view-item-normalize.js +68 -0
  468. package/dist/views/metadata-admin/view-schema.d.ts +16 -0
  469. package/dist/views/metadata-admin/view-schema.js +107 -0
  470. package/dist/views/metadata-admin/view-variant-model.d.ts +23 -0
  471. package/dist/views/metadata-admin/view-variant-model.js +64 -0
  472. package/dist/views/metadata-admin/widgets.d.ts +89 -1
  473. package/dist/views/metadata-admin/widgets.js +491 -17
  474. package/dist/views/runtime-metadata-persistence.d.ts +78 -0
  475. package/dist/views/runtime-metadata-persistence.js +89 -0
  476. package/dist/views/useOpenRecordList.d.ts +18 -0
  477. package/dist/views/useOpenRecordList.js +36 -0
  478. package/dist/views/userFilterUrlState.d.ts +15 -0
  479. package/dist/views/userFilterUrlState.js +53 -0
  480. package/dist/views/view-config-adapter.d.ts +38 -0
  481. package/dist/views/view-config-adapter.js +80 -0
  482. package/package.json +52 -34
  483. package/dist/views/DesignDrawer.d.ts +0 -28
  484. package/dist/views/DesignDrawer.js +0 -51
  485. package/dist/views/metadata-admin/DesignerEditorWrapper.d.ts +0 -68
  486. package/dist/views/metadata-admin/DesignerEditorWrapper.js +0 -158
@@ -11,7 +11,7 @@ import { useParams, useNavigate, useLocation, Link } from 'react-router-dom';
11
11
  import { DetailView, RecordChatterPanel, buildDefaultPageSchema, extractMentions } from '@object-ui/plugin-detail';
12
12
  import { Empty, EmptyTitle, EmptyDescription } from '@object-ui/components';
13
13
  import { useAuth, createAuthenticatedFetch } from '@object-ui/auth';
14
- import { ActionProvider, useObjectTranslation, useObjectLabel, usePageAssignment, RecordContextProvider, SchemaRenderer, DiscussionContextProvider, HighlightFieldsProvider } from '@object-ui/react';
14
+ import { ActionProvider, useObjectTranslation, useObjectLabel, usePageAssignment, RecordContextProvider, SchemaRenderer, DiscussionContextProvider, HighlightFieldsProvider, useGlobalUndo } from '@object-ui/react';
15
15
  import { buildExpandFields } from '@object-ui/core';
16
16
  import { toast } from 'sonner';
17
17
  import { useRecordPresence, PresenceAvatars } from '@object-ui/collaboration';
@@ -20,14 +20,18 @@ import { MetadataPanel, useMetadataInspector } from './MetadataInspector';
20
20
  import { SkeletonDetail } from '../skeletons';
21
21
  import { ManagedByBadge } from '../components/ManagedByBadge';
22
22
  import { resolveCrudAffordances } from '../utils/crudAffordances';
23
+ import { deriveRelatedLists } from '../utils/deriveRelatedLists';
23
24
  import { hasExplicitDiscussion } from '../utils/pageSchemaIntrospect';
24
25
  import { ActionConfirmDialog } from './ActionConfirmDialog';
25
26
  import { ActionParamDialog } from './ActionParamDialog';
27
+ import { ActionResultDialog } from './ActionResultDialog';
28
+ import { FlowRunner } from './FlowRunner';
26
29
  import { resolveActionParams } from '../utils/resolveActionParams';
27
30
  import { useRecordBreadcrumbTitle } from '../context/NavigationContext';
28
31
  import { useRecordApprovals } from '../hooks/useRecordApprovals';
29
32
  import { getRecordDisplayName } from '../utils';
30
33
  import { useFavorites } from '../hooks/useFavorites';
34
+ import { useActionModal } from '../hooks/useActionModal';
31
35
  import { useRecentItems } from '../hooks/useRecentItems';
32
36
  const FALLBACK_USER = { id: 'current-user', name: 'Demo User' };
33
37
  /**
@@ -79,13 +83,15 @@ export function RecordDetailView({ dataSource, objects, onEdit, objectNameOverri
79
83
  const location = useLocation();
80
84
  const originFrom = location.state?.from;
81
85
  const { t } = useObjectTranslation();
82
- const { objectLabel, viewLabel: _vLabel, sectionLabel, actionLabel, actionConfirm, actionSuccess, fieldLabel, fieldOptionLabel } = useObjectLabel();
86
+ const { objectLabel, viewLabel: _vLabel, sectionLabel, actionLabel, actionConfirm, actionSuccess, actionParamText, actionParamOptionLabel, actionDescription, fieldLabel, fieldOptionLabel } = useObjectLabel();
83
87
  const { isFavorite, toggleFavorite, refreshLabel: refreshFavoriteLabel } = useFavorites();
84
88
  const { addRecentItem } = useRecentItems();
85
89
  const [isLoading, setIsLoading] = useState(true);
86
90
  const [feedItems, setFeedItems] = useState([]);
87
91
  const [mentionSuggestions, setMentionSuggestions] = useState([]);
88
92
  const [actionRefreshKey, setActionRefreshKey] = useState(0);
93
+ // Screen-flow runtime: a paused `screen`-node flow launched from a record action.
94
+ const [screenFlow, setScreenFlow] = useState(null);
89
95
  const [childRelatedData, setChildRelatedData] = useState({});
90
96
  const [historyEntries, setHistoryEntries] = useState(null);
91
97
  const [historyLoading, setHistoryLoading] = useState(false);
@@ -257,12 +263,18 @@ export function RecordDetailView({ dataSource, objects, onEdit, objectNameOverri
257
263
  const [confirmState, setConfirmState] = useState({ open: false, message: '' });
258
264
  // Param collection dialog state (promise-based)
259
265
  const [paramState, setParamState] = useState({ open: false, params: [] });
266
+ // Result-dialog state — one-shot reveal of action response data
267
+ // (2FA secrets, OAuth client_secret, recovery codes).
268
+ const [resultDialogState, setResultDialogState] = useState({ open: false });
269
+ const resultDialogHandler = useCallback((spec, data) => new Promise((resolve) => {
270
+ setResultDialogState({ open: true, spec, data, resolve });
271
+ }), []);
260
272
  const confirmHandler = useCallback((message, options) => {
261
273
  return new Promise((resolve) => {
262
274
  setConfirmState({ open: true, message, options, resolve });
263
275
  });
264
276
  }, []);
265
- const paramCollectionHandler = useCallback((params) => {
277
+ const paramCollectionHandler = useCallback((params, action) => {
266
278
  return new Promise((resolve) => {
267
279
  const resolved = resolveActionParams(params, {
268
280
  objectName: objectName || objectDef?.name || '',
@@ -270,15 +282,48 @@ export function RecordDetailView({ dataSource, objects, onEdit, objectNameOverri
270
282
  fieldLabel,
271
283
  fieldOptionLabel,
272
284
  });
273
- setParamState({ open: true, params: resolved, resolve });
285
+ // Localize param label/placeholder/helpText (see ObjectView for the
286
+ // convention); falls back to the metadata literal.
287
+ const objForI18n = objectName || objectDef?.name;
288
+ const localized = resolved.map((p) => ({
289
+ ...p,
290
+ label: actionParamText(objForI18n, action?.name, p.name, 'label', p.label) ?? p.label,
291
+ placeholder: actionParamText(objForI18n, action?.name, p.name, 'placeholder', p.placeholder) ?? p.placeholder,
292
+ helpText: actionParamText(objForI18n, action?.name, p.name, 'helpText', p.helpText) ?? p.helpText,
293
+ options: Array.isArray(p.options)
294
+ ? p.options.map((o) => ({ ...o, label: actionParamOptionLabel(objForI18n, action?.name, p.name, o.value, o.label) }))
295
+ : p.options,
296
+ }));
297
+ setParamState({
298
+ open: true,
299
+ params: localized,
300
+ // Title the dialog as the action rather than the generic "Action parameters".
301
+ title: action?.label || action?.title,
302
+ description: actionDescription(objForI18n, action?.name, action?.description),
303
+ resolve,
304
+ });
274
305
  });
275
- }, [objectName, objectDef, objects, fieldLabel, fieldOptionLabel]);
306
+ }, [objectName, objectDef, objects, fieldLabel, fieldOptionLabel, actionParamText, actionParamOptionLabel]);
307
+ // Global undo/redo (Ctrl+Z), backed by the dataSource — the success toast's
308
+ // "Undo" button (for `undoable` actions) restores the record's prior values.
309
+ const undoCtl = useGlobalUndo({
310
+ dataSource,
311
+ onUndo: () => { setActionRefreshKey(k => k + 1); toast.success('Change undone'); },
312
+ });
276
313
  const toastHandler = useCallback((message, options) => {
277
- if (options?.type === 'error')
314
+ if (options?.type === 'error') {
278
315
  toast.error(message);
279
- else
280
- toast.success(message);
281
- }, []);
316
+ return;
317
+ }
318
+ if (options?.undo) {
319
+ toast.success(message, {
320
+ duration: options.duration,
321
+ action: { label: options.undo.label || 'Undo', onClick: () => { void undoCtl.undo(); } },
322
+ });
323
+ return;
324
+ }
325
+ toast.success(message, { duration: options?.duration });
326
+ }, [undoCtl]);
282
327
  const navigateHandler = useCallback((url, options) => {
283
328
  if (options?.external || options?.newTab) {
284
329
  window.open(url, '_blank', 'noopener,noreferrer');
@@ -291,7 +336,19 @@ export function RecordDetailView({ dataSource, objects, onEdit, objectNameOverri
291
336
  const apiHandler = useCallback(async (action) => {
292
337
  try {
293
338
  const target = action.target || action.name;
294
- const params = action.params || {};
339
+ const params = { ...(action.params || {}) };
340
+ delete params._rowRecord;
341
+ // Merge `bodyExtra` constant fields into the update payload. Per the
342
+ // ActionSchema contract these are "applied last; overrides user params",
343
+ // and the PageView/list executeAPI path already honors them. Without this
344
+ // merge, a pure-confirm action (confirmText, no `params` array — the
345
+ // trigger carried entirely in `bodyExtra`) collects empty `params`, so the
346
+ // generic `default` branch below skips the update and the action silently
347
+ // no-ops on the record-detail page while working from a list row.
348
+ if (action.bodyExtra && typeof action.bodyExtra === 'object') {
349
+ Object.assign(params, action.bodyExtra);
350
+ }
351
+ let undo;
295
352
  switch (target) {
296
353
  case 'opportunity_change_stage':
297
354
  await dataSource.update(objectName, pureRecordId, { stage: params.new_stage });
@@ -305,6 +362,23 @@ export function RecordDetailView({ dataSource, objects, onEdit, objectNameOverri
305
362
  default:
306
363
  // Generic: update record with collected params
307
364
  if (Object.keys(params).length > 0) {
365
+ // Undoable single-record update: capture the changed fields' prior
366
+ // values from the loaded record so the success toast can offer Undo.
367
+ if (action.undoable && pageRecord && objectName && pureRecordId) {
368
+ const undoData = {};
369
+ for (const k of Object.keys(params))
370
+ undoData[k] = pageRecord[k] ?? null;
371
+ undo = {
372
+ id: `undo-${objectName}-${pureRecordId}-${Date.now()}`,
373
+ type: 'update',
374
+ objectName,
375
+ recordId: String(pureRecordId),
376
+ timestamp: Date.now(),
377
+ description: action.label || `Undo ${objectName}`,
378
+ undoData,
379
+ redoData: { ...params },
380
+ };
381
+ }
308
382
  await dataSource.update(objectName, pureRecordId, params);
309
383
  }
310
384
  break;
@@ -313,12 +387,20 @@ export function RecordDetailView({ dataSource, objects, onEdit, objectNameOverri
313
387
  if (shouldRefresh) {
314
388
  setActionRefreshKey(k => k + 1);
315
389
  }
316
- return { success: true, reload: shouldRefresh };
390
+ else if (undo) {
391
+ // Even when refreshAfter isn't set, reflect the change so the user sees
392
+ // it (and the subsequent Undo) on the open record.
393
+ setActionRefreshKey(k => k + 1);
394
+ }
395
+ return { success: true, reload: shouldRefresh, undo };
317
396
  }
318
397
  catch (error) {
319
398
  return { success: false, error: error.message };
320
399
  }
321
- }, [dataSource, objectName, pureRecordId]);
400
+ }, [dataSource, objectName, pureRecordId, pageRecord]);
401
+ // Client-side modal transport: `type:'modal'` actions open here (Dialog /
402
+ // Sheet / Drawer by `placement`) and render arbitrary SchemaNode content.
403
+ const { modalHandler, modalElement } = useActionModal(dataSource);
322
404
  // Authenticated fetch for direct backend calls (e.g. flow trigger).
323
405
  const authFetch = useMemo(() => createAuthenticatedFetch(), []);
324
406
  // Flow action handler — POST to /api/v1/automation/{name}/trigger.
@@ -347,6 +429,15 @@ export function RecordDetailView({ dataSource, objects, onEdit, objectNameOverri
347
429
  const errMsg = json?.error || `Flow "${flowName}" failed (HTTP ${res.status})`;
348
430
  return { success: false, error: errMsg };
349
431
  }
432
+ // Screen-flow runtime: the run paused at a `screen` node awaiting input —
433
+ // open the FlowRunner to render the form + resume (refresh on completion).
434
+ const data = json?.data ?? {};
435
+ if (data.status === 'paused' && data.screen) {
436
+ setScreenFlow({ flowName, runId: data.runId, screen: data.screen });
437
+ // The action only OPENED the wizard — it hasn't completed. Suppress the
438
+ // action-level success toast; the flow-runner owns completion messaging.
439
+ return { success: true, silent: true };
440
+ }
350
441
  const shouldRefresh = action.refreshAfter !== false;
351
442
  if (shouldRefresh) {
352
443
  setActionRefreshKey(k => k + 1);
@@ -362,6 +453,7 @@ export function RecordDetailView({ dataSource, objects, onEdit, objectNameOverri
362
453
  // server-registered handler name (engine.registerAction). Sends the
363
454
  // current recordId, objectName, and any collected/static params, and the
364
455
  // server resolves the handler (with wildcard '*' fallback) and runs it.
456
+ const serverActionInFlight = useRef(new Set());
365
457
  const serverActionHandler = useCallback(async (action) => {
366
458
  const targetName = action.target || action.name;
367
459
  if (!targetName) {
@@ -370,6 +462,12 @@ export function RecordDetailView({ dataSource, objects, onEdit, objectNameOverri
370
462
  const params = (action.params && !Array.isArray(action.params))
371
463
  ? action.params
372
464
  : {};
465
+ // Re-entrancy guard: ignore a repeat click while this action+record runs.
466
+ const inflightKey = `${targetName}:${pureRecordId ?? ''}`;
467
+ if (serverActionInFlight.current.has(inflightKey)) {
468
+ return { success: false, error: 'Action already in progress' };
469
+ }
470
+ serverActionInFlight.current.add(inflightKey);
373
471
  // ── Popup-blocker workaround ──────────────────────────────────────
374
472
  // When `action.opensInNewTab` is set, the handler is known to return
375
473
  // `{ redirectUrl: ... }` for the UI to navigate to. We pre-open
@@ -381,8 +479,20 @@ export function RecordDetailView({ dataSource, objects, onEdit, objectNameOverri
381
479
  // the user always gets there.
382
480
  let preOpenedTab = null;
383
481
  if (action.opensInNewTab) {
482
+ // NOTE: do NOT pass 'noopener' here — per spec it forces window.open to
483
+ // return null even when the tab opens, so we'd lose the handle, fall
484
+ // through to the popup branch below, and end up navigating the *current*
485
+ // tab to the redirectUrl (the double-navigation bug: env opens in a new
486
+ // tab AND the list/detail page jumps to the now-consumed SSO URL). We
487
+ // need the reference to drive the pre-opened tab to the SSO redirect.
384
488
  try {
385
- preOpenedTab = window.open('about:blank', '_blank', 'noopener,noreferrer');
489
+ preOpenedTab = window.open('about:blank', '_blank');
490
+ // Paint progress immediately so the new tab isn't blank/frozen during
491
+ // the (slow) SSO-handoff mint.
492
+ if (preOpenedTab) {
493
+ preOpenedTab.document.write('<!doctype html><meta charset="utf-8"><title>正在打开… Opening…</title><body style="margin:0;font-family:system-ui,sans-serif;display:flex;flex-direction:column;align-items:center;justify-content:center;height:100vh;gap:16px;color:#4b5563"><div style="width:28px;height:28px;border:3px solid #e5e7eb;border-top-color:#6366f1;border-radius:50%;animation:s .8s linear infinite"></div><div>正在为你打开环境…</div><style>@keyframes s{to{transform:rotate(360deg)}}</style></body>');
494
+ preOpenedTab.document.close();
495
+ }
386
496
  }
387
497
  catch {
388
498
  preOpenedTab = null;
@@ -390,6 +500,63 @@ export function RecordDetailView({ dataSource, objects, onEdit, objectNameOverri
390
500
  }
391
501
  try {
392
502
  const baseUrl = import.meta.env.VITE_SERVER_URL || '';
503
+ // ── Zero-roundtrip fast path ────────────────────────────────────────
504
+ // `newTabUrl` names a GET endpoint that performs ALL auth/authz itself
505
+ // (e.g. /sso-open re-runs every check the POST half would have done),
506
+ // so the POST round trip would add nothing but click latency. Drive the
507
+ // pre-opened tab there immediately — the spinner page stays painted
508
+ // until the (possibly slow) endpoint commits its redirect.
509
+ const newTabUrl = typeof action.newTabUrl === 'string' ? action.newTabUrl : '';
510
+ if (action.opensInNewTab && newTabUrl) {
511
+ if (pureRecordId == null) {
512
+ if (preOpenedTab) {
513
+ try {
514
+ preOpenedTab.close();
515
+ }
516
+ catch { /* ignore */ }
517
+ }
518
+ return { success: false, error: 'This action runs on a single record — no record id available.' };
519
+ }
520
+ // Absolute URL required: the pre-opened tab is an about:blank document,
521
+ // so a bare-relative href has no reliable resolution base.
522
+ const directUrl = `${baseUrl || window.location.origin}${newTabUrl.replace('{recordId}', encodeURIComponent(String(pureRecordId)))}`;
523
+ if (preOpenedTab) {
524
+ try {
525
+ preOpenedTab.location.href = directUrl;
526
+ }
527
+ catch {
528
+ try {
529
+ preOpenedTab.close();
530
+ }
531
+ catch { /* ignore */ }
532
+ window.location.href = directUrl;
533
+ }
534
+ }
535
+ else {
536
+ let popup = null;
537
+ try {
538
+ popup = window.open(directUrl, '_blank');
539
+ }
540
+ catch {
541
+ popup = null;
542
+ }
543
+ if (!popup) {
544
+ toast('浏览器拦截了弹窗 / Popup blocked', {
545
+ description: '点击在新标签页打开环境',
546
+ action: { label: '打开环境', onClick: () => { try {
547
+ window.open(directUrl, '_blank');
548
+ }
549
+ catch {
550
+ window.location.href = directUrl;
551
+ } } },
552
+ duration: 10000,
553
+ });
554
+ }
555
+ }
556
+ if (action.refreshAfter === true)
557
+ setActionRefreshKey(k => k + 1);
558
+ return { success: true };
559
+ }
393
560
  const obj = action.objectName || objectName || 'global';
394
561
  const res = await authFetch(`${baseUrl}/api/v1/actions/${encodeURIComponent(obj)}/${encodeURIComponent(targetName)}`, {
395
562
  method: 'POST',
@@ -397,14 +564,25 @@ export function RecordDetailView({ dataSource, objects, onEdit, objectNameOverri
397
564
  body: JSON.stringify({ recordId: pureRecordId, params }),
398
565
  });
399
566
  const json = await res.json().catch(() => null);
400
- if (!res.ok || (json && json.success === false)) {
401
- const errMsg = json?.error || `Action "${targetName}" failed (HTTP ${res.status})`;
567
+ // The action route wraps the handler's return value in a {success, data}
568
+ // envelope. A script action that THROWS is reported as
569
+ // `data: { success: false, error }` while the OUTER success stays true,
570
+ // so we must inspect the inner envelope too — otherwise a failed action
571
+ // is mistaken for success and fires the green "completed" toast while the
572
+ // real error is swallowed.
573
+ const inner = json?.data;
574
+ const innerFailed = inner && typeof inner === 'object' && inner.success === false;
575
+ if (!res.ok || (json && json.success === false) || innerFailed) {
576
+ const errMsg = (innerFailed && inner.error) || json?.error || `Action "${targetName}" failed (HTTP ${res.status})`;
402
577
  if (preOpenedTab) {
403
578
  try {
404
579
  preOpenedTab.close();
405
580
  }
406
581
  catch { /* ignore */ }
407
582
  }
583
+ // Surface the failure — this custom new-tab path bypasses
584
+ // ActionRunner's toast-on-error, so otherwise the user gets no feedback.
585
+ toast.error(errMsg);
408
586
  return { success: false, error: errMsg };
409
587
  }
410
588
  const shouldRefresh = action.refreshAfter !== false;
@@ -434,14 +612,26 @@ export function RecordDetailView({ dataSource, objects, onEdit, objectNameOverri
434
612
  }
435
613
  else {
436
614
  let popup = null;
615
+ // No 'noopener' so a successful open returns a truthy handle; with
616
+ // it, the null return would always trip the current-tab fallback.
437
617
  try {
438
- popup = window.open(redirectUrl, '_blank', 'noopener,noreferrer');
618
+ popup = window.open(redirectUrl, '_blank');
439
619
  }
440
620
  catch {
441
621
  popup = null;
442
622
  }
443
623
  if (!popup) {
444
- window.location.href = redirectUrl;
624
+ // Don't silently hijack the current tab — offer a one-click open.
625
+ toast('浏览器拦截了弹窗 / Popup blocked', {
626
+ description: '点击在新标签页打开环境',
627
+ action: { label: '打开环境', onClick: () => { try {
628
+ window.open(redirectUrl, '_blank');
629
+ }
630
+ catch {
631
+ window.location.href = redirectUrl;
632
+ } } },
633
+ duration: 10000,
634
+ });
445
635
  }
446
636
  }
447
637
  }
@@ -462,13 +652,19 @@ export function RecordDetailView({ dataSource, objects, onEdit, objectNameOverri
462
652
  }
463
653
  catch { /* ignore */ }
464
654
  }
465
- return { success: false, error: error.message };
655
+ const msg = error.message;
656
+ toast.error(msg);
657
+ return { success: false, error: msg };
658
+ }
659
+ finally {
660
+ serverActionInFlight.current.delete(inflightKey);
466
661
  }
467
662
  }, [authFetch, pureRecordId, objectName]);
468
663
  // ─── Approvals ─────────────────────────────────────────────────────
469
- // Surfaces "Submit for Approval" / "Recall" buttons on the record header
470
- // when an active approval process is registered for this object, and a
471
- // status badge when a request exists.
664
+ // Since ADR-0019 an approval is a flow node: the flow opens the request,
665
+ // there is no manual submit/recall from the record header. When the current
666
+ // user is a pending approver, surface "Approve" / "Reject" on the header and
667
+ // a status badge whenever a request exists.
472
668
  const approvals = useRecordApprovals(objectName, pureRecordId, user?.id);
473
669
  // Hold latest approvals snapshot in a ref so the action handler
474
670
  // (memoized once inside ActionRunner) always sees fresh state instead of
@@ -481,14 +677,11 @@ export function RecordDetailView({ dataSource, objects, onEdit, objectNameOverri
481
677
  ? action.params
482
678
  : {};
483
679
  try {
484
- if (target === 'submit_approval') {
485
- await approvalsRef.current.submit({
486
- processName: params.processName,
487
- comment: params.comment,
488
- });
680
+ if (target === 'approve_request') {
681
+ await approvalsRef.current.approve({ comment: params.comment });
489
682
  }
490
- else if (target === 'recall_approval') {
491
- await approvalsRef.current.recall({ comment: params.comment });
683
+ else if (target === 'reject_request') {
684
+ await approvalsRef.current.reject({ comment: params.comment });
492
685
  }
493
686
  else {
494
687
  return { success: false, error: `Unknown approval target: ${target}` };
@@ -502,29 +695,36 @@ export function RecordDetailView({ dataSource, objects, onEdit, objectNameOverri
502
695
  }, []);
503
696
  // Discover reverse references: other objects with lookup/master_detail fields
504
697
  // pointing to the current object (e.g., order_item.order → order).
505
- const childRelations = useMemo(() => {
506
- if (!objectDef || !objects)
507
- return [];
508
- const relations = [];
509
- for (const obj of objects) {
510
- if (obj.name === objectDef.name)
511
- continue;
512
- for (const [fieldName, fieldDef] of Object.entries(obj.fields || {})) {
513
- if (fieldDef &&
514
- (fieldDef.type === 'lookup' || fieldDef.type === 'master_detail') &&
515
- (fieldDef.reference_to || fieldDef.reference) === objectDef.name) {
516
- relations.push({
517
- childObject: obj.name,
518
- childLabel: obj.label || obj.name,
519
- referenceField: fieldName,
520
- });
521
- }
522
- }
523
- }
524
- return relations;
525
- }, [objectDef, objects]);
526
- // Fetch related child records for each reverse reference
698
+ //
699
+ // Audit FKs (`created_by` / `updated_by` / `owner_id`) are skipped — they
700
+ // exist on virtually every object, and on a `sys_user` page they would
701
+ // produce one related entry per (object × audit-FK) pair (dozens of
702
+ // duplicate "用户偏好 / 邮件模板 / 角色 …" cards in the right rail and
703
+ // tabs). The semantic owner field for a child record is its primary
704
+ // `*_id` lookup; audit attribution belongs in audit views, not in the
705
+ // related-records summary.
706
+ // Detail-page related lists — the read-side mirror of the form's inline
707
+ // master-detail. Derived purely from the relationship graph: every child
708
+ // object whose lookup/master_detail FK references this object becomes a
709
+ // related list (owned `master_detail` children first), unless its FK opts
710
+ // out via `relatedList: false`. `relatedListTitle` / `relatedListColumns`
711
+ // on the FK override the derived title / columns. Audit FKs are skipped and
712
+ // children deduped — see `deriveRelatedLists`.
713
+ const childRelations = useMemo(() => deriveRelatedLists(objectDef, objects), [objectDef, objects]);
714
+ // Fetch related child records for each reverse reference.
715
+ //
716
+ // PERF: only the legacy `DetailView` path consumes `childRelatedData`
717
+ // (it's threaded into `detailSchema.related[].data`). The default
718
+ // schema path renders each related list via `record:related_list`,
719
+ // whose `RelatedList` self-fetches lazily when its tab is shown — so
720
+ // preloading here would just fire ~N redundant concurrent queries on
721
+ // every record open (measured: a record with 8 related lists fired ~50
722
+ // concurrent requests, all TTFB ~9s) for data the schema path never
723
+ // reads. Skip the fan-out entirely whenever the schema page renders;
724
+ // load eagerly only for the legacy fallback that needs it.
527
725
  useEffect(() => {
726
+ if (effectivePage)
727
+ return;
528
728
  if (!dataSource || !pureRecordId || childRelations.length === 0)
529
729
  return;
530
730
  let cancelled = false;
@@ -548,7 +748,7 @@ export function RecordDetailView({ dataSource, objects, onEdit, objectNameOverri
548
748
  setChildRelatedData(data);
549
749
  });
550
750
  return () => { cancelled = true; };
551
- }, [dataSource, pureRecordId, childRelations]);
751
+ }, [dataSource, pureRecordId, childRelations, objectDef, effectivePage]);
552
752
  // ── Audit history fetch ────────────────────────────────────────────
553
753
  // Loads recent sys_audit_log entries for this record so the DetailView can
554
754
  // render a read-only "History" tab. Gated on three preconditions to keep
@@ -777,7 +977,7 @@ export function RecordDetailView({ dataSource, objects, onEdit, objectNameOverri
777
977
  const mapped = res.data.map((c) => ({
778
978
  id: c.id,
779
979
  type: 'comment',
780
- actor: c.author_name ?? 'Unknown',
980
+ actor: c.author_name ?? t('detail.unknownUser', { defaultValue: 'Unknown' }),
781
981
  actorAvatarUrl: c.author_avatar_url ?? undefined,
782
982
  body: c.body ?? '',
783
983
  createdAt: c.created_at,
@@ -838,8 +1038,8 @@ export function RecordDetailView({ dataSource, objects, onEdit, objectNameOverri
838
1038
  return;
839
1039
  const mapped = [];
840
1040
  for (const row of res.data) {
841
- const t = activityTypeToFeed[row.type];
842
- if (!t)
1041
+ const feedType = activityTypeToFeed[row.type];
1042
+ if (!feedType)
843
1043
  continue;
844
1044
  // Prefer the explicit `timestamp` column, but tolerate older
845
1045
  // rows where the driver leaked the literal "NOW()" — fall
@@ -850,11 +1050,15 @@ export function RecordDetailView({ dataSource, objects, onEdit, objectNameOverri
850
1050
  }
851
1051
  mapped.push({
852
1052
  id: row.id,
853
- type: t,
854
- actor: row.actor_name ?? 'System',
1053
+ type: feedType,
1054
+ actor: row.actor_name ?? t('detail.systemActor', { defaultValue: 'System' }),
855
1055
  actorAvatarUrl: row.actor_avatar_url ?? undefined,
856
1056
  body: row.summary ?? '',
857
1057
  createdAt: when,
1058
+ // ADR-0052 ActivityPointer: drill from the summary to the source
1059
+ // rich entity (sys_email row, call/meeting task, …) when present.
1060
+ sourceObject: row.source_object ?? undefined,
1061
+ sourceId: row.source_id ?? undefined,
858
1062
  });
859
1063
  }
860
1064
  if (!mapped.length)
@@ -878,11 +1082,12 @@ export function RecordDetailView({ dataSource, objects, onEdit, objectNameOverri
878
1082
  }, [dataSource, objectName, pureRecordId, currentUser]);
879
1083
  /**
880
1084
  * Note: comment-mention → notification fan-out lives on the server
881
- * (`@objectstack/plugin-audit` registers a `sys_comment` afterInsert
882
- * hook that parses the `mentions` JSON and writes one `sys_notification`
883
- * row per recipient). The client's only job is to ensure
1085
+ * (`@objectstack/plugin-audit` registers a `sys_comment` afterInsert hook
1086
+ * that parses the `mentions` JSON and calls `messaging.emit('collab.mention')`
1087
+ * ADR-0030 single ingress which materializes one `sys_inbox_message` per
1088
+ * recipient that the bell then reads). The client's only job is to ensure
884
1089
  * `sys_comment.mentions` carries the real id list (see handleAddComment
885
- * /handleAddReply below). Deployments without plugin-audit will not
1090
+ * /handleAddReply below). Deployments without the messaging pipeline will not
886
1091
  * deliver bell notifications, which is the expected degradation.
887
1092
  */
888
1093
  const handleAddComment = useCallback(async (text) => {
@@ -1126,57 +1331,44 @@ export function RecordDetailView({ dataSource, objects, onEdit, objectNameOverri
1126
1331
  successMessage: actionSuccess(objectDef.name, a.name, a.successMessage),
1127
1332
  }),
1128
1333
  }));
1129
- // Inject approval actions — only when the approvals plugin is
1130
- // available and an active process exists for this object.
1131
- if (approvals.available && approvals.processes.length > 0) {
1132
- if (approvals.canSubmit) {
1133
- base.push({
1134
- name: 'submit_approval',
1135
- type: 'approval',
1136
- target: 'submit_approval',
1137
- label: t('approvals.submitForApproval', { defaultValue: 'Submit for Approval' }),
1138
- icon: 'send',
1139
- variant: 'default',
1140
- locations: ['record_header'],
1141
- refreshAfter: true,
1142
- successMessage: t('approvals.submitSuccess', { defaultValue: 'Approval request submitted' }),
1143
- ...(approvals.processes.length === 1
1144
- ? { params: { processName: approvals.processes[0].name } }
1145
- : {
1146
- collectParams: [{
1147
- name: 'processName',
1148
- label: t('approvals.process', { defaultValue: 'Process' }),
1149
- type: 'select',
1150
- required: true,
1151
- options: approvals.processes.map((p) => ({
1152
- value: p.name,
1153
- label: p.label || p.name,
1154
- })),
1155
- }, {
1156
- name: 'comment',
1157
- label: t('approvals.comment', { defaultValue: 'Comment (optional)' }),
1158
- type: 'text',
1159
- multiline: true,
1160
- }],
1161
- }),
1162
- });
1163
- }
1164
- if (approvals.canRecall) {
1165
- base.push({
1166
- name: 'recall_approval',
1167
- type: 'approval',
1168
- target: 'recall_approval',
1169
- label: t('approvals.recall', { defaultValue: 'Recall' }),
1170
- icon: 'undo',
1171
- variant: 'outline',
1172
- locations: ['record_header'],
1173
- refreshAfter: true,
1174
- confirmText: t('approvals.recallConfirm', {
1175
- defaultValue: 'Recall this pending approval request?',
1176
- }),
1177
- successMessage: t('approvals.recallSuccess', { defaultValue: 'Approval recalled' }),
1178
- });
1179
- }
1334
+ // Inject approval actions — only when the current user is a pending
1335
+ // approver for this record (ADR-0019: approvals are opened by a flow
1336
+ // node, so there is no manual submit/recall; an approver records a
1337
+ // decision that resumes the flow down its approve/reject edge).
1338
+ if (approvals.available && approvals.canDecide) {
1339
+ const commentParam = {
1340
+ name: 'comment',
1341
+ label: t('approvals.comment', { defaultValue: 'Comment (optional)' }),
1342
+ type: 'text',
1343
+ multiline: true,
1344
+ };
1345
+ base.push({
1346
+ name: 'approve_request',
1347
+ type: 'approval',
1348
+ target: 'approve_request',
1349
+ label: t('approvals.approve', { defaultValue: 'Approve' }),
1350
+ icon: 'check',
1351
+ variant: 'default',
1352
+ locations: ['record_header'],
1353
+ refreshAfter: true,
1354
+ collectParams: [commentParam],
1355
+ successMessage: t('approvals.approveSuccess', { defaultValue: 'Approved' }),
1356
+ });
1357
+ base.push({
1358
+ name: 'reject_request',
1359
+ type: 'approval',
1360
+ target: 'reject_request',
1361
+ label: t('approvals.reject', { defaultValue: 'Reject' }),
1362
+ icon: 'x',
1363
+ variant: 'destructive',
1364
+ locations: ['record_header'],
1365
+ refreshAfter: true,
1366
+ confirmText: t('approvals.rejectConfirm', {
1367
+ defaultValue: 'Reject this approval request?',
1368
+ }),
1369
+ collectParams: [commentParam],
1370
+ successMessage: t('approvals.rejectSuccess', { defaultValue: 'Rejected' }),
1371
+ });
1180
1372
  }
1181
1373
  return base;
1182
1374
  })();
@@ -1191,12 +1383,15 @@ export function RecordDetailView({ dataSource, objects, onEdit, objectNameOverri
1191
1383
  // surfaces as header `+ New` / `View All` buttons and per-row Edit /
1192
1384
  // Delete controls.
1193
1385
  const baseAppUrl = appName ? `/apps/${appName}` : '';
1194
- const related = childRelations.map(({ childObject, childLabel, referenceField }) => {
1386
+ const related = childRelations.map(({ childObject, childLabel, referenceField, title: titleOverride, columns: columnsOverride }) => {
1195
1387
  const childObjectDef = objects.find((o) => o.name === childObject);
1196
1388
  const parentId = pureRecordId || '';
1197
- const localizedTitle = childObjectDef
1198
- ? objectLabel({ name: childObjectDef.name, label: childObjectDef.label || childLabel })
1199
- : childLabel;
1389
+ // A `relatedListTitle` on the relationship wins; else fall back to the
1390
+ // localized child-object label.
1391
+ const localizedTitle = titleOverride
1392
+ || (childObjectDef
1393
+ ? objectLabel({ name: childObjectDef.name, label: childObjectDef.label || childLabel })
1394
+ : childLabel);
1200
1395
  const buildNewUrl = () => {
1201
1396
  const qs = new URLSearchParams({ [referenceField]: parentId }).toString();
1202
1397
  return `${baseAppUrl}/${childObject}/new${qs ? `?${qs}` : ''}`;
@@ -1263,7 +1458,20 @@ export function RecordDetailView({ dataSource, objects, onEdit, objectNameOverri
1263
1458
  api: childObject,
1264
1459
  data: childRelatedData[childObject] || [],
1265
1460
  referenceField,
1461
+ // Explicit columns from `relatedListColumns` on the relationship; when
1462
+ // absent the related-list renderer auto-derives them from the child
1463
+ // object's fields.
1464
+ ...(Array.isArray(columnsOverride) && columnsOverride.length > 0
1465
+ ? { columns: columnsOverride }
1466
+ : {}),
1266
1467
  icon: childObjectDef?.icon,
1468
+ // Surface the child object's canonical display field so the
1469
+ // right-rail can show meaningful labels (`user_agent`, `email`,
1470
+ // …) instead of opaque IDs like `kCc8mhJr0bRs0r9Ykd09…`.
1471
+ displayField: childObjectDef?.displayNameField ||
1472
+ (Array.isArray(childObjectDef?.compactLayout)
1473
+ ? childObjectDef.compactLayout[0]
1474
+ : undefined),
1267
1475
  onNew,
1268
1476
  onViewAll,
1269
1477
  onRowClick,
@@ -1307,7 +1515,7 @@ export function RecordDetailView({ dataSource, objects, onEdit, objectNameOverri
1307
1515
  }),
1308
1516
  };
1309
1517
  // eslint-disable-next-line react-hooks/exhaustive-deps
1310
- }, [objectDef?.name, pureRecordId, childRelatedData, actionRefreshKey, appName, navigate, dataSource, t, objectLabel, objects, historyEnabled, historyEntries, historyLoading, approvals.available, approvals.processes, approvals.canSubmit, approvals.canRecall, approvals.pendingRequest, approvals.latestRequest, embedded]);
1518
+ }, [objectDef?.name, pureRecordId, childRelatedData, actionRefreshKey, appName, navigate, dataSource, t, objectLabel, objects, historyEnabled, historyEntries, historyLoading, approvals.available, approvals.canDecide, approvals.pendingRequest, approvals.latestRequest, embedded]);
1311
1519
  if (isLoading) {
1312
1520
  return _jsx(SkeletonDetail, {});
1313
1521
  }
@@ -1489,51 +1697,58 @@ export function RecordDetailView({ dataSource, objects, onEdit, objectNameOverri
1489
1697
  // Per-object opt-outs read from `objectDef.detail.*`. Lets
1490
1698
  // catalog/atomic objects (product, task, ...) keep a focused
1491
1699
  // single-column layout instead of inheriting the rail.
1700
+ showReferenceRail: objectDef?.detail?.showReferenceRail === true || undefined,
1492
1701
  hideReferenceRail: objectDef?.detail?.hideReferenceRail === true || undefined,
1493
1702
  hideRelatedTab: objectDef?.detail?.hideRelatedTab === true || undefined,
1494
1703
  ...(assignedSlots ? { slots: assignedSlots } : {}),
1495
1704
  });
1496
- return (_jsxs("div", { className: "h-full bg-background overflow-hidden flex flex-col relative", children: [_jsxs("div", { className: "absolute top-2 sm:top-4 right-2 sm:right-4 z-50 flex items-center gap-2", children: [recordPresence.length > 0 && (_jsx(PresenceAvatars, { users: recordPresence, size: "sm", maxVisible: 3, showStatus: true })), _jsx(ManagedByBadge, { managedBy: objectDef?.managedBy })] }), _jsx(RecordContextProvider, { objectName: objectName, recordId: pureRecordId, data: pageRecord, objectSchema: objectDef, dataSource: dataSource, embedded: embedded, headerSystemActions: synthSystemActions, isFavorite: isRecordFavorite, onToggleFavorite: favoriteRecord ? handleToggleRecordFavorite : undefined, children: _jsx(HighlightFieldsProvider, { children: _jsx(DiscussionContextProvider, { items: feedItems, onAddComment: handleAddComment, onAddReply: handleAddReply, onToggleReaction: handleToggleReaction, mentionSuggestions: mentionSuggestions, children: _jsx(ActionProvider, { context: { record: pageRecord || {}, objectName, user: currentUser }, onConfirm: confirmHandler, onToast: toastHandler, onNavigate: navigateHandler, onParamCollection: paramCollectionHandler, handlers: { api: apiHandler, flow: flowHandler, script: serverActionHandler, modal: serverActionHandler, approval: approvalHandler }, children: _jsxs("div", { className: "flex-1 overflow-hidden flex flex-row", children: [_jsxs("div", { className: "flex-1 overflow-auto p-3 sm:p-4 lg:p-6 scroll-pb-48", children: [originFrom?.pathname && originFrom?.label && (_jsxs(Link, { to: originFrom.pathname, className: "inline-flex items-center gap-1 mb-3 text-sm text-muted-foreground hover:text-foreground transition-colors", children: [_jsx(ChevronLeft, { className: "h-4 w-4" }), _jsx("span", { children: originFrom.label })] })), _jsx(SchemaRenderer, { schema: renderedPage }), showAutoDiscussion && (_jsx("div", { className: "mt-6", children: _jsx(RecordChatterPanel, { config: {
1497
- position: 'bottom',
1498
- collapsible: false,
1499
- feed: {
1500
- enableReactions: true,
1501
- enableThreading: true,
1502
- showCommentInput: true,
1503
- },
1504
- }, items: feedItems, onAddComment: handleAddComment, onAddReply: handleAddReply, onToggleReaction: handleToggleReaction, mentionSuggestions: mentionSuggestions }) }))] }), _jsx(MetadataPanel, { open: showDebug, sections: [{ title: 'Page Schema', data: renderedPage }] })] }) }) }) }) }), _jsx(ActionConfirmDialog, { state: confirmState, onOpenChange: (open) => {
1705
+ return (_jsxs("div", { className: "h-full bg-background overflow-hidden flex flex-col relative", children: [_jsxs("div", { className: "absolute top-2 sm:top-4 right-2 sm:right-4 z-50 flex items-center gap-2", children: [recordPresence.length > 0 && (_jsx(PresenceAvatars, { users: recordPresence, size: "sm", maxVisible: 3, showStatus: true })), _jsx(ManagedByBadge, { managedBy: objectDef?.managedBy })] }), _jsx(RecordContextProvider, { objectName: objectName, recordId: pureRecordId, data: pageRecord, objectSchema: objectDef, dataSource: dataSource, embedded: embedded, headerSystemActions: synthSystemActions, isFavorite: isRecordFavorite, onToggleFavorite: favoriteRecord ? handleToggleRecordFavorite : undefined, children: _jsx(HighlightFieldsProvider, { children: _jsx(DiscussionContextProvider, { items: feedItems, onAddComment: handleAddComment, onAddReply: handleAddReply, onToggleReaction: handleToggleReaction, mentionSuggestions: mentionSuggestions, children: _jsxs(ActionProvider, { context: { record: pageRecord || {}, objectName, user: currentUser }, onConfirm: confirmHandler, onToast: toastHandler, onNavigate: navigateHandler, onParamCollection: paramCollectionHandler, onResultDialog: resultDialogHandler, onModal: modalHandler, handlers: { api: apiHandler, flow: flowHandler, script: serverActionHandler, approval: approvalHandler }, children: [_jsxs("div", { className: "flex-1 overflow-hidden flex flex-row", children: [_jsxs("div", { className: "flex-1 overflow-auto p-3 sm:p-4 lg:p-6 scroll-pb-48", children: [originFrom?.pathname && originFrom?.label && (_jsxs(Link, { to: originFrom.pathname, className: "inline-flex items-center gap-1 mb-3 text-sm text-muted-foreground hover:text-foreground transition-colors", children: [_jsx(ChevronLeft, { className: "h-4 w-4" }), _jsx("span", { children: originFrom.label })] })), _jsx(SchemaRenderer, { schema: renderedPage }), showAutoDiscussion && (_jsx("div", { className: "mt-6", children: _jsx(RecordChatterPanel, { config: {
1706
+ position: 'bottom',
1707
+ collapsible: false,
1708
+ feed: {
1709
+ enableReactions: true,
1710
+ enableThreading: true,
1711
+ showCommentInput: true,
1712
+ },
1713
+ }, items: feedItems, onAddComment: handleAddComment, onAddReply: handleAddReply, onToggleReaction: handleToggleReaction, mentionSuggestions: mentionSuggestions }) }))] }), _jsx(MetadataPanel, { open: showDebug, sections: [{ title: 'Page Schema', data: renderedPage }] })] }), modalElement] }) }) }) }), _jsx(ActionConfirmDialog, { state: confirmState, onOpenChange: (open) => {
1505
1714
  if (!open)
1506
1715
  setConfirmState(s => ({ ...s, open: false }));
1507
1716
  } }), _jsx(ActionParamDialog, { state: paramState, onOpenChange: (open) => {
1508
1717
  if (!open)
1509
1718
  setParamState(s => ({ ...s, open: false }));
1510
- } })] }));
1719
+ } }), _jsx(ActionResultDialog, { state: resultDialogState, onAcknowledge: () => {
1720
+ resultDialogState.resolve?.();
1721
+ setResultDialogState({ open: false });
1722
+ } }), _jsx(FlowRunner, { state: screenFlow, authFetch: authFetch, baseUrl: import.meta.env.VITE_SERVER_URL || '', dataSource: dataSource, objects: objects, onClose: () => setScreenFlow(null), onComplete: () => { setScreenFlow(null); setActionRefreshKey(k => k + 1); } })] }));
1511
1723
  }
1512
- return (_jsxs("div", { className: "h-full bg-background overflow-hidden flex flex-col relative", children: [_jsxs("div", { className: "absolute top-2 sm:top-4 right-2 sm:right-4 z-50 flex items-center gap-2", children: [recordPresence.length > 0 && (_jsx(PresenceAvatars, { users: recordPresence, size: "sm", maxVisible: 3, showStatus: true })), _jsx(ManagedByBadge, { managedBy: objectDef?.managedBy })] }), _jsxs("div", { className: "flex-1 overflow-hidden flex flex-row", children: [_jsx("div", { className: "flex-1 overflow-auto p-3 sm:p-4 lg:p-6 scroll-pb-48", children: _jsx(ActionProvider, { context: { record: {}, objectName, user: currentUser }, onConfirm: confirmHandler, onToast: toastHandler, onNavigate: navigateHandler, onParamCollection: paramCollectionHandler, handlers: { api: apiHandler, flow: flowHandler, script: serverActionHandler, modal: serverActionHandler, approval: approvalHandler }, children: _jsx(DetailView, { schema: detailSchema, dataSource: dataSource, objectLabel: objectLabel({ name: objectDef.name, label: objectDef.label }), isFavorite: isRecordFavorite, onToggleFavorite: favoriteRecord ? handleToggleRecordFavorite : undefined, onDataLoaded: (record) => {
1513
- if (!record || typeof record !== 'object')
1514
- return;
1515
- // Resolve the same way DetailView's header does, so the
1516
- // breadcrumb matches the on-page title (e.g. "David Kim"
1517
- // instead of "#lead-1778…").
1518
- const resolved = getRecordDisplayName(objectDef, record);
1519
- if (resolved && resolved !== recordTitle && resolved !== 'Untitled') {
1520
- setRecordTitle(resolved);
1521
- }
1522
- }, onEdit: () => {
1523
- onEdit({ id: pureRecordId });
1524
- }, discussionSlot: _jsx(RecordChatterPanel, { config: {
1525
- position: 'bottom',
1526
- collapsible: false,
1527
- feed: {
1528
- enableReactions: true,
1529
- enableThreading: true,
1530
- showCommentInput: true,
1531
- },
1532
- }, items: feedItems, onAddComment: handleAddComment, onAddReply: handleAddReply, onToggleReaction: handleToggleReaction }) }, actionRefreshKey) }) }), _jsx(MetadataPanel, { open: showDebug, sections: [{ title: 'View Schema', data: detailSchema }] })] }), _jsx(ActionConfirmDialog, { state: confirmState, onOpenChange: (open) => {
1724
+ return (_jsxs("div", { className: "h-full bg-background overflow-hidden flex flex-col relative", children: [_jsxs("div", { className: "absolute top-2 sm:top-4 right-2 sm:right-4 z-50 flex items-center gap-2", children: [recordPresence.length > 0 && (_jsx(PresenceAvatars, { users: recordPresence, size: "sm", maxVisible: 3, showStatus: true })), _jsx(ManagedByBadge, { managedBy: objectDef?.managedBy })] }), _jsxs("div", { className: "flex-1 overflow-hidden flex flex-row", children: [_jsx("div", { className: "flex-1 overflow-auto p-3 sm:p-4 lg:p-6 scroll-pb-48", children: _jsx("div", { className: "mx-auto w-full max-w-[1400px]", children: _jsxs(ActionProvider, { context: { record: {}, objectName, user: currentUser }, onConfirm: confirmHandler, onToast: toastHandler, onNavigate: navigateHandler, onParamCollection: paramCollectionHandler, onResultDialog: resultDialogHandler, onModal: modalHandler, handlers: { api: apiHandler, flow: flowHandler, script: serverActionHandler, approval: approvalHandler }, children: [_jsx(DetailView, { schema: detailSchema, dataSource: dataSource, objectLabel: objectLabel({ name: objectDef.name, label: objectDef.label }), isFavorite: isRecordFavorite, onToggleFavorite: favoriteRecord ? handleToggleRecordFavorite : undefined, onDataLoaded: (record) => {
1725
+ if (!record || typeof record !== 'object')
1726
+ return;
1727
+ // Resolve the same way DetailView's header does, so the
1728
+ // breadcrumb matches the on-page title (e.g. "David Kim"
1729
+ // instead of "#lead-1778…").
1730
+ const resolved = getRecordDisplayName(objectDef, record);
1731
+ if (resolved && resolved !== recordTitle && resolved !== 'Untitled') {
1732
+ setRecordTitle(resolved);
1733
+ }
1734
+ }, onEdit: () => {
1735
+ onEdit({ id: pureRecordId });
1736
+ }, discussionSlot: _jsx(RecordChatterPanel, { config: {
1737
+ position: 'bottom',
1738
+ collapsible: false,
1739
+ feed: {
1740
+ enableReactions: true,
1741
+ enableThreading: true,
1742
+ showCommentInput: true,
1743
+ },
1744
+ }, items: feedItems, onAddComment: handleAddComment, onAddReply: handleAddReply, onToggleReaction: handleToggleReaction }) }, actionRefreshKey), modalElement] }) }) }), _jsx(MetadataPanel, { open: showDebug, sections: [{ title: 'View Schema', data: detailSchema }] })] }), _jsx(ActionConfirmDialog, { state: confirmState, onOpenChange: (open) => {
1533
1745
  if (!open)
1534
1746
  setConfirmState(s => ({ ...s, open: false }));
1535
1747
  } }), _jsx(ActionParamDialog, { state: paramState, onOpenChange: (open) => {
1536
1748
  if (!open)
1537
1749
  setParamState(s => ({ ...s, open: false }));
1538
- } })] }));
1750
+ } }), _jsx(ActionResultDialog, { state: resultDialogState, onAcknowledge: () => {
1751
+ resultDialogState.resolve?.();
1752
+ setResultDialogState({ open: false });
1753
+ } }), _jsx(FlowRunner, { state: screenFlow, authFetch: authFetch, baseUrl: import.meta.env.VITE_SERVER_URL || '', dataSource: dataSource, objects: objects, onClose: () => setScreenFlow(null), onComplete: () => { setScreenFlow(null); setActionRefreshKey(k => k + 1); } })] }));
1539
1754
  }