@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,6 +11,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
11
11
  */
12
12
  import { useMemo, useState, useCallback, useEffect, useRef, lazy, Suspense } from 'react';
13
13
  import { useParams, useSearchParams, useNavigate, useLocation } from 'react-router-dom';
14
+ import { parseUserFilterParams, applyUserFilterParams } from './userFilterUrlState';
14
15
  const ObjectChart = lazy(() => import('@object-ui/plugin-charts').then((m) => ({ default: m.ObjectChart })));
15
16
  const ImportWizard = lazy(() => import('@object-ui/plugin-grid').then((m) => ({ default: m.ImportWizard })));
16
17
  import { ListView } from '@object-ui/plugin-list';
@@ -24,6 +25,8 @@ import { useFavorites } from '../hooks/useFavorites';
24
25
  import { getIcon } from '../utils/getIcon';
25
26
  import { MetadataPanel, useMetadataInspector } from './MetadataInspector';
26
27
  import { ViewConfigPanel } from './ViewConfigPanel';
28
+ import { useMetadataClient } from './metadata-admin/useMetadata';
29
+ import { persistRuntimeMetadata, createRuntimeMetadata } from './runtime-metadata-persistence';
27
30
  import { CreateViewDialog } from './CreateViewDialog';
28
31
  import { PageHeader } from '../layout/PageHeader';
29
32
  import { useMobileViewSwitcherRegistration } from '../layout/MobileViewSwitcherContext';
@@ -34,13 +37,11 @@ import { resolveManagedByEmptyState } from '../utils/managedByEmptyState';
34
37
  import { useObjectActions } from '../hooks/useObjectActions';
35
38
  import { useObjectTranslation, useObjectLabel } from '@object-ui/i18n';
36
39
  import { usePermissions } from '@object-ui/permissions';
37
- import { useAuth, createAuthenticatedFetch } from '@object-ui/auth';
40
+ import { useAuth } from '@object-ui/auth';
38
41
  import { useRealtimeSubscription, useConflictResolution } from '@object-ui/collaboration';
39
42
  import { ActionProvider, useNavigationOverlay, SchemaRenderer } from '@object-ui/react';
40
43
  import { toast } from 'sonner';
41
- import { ActionConfirmDialog } from './ActionConfirmDialog';
42
- import { ActionParamDialog } from './ActionParamDialog';
43
- import { resolveActionParams } from '../utils/resolveActionParams';
44
+ import { useConsoleActionRuntime } from '../hooks/useConsoleActionRuntime';
44
45
  /** Map view types to Lucide icons (Airtable-style) */
45
46
  const VIEW_TYPE_ICONS = {
46
47
  grid: TableIcon,
@@ -87,121 +88,39 @@ function substituteFilterTokens(filter, currentUserId) {
87
88
  };
88
89
  return filter.map(sub);
89
90
  }
90
- /**
91
- * Translate a NamedListView spec object (shape: `type`, `label`, `columns`,
92
- * `filter`, `sort`, `kanban`/`chart`/`gantt`/... sub-blocks, `bulkActions`,
93
- * `rowActions`, `pagination`, ...) into the `sys_view` storage shape that the
94
- * server's `sys_view` object schema actually exposes (snake_case scalars +
95
- * `*_json` text columns for complex shapes).
96
- *
97
- * The server rejects any other column name (`bulkActions`, `objectName`,
98
- * `isPinned`, ...) with `table sys_view has no column named …`, and knex
99
- * flattens raw arrays into positional bindings which mangles the SQL — so
100
- * every write path that targets `sys_view` MUST go through this helper.
101
- */
102
- function toSysViewPayload(config, objectName, opts = {}) {
103
- const VIEW_TYPE_KEYS = [
104
- 'kanban', 'calendar', 'timeline', 'gantt',
105
- 'gallery', 'map', 'chart', 'grid',
106
- ];
107
- // Fold view-type-specific sub-blocks plus any non-storage NamedListView
108
- // fields into a single `config_json` blob so the round-trip preserves
109
- // everything the renderer might need (bulkActions, rowActions, pagination,
110
- // navigation, emptyState, exportOptions, rowHeight, isPinned, isDefault,
111
- // visibility, sortOrder, …).
112
- const subConfig = {};
113
- for (const k of VIEW_TYPE_KEYS) {
114
- if (config[k] && typeof config[k] === 'object') {
115
- Object.assign(subConfig, config[k]);
116
- }
117
- }
118
- const EXTRA_CONFIG_KEYS = [
119
- 'bulkActions', 'bulkActionDefs', 'rowActions', 'pagination', 'navigation',
120
- 'emptyState', 'exportOptions', 'rowHeight',
121
- 'isPinned', 'isDefault', 'visibility', 'sortOrder',
122
- 'showSort',
123
- ];
124
- for (const k of EXTRA_CONFIG_KEYS) {
125
- if (config[k] !== undefined)
126
- subConfig[k] = config[k];
91
+ export function ObjectView({ dataSource, objects, onEdit, externalRefreshKey }) {
92
+ const { objectName } = useParams();
93
+ const { t } = useObjectTranslation();
94
+ // Resolve the object definition up front. When it's missing we render the
95
+ // "object not found" empty state *here*, before the inner component mounts.
96
+ // This is the key to keeping the Rules of Hooks satisfied: ObjectViewInner
97
+ // holds ~50 hooks and must call them unconditionally, so the missing-object
98
+ // branch lives in this thin wrapper instead of as a mid-component early
99
+ // return. The inner subtree then mounts/unmounts as a whole (object exists
100
+ // doesn't) rather than toggling the number of hooks executed per render.
101
+ const objectDef = objects.find((o) => o.name === objectName);
102
+ if (!objectDef) {
103
+ return (_jsx("div", { className: "h-full p-4 flex items-center justify-center", children: _jsxs(Empty, { children: [_jsx("div", { className: "mx-auto mb-4 flex h-12 w-12 items-center justify-center rounded-full bg-muted", children: _jsx(TableIcon, { className: "h-6 w-6 text-muted-foreground" }) }), _jsx(EmptyTitle, { children: t('console.objectView.objectNotFound') }), _jsxs(EmptyDescription, { children: [t('console.objectView.objectNotFoundDescription', { objectName }), ' ', t('console.objectView.objectNotFoundHint')] })] }) }));
127
104
  }
128
- const incomingColumns = Array.isArray(config.columns) && config.columns.length > 0
129
- ? config.columns
130
- : (opts.defaultColumns ?? []);
131
- const viewType = config.type || 'grid';
132
- const baseLabel = config.label || config.name || 'Untitled View';
133
- const slug = baseLabel
134
- .toLowerCase()
135
- .replace(/[^a-z0-9]+/g, '_')
136
- .replace(/^_+|_+$/g, '')
137
- .slice(0, 60) || 'view';
138
- return {
139
- name: `${slug}_${Date.now().toString(36)}`,
140
- label: baseLabel,
141
- object_name: objectName,
142
- view_type: viewType,
143
- columns_json: JSON.stringify(incomingColumns),
144
- filters_json: config.filter ? JSON.stringify(config.filter) : null,
145
- sort_json: config.sort ? JSON.stringify(config.sort) : null,
146
- config_json: Object.keys(subConfig).length > 0
147
- ? JSON.stringify(subConfig)
148
- : null,
149
- page_size: config.pageSize ?? 25,
150
- show_search: config.showSearch !== false,
151
- show_filters: config.showFilters !== false,
152
- managed_by: 'user',
153
- };
105
+ return (_jsx(ObjectViewInner, { dataSource: dataSource, objects: objects, onEdit: onEdit, externalRefreshKey: externalRefreshKey }));
154
106
  }
155
107
  /**
156
- * Inverse of {@link toSysViewPayload}. Decodes a raw `sys_view` record
157
- * (snake_case fields + `*_json` text columns) back into the NamedListView
158
- * spec shape (`type`, `columns`, `filter`, `sort`, plus everything stashed
159
- * inside `config_json`) so the rest of the UI — ViewTabBar, ListView, the
160
- * grid renderer — can consume it without caring about the storage layer.
161
- *
162
- * Robust to fixtures/mocks that already store the spec shape directly
163
- * (older tests, the in-memory dev adapter): if `*_json` is missing we fall
164
- * back to `sv.columns` / `sv.filter` / `sv.sort` as-is.
108
+ * Inner ObjectView body. Only mounted by {@link ObjectView} once the object
109
+ * definition is known to exist, so every hook below runs unconditionally on
110
+ * every render of this component no early return sits between hook calls.
165
111
  */
166
- function fromSysViewRecord(sv) {
167
- const parse = (raw) => {
168
- if (raw == null)
169
- return undefined;
170
- if (typeof raw !== 'string')
171
- return raw;
172
- try {
173
- return JSON.parse(raw);
174
- }
175
- catch {
176
- return undefined;
177
- }
178
- };
179
- const columns = parse(sv.columns_json) ?? sv.columns;
180
- const filter = parse(sv.filters_json) ?? sv.filter;
181
- const sort = parse(sv.sort_json) ?? sv.sort;
182
- const extra = parse(sv.config_json) ?? {};
183
- return {
184
- ...sv,
185
- ...extra,
186
- type: sv.view_type ?? sv.type ?? 'grid',
187
- objectName: sv.object_name ?? sv.objectName,
188
- columns,
189
- filter,
190
- sort,
191
- showSearch: sv.show_search ?? sv.showSearch,
192
- showFilters: sv.show_filters ?? sv.showFilters,
193
- pageSize: sv.page_size ?? sv.pageSize,
194
- };
195
- }
196
- export function ObjectView({ dataSource, objects, onEdit, externalRefreshKey }) {
112
+ function ObjectViewInner({ dataSource, objects, onEdit, externalRefreshKey }) {
197
113
  const navigate = useNavigate();
198
114
  const { appName, objectName, viewId } = useParams();
199
115
  const [searchParams, setSearchParams] = useSearchParams();
200
116
  const location = useLocation();
201
117
  const { showDebug } = useMetadataInspector();
202
118
  const { t } = useObjectTranslation();
203
- const { objectLabel, objectDescription: objectDesc, viewLabel, viewEmptyState, actionLabel, actionConfirm, actionSuccess, fieldLabel, fieldOptionLabel } = useObjectLabel();
119
+ const { objectLabel, objectDescription: objectDesc, viewLabel, viewEmptyState, actionLabel, actionConfirm, actionSuccess, actionParamText, fieldLabel, fieldOptionLabel } = useObjectLabel();
204
120
  const { isFavorite, toggleFavorite } = useFavorites();
121
+ // ADR-0034: runtime view edits persist via the metadata draft/publish
122
+ // model (the `sys_view` table is retired).
123
+ const metadataClient = useMetadataClient();
205
124
  // Inline view config panel state (Airtable-style right sidebar)
206
125
  const [showViewConfigPanel, setShowViewConfigPanel] = useState(false);
207
126
  const [viewConfigPanelMode, setViewConfigPanelMode] = useState('edit');
@@ -243,28 +162,23 @@ export function ObjectView({ dataSource, objects, onEdit, externalRefreshKey })
243
162
  const handleViewConfigSave = useCallback((draft) => {
244
163
  setViewDraft(draft);
245
164
  setRefreshKey(k => k + 1);
246
- // Persist to backend if dataSource supports it
247
- if (dataSource?.updateViewConfig) {
248
- const objName = objectName;
249
- const vid = draft.id;
250
- if (objName && vid) {
251
- dataSource.updateViewConfig(objName, vid, draft).catch((err) => {
252
- console.error('[ViewConfigPanel] Failed to persist view config:', err);
253
- });
254
- }
255
- else {
256
- console.warn('[ViewConfigPanel] Cannot persist view config: missing objectName or viewId.');
257
- }
165
+ // ADR-0034: stage a per-item draft via the metadata seam; an explicit
166
+ // Publish (RuntimeDraftBar) promotes it + records a version.
167
+ const vid = draft.id;
168
+ if (metadataClient && vid) {
169
+ persistRuntimeMetadata('view', vid, draft, { metadataClient }).catch((err) => {
170
+ console.error('[ViewConfigPanel] Failed to persist view config:', err);
171
+ });
258
172
  }
259
173
  else {
260
- console.warn('[ViewConfigPanel] dataSource.updateViewConfig is not available. View config saved locally only.');
174
+ console.warn('[ViewConfigPanel] Cannot persist view config: missing metadataClient or viewId.');
261
175
  }
262
- }, [dataSource, objectName]);
176
+ }, [metadataClient]);
263
177
  /** Create a new view via the config panel */
264
178
  const handleViewCreate = useCallback(async (config) => {
265
179
  try {
266
180
  let createdId;
267
- if (dataSource?.create) {
181
+ if (metadataClient) {
268
182
  // Prefill sensible defaults so the saved view renders rows
269
183
  // immediately even if the user didn't pick columns yet.
270
184
  const objectDef = objects?.find?.((o) => o.name === objectName);
@@ -305,16 +219,14 @@ export function ObjectView({ dataSource, objects, onEdit, externalRefreshKey })
305
219
  spec.gallery = { ...existing, visibleFields: incomingColumns };
306
220
  }
307
221
  }
308
- if (typeof dataSource?.createView === 'function') {
309
- const created = await dataSource.createView(objectName, spec);
310
- createdId = created?.name || config?.name;
311
- }
312
- else if (dataSource?.create) {
313
- // Legacy fallback for adapters that don't expose createView.
314
- const payload = toSysViewPayload(spec, objectName, { defaultColumns });
315
- const created = await dataSource.create('sys_view', payload);
316
- createdId = created?.id ?? created?._id;
317
- }
222
+ // ADR-0034: a new view is created as an invisible per-item
223
+ // draft via the metadata seam; an explicit Publish promotes it.
224
+ // UI-layer concerns (default columns, kanban/gallery massaging
225
+ // above, and the auto-activation below) stay here.
226
+ const draftName = String(config?.name ?? config?.id ?? spec?.id ?? '');
227
+ createdId = await createRuntimeMetadata('view', draftName, spec, {
228
+ metadataClient,
229
+ });
318
230
  }
319
231
  setShowViewConfigPanel(false);
320
232
  setViewConfigPanelMode('edit');
@@ -334,20 +246,32 @@ export function ObjectView({ dataSource, objects, onEdit, externalRefreshKey })
334
246
  catch (err) {
335
247
  console.error('[ViewConfigPanel] Failed to create view:', err);
336
248
  }
337
- }, [dataSource, objectName, objects, navigate, viewId]);
249
+ }, [dataSource, objectName, objects, navigate, viewId, metadataClient]);
338
250
  // Record count tracking for footer
339
251
  const [recordCount, setRecordCount] = useState(undefined);
340
252
  // Admin users automatically get design tools (no toggle needed)
341
253
  const { user, activeOrganization } = useAuth();
342
254
  const isAdmin = user?.role === 'admin';
343
255
  const { can } = usePermissions();
344
- // Get Object Definition
256
+ // Get Object Definition. The outer ObjectView wrapper already guards the
257
+ // missing-object case, so this always resolves while this component is
258
+ // mounted — every hook below can therefore run unconditionally.
345
259
  const objectDef = objects.find((o) => o.name === objectName);
346
- if (!objectDef) {
347
- return (_jsx("div", { className: "h-full p-4 flex items-center justify-center", children: _jsxs(Empty, { children: [_jsx("div", { className: "mx-auto mb-4 flex h-12 w-12 items-center justify-center rounded-full bg-muted", children: _jsx(TableIcon, { className: "h-6 w-6 text-muted-foreground" }) }), _jsx(EmptyTitle, { children: t('console.objectView.objectNotFound') }), _jsxs(EmptyDescription, { children: [t('console.objectView.objectNotFoundDescription', { objectName }), ' ', t('console.objectView.objectNotFoundHint')] })] }) }));
348
- }
349
260
  // Refresh trigger — bumped after view CRUD or external data mutations.
350
261
  const [refreshKey, setRefreshKey] = useState(0);
262
+ // Shared console action runtime: confirm/param/result dialogs, the
263
+ // authenticated api/flow/server-action handlers, SPA navigation, and the
264
+ // paused screen-flow runner. The same runtime PageView mounts (#1605).
265
+ // ObjectView additionally feeds its confirm/toast handlers into
266
+ // useObjectActions below, so it consumes the hook directly (rather than the
267
+ // ConsoleActionRuntimeProvider wrapper).
268
+ const actionRuntime = useConsoleActionRuntime({
269
+ dataSource,
270
+ objects,
271
+ objectName: objectDef.name,
272
+ onRefresh: () => setRefreshKey((k) => k + 1),
273
+ });
274
+ const { confirmHandler, toastHandler } = actionRuntime;
351
275
  // Resolve which generic CRUD affordances belong in the toolbar for
352
276
  // this object's lifecycle bucket (`managedBy`). config tables show
353
277
  // New/Edit/Delete but no CSV Import; system / append-only / better-auth
@@ -364,10 +288,11 @@ export function ObjectView({ dataSource, objects, onEdit, externalRefreshKey })
364
288
  }, [externalRefreshKey]);
365
289
  // Import wizard open/close state — toolbar entry triggers it.
366
290
  const [showImport, setShowImport] = useState(false);
367
- // ─── User-defined views (sys_view) ──────────────────────────────────
368
- // Saved views created via the ViewConfigPanel ("Add View") are persisted
369
- // to the `sys_view` object. We fetch them here and merge into `views` so
370
- // the ViewTabBar can render them alongside metadata-defined listViews.
291
+ // ─── User-defined views (metadata overlay) ──────────────────────────
292
+ // Saved views created via the ViewConfigPanel ("Add View") live in the
293
+ // metadata overlay (`/meta/view`). We fetch them via `listViews` and merge
294
+ // into `views` so the ViewTabBar renders them alongside metadata-defined
295
+ // listViews.
371
296
  const [savedViews, setSavedViews] = useState([]);
372
297
  useEffect(() => {
373
298
  let cancelled = false;
@@ -375,10 +300,8 @@ export function ObjectView({ dataSource, objects, onEdit, externalRefreshKey })
375
300
  setSavedViews([]);
376
301
  return;
377
302
  }
378
- // ADR-0005: use the metadata overlay API instead of writing to
379
- // the physical `sys_view` table (which has incompatible columns).
380
- // Falls back to the legacy `find('sys_view', ...)` path only when
381
- // the adapter doesn't expose `listViews` (e.g. test mocks).
303
+ // Read saved views from the metadata overlay (`/meta/view`) via the
304
+ // adapter's `listViews`. Adapters without it surface no saved views.
382
305
  if (typeof dataSource?.listViews === 'function') {
383
306
  dataSource.listViews(objectName)
384
307
  .then((rows) => {
@@ -405,41 +328,9 @@ export function ObjectView({ dataSource, objects, onEdit, externalRefreshKey })
405
328
  });
406
329
  return () => { cancelled = true; };
407
330
  }
408
- if (!dataSource?.find) {
409
- setSavedViews([]);
410
- return;
411
- }
412
- dataSource
413
- .find('sys_view', {
414
- $filter: ['object_name', '=', objectName],
415
- $orderby: [{ field: 'created_at', order: 'asc' }],
416
- $top: 200,
417
- })
418
- .then((res) => {
419
- if (cancelled)
420
- return;
421
- const rows = Array.isArray(res)
422
- ? res
423
- : Array.isArray(res?.data) ? res.data
424
- : Array.isArray(res?.records) ? res.records
425
- : Array.isArray(res?.value) ? res.value
426
- : [];
427
- // Defensive client-side filter: only keep rows that look like
428
- // sys_view records for *this* object. Adapters that don't
429
- // honour $filter (or test mocks that ignore it) won't pollute
430
- // the view list with arbitrary records. Match either casing —
431
- // the storage column is `object_name`, but older mock fixtures
432
- // and tests may still emit `objectName`.
433
- const filtered = rows
434
- .filter(r => r && (r.object_name === objectName || r.objectName === objectName))
435
- .map(fromSysViewRecord);
436
- setSavedViews(filtered);
437
- })
438
- .catch((err) => {
439
- console.error('[ObjectView] Failed to load sys_view records:', err);
440
- if (!cancelled)
441
- setSavedViews([]);
442
- });
331
+ // No overlay API available (e.g. a minimal adapter / test mock) → no
332
+ // saved views. The retired `sys_view` table is no longer read.
333
+ setSavedViews([]);
443
334
  return () => { cancelled = true; };
444
335
  }, [dataSource, objectName, refreshKey]);
445
336
  // Persisted per-view config overrides (e.g. density toggle). Saved
@@ -766,13 +657,10 @@ export function ObjectView({ dataSource, objects, onEdit, externalRefreshKey })
766
657
  return;
767
658
  }
768
659
  try {
769
- // ADR-0005 overlay path — `vid` is the view's `name` field
660
+ // Metadata overlay path — `vid` is the view's `name` field.
770
661
  if (typeof dataSource?.updateView === 'function') {
771
662
  await dataSource.updateView(objectName, vid, { label: newName });
772
663
  }
773
- else if (dataSource?.update) {
774
- await dataSource.update('sys_view', vid, { label: newName });
775
- }
776
664
  setRefreshKey(k => k + 1);
777
665
  }
778
666
  catch (err) {
@@ -780,34 +668,6 @@ export function ObjectView({ dataSource, objects, onEdit, externalRefreshKey })
780
668
  toast.error(t('objectViewActions.renameFailed'));
781
669
  }
782
670
  }, [dataSource, objectName, isSavedView, t]);
783
- // Promise-based confirm/param dialogs — declared early so destructive
784
- // handlers (delete, etc.) can `await confirmHandler(...)` for a proper
785
- // Airtable-style confirmation flow.
786
- const [confirmState, setConfirmState] = useState({ open: false, message: '' });
787
- const [paramState, setParamState] = useState({ open: false, params: [] });
788
- const confirmHandler = useCallback((message, options) => {
789
- return new Promise((resolve) => {
790
- setConfirmState({ open: true, message, options, resolve });
791
- });
792
- }, []);
793
- const paramCollectionHandler = useCallback((params, action) => {
794
- return new Promise((resolve) => {
795
- // List_item actions stash the row record under params._rowRecord
796
- // (see ObjectGrid → onRowAction). Pull it out so resolveActionParams
797
- // can pre-fill `defaultFromRow` params from the row's current values.
798
- const row = action?.params && !Array.isArray(action.params)
799
- ? action.params._rowRecord
800
- : undefined;
801
- const resolved = resolveActionParams(params, {
802
- objectName: objectName || objectDef?.name || '',
803
- objects: objects || [],
804
- fieldLabel,
805
- fieldOptionLabel,
806
- row,
807
- });
808
- setParamState({ open: true, params: resolved, resolve });
809
- });
810
- }, [objectName, objectDef, objects, fieldLabel, fieldOptionLabel]);
811
671
  const handleDeleteView = useCallback(async (vid) => {
812
672
  if (!dataSource)
813
673
  return;
@@ -829,9 +689,6 @@ export function ObjectView({ dataSource, objects, onEdit, externalRefreshKey })
829
689
  if (typeof dataSource?.deleteView === 'function') {
830
690
  await dataSource.deleteView(objectName, vid);
831
691
  }
832
- else if (dataSource?.delete) {
833
- await dataSource.delete('sys_view', vid);
834
- }
835
692
  // If we deleted the active view, fall back to the first remaining view.
836
693
  if (vid === activeViewId) {
837
694
  const fallback = views.find((v) => v.id !== vid);
@@ -845,58 +702,6 @@ export function ObjectView({ dataSource, objects, onEdit, externalRefreshKey })
845
702
  toast.error(t('objectViewActions.deleteFailed'));
846
703
  }
847
704
  }, [dataSource, isSavedView, activeViewId, views, viewId, navigate, t, confirmHandler]);
848
- const handleDuplicateView = useCallback(async (vid) => {
849
- if (!dataSource)
850
- return;
851
- const source = views.find((v) => v.id === vid);
852
- if (!source)
853
- return;
854
- try {
855
- // ADR-0005 overlay path — store the full NamedListView spec
856
- // shape directly under a unique `name`. No legacy sys_view
857
- // column-flattening required.
858
- const baseName = String(source.name || vid).toLowerCase()
859
- .replace(/[^a-z0-9_]+/g, '_').replace(/^_+|_+$/g, '') || 'view';
860
- const newName = `${baseName}_copy_${Date.now().toString(36)}`;
861
- // Drop `id` so the overlay row is keyed purely by `name`; copying
862
- // the source's `id` would collide with the source view in the
863
- // tab-bar dedup logic and silently shadow it.
864
- const { id: _omitId, ...rest } = source;
865
- const spec = {
866
- ...rest,
867
- name: newName,
868
- label: `${source.label || vid} (Copy)`,
869
- isDefault: false,
870
- isPinned: false,
871
- data: source.data || { provider: 'object', object: objectName },
872
- object: source.object || objectName,
873
- };
874
- let newId;
875
- if (typeof dataSource?.createView === 'function') {
876
- const created = await dataSource.createView(objectName, spec);
877
- newId = created?.name || newName;
878
- }
879
- else if (dataSource?.create) {
880
- const payload = toSysViewPayload(spec, objectName);
881
- const created = await dataSource.create('sys_view', payload);
882
- newId = created?.id ?? created?._id;
883
- }
884
- setRefreshKey(k => k + 1);
885
- // Auto-activate the duplicate (Airtable parity).
886
- if (newId) {
887
- if (viewId) {
888
- navigate(`../${newId}`, { relative: 'path' });
889
- }
890
- else {
891
- navigate(`view/${newId}`);
892
- }
893
- }
894
- }
895
- catch (err) {
896
- console.error('[ViewTabBar] Failed to duplicate view:', err);
897
- toast.error('Failed to duplicate view');
898
- }
899
- }, [dataSource, views, objectName, navigate, viewId]);
900
705
  const handlePinView = useCallback(async (vid, pinned) => {
901
706
  if (!dataSource)
902
707
  return;
@@ -908,9 +713,6 @@ export function ObjectView({ dataSource, objects, onEdit, externalRefreshKey })
908
713
  if (typeof dataSource?.updateView === 'function') {
909
714
  await dataSource.updateView(objectName, vid, { isPinned: pinned });
910
715
  }
911
- else if (dataSource?.update) {
912
- await dataSource.update('sys_view', vid, { isPinned: pinned });
913
- }
914
716
  setRefreshKey(k => k + 1);
915
717
  }
916
718
  catch (err) {
@@ -922,23 +724,18 @@ export function ObjectView({ dataSource, objects, onEdit, externalRefreshKey })
922
724
  return;
923
725
  if (!isSavedView(vid)) {
924
726
  toast.error(t('console.objectView.cannotEditMetaView')
925
- || 'System view — duplicate it to mark a default.');
727
+ || 'System view — it cannot be set as a default.');
926
728
  return;
927
729
  }
928
730
  try {
929
731
  // Clear `isDefault` on all other saved views, then set this one.
930
- const hasOverlay = typeof dataSource?.updateView === 'function';
732
+ if (typeof dataSource?.updateView !== 'function')
733
+ return;
734
+ const updateView = dataSource.updateView;
931
735
  const updates = savedViews
932
736
  .filter((sv) => (sv.id || sv._id) !== vid && sv.isDefault)
933
- .map((sv) => {
934
- const id = sv.id || sv._id;
935
- return hasOverlay
936
- ? dataSource.updateView(objectName, id, { isDefault: false })
937
- : dataSource.update('sys_view', id, { isDefault: false });
938
- });
939
- updates.push(hasOverlay
940
- ? dataSource.updateView(objectName, vid, { isDefault: true })
941
- : dataSource.update('sys_view', vid, { isDefault: true }));
737
+ .map((sv) => updateView(objectName, sv.id || sv._id, { isDefault: false }));
738
+ updates.push(updateView(objectName, vid, { isDefault: true }));
942
739
  await Promise.all(updates);
943
740
  setRefreshKey(k => k + 1);
944
741
  }
@@ -959,15 +756,12 @@ export function ObjectView({ dataSource, objects, onEdit, externalRefreshKey })
959
756
  catch { /* ignore */ }
960
757
  // Best-effort: also persist `sortOrder` on each saved view so other
961
758
  // sessions / users can pick up the order from the backend.
962
- if (dataSource) {
963
- const hasOverlay = typeof dataSource?.updateView === 'function';
759
+ if (typeof dataSource?.updateView === 'function') {
760
+ const updateView = dataSource.updateView;
964
761
  const savedIdSet = new Set(savedViews.map((sv) => sv.id || sv._id));
965
762
  const updates = orderedIds
966
763
  .filter(id => savedIdSet.has(id))
967
- .map((id, idx) => hasOverlay
968
- ? dataSource.updateView(objectName, id, { sortOrder: idx })
969
- : dataSource.update?.('sys_view', id, { sortOrder: idx }))
970
- .filter(Boolean);
764
+ .map((id, idx) => updateView(objectName, id, { sortOrder: idx }));
971
765
  try {
972
766
  await Promise.all(updates);
973
767
  }
@@ -980,10 +774,10 @@ export function ObjectView({ dataSource, objects, onEdit, externalRefreshKey })
980
774
  const handleConfigView = useCallback((vid) => {
981
775
  // System (metadata-defined) views are read-only — opening the
982
776
  // ViewConfigPanel against one would let the user save changes that
983
- // never persist. Steer them to "Duplicate view" instead.
777
+ // never persist.
984
778
  if (!isSavedView(vid)) {
985
779
  toast.error(t('console.objectView.cannotEditMetaView')
986
- || 'System view — duplicate it to make changes.');
780
+ || 'System view — it cannot be edited.');
987
781
  return;
988
782
  }
989
783
  if (vid !== activeViewId)
@@ -994,16 +788,12 @@ export function ObjectView({ dataSource, objects, onEdit, externalRefreshKey })
994
788
  const handleAddView = useCallback(() => {
995
789
  setShowCreateViewDialog(true);
996
790
  }, []);
997
- // ─── ActionProvider handlers for schema-driven toolbar actions ──────
791
+ // Current user also used below for `{current_user_id}` filter-token
792
+ // substitution. The schema-action handlers (toast/navigate/api/flow/server)
793
+ // now live in the shared `useConsoleActionRuntime` hook (declared earlier).
998
794
  const currentUser = user
999
795
  ? { id: user.id, name: user.name, avatar: user.image }
1000
796
  : FALLBACK_USER;
1001
- const toastHandler = useCallback((message, options) => {
1002
- if (options?.type === 'error')
1003
- toast.error(message);
1004
- else
1005
- toast.success(message);
1006
- }, []);
1007
797
  // Action system for toolbar operations — refreshKey moved up (declared earlier).
1008
798
  // Wired to confirmHandler/toastHandler so deletes use the Shadcn AlertDialog
1009
799
  // and Sonner toast instead of native window.confirm.
@@ -1014,200 +804,10 @@ export function ObjectView({ dataSource, objects, onEdit, externalRefreshKey })
1014
804
  onEdit,
1015
805
  onRefresh: () => setRefreshKey(k => k + 1),
1016
806
  onConfirm: confirmHandler,
807
+ // ToastHandler's `type` is a string-literal union — a subset of the
808
+ // looser `{ type?: string }` useObjectActions declares; cast is sound.
1017
809
  onToast: toastHandler,
1018
810
  });
1019
- const navigateHandler = useCallback((url, options) => {
1020
- if (options?.external || options?.newTab) {
1021
- window.open(url, '_blank', 'noopener,noreferrer');
1022
- }
1023
- else {
1024
- navigate(url);
1025
- }
1026
- }, [navigate]);
1027
- // Authenticated fetch for direct backend calls (e.g. flow trigger,
1028
- // schema actions targeting absolute API paths). Declared before
1029
- // apiHandler so the latter can close over it.
1030
- const authFetch = useMemo(() => createAuthenticatedFetch(), []);
1031
- const apiHandler = useCallback(async (action) => {
1032
- try {
1033
- const target = action.target || action.name;
1034
- const params = action.params || {};
1035
- // Absolute HTTP target (e.g. /api/v1/auth/organization/invite-member,
1036
- // http://..., https://...) — bypass dataSource and call the API
1037
- // directly through the authenticated fetch wrapper so:
1038
- // - Authorization: Bearer <token> is injected
1039
- // - X-Tenant-ID is injected (multi-tenant routing)
1040
- // - Same-origin cookies (better-auth.session_token) ride along
1041
- //
1042
- // This is the canonical path for schema actions on managed-by
1043
- // tables (sys_user/invite_user, sys_session/revoke, …) where
1044
- // generic CRUD does not apply.
1045
- const targetStr = typeof target === 'string' ? target : '';
1046
- const isAbsolute = targetStr.startsWith('/') || /^https?:\/\//i.test(targetStr);
1047
- if (isAbsolute) {
1048
- const baseUrl = import.meta.env.VITE_SERVER_URL || '';
1049
- // Row context is stashed on params under `_rowRecord` by the
1050
- // row-action dispatcher (see ObjectGrid → onRowAction). Pull
1051
- // it out before assembling the request body.
1052
- const rawParams = { ...params };
1053
- const rowRecord = rawParams._rowRecord;
1054
- delete rawParams._rowRecord;
1055
- // Interpolate `{field}` tokens in the target URL from the
1056
- // row record. Lets actions hit data-API endpoints like
1057
- // `PATCH /api/v1/sys_api_key/{id}` without bespoke wiring.
1058
- let resolvedTarget = targetStr;
1059
- if (rowRecord && /\{[a-z_][a-z0-9_]*\}/i.test(resolvedTarget)) {
1060
- resolvedTarget = resolvedTarget.replace(/\{([a-z_][a-z0-9_]*)\}/gi, (_, k) => {
1061
- const v = rowRecord[k];
1062
- return v == null ? '' : encodeURIComponent(String(v));
1063
- });
1064
- }
1065
- const url = resolvedTarget.startsWith('http') ? resolvedTarget : `${baseUrl}${resolvedTarget}`;
1066
- // Apply bodyShape: 'flat' (default) keeps user params at top
1067
- // level; { wrap: 'data' } nests them under that key while
1068
- // `recordIdParam` / `organizationId` stay flat (better-auth
1069
- // organization/update semantics).
1070
- const wrap = action.bodyShape && typeof action.bodyShape === 'object' && action.bodyShape.wrap
1071
- ? action.bodyShape.wrap
1072
- : undefined;
1073
- const body = wrap
1074
- ? { [wrap]: rawParams }
1075
- : { ...rawParams };
1076
- // Inject row id (or chosen row field) for list_item actions.
1077
- if (rowRecord && action.recordIdParam) {
1078
- const rowField = action.recordIdField || 'id';
1079
- const rowValue = rowRecord[rowField];
1080
- if (rowValue != null)
1081
- body[action.recordIdParam] = rowValue;
1082
- }
1083
- // Auto-inject organizationId only for better-auth org-scoped
1084
- // endpoints. Data-API endpoints (/api/v1/{object}/{id}) must
1085
- // NOT receive a stray organizationId field — that would try
1086
- // to overwrite the row's tenant column.
1087
- const isAuthOrgEndpoint = /\/api\/v1\/auth\//.test(resolvedTarget);
1088
- if (isAuthOrgEndpoint && !body.organizationId && activeOrganization?.id) {
1089
- body.organizationId = activeOrganization.id;
1090
- }
1091
- // Merge static body fragment last so constants override any
1092
- // user-collected values (e.g. resend:true on resend-invite,
1093
- // revoked:true on revoke-api-key).
1094
- if (action.bodyExtra && typeof action.bodyExtra === 'object') {
1095
- Object.assign(body, action.bodyExtra);
1096
- }
1097
- const method = (action.method || 'POST').toUpperCase();
1098
- const init = {
1099
- method,
1100
- headers: { 'Content-Type': 'application/json' },
1101
- credentials: 'include',
1102
- };
1103
- // GET/DELETE conventionally have no body; for everything else
1104
- // we serialize. (We don't expect GET here today, but keep the
1105
- // guard for safety.)
1106
- if (method !== 'GET' && method !== 'DELETE') {
1107
- init.body = JSON.stringify(body);
1108
- }
1109
- const res = await authFetch(url, init);
1110
- if (!res.ok) {
1111
- let detail = `HTTP ${res.status}`;
1112
- try {
1113
- const j = await res.json();
1114
- detail = j?.error || j?.message || detail;
1115
- }
1116
- catch { /* response body not JSON */ }
1117
- return { success: false, error: detail };
1118
- }
1119
- const data = await res.json().catch(() => ({}));
1120
- if (action.refreshAfter !== false)
1121
- setRefreshKey(k => k + 1);
1122
- return { success: true, data, reload: action.refreshAfter !== false };
1123
- }
1124
- // Generic list-level API handler: update/execute via dataSource
1125
- if (typeof dataSource.execute === 'function') {
1126
- await dataSource.execute(objectDef.name, target, params);
1127
- }
1128
- else if (params.recordId && Object.keys(params).length > 1 && typeof dataSource.update === 'function') {
1129
- await dataSource.update(objectDef.name, params.recordId, params);
1130
- }
1131
- const shouldRefresh = action.refreshAfter !== false;
1132
- if (shouldRefresh) {
1133
- setRefreshKey(k => k + 1);
1134
- }
1135
- return { success: true, reload: shouldRefresh };
1136
- }
1137
- catch (error) {
1138
- return { success: false, error: error.message };
1139
- }
1140
- }, [dataSource, objectDef.name, authFetch, activeOrganization]);
1141
- // Flow action handler — POST to /api/v1/automation/{name}/trigger.
1142
- // Triggered when an Action with `type: 'flow'` is invoked from list-level
1143
- // locations (list_toolbar, list_item). For list_item the row's recordId is
1144
- // expected in `action.params.recordId`.
1145
- const flowHandler = useCallback(async (action) => {
1146
- const flowName = action.target || action.name;
1147
- if (!flowName) {
1148
- return { success: false, error: 'No flow target provided for flow action' };
1149
- }
1150
- try {
1151
- const baseUrl = import.meta.env.VITE_SERVER_URL || '';
1152
- const params = action.params || {};
1153
- const res = await authFetch(`${baseUrl}/api/v1/automation/${encodeURIComponent(flowName)}/trigger`, {
1154
- method: 'POST',
1155
- headers: { 'Content-Type': 'application/json' },
1156
- body: JSON.stringify({
1157
- recordId: params.recordId,
1158
- objectName: objectDef.name,
1159
- params,
1160
- }),
1161
- });
1162
- const json = await res.json().catch(() => null);
1163
- if (!res.ok || (json && json.success === false)) {
1164
- const errMsg = json?.error || `Flow "${flowName}" failed (HTTP ${res.status})`;
1165
- return { success: false, error: errMsg };
1166
- }
1167
- const shouldRefresh = action.refreshAfter !== false;
1168
- if (shouldRefresh) {
1169
- setRefreshKey(k => k + 1);
1170
- }
1171
- return { success: true, data: json?.data, reload: shouldRefresh };
1172
- }
1173
- catch (error) {
1174
- return { success: false, error: error.message };
1175
- }
1176
- }, [authFetch, objectDef.name]);
1177
- // Server-side action handler — POST to /api/v1/actions/{object}/{action}.
1178
- // For list-toolbar/list-item `script` and `modal` actions whose `target`
1179
- // matches a server-registered handler. selectedIds (from action.params)
1180
- // is forwarded so bulk handlers like massUpdateStage / addToCampaign work.
1181
- const serverActionHandler = useCallback(async (action) => {
1182
- const targetName = action.target || action.name;
1183
- if (!targetName) {
1184
- return { success: false, error: 'No action target provided' };
1185
- }
1186
- const params = (action.params && !Array.isArray(action.params))
1187
- ? action.params
1188
- : {};
1189
- try {
1190
- const baseUrl = import.meta.env.VITE_SERVER_URL || '';
1191
- const obj = action.objectName || objectDef.name || 'global';
1192
- const res = await authFetch(`${baseUrl}/api/v1/actions/${encodeURIComponent(obj)}/${encodeURIComponent(targetName)}`, {
1193
- method: 'POST',
1194
- headers: { 'Content-Type': 'application/json' },
1195
- body: JSON.stringify({ recordId: params.recordId, params }),
1196
- });
1197
- const json = await res.json().catch(() => null);
1198
- if (!res.ok || (json && json.success === false)) {
1199
- const errMsg = json?.error || `Action "${targetName}" failed (HTTP ${res.status})`;
1200
- return { success: false, error: errMsg };
1201
- }
1202
- const shouldRefresh = action.refreshAfter !== false;
1203
- if (shouldRefresh)
1204
- setRefreshKey(k => k + 1);
1205
- return { success: true, data: json?.data, reload: shouldRefresh };
1206
- }
1207
- catch (error) {
1208
- return { success: false, error: error.message };
1209
- }
1210
- }, [authFetch, objectDef.name]);
1211
811
  // Real-time: auto-refresh when server reports data changes
1212
812
  const { lastMessage: realtimeMessage } = useRealtimeSubscription({
1213
813
  channel: `object:${objectDef.name}`,
@@ -1261,17 +861,33 @@ export function ObjectView({ dataSource, objects, onEdit, externalRefreshKey })
1261
861
  * which matches the shape consumed by the list view's data fetcher when
1262
862
  * merging base filters.
1263
863
  */
864
+ // Dep on the serialized `filter[...]` entries only — `uf_*` user-filter
865
+ // params also live in the URL and must not invalidate this memo (a new
866
+ // array identity here rebuilds the whole list schema and refetches).
867
+ const filterParamsKey = Array.from(searchParams.entries())
868
+ .filter(([k]) => k.startsWith('filter['))
869
+ .map(([k, v]) => `${k}=${v}`)
870
+ .join('&');
1264
871
  const urlFilters = useMemo(() => {
1265
872
  const out = [];
1266
- searchParams.forEach((value, key) => {
873
+ new URLSearchParams(filterParamsKey).forEach((value, key) => {
1267
874
  const m = /^filter\[(.+)\]$/.exec(key);
1268
875
  if (m && m[1] && value !== '') {
1269
876
  out.push([m[1], '=', value]);
1270
877
  }
1271
878
  });
1272
879
  return out;
1273
- // eslint-disable-next-line react-hooks/exhaustive-deps
1274
- }, [searchParams.toString()]);
880
+ }, [filterParamsKey]);
881
+ /**
882
+ * End-user filter selections restored from `uf_*` URL params (ADR-0047
883
+ * persistence). Captured once per ObjectView mount — UserFilters only
884
+ * reads them at its own mount, and later URL writes must not churn the
885
+ * schema memo.
886
+ */
887
+ const [initialUfSelections] = useState(() => parseUserFilterParams(new URLSearchParams(window.location.search)));
888
+ const handleUserFilterSelectionsChange = useCallback((selections) => {
889
+ setSearchParams(prev => applyUserFilterParams(prev, selections), { replace: true });
890
+ }, [setSearchParams]);
1275
891
  // Memoize onNavigate to prevent stale closure in useNavigationOverlay's handleClick
1276
892
  const handleNavOverlayNavigate = useCallback((recordId, action) => {
1277
893
  if (action === 'new_window') {
@@ -1383,16 +999,48 @@ export function ObjectView({ dataSource, objects, onEdit, externalRefreshKey })
1383
999
  }
1384
1000
  if (viewDef.type === 'chart') {
1385
1001
  const chartConfig = viewDef.chart || {};
1002
+ // ADR-0021 (#1890): dataset-bound chart — the single author-facing
1003
+ // shape. Selects dimensions/measures BY NAME and runs through the
1004
+ // governed queryDataset path (numbers consistent across surfaces).
1005
+ if (chartConfig.dataset) {
1006
+ const dims = Array.isArray(chartConfig.dimensions) ? chartConfig.dimensions : [];
1007
+ const vals = Array.isArray(chartConfig.values) ? chartConfig.values : [];
1008
+ return (_jsx(Suspense, { fallback: _jsx("div", { className: "p-4 text-sm text-muted-foreground", children: "Loading chart\u2026" }), children: _jsx(ObjectChart, { dataSource: ds, schema: {
1009
+ type: 'object-chart',
1010
+ dataset: chartConfig.dataset,
1011
+ dimensions: dims,
1012
+ values: vals,
1013
+ chartType: chartConfig.chartType || 'bar',
1014
+ xAxisKey: dims[0],
1015
+ series: vals.map((v) => ({ dataKey: v, label: v })),
1016
+ config: chartConfig.config,
1017
+ className: 'h-[400px] w-full',
1018
+ } }) }, key));
1019
+ }
1020
+ // ObjectChart consumes a structured `aggregate` ({ field, function,
1021
+ // groupBy }) + `xAxisKey` + `series`, NOT the flat spec-level
1022
+ // `xAxisField`/`yAxisFields`/`aggregation` keys. Translate here so the
1023
+ // chart actually runs its aggregate query (otherwise it renders empty).
1024
+ const categoryField = chartConfig.xAxisField || 'name';
1025
+ const valueField = (Array.isArray(chartConfig.yAxisFields) && chartConfig.yAxisFields[0]) || 'value';
1026
+ const aggFn = chartConfig.aggregation || 'count';
1027
+ const series = chartConfig.series && chartConfig.series.length > 0
1028
+ ? chartConfig.series
1029
+ : [{ dataKey: valueField, label: valueField }];
1386
1030
  return (_jsx(Suspense, { fallback: _jsx("div", { className: "p-4 text-sm text-muted-foreground", children: "Loading chart\u2026" }), children: _jsx(ObjectChart, { dataSource: ds, schema: {
1387
1031
  type: 'object-chart',
1388
1032
  objectName: objectDef.name,
1389
- chartType: chartConfig.chartType,
1390
- xAxisField: chartConfig.xAxisField,
1391
- yAxisFields: chartConfig.yAxisFields,
1392
- aggregation: chartConfig.aggregation,
1393
- series: chartConfig.series,
1033
+ chartType: chartConfig.chartType || 'bar',
1034
+ aggregate: {
1035
+ field: valueField,
1036
+ function: aggFn,
1037
+ groupBy: categoryField,
1038
+ },
1039
+ xAxisKey: categoryField,
1040
+ series,
1394
1041
  config: chartConfig.config,
1395
1042
  filter: chartConfig.filter,
1043
+ className: 'h-[400px] w-full',
1396
1044
  } }) }, key));
1397
1045
  }
1398
1046
  const fullSchema = {
@@ -1431,9 +1079,20 @@ export function ObjectView({ dataSource, objects, onEdit, externalRefreshKey })
1431
1079
  persistViewPatch(viewDef.id, viewDef, { columnState: state });
1432
1080
  },
1433
1081
  inlineEdit: viewDef.inlineEdit ?? viewDef.editRecordsInline ?? listSchema.inlineEdit,
1434
- appearance: viewDef.showDescription != null
1435
- ? { showDescription: viewDef.showDescription }
1436
- : listSchema.appearance,
1082
+ // ADR-0047 — spec `appearance` (incl. allowedVisualizations, the
1083
+ // runtime visualization whitelist) flows from the view metadata;
1084
+ // the legacy bare `showDescription` flag is folded in on top.
1085
+ appearance: viewDef.appearance
1086
+ ? (viewDef.showDescription != null
1087
+ ? { ...viewDef.appearance, showDescription: viewDef.showDescription }
1088
+ : viewDef.appearance)
1089
+ : (viewDef.showDescription != null
1090
+ ? { showDescription: viewDef.showDescription }
1091
+ : listSchema.appearance),
1092
+ // Offer the visualization switcher only when the author
1093
+ // whitelisted more than one type; ListView intersects the
1094
+ // whitelist with capability-resolvable types.
1095
+ showViewSwitcher: ((viewDef.appearance ?? listSchema.appearance)?.allowedVisualizations?.length ?? 0) > 1,
1437
1096
  // Propagate toolbar/display flags for all view types
1438
1097
  showSearch: viewDef.showSearch ?? listSchema.showSearch,
1439
1098
  showSort: viewDef.showSort ?? listSchema.showSort,
@@ -1473,23 +1132,42 @@ export function ObjectView({ dataSource, objects, onEdit, externalRefreshKey })
1473
1132
  * remains for back-compat where the action lives elsewhere.
1474
1133
  */
1475
1134
  rowActionDefs: (Array.isArray(objectDef?.actions)
1476
- ? objectDef.actions.filter((a) => Array.isArray(a?.locations) && a.locations.includes('list_item'))
1135
+ ? objectDef.actions
1136
+ .filter((a) => Array.isArray(a?.locations) && a.locations.includes('list_item'))
1137
+ // Localize label / confirm / success the same way the
1138
+ // record_header and list_toolbar paths do — the row kebab
1139
+ // previously rendered raw English `a.label`. The `visible`
1140
+ // CEL is forwarded untouched (spread) and evaluated per-row
1141
+ // at render time inside RowActionMenu.
1142
+ .map((a) => ({
1143
+ ...a,
1144
+ label: actionLabel(objectDef.name, a.name, a.label || a.name),
1145
+ ...(a.confirmText !== undefined && {
1146
+ confirmText: actionConfirm(objectDef.name, a.name, a.confirmText),
1147
+ }),
1148
+ ...(a.successMessage !== undefined && {
1149
+ successMessage: actionSuccess(objectDef.name, a.name, a.successMessage),
1150
+ }),
1151
+ }))
1477
1152
  : []),
1478
1153
  bulkActions: viewDef.bulkActions ?? listSchema.bulkActions,
1479
1154
  bulkActionDefs: viewDef.bulkActionDefs ?? listSchema.bulkActionDefs,
1480
1155
  sharing: viewDef.sharing ?? listSchema.sharing,
1481
1156
  addRecord: viewDef.addRecord ?? listSchema.addRecord,
1482
1157
  conditionalFormatting: viewDef.conditionalFormatting ?? listSchema.conditionalFormatting,
1483
- quickFilters: viewDef.quickFilters ?? listSchema.quickFilters,
1484
- userFilters: viewDef.userFilters ?? listSchema.userFilters,
1158
+ // ADR-0053: this is the object default list = "views" mode; the
1159
+ // ViewTabBar above is the only nav control. The in-list Airtable-
1160
+ // style filter rows (quickFilters / userFilters / tabs) belong to
1161
+ // page "filters" mode (InterfaceListPage), so suppress them here.
1162
+ quickFilters: undefined,
1163
+ userFilters: undefined,
1485
1164
  showRecordCount: viewDef.showRecordCount ?? listSchema.showRecordCount,
1486
1165
  allowPrinting: viewDef.allowPrinting ?? listSchema.allowPrinting,
1487
1166
  virtualScroll: viewDef.virtualScroll ?? listSchema.virtualScroll,
1488
1167
  emptyState: viewEmptyState(objectDef.name, viewDef.name || viewDef.id || '', viewDef.emptyState
1489
1168
  ?? listSchema.emptyState
1490
- ?? resolveManagedByEmptyState(objectDef?.managedBy)),
1169
+ ?? resolveManagedByEmptyState(objectDef?.managedBy, t)),
1491
1170
  aria: viewDef.aria ?? listSchema.aria,
1492
- tabs: listSchema.tabs,
1493
1171
  // Propagate filter/sort as default filters/sort for data flow
1494
1172
  ...((() => {
1495
1173
  const combined = [
@@ -1540,12 +1218,26 @@ export function ObjectView({ dataSource, objects, onEdit, externalRefreshKey })
1540
1218
  subtitleField: viewDef.gallery?.subtitleField,
1541
1219
  },
1542
1220
  gantt: {
1221
+ // Spread the full view-defined gantt config first so the
1222
+ // renderer's extended fields (parentField/typeField for the
1223
+ // summary→step hierarchy, baseline*, groupByField,
1224
+ // resourceView/assignee*, tooltipFields, quickFilters, …)
1225
+ // survive; then layer the three required defaults last so an
1226
+ // omitted source value still falls back. (Mirrors the gallery
1227
+ // branch above — a bare whitelist here was dropping every
1228
+ // field past colorField and flattening the chart.)
1229
+ ...(viewDef.gantt || {}),
1543
1230
  startDateField: viewDef.gantt?.startDateField || 'start_date',
1544
1231
  endDateField: viewDef.gantt?.endDateField || 'end_date',
1545
1232
  titleField: viewDef.gantt?.titleField || 'name',
1546
- progressField: viewDef.gantt?.progressField,
1547
- dependenciesField: viewDef.gantt?.dependenciesField,
1548
- colorField: viewDef.gantt?.colorField,
1233
+ },
1234
+ tree: {
1235
+ // Self-referencing tree-grid config (plugin-tree). Spread the
1236
+ // full view-defined tree first so parentField/fields/
1237
+ // defaultExpandedDepth survive; labelField falls back to the
1238
+ // object title. parentField auto-detects when omitted.
1239
+ ...(viewDef.tree || {}),
1240
+ labelField: viewDef.tree?.labelField || viewDef.tree?.titleField || objectDef.titleField || 'name',
1549
1241
  },
1550
1242
  chart: {
1551
1243
  chartType: viewDef.chart?.chartType,
@@ -1589,8 +1281,8 @@ export function ObjectView({ dataSource, objects, onEdit, externalRefreshKey })
1589
1281
  persistViewPatch(viewDef.id, viewDef, { hiddenFields: hidden });
1590
1282
  }, onColumnStateChange: (state) => {
1591
1283
  persistViewPatch(viewDef.id, viewDef, { columnState: state });
1592
- }, dataSource: ds }, key));
1593
- }, [activeView, objectDef, objectName, refreshKey, navOverlay, actions, persistViewPatch, urlFilters]);
1284
+ }, userFilterSelections: initialUfSelections, onUserFilterSelectionsChange: handleUserFilterSelectionsChange, dataSource: ds }, key));
1285
+ }, [activeView, objectDef, objectName, refreshKey, navOverlay, actions, persistViewPatch, urlFilters, initialUfSelections, handleUserFilterSelectionsChange]);
1594
1286
  // Memoize the merged views array so PluginObjectView doesn't get a new
1595
1287
  // reference on every render (which would trigger unnecessary data refetches).
1596
1288
  const mergedViews = useMemo(() => views.map((v) => v.id === activeViewId && viewDraft && viewDraft.id === v.id
@@ -1610,7 +1302,6 @@ export function ObjectView({ dataSource, objects, onEdit, externalRefreshKey })
1610
1302
  viewActions: isAdmin ? [
1611
1303
  { type: 'settings' },
1612
1304
  { type: 'share' },
1613
- { type: 'duplicate' },
1614
1305
  { type: 'delete' },
1615
1306
  ] : [],
1616
1307
  onNavigate: (recordId, mode) => {
@@ -1633,15 +1324,7 @@ export function ObjectView({ dataSource, objects, onEdit, externalRefreshKey })
1633
1324
  }
1634
1325
  },
1635
1326
  }), [objectDef, onEdit, activeView?.showSearch, activeView?.showFilters, activeView?.showSort, activeView?.name, activeView?.label, navigate, viewId, isAdmin, location.pathname, location.search, viewLabel, objectLabel]);
1636
- return (_jsxs(ActionProvider, { context: {
1637
- objectName: objectDef.name,
1638
- user: currentUser,
1639
- // Expose active org so `type: 'url'` actions can template
1640
- // `/organizations/${activeOrganization.slug}/...` etc.
1641
- activeOrganization: activeOrganization
1642
- ? { id: activeOrganization.id, slug: activeOrganization.slug, name: activeOrganization.name }
1643
- : null,
1644
- }, onConfirm: confirmHandler, onToast: toastHandler, onNavigate: navigateHandler, onParamCollection: paramCollectionHandler, handlers: { api: apiHandler, flow: flowHandler, script: serverActionHandler, modal: serverActionHandler }, children: [_jsxs("div", { className: "h-full flex flex-col bg-background min-w-0 overflow-hidden", children: [_jsx("div", { className: "hidden sm:block", children: _jsx(PageHeader, { title: _jsxs("span", { className: "inline-flex items-center gap-2", children: [_jsx("span", { className: "truncate", children: objectLabel(objectDef) }), _jsx(ManagedByBadge, { managedBy: objectDef?.managedBy })] }), description: objectDef.description ? objectDesc(objectDef) : undefined, icon: (() => { const I = getIcon(objectDef?.icon); return _jsx(I, { className: "h-4 w-4" }); })(), actions: _jsxs(_Fragment, { children: [objectName && (_jsx(Button, { size: "sm", variant: "ghost", onClick: () => toggleFavorite({
1327
+ return (_jsxs(ActionProvider, { ...actionRuntime.actionProviderProps, children: [_jsxs("div", { className: "h-full flex flex-col bg-background min-w-0 overflow-hidden", children: [_jsx("div", { className: "hidden sm:block", children: _jsx(PageHeader, { title: _jsxs("span", { className: "inline-flex items-center gap-2", children: [_jsx("span", { className: "truncate", children: objectLabel(objectDef) }), _jsx(ManagedByBadge, { managedBy: objectDef?.managedBy })] }), description: objectDef.description ? objectDesc(objectDef) : undefined, icon: (() => { const I = getIcon(objectDef?.icon); return _jsx(I, { className: "h-4 w-4" }); })(), actions: _jsxs(_Fragment, { children: [objectName && (_jsx(Button, { size: "sm", variant: "ghost", onClick: () => toggleFavorite({
1645
1328
  id: `object:${objectName}`,
1646
1329
  label: objectLabel(objectDef),
1647
1330
  href: `/apps/${appName}/${objectName}`,
@@ -1704,7 +1387,7 @@ export function ObjectView({ dataSource, objects, onEdit, externalRefreshKey })
1704
1387
  readonly: isSystem,
1705
1388
  readonlyReason: isSystem
1706
1389
  ? (t('console.objectView.systemViewReadonly')
1707
- || 'System view defined in code — duplicate to customize.')
1390
+ || 'System view defined in code — read-only.')
1708
1391
  : undefined,
1709
1392
  };
1710
1393
  });
@@ -1713,27 +1396,21 @@ export function ObjectView({ dataSource, objects, onEdit, externalRefreshKey })
1713
1396
  showAddButton: isAdmin,
1714
1397
  showPinnedSection: true,
1715
1398
  showVisibilityGroups: true,
1716
- }, onAddView: isAdmin ? handleAddView : undefined, onRenameView: isAdmin ? handleRenameView : undefined, onDeleteView: isAdmin ? handleDeleteView : undefined, onDuplicateView: isAdmin ? handleDuplicateView : undefined, onPinView: isAdmin ? handlePinView : undefined, onSetDefaultView: isAdmin ? handleSetDefaultView : undefined, onConfigView: isAdmin ? handleConfigView : undefined, onManageViews: isAdmin ? () => setManageViewsOpen(true) : undefined }), isAdmin && (_jsx(ManageViewsDialog, { open: manageViewsOpen, onOpenChange: setManageViewsOpen, views: viewTabItems, activeViewId: activeViewId, viewTypeIcons: VIEW_TYPE_ICONS, onRename: handleRenameView, onDelete: handleDeleteView, onDuplicate: handleDuplicateView, onSetDefault: handleSetDefaultView, onSetPinned: handlePinView, onReorder: handleReorderViews, onAddView: handleAddView, onConfigView: handleConfigView }))] }) }));
1399
+ }, onAddView: isAdmin ? handleAddView : undefined, onRenameView: isAdmin ? handleRenameView : undefined, onDeleteView: isAdmin ? handleDeleteView : undefined, onPinView: isAdmin ? handlePinView : undefined, onSetDefaultView: isAdmin ? handleSetDefaultView : undefined, onConfigView: isAdmin ? handleConfigView : undefined, onManageViews: isAdmin ? () => setManageViewsOpen(true) : undefined }), isAdmin && (_jsx(ManageViewsDialog, { open: manageViewsOpen, onOpenChange: setManageViewsOpen, views: viewTabItems, activeViewId: activeViewId, viewTypeIcons: VIEW_TYPE_ICONS, onRename: handleRenameView, onDelete: handleDeleteView, onSetDefault: handleSetDefaultView, onSetPinned: handlePinView, onReorder: handleReorderViews, onAddView: handleAddView, onConfigView: handleConfigView }))] }) }));
1717
1400
  })(), _jsxs("div", { className: "flex-1 overflow-hidden relative flex flex-row", children: [navOverlay.mode === 'split' && navOverlay.isOpen ? (_jsx(NavigationOverlay, { ...navOverlay, setIsOpen: (open) => { if (!open)
1718
1401
  handleDrawerClose(); }, title: objectLabel(objectDef), onExpand: handleExpandDrawer, expandLabel: t('console.objectView.expandToPage', { defaultValue: 'Open as full page' }), storageKey: `drawer-width:${objectDef.name}`, mainContent: _jsxs("div", { className: "flex-1 min-w-0 relative h-full flex flex-col", children: [_jsx("div", { className: "flex-1 relative overflow-hidden", children: _jsx("div", { className: "h-full overflow-auto", children: _jsx(PluginObjectView, { schema: objectViewSchema, dataSource: dataSource, views: mergedViews, activeViewId: activeViewId, onViewChange: handleViewChange, onEdit: (record) => onEdit?.(record), onRowClick: (record, event) => {
1719
1402
  handleRowClick(record, event);
1720
- }, renderListView: renderListView, onCreateView: handleCreateView, onViewAction: handleViewAction }) }) }), typeof recordCount === 'number' && (_jsx("div", { "data-testid": "record-count-footer", className: "border-t px-3 sm:px-4 py-1.5 text-xs text-muted-foreground bg-muted/5 shrink-0", children: t('console.objectView.recordCount', { count: recordCount }) }))] }), children: (record) => {
1403
+ }, renderListView: renderListView, onCreateView: handleCreateView, hideNamedViewTabs: true, onViewAction: handleViewAction }) }) }), typeof recordCount === 'number' && (_jsx("div", { "data-testid": "record-count-footer", className: "border-t px-3 sm:px-4 py-1.5 text-xs text-muted-foreground bg-muted/5 shrink-0", children: t('console.objectView.recordCount', { count: recordCount }) }))] }), children: (record) => {
1721
1404
  const recordId = (record.id || record._id);
1722
1405
  return (_jsx(RecordDetailView, { dataSource: dataSource, objects: objects, onEdit: onEdit, objectNameOverride: objectDef.name, recordIdOverride: recordId, embedded: true }));
1723
1406
  } })) : (_jsx("div", { className: "flex-1 min-w-0 relative h-full flex flex-col", children: _jsx("div", { className: "flex-1 relative overflow-hidden", children: _jsx("div", { className: "h-full overflow-auto", children: _jsx(PluginObjectView, { schema: objectViewSchema, dataSource: dataSource, views: mergedViews, activeViewId: activeViewId, onViewChange: handleViewChange, onEdit: (record) => onEdit?.(record), onRowClick: (record, event) => {
1724
1407
  handleRowClick(record, event);
1725
- }, renderListView: renderListView, onCreateView: handleCreateView, onViewAction: handleViewAction }) }) }) })), _jsx(MetadataPanel, { open: showDebug && isAdmin, sections: [
1408
+ }, renderListView: renderListView, onCreateView: handleCreateView, hideNamedViewTabs: true, onViewAction: handleViewAction }) }) }) })), _jsx(MetadataPanel, { open: showDebug && isAdmin, sections: [
1726
1409
  { title: 'View Configuration', data: activeView },
1727
1410
  { title: 'Object Definition', data: objectDef },
1728
- ] }), _jsx("div", { "data-testid": "view-config-panel-wrapper", className: `transition-[max-width,opacity] duration-300 ease-in-out overflow-hidden ${showViewConfigPanel && isAdmin ? 'max-w-[280px] opacity-100' : 'max-w-0 opacity-0'}`, children: _jsx(ViewConfigPanel, { open: showViewConfigPanel && isAdmin, onClose: () => { setShowViewConfigPanel(false); setViewConfigPanelMode('edit'); }, mode: viewConfigPanelMode, activeView: activeView, objectDef: objectDef, recordCount: recordCount, onSave: handleViewConfigSave, onViewUpdate: handleViewUpdate, onCreate: handleViewCreate }) }), _jsx(CreateViewDialog, { open: showCreateViewDialog && isAdmin, onOpenChange: setShowCreateViewDialog, existingLabels: views.map((v) => v.label).filter(Boolean), objectDef: objectDef, onCreate: (cfg) => handleViewCreate(cfg) })] }), navOverlay.mode !== 'split' && (_jsx(NavigationOverlay, { ...navOverlay, setIsOpen: (open) => { if (!open)
1411
+ ] }), _jsx("div", { "data-testid": "view-config-panel-wrapper", className: `transition-[max-width,opacity] duration-300 ease-in-out overflow-hidden ${showViewConfigPanel && isAdmin ? 'max-w-[280px] opacity-100' : 'max-w-0 opacity-0'}`, children: _jsx(ViewConfigPanel, { open: showViewConfigPanel && isAdmin, onClose: () => { setShowViewConfigPanel(false); setViewConfigPanelMode('edit'); }, mode: viewConfigPanelMode, activeView: activeView, objectDef: objectDef, recordCount: recordCount, onSave: handleViewConfigSave, onViewUpdate: handleViewUpdate, onCreate: handleViewCreate, metadataClient: metadataClient, onAfterChange: () => setRefreshKey(k => k + 1) }) }), _jsx(CreateViewDialog, { open: showCreateViewDialog && isAdmin, onOpenChange: setShowCreateViewDialog, existingLabels: views.map((v) => v.label).filter(Boolean), objectDef: objectDef, onCreate: (cfg) => handleViewCreate(cfg) })] }), navOverlay.mode !== 'split' && (_jsx(NavigationOverlay, { ...navOverlay, setIsOpen: (open) => { if (!open)
1729
1412
  handleDrawerClose(); }, title: objectLabel(objectDef), onExpand: handleExpandDrawer, expandLabel: t('console.objectView.expandToPage', { defaultValue: 'Open as full page' }), storageKey: `drawer-width:${objectDef.name}`, children: (record) => {
1730
1413
  const recordId = (record.id || record._id);
1731
1414
  return (_jsx(RecordDetailView, { dataSource: dataSource, objects: objects, onEdit: onEdit, objectNameOverride: objectDef.name, recordIdOverride: recordId, embedded: true }));
1732
- } }))] }), _jsx(ActionConfirmDialog, { state: confirmState, onOpenChange: (open) => {
1733
- if (!open)
1734
- setConfirmState({ open: false, message: '' });
1735
- } }), _jsx(ActionParamDialog, { state: paramState, onOpenChange: (open) => {
1736
- if (!open)
1737
- setParamState({ open: false, params: [] });
1738
- } })] }));
1415
+ } }))] }), actionRuntime.dialogs] }));
1739
1416
  }