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