@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
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
|
|
3
|
+
/**
|
|
4
|
+
* CloudConnectionPanel — the RFC 8628 device-code binding state machine,
|
|
5
|
+
* registered as the SDUI widget `cloud-connection:panel`.
|
|
6
|
+
*
|
|
7
|
+
* This is deliberately the ONLY React in the Cloud Connection surface:
|
|
8
|
+
* the page shell, nav placement and labels ship as metadata WITH the
|
|
9
|
+
* `@objectstack/cloud-connection` plugin (cloud ADR-0008 / console
|
|
10
|
+
* SDUI-first direction). The widget talks to the runtime's same-origin
|
|
11
|
+
* `/api/v1/cloud-connection/*` routes.
|
|
12
|
+
*
|
|
13
|
+
* Zero-input flow (ADR runtime-identity-binding §2.3): [Connect] →
|
|
14
|
+
* bind/start (no environment id — the registration is created cloud-side
|
|
15
|
+
* at approval) → the approval page auto-opens in a popup with the code
|
|
16
|
+
* pre-filled and the device named → bind/poll … → bound. The visible
|
|
17
|
+
* user code is the popup-blocked fallback, not the primary path.
|
|
18
|
+
*
|
|
19
|
+
* The runtime credential never reaches the browser — bind/poll persists
|
|
20
|
+
* it server-side and strips it from the response.
|
|
21
|
+
*/
|
|
22
|
+
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
23
|
+
import { Cloud, CloudOff, Copy, ExternalLink, Loader2, AlertCircle, CheckCircle2, Unplug, } from 'lucide-react';
|
|
24
|
+
import { ComponentRegistry } from '@object-ui/core';
|
|
25
|
+
const BASE = '/api/v1/cloud-connection';
|
|
26
|
+
async function getJson(url, init) {
|
|
27
|
+
const resp = await fetch(url, {
|
|
28
|
+
credentials: 'same-origin',
|
|
29
|
+
headers: { 'Content-Type': 'application/json' },
|
|
30
|
+
...init,
|
|
31
|
+
});
|
|
32
|
+
const body = await resp.json().catch(() => ({}));
|
|
33
|
+
if (!resp.ok && body?.success !== true) {
|
|
34
|
+
const msg = body?.error?.message ?? body?.error?.code ?? body?.error ?? `HTTP ${resp.status}`;
|
|
35
|
+
throw new Error(typeof msg === 'string' ? msg : JSON.stringify(msg));
|
|
36
|
+
}
|
|
37
|
+
return body;
|
|
38
|
+
}
|
|
39
|
+
export function CloudConnectionPanel() {
|
|
40
|
+
const [phase, setPhase] = useState({ kind: 'loading' });
|
|
41
|
+
const [busy, setBusy] = useState(false);
|
|
42
|
+
const [copied, setCopied] = useState(false);
|
|
43
|
+
const pollTimer = useRef(null);
|
|
44
|
+
const stopPolling = useCallback(() => {
|
|
45
|
+
if (pollTimer.current) {
|
|
46
|
+
clearTimeout(pollTimer.current);
|
|
47
|
+
pollTimer.current = null;
|
|
48
|
+
}
|
|
49
|
+
}, []);
|
|
50
|
+
const refreshStatus = useCallback(async () => {
|
|
51
|
+
try {
|
|
52
|
+
const body = await getJson(`${BASE}/status`);
|
|
53
|
+
const data = body?.data ?? { environmentId: null, bound: false, connection: null };
|
|
54
|
+
setPhase(data.bound ? { kind: 'bound', status: data } : { kind: 'unbound' });
|
|
55
|
+
}
|
|
56
|
+
catch (err) {
|
|
57
|
+
setPhase({ kind: 'error', message: err?.message ?? String(err) });
|
|
58
|
+
}
|
|
59
|
+
}, []);
|
|
60
|
+
useEffect(() => {
|
|
61
|
+
void refreshStatus();
|
|
62
|
+
return stopPolling;
|
|
63
|
+
}, [refreshStatus, stopPolling]);
|
|
64
|
+
const poll = useCallback((code, startedAt) => {
|
|
65
|
+
const intervalMs = Math.max(code.interval, 2) * 1000;
|
|
66
|
+
const tick = async () => {
|
|
67
|
+
if (Date.now() - startedAt > code.expires_in * 1000) {
|
|
68
|
+
setPhase({ kind: 'error', message: 'The request expired before it was approved. Start again.' });
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
try {
|
|
72
|
+
const body = await getJson(`${BASE}/bind/poll`, {
|
|
73
|
+
method: 'POST',
|
|
74
|
+
body: JSON.stringify({ device_code: code.device_code }),
|
|
75
|
+
});
|
|
76
|
+
if (body?.data?.pending) {
|
|
77
|
+
pollTimer.current = setTimeout(tick, intervalMs);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
if (body?.data?.bound || body?.success) {
|
|
81
|
+
await refreshStatus();
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
setPhase({ kind: 'error', message: body?.error?.code ?? 'Binding failed.' });
|
|
85
|
+
}
|
|
86
|
+
catch (err) {
|
|
87
|
+
setPhase({ kind: 'error', message: err?.message ?? String(err) });
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
pollTimer.current = setTimeout(tick, intervalMs);
|
|
91
|
+
}, [refreshStatus]);
|
|
92
|
+
const connect = useCallback(async () => {
|
|
93
|
+
setBusy(true);
|
|
94
|
+
try {
|
|
95
|
+
const body = await getJson(`${BASE}/bind/start`, { method: 'POST', body: '{}' });
|
|
96
|
+
const code = body?.data;
|
|
97
|
+
if (!code?.device_code || !code?.user_code)
|
|
98
|
+
throw new Error('Device code request failed.');
|
|
99
|
+
// Auto-open the approval page — the GitHub-login moment. Still within
|
|
100
|
+
// the click's transient activation, so popup blockers generally allow
|
|
101
|
+
// it; the code display below is the blocked-popup fallback.
|
|
102
|
+
const link = code.verification_uri_complete ?? code.verification_uri;
|
|
103
|
+
let popupOpened = false;
|
|
104
|
+
if (link) {
|
|
105
|
+
try {
|
|
106
|
+
popupOpened = Boolean(window.open(link, '_blank', 'noopener,width=520,height=720'));
|
|
107
|
+
}
|
|
108
|
+
catch { /* blocked — fallback UI below */ }
|
|
109
|
+
}
|
|
110
|
+
setPhase({ kind: 'waiting', code, popupOpened });
|
|
111
|
+
poll(code, Date.now());
|
|
112
|
+
}
|
|
113
|
+
catch (err) {
|
|
114
|
+
setPhase({ kind: 'error', message: err?.message ?? String(err) });
|
|
115
|
+
}
|
|
116
|
+
finally {
|
|
117
|
+
setBusy(false);
|
|
118
|
+
}
|
|
119
|
+
}, [poll]);
|
|
120
|
+
const disconnect = useCallback(async () => {
|
|
121
|
+
setBusy(true);
|
|
122
|
+
try {
|
|
123
|
+
await getJson(`${BASE}/unbind`, { method: 'POST', body: '{}' });
|
|
124
|
+
await refreshStatus();
|
|
125
|
+
}
|
|
126
|
+
catch (err) {
|
|
127
|
+
setPhase({ kind: 'error', message: err?.message ?? String(err) });
|
|
128
|
+
}
|
|
129
|
+
finally {
|
|
130
|
+
setBusy(false);
|
|
131
|
+
}
|
|
132
|
+
}, [refreshStatus]);
|
|
133
|
+
const copyCode = useCallback(async (code) => {
|
|
134
|
+
try {
|
|
135
|
+
await navigator.clipboard.writeText(code);
|
|
136
|
+
setCopied(true);
|
|
137
|
+
setTimeout(() => setCopied(false), 1500);
|
|
138
|
+
}
|
|
139
|
+
catch { /* clipboard unavailable — user can select the text */ }
|
|
140
|
+
}, []);
|
|
141
|
+
if (phase.kind === 'loading') {
|
|
142
|
+
return (_jsxs("div", { className: "flex items-center gap-2 rounded-lg border p-6 text-sm text-muted-foreground", children: [_jsx(Loader2, { className: "h-4 w-4 animate-spin", "aria-hidden": "true" }), " Checking connection\u2026"] }));
|
|
143
|
+
}
|
|
144
|
+
if (phase.kind === 'error') {
|
|
145
|
+
return (_jsxs("div", { className: "flex flex-col gap-3 rounded-lg border border-destructive/40 bg-destructive/5 p-6", children: [_jsxs("div", { className: "flex items-center gap-2 text-sm text-destructive", children: [_jsx(AlertCircle, { className: "h-4 w-4", "aria-hidden": "true" }), " ", phase.message] }), _jsx("button", { type: "button", className: "self-start rounded-md border px-3 py-1.5 text-sm hover:bg-accent", onClick: () => { stopPolling(); void refreshStatus(); }, children: "Try again" })] }));
|
|
146
|
+
}
|
|
147
|
+
if (phase.kind === 'waiting') {
|
|
148
|
+
const link = phase.code.verification_uri_complete ?? phase.code.verification_uri;
|
|
149
|
+
return (_jsxs("div", { className: "flex flex-col gap-4 rounded-lg border p-6", children: [_jsxs("div", { className: "flex items-center gap-2 text-sm text-muted-foreground", children: [_jsx(Loader2, { className: "h-4 w-4 animate-spin", "aria-hidden": "true" }), phase.popupOpened
|
|
150
|
+
? 'Approve the connection in the window that just opened — this page updates by itself.'
|
|
151
|
+
: 'Waiting for approval in the cloud console…'] }), !phase.popupOpened && link ? (_jsxs("a", { className: "inline-flex items-center gap-1.5 self-start rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90", href: link, target: "_blank", rel: "noreferrer", children: ["Open the approval page ", _jsx(ExternalLink, { className: "h-3.5 w-3.5", "aria-hidden": "true" })] })) : null, _jsxs("div", { className: "flex items-center gap-3", children: [_jsx("code", { className: "rounded-md bg-muted px-4 py-2 text-2xl font-semibold tracking-[0.25em]", children: phase.code.user_code }), _jsxs("button", { type: "button", className: "inline-flex items-center gap-1.5 rounded-md border px-3 py-1.5 text-sm hover:bg-accent", onClick: () => void copyCode(phase.code.user_code), children: [_jsx(Copy, { className: "h-3.5 w-3.5", "aria-hidden": "true" }), " ", copied ? 'Copied' : 'Copy'] })] }), _jsxs("p", { className: "text-sm text-muted-foreground", children: ["The code is pre-filled on the approval page", phase.popupOpened && link ? (_jsxs(_Fragment, { children: [' ', "\u2014 if the window did not appear,", ' ', _jsxs("a", { className: "inline-flex items-center gap-1 text-primary underline-offset-2 hover:underline", href: link, target: "_blank", rel: "noreferrer", children: ["open it here ", _jsx(ExternalLink, { className: "h-3 w-3", "aria-hidden": "true" })] }), "."] })) : '.'] }), _jsx("button", { type: "button", className: "self-start rounded-md border px-3 py-1.5 text-sm hover:bg-accent", onClick: () => { stopPolling(); void refreshStatus(); }, children: "Cancel" })] }));
|
|
152
|
+
}
|
|
153
|
+
if (phase.kind === 'bound') {
|
|
154
|
+
const conn = phase.status.connection ?? {};
|
|
155
|
+
const runtimeId = conn.runtime_id ?? phase.status.runtimeId;
|
|
156
|
+
return (_jsxs("div", { className: "flex flex-col gap-4 rounded-lg border p-6", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(CheckCircle2, { className: "h-5 w-5 text-emerald-600", "aria-hidden": "true" }), _jsx("span", { className: "font-medium", children: "Connected to ObjectStack Cloud" })] }), _jsxs("dl", { className: "grid grid-cols-[auto_1fr] gap-x-6 gap-y-1.5 text-sm", children: [conn.name ? (_jsxs(_Fragment, { children: [_jsx("dt", { className: "text-muted-foreground", children: "Runtime" }), _jsx("dd", { children: conn.name })] })) : null, conn.organization_id ? (_jsxs(_Fragment, { children: [_jsx("dt", { className: "text-muted-foreground", children: "Organization" }), _jsx("dd", { className: "font-mono", children: conn.organization_id })] })) : null, conn.account_email ? (_jsxs(_Fragment, { children: [_jsx("dt", { className: "text-muted-foreground", children: "Approved by" }), _jsx("dd", { children: conn.account_email })] })) : null, runtimeId ? (_jsxs(_Fragment, { children: [_jsx("dt", { className: "text-muted-foreground", children: "Runtime ID" }), _jsx("dd", { className: "font-mono text-xs", children: runtimeId })] })) : null, phase.status.environmentId ? (_jsxs(_Fragment, { children: [_jsx("dt", { className: "text-muted-foreground", children: "Environment" }), _jsx("dd", { className: "font-mono", children: phase.status.environmentId })] })) : null, conn.bound_at ? (_jsxs(_Fragment, { children: [_jsx("dt", { className: "text-muted-foreground", children: "Since" }), _jsx("dd", { children: new Date(conn.bound_at).toLocaleString() })] })) : null] }), _jsx("p", { className: "text-sm text-muted-foreground", children: "Your organization's private packages now appear in the Marketplace under \u201CYour organization\u201D." }), _jsxs("button", { type: "button", disabled: busy, className: "inline-flex items-center gap-1.5 self-start rounded-md border border-destructive/40 px-3 py-1.5 text-sm text-destructive hover:bg-destructive/5 disabled:opacity-50", onClick: () => void disconnect(), children: [_jsx(Unplug, { className: "h-3.5 w-3.5", "aria-hidden": "true" }), " Disconnect"] })] }));
|
|
157
|
+
}
|
|
158
|
+
// unbound — zero input: no environment id, nothing to paste anywhere.
|
|
159
|
+
return (_jsxs("div", { className: "flex flex-col gap-4 rounded-lg border p-6", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(CloudOff, { className: "h-5 w-5 text-muted-foreground", "aria-hidden": "true" }), _jsx("span", { className: "font-medium", children: "Not connected" })] }), _jsx("p", { className: "text-sm text-muted-foreground", children: "Connect this runtime to an ObjectStack control plane to browse your organization's private packages and install them here. Approval is a single click in your cloud account \u2014 no ids or credentials are typed into this page." }), _jsxs("button", { type: "button", disabled: busy, className: "inline-flex items-center gap-1.5 self-start rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90 disabled:opacity-50", onClick: () => void connect(), children: [busy ? _jsx(Loader2, { className: "h-4 w-4 animate-spin", "aria-hidden": "true" }) : _jsx(Cloud, { className: "h-4 w-4", "aria-hidden": "true" }), "Connect"] })] }));
|
|
160
|
+
}
|
|
161
|
+
// SDUI registration: page metadata (shipped by @objectstack/cloud-connection)
|
|
162
|
+
// references this widget by type. The renderer passes the component node as
|
|
163
|
+
// `schema`; the panel needs no properties today.
|
|
164
|
+
ComponentRegistry.register('cloud-connection:panel', () => _jsx(CloudConnectionPanel, {}), {
|
|
165
|
+
namespace: 'app-shell',
|
|
166
|
+
label: 'Cloud Connection Panel',
|
|
167
|
+
category: 'plugin',
|
|
168
|
+
inputs: [],
|
|
169
|
+
});
|
|
@@ -11,5 +11,5 @@ interface AppCardProps {
|
|
|
11
11
|
isFavorite: boolean;
|
|
12
12
|
index?: number;
|
|
13
13
|
}
|
|
14
|
-
export declare function AppCard({ app, onClick, isFavorite, index }: AppCardProps): import("react
|
|
14
|
+
export declare function AppCard({ app, onClick, isFavorite, index }: AppCardProps): import("react").JSX.Element;
|
|
15
15
|
export {};
|
|
@@ -9,7 +9,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
9
9
|
import { Star, StarOff, ArrowUpRight } from 'lucide-react';
|
|
10
10
|
import { Card, CardContent, Button, Badge } from '@object-ui/components';
|
|
11
11
|
import { useObjectTranslation, useObjectLabel } from '@object-ui/i18n';
|
|
12
|
-
import { resolveI18nLabel } from '../../utils';
|
|
12
|
+
import { resolveI18nLabel, appRouteSegment } from '../../utils';
|
|
13
13
|
import { useFavorites } from '../../hooks/useFavorites';
|
|
14
14
|
import { getIcon } from '../../utils/getIcon';
|
|
15
15
|
import { cn } from '@object-ui/components';
|
|
@@ -36,25 +36,19 @@ export function AppCard({ app, onClick, isFavorite, index = 0 }) {
|
|
|
36
36
|
const Icon = getIcon(app.icon);
|
|
37
37
|
const label = appLabel({ name: app.name, label: resolveI18nLabel(app.label, t) });
|
|
38
38
|
const description = appDescription({ name: app.name, description: resolveI18nLabel(app.description, t) });
|
|
39
|
-
const primaryColor = app.branding?.primaryColor;
|
|
40
39
|
const accent = ACCENTS[(hashStr(app.name) + index) % ACCENTS.length];
|
|
41
40
|
const handleToggleFavorite = (e) => {
|
|
42
41
|
e.stopPropagation();
|
|
43
42
|
toggleFavorite({
|
|
44
43
|
id: `app:${app.name}`,
|
|
45
44
|
label,
|
|
46
|
-
|
|
45
|
+
// ADR-0048 — link to the canonical package-id route segment, not the
|
|
46
|
+
// app name, so the favorite opens `/apps/<packageId>` like the nav does.
|
|
47
|
+
href: `/apps/${appRouteSegment(app) ?? app.name}`,
|
|
47
48
|
type: 'object',
|
|
48
49
|
});
|
|
49
50
|
};
|
|
50
|
-
return (_jsxs(Card, {
|
|
51
|
-
if (e.key === 'Enter' || e.key === ' ') {
|
|
52
|
-
e.preventDefault();
|
|
53
|
-
onClick();
|
|
54
|
-
}
|
|
55
|
-
}, "data-testid": `app-card-${app.name}`, style: primaryColor ? { borderColor: undefined } : undefined, children: [_jsx("div", { "aria-hidden": true, className: cn('absolute inset-x-0 top-0 h-1', primaryColor ? '' : accent.solid), style: primaryColor ? { backgroundColor: primaryColor } : undefined }), !primaryColor && (_jsx("div", { "aria-hidden": true, className: cn('absolute inset-0 bg-gradient-to-br opacity-0 transition-opacity duration-300 group-hover:opacity-100', accent.from, accent.to) })), _jsxs(CardContent, { className: "relative p-5", children: [_jsx(Button, { variant: "ghost", size: "sm", className: "absolute top-2 right-2 h-8 w-8 p-0 opacity-0 group-hover:opacity-100 focus-visible:opacity-100 transition-opacity", onClick: handleToggleFavorite, "aria-label": isFavorite
|
|
51
|
+
return (_jsxs(Card, { className: cn('group relative overflow-hidden border border-border/70 bg-card/80 backdrop-blur-sm', 'transition-[transform,box-shadow,border-color] duration-200 hover:-translate-y-0.5 hover:shadow-lg active:scale-[0.985] active:-translate-y-0', 'motion-reduce:transition-none motion-reduce:hover:transform-none', accent.ring), "data-testid": `app-card-${app.name}`, children: [_jsx("button", { type: "button", "aria-label": label, className: "absolute inset-0 z-10 rounded-lg focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2", onClick: onClick, "data-testid": `app-card-open-${app.name}` }), _jsx("div", { "aria-hidden": true, className: cn('absolute inset-0 bg-gradient-to-br opacity-0 transition-opacity duration-300 group-hover:opacity-100', accent.from, accent.to) }), _jsxs(CardContent, { className: "relative flex h-full flex-col p-5", children: [_jsx(Button, { variant: "ghost", size: "sm", className: "absolute top-2 right-2 z-20 h-8 w-8 p-0 opacity-0 transition-opacity group-hover:opacity-100 focus-visible:opacity-100", onClick: handleToggleFavorite, "aria-label": isFavorite
|
|
56
52
|
? t('common.removeFromFavorites', { defaultValue: 'Remove from favorites' }) + ` — ${label}`
|
|
57
|
-
: t('common.addToFavorites', { defaultValue: 'Add to favorites' }) + ` — ${label}`, "aria-pressed": isFavorite, "data-testid": `favorite-btn-${app.name}`, children: isFavorite ? (_jsx(Star, { className: "h-4 w-4 fill-amber-400 text-amber-400" })) : (_jsx(StarOff, { className: "h-4 w-4" })) }), _jsx("div", { className: cn('inline-flex h-14 w-14 items-center justify-center rounded-
|
|
58
|
-
? { backgroundColor: `${primaryColor}1f`, boxShadow: `inset 0 0 0 1px ${primaryColor}33` }
|
|
59
|
-
: undefined, children: _jsx(Icon, { className: cn('h-7 w-7', primaryColor ? '' : accent.text), style: primaryColor ? { color: primaryColor } : undefined }) }), _jsxs("div", { children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("h3", { className: "font-semibold text-base sm:text-lg leading-tight truncate", children: label }), app.isDefault && (_jsx(Badge, { variant: "secondary", className: "shrink-0 text-[10px] px-1.5 py-0", children: t('home.appCard.default', { defaultValue: 'Default' }) }))] }), _jsx("p", { className: cn('text-sm text-muted-foreground mt-1.5 line-clamp-2 min-h-[2.5rem]', !description && 'italic'), children: description || t('home.appCard.noDescription', { defaultValue: 'No description' }) })] }), _jsx("div", { className: "mt-4 flex items-center justify-between text-xs font-medium", children: _jsxs("span", { className: "inline-flex items-center gap-1 text-muted-foreground transition-colors group-hover:text-foreground", children: [t('home.open', { defaultValue: 'Open' }), _jsx(ArrowUpRight, { className: "h-3.5 w-3.5 transition-transform duration-200 group-hover:translate-x-0.5 group-hover:-translate-y-0.5" })] }) })] })] }));
|
|
53
|
+
: t('common.addToFavorites', { defaultValue: 'Add to favorites' }) + ` — ${label}`, "aria-pressed": isFavorite, "data-testid": `favorite-btn-${app.name}`, children: isFavorite ? (_jsx(Star, { className: "h-4 w-4 fill-amber-400 text-amber-400" })) : (_jsx(StarOff, { className: "h-4 w-4" })) }), _jsx("div", { className: cn('inline-flex h-14 w-14 items-center justify-center rounded-2xl mb-4 ring-1 ring-inset', 'bg-gradient-to-br ring-border/40', accent.from, accent.to), children: _jsx(Icon, { className: cn('h-7 w-7', accent.text) }) }), _jsxs("div", { children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("h3", { className: "font-semibold text-base sm:text-lg leading-tight truncate", children: label }), app.isDefault && (_jsx(Badge, { variant: "secondary", className: "shrink-0 text-[10px] px-1.5 py-0", children: t('home.appCard.default', { defaultValue: 'Default' }) }))] }), _jsx("p", { className: "text-sm text-muted-foreground mt-1.5 line-clamp-2 min-h-[2.5rem]", children: description || t('home.appCard.noDescription', { defaultValue: 'No description' }) })] }), _jsx("div", { className: "mt-auto pt-4 flex items-center justify-between text-xs font-medium", children: _jsxs("span", { className: "inline-flex items-center gap-1 text-muted-foreground transition-colors group-hover:text-foreground", children: [t('home.open', { defaultValue: 'Open' }), _jsx(ArrowUpRight, { className: "h-3.5 w-3.5 transition-transform duration-200 group-hover:translate-x-0.5 group-hover:-translate-y-0.5" })] }) })] })] }));
|
|
60
54
|
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { FavoriteItem } from '../../hooks/useFavorites';
|
|
2
|
+
export declare function HomeAppsStrip({ apps, favorites, onOpen, onBrowseMarketplace, isAdmin, }: {
|
|
3
|
+
apps: any[];
|
|
4
|
+
favorites: FavoriteItem[];
|
|
5
|
+
onOpen: (app: any) => void;
|
|
6
|
+
onBrowseMarketplace: () => void;
|
|
7
|
+
isAdmin: boolean;
|
|
8
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* HomeAppsStrip
|
|
4
|
+
*
|
|
5
|
+
* iOS-springboard-style app launcher for Home: vibrant gradient squircle
|
|
6
|
+
* icons with the name beneath. Business users live in a handful of apps and
|
|
7
|
+
* switch via the top-bar AppSwitcher / ⌘K — so Home shows apps as recognizable
|
|
8
|
+
* icons, not a wall of marketing cards.
|
|
9
|
+
*
|
|
10
|
+
* Scales from a few apps to hundreds: a capped grid with a "+N more / Show all"
|
|
11
|
+
* toggle keeps the fold stable no matter how many apps exist. Favorites sort
|
|
12
|
+
* first.
|
|
13
|
+
*
|
|
14
|
+
* @module
|
|
15
|
+
*/
|
|
16
|
+
import { useMemo, useState } from 'react';
|
|
17
|
+
import { LayoutGrid, Store, Star } from 'lucide-react';
|
|
18
|
+
import { Button, cn } from '@object-ui/components';
|
|
19
|
+
import { useObjectTranslation, useObjectLabel } from '@object-ui/i18n';
|
|
20
|
+
import { resolveI18nLabel } from '../../utils';
|
|
21
|
+
import { getIcon } from '../../utils/getIcon';
|
|
22
|
+
const COMPACT_LIMIT = 19;
|
|
23
|
+
// iOS-springboard icon tints: a vibrant gradient per app, assigned
|
|
24
|
+
// deterministically by name so an app keeps its colour across sessions.
|
|
25
|
+
// (Literal class strings so Tailwind's source scan emits them.)
|
|
26
|
+
const ICON_GRADIENTS = [
|
|
27
|
+
'from-blue-500 to-indigo-600',
|
|
28
|
+
'from-violet-500 to-purple-600',
|
|
29
|
+
'from-pink-500 to-rose-600',
|
|
30
|
+
'from-amber-400 to-orange-500',
|
|
31
|
+
'from-emerald-500 to-teal-600',
|
|
32
|
+
'from-sky-500 to-cyan-600',
|
|
33
|
+
'from-fuchsia-500 to-pink-600',
|
|
34
|
+
'from-orange-500 to-red-600',
|
|
35
|
+
'from-indigo-500 to-blue-600',
|
|
36
|
+
'from-teal-500 to-green-600',
|
|
37
|
+
];
|
|
38
|
+
// Soft top-highlight + drop shadow → iOS icon depth/gloss.
|
|
39
|
+
const ICON_GLOSS = 'shadow-[0_4px_10px_-2px_rgb(0_0_0/0.25),inset_0_1px_0_0_rgb(255_255_255/0.45)]';
|
|
40
|
+
function hashStr(s) {
|
|
41
|
+
let h = 0;
|
|
42
|
+
for (let i = 0; i < s.length; i++)
|
|
43
|
+
h = (h * 31 + s.charCodeAt(i)) | 0;
|
|
44
|
+
return Math.abs(h);
|
|
45
|
+
}
|
|
46
|
+
export function HomeAppsStrip({ apps, favorites, onOpen, onBrowseMarketplace, isAdmin, }) {
|
|
47
|
+
const { t } = useObjectTranslation();
|
|
48
|
+
const { appLabel } = useObjectLabel();
|
|
49
|
+
const [showAll, setShowAll] = useState(false);
|
|
50
|
+
const favNames = useMemo(() => new Set(favorites.filter((f) => f.id.startsWith('app:')).map((f) => f.id.slice(4))), [favorites]);
|
|
51
|
+
const ordered = useMemo(() => [...apps].sort((a, b) => (favNames.has(b.name) ? 1 : 0) - (favNames.has(a.name) ? 1 : 0)), [apps, favNames]);
|
|
52
|
+
const overflow = ordered.length - COMPACT_LIMIT;
|
|
53
|
+
const visible = showAll ? ordered : ordered.slice(0, COMPACT_LIMIT);
|
|
54
|
+
return (_jsxs("section", { className: "mb-6", children: [_jsxs("div", { className: "mb-3 flex items-center gap-2.5", children: [_jsx("span", { className: "inline-flex h-8 w-8 items-center justify-center rounded-xl border border-border bg-muted text-muted-foreground", children: _jsx(LayoutGrid, { className: "h-4 w-4" }) }), _jsx("h2", { className: "text-base font-semibold tracking-tight", children: t('home.yourApps', { defaultValue: 'Your apps' }) }), _jsx("span", { className: "text-sm text-muted-foreground", children: ordered.length }), isAdmin && (_jsxs(Button, { variant: "ghost", size: "sm", className: "ml-auto h-8 text-muted-foreground", onClick: onBrowseMarketplace, "data-testid": "browse-marketplace-btn", children: [_jsx(Store, { className: "mr-1.5 h-4 w-4" }), t('home.browseMarketplace', { defaultValue: 'Browse App Marketplace' })] }))] }), _jsxs("div", { className: "grid grid-cols-4 gap-1 sm:grid-cols-6 lg:grid-cols-8 xl:grid-cols-10", children: [visible.map((app) => {
|
|
55
|
+
const Icon = getIcon(app.icon);
|
|
56
|
+
const label = appLabel({ name: app.name, label: resolveI18nLabel(app.label, t) });
|
|
57
|
+
const fav = favNames.has(app.name);
|
|
58
|
+
const grad = ICON_GRADIENTS[hashStr(app.name) % ICON_GRADIENTS.length];
|
|
59
|
+
return (_jsxs("button", { type: "button", onClick: () => onOpen(app), className: "group relative flex flex-col items-center gap-2 rounded-xl p-2.5 text-center transition hover:bg-muted/40 active:scale-[0.96]", "data-testid": `app-tile-${app.name}`, children: [_jsxs("span", { className: cn('relative inline-flex h-12 w-12 items-center justify-center rounded-[13px]', 'bg-gradient-to-br text-white transition-transform group-hover:scale-105', ICON_GLOSS, grad), children: [_jsx(Icon, { className: "h-6 w-6" }), fav && (_jsx("span", { className: "absolute -right-1 -top-1 inline-flex h-4 w-4 items-center justify-center rounded-full bg-amber-400 ring-2 ring-background", children: _jsx(Star, { className: "h-2.5 w-2.5 fill-white text-white" }) }))] }), _jsx("span", { className: "w-full truncate text-xs font-medium", children: label })] }, app.name));
|
|
60
|
+
}), !showAll && overflow > 0 && (_jsxs("button", { type: "button", onClick: () => setShowAll(true), className: "group flex flex-col items-center gap-2 rounded-xl p-2.5 text-center transition hover:bg-muted/40 active:scale-[0.96]", "data-testid": "apps-show-all", children: [_jsxs("span", { className: "inline-flex h-12 w-12 items-center justify-center rounded-[13px] border border-dashed border-border text-sm font-medium text-muted-foreground transition-colors group-hover:border-foreground/30 group-hover:text-foreground", children: ["+", overflow] }), _jsx("span", { className: "w-full truncate text-xs text-muted-foreground", children: t('home.showMoreApps', { defaultValue: 'More' }) })] }))] }), showAll && overflow > 0 && (_jsx("button", { type: "button", onClick: () => setShowAll(false), className: "mt-2.5 text-xs text-primary hover:underline", children: t('home.showLess', { defaultValue: 'Show less' }) }))] }));
|
|
61
|
+
}
|
|
@@ -16,5 +16,5 @@ interface HomeLayoutProps {
|
|
|
16
16
|
*/
|
|
17
17
|
userId?: string;
|
|
18
18
|
}
|
|
19
|
-
export declare function HomeLayout({ children, userId }: HomeLayoutProps):
|
|
19
|
+
export declare function HomeLayout({ children, userId }: HomeLayoutProps): React.JSX.Element;
|
|
20
20
|
export {};
|
|
@@ -12,12 +12,14 @@ import { useEffect } from 'react';
|
|
|
12
12
|
import { useNavigationContext } from '../../context/NavigationContext';
|
|
13
13
|
import { AppHeader } from '../../layout/AppHeader';
|
|
14
14
|
import { useDiscovery } from '@object-ui/react';
|
|
15
|
+
import { useObjectTranslation } from '@object-ui/i18n';
|
|
15
16
|
// Lightweight FAB stub — the heavy chat chunk graph only downloads on
|
|
16
17
|
// first hover/click. See ../../layout/ConsoleChatbotFab.tsx.
|
|
17
18
|
import { ConsoleChatbotFab } from '../../layout/ConsoleChatbotFab';
|
|
18
19
|
export function HomeLayout({ children, userId }) {
|
|
19
20
|
const { setContext } = useNavigationContext();
|
|
20
21
|
const { isAiEnabled } = useDiscovery();
|
|
22
|
+
const { t } = useObjectTranslation();
|
|
21
23
|
// Render the chatbot whenever AI is reachable. If the developer has explicitly
|
|
22
24
|
// configured `VITE_AI_BASE_URL`, trust that opt-in even when discovery
|
|
23
25
|
// reports AI as disabled (e.g. framework started without `--preset full`).
|
|
@@ -26,5 +28,5 @@ export function HomeLayout({ children, userId }) {
|
|
|
26
28
|
useEffect(() => {
|
|
27
29
|
setContext('home');
|
|
28
30
|
}, [setContext]);
|
|
29
|
-
return (_jsxs("div", { className: "flex min-h-svh w-full flex-col bg-background", "data-testid": "home-layout", children: [_jsx("header", { className: "sticky top-0 z-30 flex h-14 w-full shrink-0 items-center gap-2 border-b bg-background px-2 sm:px-4", children: _jsx(AppHeader, { variant: "home" }) }), _jsx("main", { className: "flex-1 min-w-0 overflow-auto pb-20 sm:pb-0", children: children }), showChatbot && _jsx(ConsoleChatbotFab, { appLabel:
|
|
31
|
+
return (_jsxs("div", { className: "flex min-h-svh w-full flex-col bg-background", "data-testid": "home-layout", children: [_jsx("header", { className: "sticky top-0 z-30 flex h-14 w-full shrink-0 items-center gap-2 border-b bg-background px-2 sm:px-4", children: _jsx(AppHeader, { variant: "home" }) }), _jsx("main", { className: "flex-1 min-w-0 overflow-auto pb-20 sm:pb-0", children: children }), showChatbot && _jsx(ConsoleChatbotFab, { appLabel: t('workspace.default', { defaultValue: 'Workspace' }), objects: [], userId: userId })] }));
|
|
30
32
|
}
|
|
@@ -9,10 +9,9 @@
|
|
|
9
9
|
* - Quick actions for creating apps, importing data, etc.
|
|
10
10
|
* - Recent apps section (from useRecentItems)
|
|
11
11
|
* - Starred/Favorite apps section (from useFavorites)
|
|
12
|
-
* - Empty state guidance for new users
|
|
13
12
|
* - Responsive grid layout
|
|
14
13
|
* - i18n support
|
|
15
14
|
*
|
|
16
15
|
* @module
|
|
17
16
|
*/
|
|
18
|
-
export declare function HomePage(): import("react
|
|
17
|
+
export declare function HomePage(): import("react").JSX.Element;
|
|
@@ -10,24 +10,72 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
10
10
|
* - Quick actions for creating apps, importing data, etc.
|
|
11
11
|
* - Recent apps section (from useRecentItems)
|
|
12
12
|
* - Starred/Favorite apps section (from useFavorites)
|
|
13
|
-
* - Empty state guidance for new users
|
|
14
13
|
* - Responsive grid layout
|
|
15
14
|
* - i18n support
|
|
16
15
|
*
|
|
17
16
|
* @module
|
|
18
17
|
*/
|
|
19
|
-
import { useMemo } from 'react';
|
|
18
|
+
import { useMemo, useState, useEffect } from 'react';
|
|
20
19
|
import { useNavigate } from 'react-router-dom';
|
|
21
20
|
import { useMetadata } from '../../providers/MetadataProvider';
|
|
22
21
|
import { useRecentItems } from '../../hooks/useRecentItems';
|
|
23
22
|
import { useFavorites } from '../../hooks/useFavorites';
|
|
24
23
|
import { useObjectTranslation } from '@object-ui/i18n';
|
|
25
24
|
import { useAuth, useIsWorkspaceAdmin } from '@object-ui/auth';
|
|
26
|
-
import {
|
|
27
|
-
import {
|
|
28
|
-
import {
|
|
25
|
+
import { useAgents, isBuildAgent, isAskAgent } from '@object-ui/plugin-chatbot';
|
|
26
|
+
import { HomeAppsStrip } from './HomeAppsStrip';
|
|
27
|
+
import { HomeActionCenter, HomeContinue, HomeActivity } from './HomeRail';
|
|
28
|
+
import { useHomeInbox } from '../../hooks/useHomeInbox';
|
|
29
|
+
import { appRouteSegment } from '../../utils';
|
|
29
30
|
import { Empty, EmptyTitle, EmptyDescription, Button } from '@object-ui/components';
|
|
30
|
-
import {
|
|
31
|
+
import { Sparkles, ShieldAlert, X, UploadCloud, MessageSquareText } from 'lucide-react';
|
|
32
|
+
import { useMetadataClient } from '../../views/metadata-admin/useMetadata';
|
|
33
|
+
import { usePublishAllDrafts } from '../../preview/usePublishAllDrafts';
|
|
34
|
+
/** Resolve the AI service base, mirroring AiChatPage/ConsoleFloatingChatbot. */
|
|
35
|
+
function resolveAiApiBase() {
|
|
36
|
+
const env = import.meta.env ?? {};
|
|
37
|
+
const fromEnv = env.VITE_AI_BASE_URL;
|
|
38
|
+
if (fromEnv)
|
|
39
|
+
return fromEnv.replace(/\/$/, '');
|
|
40
|
+
const serverUrl = env.VITE_SERVER_URL ?? '';
|
|
41
|
+
return `${serverUrl.replace(/\/$/, '')}/api/v1/ai`;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Which AI home CTAs to surface, driven by the live agent catalog (the single
|
|
45
|
+
* source of truth) — gated PER agent, because the community edition can be in
|
|
46
|
+
* any of three states:
|
|
47
|
+
* - `askAvailable` — a data/query agent (`ask`/`data_chat`) is deployed → "Ask AI".
|
|
48
|
+
* - `buildAvailable` — a build/authoring agent is deployed → "Build with AI".
|
|
49
|
+
* That's a cloud / AI-Studio feature, ABSENT on open-source builds.
|
|
50
|
+
* - `aiEnabled` — any agent at all (AI is on here in some form).
|
|
51
|
+
* All false while the catalog loads or when AI isn't enabled, so nothing
|
|
52
|
+
* flashes and no AI CTA appears where there's no agent to back it.
|
|
53
|
+
*/
|
|
54
|
+
function useHomeAiAvailability() {
|
|
55
|
+
const apiBase = useMemo(() => resolveAiApiBase(), []);
|
|
56
|
+
const { agents } = useAgents({ apiBase });
|
|
57
|
+
return {
|
|
58
|
+
aiEnabled: agents.length > 0,
|
|
59
|
+
askAvailable: agents.some((a) => isAskAgent(a.name)),
|
|
60
|
+
buildAvailable: agents.some((a) => isBuildAgent(a.name)),
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Home AI call-to-action(s). "Build with AI" only when a build agent is
|
|
65
|
+
* deployed; "Ask AI" only when a data/query agent is deployed. Renders nothing
|
|
66
|
+
* when neither exists (AI off, or only custom agents — those are reachable via
|
|
67
|
+
* the assistant launcher / FAB). `layout="stack"` is used by the empty-state;
|
|
68
|
+
* the hero uses the default inline row. Availability is passed in so the host
|
|
69
|
+
* fetches the catalog once.
|
|
70
|
+
*/
|
|
71
|
+
function HomeAiActions({ askAvailable, buildAvailable, navigate, t, layout = 'row', }) {
|
|
72
|
+
if (!askAvailable && !buildAvailable)
|
|
73
|
+
return null;
|
|
74
|
+
const container = layout === 'stack'
|
|
75
|
+
? 'mt-6 flex flex-col sm:flex-row items-center gap-3'
|
|
76
|
+
: 'flex shrink-0 items-center gap-2';
|
|
77
|
+
return (_jsxs("div", { className: container, children: [buildAvailable && (_jsxs(Button, { onClick: () => navigate('/ai/build'), "data-testid": "home-build-with-ai", children: [_jsx(Sparkles, { className: "mr-2 h-4 w-4" }), t('home.buildWithAI', { defaultValue: 'Build with AI' })] })), askAvailable && (_jsxs(Button, { variant: buildAvailable ? 'outline' : 'default', onClick: () => navigate('/ai/ask'), "data-testid": "home-ask-ai", children: [_jsx(MessageSquareText, { className: "mr-2 h-4 w-4" }), t('home.askAI', { defaultValue: 'Ask AI' })] }))] }));
|
|
78
|
+
}
|
|
31
79
|
function pickGreetingKey(hour) {
|
|
32
80
|
if (hour < 5)
|
|
33
81
|
return 'home.greetingNight';
|
|
@@ -40,14 +88,82 @@ function pickGreetingKey(hour) {
|
|
|
40
88
|
return 'home.greetingNight';
|
|
41
89
|
}
|
|
42
90
|
/**
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
91
|
+
* Pending-drafts banner — closes the AI magic-moment loop. After the metadata
|
|
92
|
+
* assistant drafts objects/views/apps (ADR-0033 draft-gated authoring), nothing
|
|
93
|
+
* is live until the human publishes. Without this, a user who just had AI build
|
|
94
|
+
* their whole system landed back on an empty-looking home with no trace of it
|
|
95
|
+
* and no path to publish. This surfaces the pending drafts and routes to the
|
|
96
|
+
* designer to review + publish. Disappears automatically once published
|
|
97
|
+
* (listDrafts → 0).
|
|
98
|
+
*/
|
|
99
|
+
function PendingDraftsBanner({ t }) {
|
|
100
|
+
const client = useMetadataClient();
|
|
101
|
+
const [drafts, setDrafts] = useState([]);
|
|
102
|
+
// Shared one-click publish (also used by the ADR-0037 draft-preview bar):
|
|
103
|
+
// packages via the probed publish-drafts path, orphans by reference, health
|
|
104
|
+
// surfaced in toasts. See usePublishAllDrafts for the full story.
|
|
105
|
+
const { publishAll, publishing } = usePublishAllDrafts(t);
|
|
106
|
+
const count = drafts.length;
|
|
107
|
+
useEffect(() => {
|
|
108
|
+
let cancelled = false;
|
|
109
|
+
Promise.resolve(client.listDrafts?.({}))
|
|
110
|
+
.then((rows) => {
|
|
111
|
+
if (cancelled || !Array.isArray(rows))
|
|
112
|
+
return;
|
|
113
|
+
setDrafts(rows
|
|
114
|
+
.filter((d) => d && typeof d.type === 'string' && typeof d.name === 'string')
|
|
115
|
+
.map((d) => ({ type: d.type, name: d.name })));
|
|
116
|
+
})
|
|
117
|
+
.catch(() => { });
|
|
118
|
+
return () => { cancelled = true; };
|
|
119
|
+
}, [client]);
|
|
120
|
+
const publish = async () => {
|
|
121
|
+
const result = await publishAll();
|
|
122
|
+
if (!result.ok)
|
|
123
|
+
return;
|
|
124
|
+
setDrafts([]);
|
|
125
|
+
// Surface the now-live app — reload so the populated home shows it.
|
|
126
|
+
setTimeout(() => { try {
|
|
127
|
+
window.location.reload();
|
|
128
|
+
}
|
|
129
|
+
catch { /* ignore */ } }, 700);
|
|
130
|
+
};
|
|
131
|
+
if (count <= 0)
|
|
132
|
+
return null;
|
|
133
|
+
return (_jsx("div", { className: "px-4 sm:px-6 lg:px-8 pt-4", children: _jsx("div", { className: "max-w-7xl mx-auto", children: _jsxs("div", { className: "flex items-center gap-3 rounded-xl border border-indigo-300/60 dark:border-indigo-700/50 bg-indigo-50 dark:bg-indigo-950/30 px-4 py-3", children: [_jsx(UploadCloud, { className: "h-5 w-5 shrink-0 text-indigo-600 dark:text-indigo-400" }), _jsx("p", { className: "flex-1 min-w-0 text-sm text-indigo-900 dark:text-indigo-200", children: t('home.pendingDrafts.message', { count, defaultValue: 'You have {{count}} unpublished change(s) — publish to make them live.' }) }), _jsx(Button, { size: "sm", onClick: publish, disabled: publishing, "data-testid": "pending-drafts-publish", children: publishing
|
|
134
|
+
? t('home.pendingDrafts.publishing', { defaultValue: 'Publishing…' })
|
|
135
|
+
: t('home.pendingDrafts.cta', { defaultValue: 'Publish' }) })] }) }) }));
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Dismissible nudge to set a local recovery password — shown when the user
|
|
139
|
+
* signed in via SSO and has no local credential yet. We no longer force this
|
|
140
|
+
* before the first session (it walled off the magic moment); this gentle,
|
|
141
|
+
* one-time reminder preserves instance self-sufficiency without the friction.
|
|
46
142
|
*/
|
|
47
|
-
function
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
143
|
+
function RecoveryPasswordReminder({ t }) {
|
|
144
|
+
const navigate = useNavigate();
|
|
145
|
+
const { hasLocalPassword } = useAuth();
|
|
146
|
+
const [show, setShow] = useState(false);
|
|
147
|
+
useEffect(() => {
|
|
148
|
+
if (typeof localStorage !== 'undefined' && localStorage.getItem('os:recovery-pw-dismissed') === '1')
|
|
149
|
+
return;
|
|
150
|
+
let cancelled = false;
|
|
151
|
+
Promise.resolve(hasLocalPassword?.())
|
|
152
|
+
.then((has) => { if (!cancelled && has === false)
|
|
153
|
+
setShow(true); })
|
|
154
|
+
.catch(() => { });
|
|
155
|
+
return () => { cancelled = true; };
|
|
156
|
+
}, [hasLocalPassword]);
|
|
157
|
+
const dismiss = () => {
|
|
158
|
+
try {
|
|
159
|
+
localStorage.setItem('os:recovery-pw-dismissed', '1');
|
|
160
|
+
}
|
|
161
|
+
catch { /* ignore */ }
|
|
162
|
+
setShow(false);
|
|
163
|
+
};
|
|
164
|
+
if (!show)
|
|
165
|
+
return null;
|
|
166
|
+
return (_jsx("div", { className: "px-4 sm:px-6 lg:px-8 pt-4", children: _jsx("div", { className: "max-w-7xl mx-auto", children: _jsxs("div", { className: "flex items-center gap-3 rounded-xl border border-amber-300/60 dark:border-amber-700/50 bg-amber-50 dark:bg-amber-950/30 px-4 py-3", children: [_jsx(ShieldAlert, { className: "h-5 w-5 shrink-0 text-amber-600 dark:text-amber-400" }), _jsx("p", { className: "flex-1 min-w-0 text-sm text-amber-900 dark:text-amber-200", children: t('home.recoveryReminder.message', { defaultValue: 'Set a recovery password so you can still sign in if single sign-on is ever unavailable.' }) }), _jsx(Button, { size: "sm", variant: "outline", onClick: () => navigate('/set-password'), "data-testid": "recovery-pw-set", children: t('home.recoveryReminder.cta', { defaultValue: 'Set password' }) }), _jsx("button", { type: "button", onClick: dismiss, "aria-label": t('home.recoveryReminder.dismiss', { defaultValue: 'Dismiss' }), className: "shrink-0 rounded-md p-1 text-amber-700/70 hover:text-amber-900 dark:text-amber-300/70 dark:hover:text-amber-100", children: _jsx(X, { className: "h-4 w-4" }) })] }) }) }));
|
|
51
167
|
}
|
|
52
168
|
export function HomePage() {
|
|
53
169
|
const navigate = useNavigate();
|
|
@@ -57,22 +173,34 @@ export function HomePage() {
|
|
|
57
173
|
const { favorites } = useFavorites();
|
|
58
174
|
const { user } = useAuth();
|
|
59
175
|
const isAdmin = useIsWorkspaceAdmin();
|
|
60
|
-
const
|
|
176
|
+
const { pendingApprovalsCount, notifications, activities } = useHomeInbox();
|
|
177
|
+
// AI CTA gating, per agent: "Build with AI" only when a build agent is
|
|
178
|
+
// deployed (cloud / AI Studio); "Ask AI" only when a data agent is; neither
|
|
179
|
+
// when AI isn't enabled. Community builds typically land in the ask-only state.
|
|
180
|
+
const { askAvailable, buildAvailable } = useHomeAiAvailability();
|
|
181
|
+
const activeApps = apps.filter((a) => a.active !== false && a.hidden !== true);
|
|
61
182
|
const recentApps = recentItems
|
|
62
183
|
.filter(item => item.type === 'object' || item.type === 'dashboard' || item.type === 'page' || item.type === 'record')
|
|
63
184
|
.slice(0, 6);
|
|
64
|
-
const starredApps = favorites
|
|
65
|
-
.filter(item => item.type === 'object' || item.type === 'dashboard' || item.type === 'page' || item.type === 'record')
|
|
66
|
-
.slice(0, 8);
|
|
67
185
|
const greeting = useMemo(() => t(pickGreetingKey(new Date().getHours()), { defaultValue: 'Welcome' }), [t]);
|
|
68
186
|
const displayName = (user?.name?.trim() || user?.email?.split('@')[0] || '').trim();
|
|
69
187
|
if (loading) {
|
|
70
188
|
return (_jsx("div", { className: "flex flex-1 items-center justify-center py-20", children: _jsx("div", { className: "text-muted-foreground", children: t('home.loading', { defaultValue: 'Loading workspace…' }) }) }));
|
|
71
189
|
}
|
|
72
190
|
if (activeApps.length === 0) {
|
|
73
|
-
return (_jsx("div", { className: "flex flex-1 items-center justify-center p-6", children: _jsxs(Empty, { children: [_jsx(EmptyTitle, { children: t('home.welcome', { defaultValue: 'Welcome to ObjectUI' }) }), _jsx(EmptyDescription, { children:
|
|
74
|
-
|
|
75
|
-
|
|
191
|
+
return (_jsxs("div", { className: "flex flex-col flex-1", children: [_jsx(PendingDraftsBanner, { t: t }), _jsx(RecoveryPasswordReminder, { t: t }), _jsx("div", { className: "flex flex-1 items-center justify-center p-6", children: isAdmin ? (_jsxs(Empty, { children: [_jsx(EmptyTitle, { children: t('home.welcome', { defaultValue: 'Welcome to ObjectUI' }) }), _jsx(EmptyDescription, { children: buildAvailable
|
|
192
|
+
? t('home.welcomeAdminDescription', {
|
|
193
|
+
defaultValue: 'Describe your business in one sentence — AI generates the objects, screens, APIs and agent tools. Or set things up yourself from the Administration menu on the left.',
|
|
194
|
+
})
|
|
195
|
+
: askAvailable
|
|
196
|
+
? t('home.welcomeAdminDescriptionNoBuild', {
|
|
197
|
+
defaultValue: 'Set up your first application from the Administration menu on the left. Once you have data, the AI assistant can help you explore it.',
|
|
198
|
+
})
|
|
199
|
+
: t('home.welcomeAdminDescriptionNoAi', {
|
|
200
|
+
defaultValue: 'Set up your first application from the Administration menu on the left.',
|
|
201
|
+
}) }), _jsx(HomeAiActions, { askAvailable: askAvailable, buildAvailable: buildAvailable, navigate: navigate, t: t, layout: "stack" })] })) : (_jsxs(Empty, { children: [_jsx(EmptyTitle, { children: t('home.noAppsTitle', { defaultValue: 'No applications yet' }) }), _jsx(EmptyDescription, { children: t('home.noAppsDescription', {
|
|
202
|
+
defaultValue: 'There are no applications available to you yet. Please contact your workspace administrator.',
|
|
203
|
+
}) })] })) })] }));
|
|
76
204
|
}
|
|
77
|
-
return (_jsxs("div", { className: "relative
|
|
205
|
+
return (_jsxs("div", { className: "relative min-h-full bg-background", children: [_jsx(PendingDraftsBanner, { t: t }), _jsx(RecoveryPasswordReminder, { t: t }), _jsx("div", { className: "px-4 sm:px-6 lg:px-8 pt-8 pb-16", children: _jsxs("div", { className: "max-w-7xl mx-auto", children: [_jsxs("div", { className: "mb-7 flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between", children: [_jsxs("div", { className: "min-w-0", children: [_jsxs("h1", { className: "text-2xl sm:text-3xl font-bold tracking-tight text-pretty", children: [_jsxs("span", { className: "text-foreground", children: [greeting, displayName ? ', ' : ''] }), displayName && _jsx("span", { className: "text-primary", children: displayName }), _jsx("span", { className: "text-foreground/40", children: "." })] }), _jsx("p", { className: "mt-1 text-sm sm:text-base text-muted-foreground", children: t('home.heroTagline', { defaultValue: 'Pick up where you left off, or explore something new.' }) })] }), _jsx(HomeAiActions, { askAvailable: askAvailable, buildAvailable: buildAvailable, navigate: navigate, t: t })] }), _jsx(HomeAppsStrip, { apps: activeApps, favorites: favorites, onOpen: (app) => navigate(`/apps/${appRouteSegment(app) ?? app.name}`), onBrowseMarketplace: () => navigate('/apps/setup/system/marketplace'), isAdmin: isAdmin }), _jsx("div", { className: "mb-6", children: _jsx(HomeActionCenter, { pendingApprovalsCount: pendingApprovalsCount, notifications: notifications, onOpenApprovals: () => navigate('/apps/setup/system/approvals'), onOpenNotification: (n) => navigate(n.actionUrl || '/apps/setup/sys_inbox_message?view=mine'), t: t }) }), _jsxs("div", { className: "grid grid-cols-1 items-start gap-6 lg:grid-cols-[minmax(0,1fr)_360px]", children: [_jsx(HomeContinue, { items: recentApps, onOpen: (href) => navigate(href), t: t }), _jsx(HomeActivity, { items: activities, onViewAll: () => navigate('/apps/setup/sys_activity'), t: t })] })] }) })] }));
|
|
78
206
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { ActivityItem } from '../../layout/ActivityFeed';
|
|
2
|
+
import type { HomeNotification } from '../../hooks/useHomeInbox';
|
|
3
|
+
import type { RecentItem } from '../../hooks/useRecentItems';
|
|
4
|
+
type TFn = (key: string, opts?: any) => string;
|
|
5
|
+
export declare function HomeActionCenter({ pendingApprovalsCount, notifications, onOpenApprovals, onOpenNotification, t, }: {
|
|
6
|
+
pendingApprovalsCount: number;
|
|
7
|
+
notifications: HomeNotification[];
|
|
8
|
+
onOpenApprovals: () => void;
|
|
9
|
+
onOpenNotification: (n: HomeNotification) => void;
|
|
10
|
+
t: TFn;
|
|
11
|
+
}): import("react").JSX.Element;
|
|
12
|
+
export declare function HomeContinue({ items, onOpen, t }: {
|
|
13
|
+
items: RecentItem[];
|
|
14
|
+
onOpen: (href: string) => void;
|
|
15
|
+
t: TFn;
|
|
16
|
+
}): import("react").JSX.Element;
|
|
17
|
+
export declare function HomeActivity({ items, onViewAll, t }: {
|
|
18
|
+
items: ActivityItem[];
|
|
19
|
+
onViewAll: () => void;
|
|
20
|
+
t: TFn;
|
|
21
|
+
}): import("react").JSX.Element;
|
|
22
|
+
export {};
|