@object-ui/app-shell 6.2.3 → 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 +948 -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,97 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
|
|
3
|
+
/**
|
|
4
|
+
* FlowRunsPanel — run history for a flow, fetched from the automation engine
|
|
5
|
+
* (`GET /api/v1/automation/{name}/runs`, the observability surface next to
|
|
6
|
+
* resume/screen). Renders each run's status / start time / duration with an
|
|
7
|
+
* expandable per-node step log (the `ExecutionLog.steps` ADR-0019/#1479 shape),
|
|
8
|
+
* so authors can see where a run paused or failed without leaving the Studio.
|
|
9
|
+
*
|
|
10
|
+
* Degrades like the palette fetch: offline / plugin-absent / older backend →
|
|
11
|
+
* a quiet "history unavailable" note, never an error state that blocks the
|
|
12
|
+
* designer.
|
|
13
|
+
*/
|
|
14
|
+
import * as React from 'react';
|
|
15
|
+
import { AlertCircle, CheckCircle2, ChevronDown, ChevronRight, Clock, Loader2, PauseCircle, RefreshCw, SkipForward } from 'lucide-react';
|
|
16
|
+
import { cn } from '@object-ui/components';
|
|
17
|
+
import { apiBase } from './useFlowNodePalette';
|
|
18
|
+
/** Fetch a flow's run history. Exposed for tests. */
|
|
19
|
+
export async function fetchFlowRuns(flowName, signal) {
|
|
20
|
+
try {
|
|
21
|
+
const res = await fetch(`${apiBase()}/automation/${encodeURIComponent(flowName)}/runs?limit=25`, { credentials: 'include', headers: { 'Content-Type': 'application/json' }, signal });
|
|
22
|
+
if (!res.ok)
|
|
23
|
+
return null; // 404/501 — plugin absent or older backend
|
|
24
|
+
const payload = (await res.json());
|
|
25
|
+
const runs = payload?.data?.runs ?? payload?.runs;
|
|
26
|
+
return Array.isArray(runs) ? runs : null;
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return null; // offline / aborted
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
const STATUS_META = {
|
|
33
|
+
completed: { icon: CheckCircle2, cls: 'text-emerald-600 dark:text-emerald-400', label: 'Completed' },
|
|
34
|
+
failed: { icon: AlertCircle, cls: 'text-rose-600 dark:text-rose-400', label: 'Failed' },
|
|
35
|
+
paused: { icon: PauseCircle, cls: 'text-amber-600 dark:text-amber-400', label: 'Paused' },
|
|
36
|
+
running: { icon: Loader2, cls: 'text-sky-600 dark:text-sky-400', label: 'Running' },
|
|
37
|
+
cancelled: { icon: SkipForward, cls: 'text-muted-foreground', label: 'Cancelled' },
|
|
38
|
+
};
|
|
39
|
+
function statusMeta(status) {
|
|
40
|
+
return STATUS_META[status] ?? { icon: Clock, cls: 'text-muted-foreground', label: status };
|
|
41
|
+
}
|
|
42
|
+
function fmtTime(iso) {
|
|
43
|
+
if (!iso)
|
|
44
|
+
return '—';
|
|
45
|
+
const d = new Date(iso);
|
|
46
|
+
return Number.isNaN(d.getTime()) ? iso : d.toLocaleString();
|
|
47
|
+
}
|
|
48
|
+
function fmtDuration(ms) {
|
|
49
|
+
if (ms == null)
|
|
50
|
+
return null;
|
|
51
|
+
if (ms < 1000)
|
|
52
|
+
return `${ms}ms`;
|
|
53
|
+
if (ms < 60000)
|
|
54
|
+
return `${(ms / 1000).toFixed(1)}s`;
|
|
55
|
+
return `${Math.round(ms / 60000)}m`;
|
|
56
|
+
}
|
|
57
|
+
function StepRow({ step }) {
|
|
58
|
+
const cls = step.status === 'success'
|
|
59
|
+
? 'text-emerald-600 dark:text-emerald-400'
|
|
60
|
+
: step.status === 'failure'
|
|
61
|
+
? 'text-rose-600 dark:text-rose-400'
|
|
62
|
+
: 'text-muted-foreground';
|
|
63
|
+
return (_jsxs("li", { className: "flex items-baseline gap-1.5 py-0.5", children: [_jsx("span", { className: cn('shrink-0 text-[9px] font-semibold uppercase', cls), children: step.status }), _jsx("span", { className: "truncate font-mono text-[10px]", title: step.nodeId, children: step.nodeId }), step.nodeType && _jsx("span", { className: "shrink-0 text-[9px] uppercase text-muted-foreground", children: step.nodeType }), fmtDuration(step.durationMs) && (_jsx("span", { className: "ml-auto shrink-0 text-[9px] text-muted-foreground", children: fmtDuration(step.durationMs) })), step.error?.message && (_jsx("span", { className: "min-w-0 truncate text-[9px] text-rose-600", title: step.error.message, children: step.error.message }))] }));
|
|
64
|
+
}
|
|
65
|
+
function RunRow({ run }) {
|
|
66
|
+
const [open, setOpen] = React.useState(false);
|
|
67
|
+
const meta = statusMeta(run.status);
|
|
68
|
+
const Icon = meta.icon;
|
|
69
|
+
const steps = Array.isArray(run.steps) ? run.steps : [];
|
|
70
|
+
return (_jsxs("li", { className: "rounded border bg-background", children: [_jsxs("button", { type: "button", onClick: () => setOpen((v) => !v), className: "flex w-full items-center gap-1.5 p-1.5 text-left", "aria-expanded": open, children: [open ? (_jsx(ChevronDown, { className: "h-3 w-3 shrink-0 text-muted-foreground" })) : (_jsx(ChevronRight, { className: "h-3 w-3 shrink-0 text-muted-foreground" })), _jsx(Icon, { className: cn('h-3.5 w-3.5 shrink-0', meta.cls, run.status === 'running' && 'animate-spin') }), _jsx("span", { className: cn('shrink-0 text-[10px] font-semibold', meta.cls), children: meta.label }), _jsx("span", { className: "min-w-0 truncate text-[10px] text-muted-foreground", title: run.id, children: fmtTime(run.startedAt) }), fmtDuration(run.durationMs) && (_jsx("span", { className: "ml-auto shrink-0 text-[10px] text-muted-foreground", children: fmtDuration(run.durationMs) }))] }), open && (_jsxs("div", { className: "border-t px-2 py-1.5", children: [_jsxs("div", { className: "pb-1 font-mono text-[9px] text-muted-foreground", title: run.id, children: ["run ", run.id, run.trigger?.type && ` · trigger ${run.trigger.type}`] }), run.error?.message && (_jsx("div", { className: "pb-1 text-[10px] text-rose-600", children: run.error.message })), steps.length === 0 ? (_jsx("div", { className: "text-[10px] italic text-muted-foreground", children: "No step log recorded." })) : (_jsx("ul", { className: "divide-y divide-border/50", children: steps.map((s, i) => (_jsx(StepRow, { step: s }, `${s.nodeId}#${i}`))) }))] }))] }));
|
|
71
|
+
}
|
|
72
|
+
export function FlowRunsPanel({ flowName }) {
|
|
73
|
+
const [runs, setRuns] = React.useState([]);
|
|
74
|
+
const [state, setState] = React.useState('loading');
|
|
75
|
+
const [reloadKey, setReloadKey] = React.useState(0);
|
|
76
|
+
React.useEffect(() => {
|
|
77
|
+
const controller = new AbortController();
|
|
78
|
+
let alive = true;
|
|
79
|
+
setState('loading');
|
|
80
|
+
(async () => {
|
|
81
|
+
const result = await fetchFlowRuns(flowName, controller.signal);
|
|
82
|
+
if (!alive)
|
|
83
|
+
return;
|
|
84
|
+
if (result === null)
|
|
85
|
+
setState('unavailable');
|
|
86
|
+
else {
|
|
87
|
+
setRuns(result);
|
|
88
|
+
setState('ready');
|
|
89
|
+
}
|
|
90
|
+
})();
|
|
91
|
+
return () => {
|
|
92
|
+
alive = false;
|
|
93
|
+
controller.abort();
|
|
94
|
+
};
|
|
95
|
+
}, [flowName, reloadKey]);
|
|
96
|
+
return (_jsxs("div", { className: "flex h-full flex-col p-3 text-xs", children: [_jsxs("div", { className: "flex items-center gap-1.5 pb-2 font-medium text-muted-foreground", children: [_jsx(Clock, { className: "h-3 w-3" }), " Runs", _jsx("button", { type: "button", onClick: () => setReloadKey((k) => k + 1), title: "Refresh run history", "aria-label": "Refresh run history", className: "ml-auto rounded p-0.5 text-muted-foreground transition-colors hover:bg-muted/50 hover:text-foreground", children: _jsx(RefreshCw, { className: cn('h-3 w-3', state === 'loading' && 'animate-spin') }) })] }), state === 'unavailable' ? (_jsx("div", { className: "italic text-muted-foreground", children: "Run history unavailable \u2014 the automation engine is offline or this flow hasn\u2019t been published." })) : state === 'ready' && runs.length === 0 ? (_jsx("div", { className: "italic text-muted-foreground", children: "No runs yet." })) : (_jsx("ul", { className: "min-h-0 flex-1 space-y-1.5 overflow-y-auto", children: runs.map((r) => (_jsx(RunRow, { run: r }, r.id))) }))] }));
|
|
97
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FlowSimulatorPanel — the designer-time debug runner UI. Drives a
|
|
3
|
+
* `FlowSimulator` (pure engine) and lifts its highlight state up so the canvas
|
|
4
|
+
* can paint the active node / traversed edges. Side effects are mocked; the
|
|
5
|
+
* panel only collects the flow's input variables as the run seed.
|
|
6
|
+
*/
|
|
7
|
+
import * as React from 'react';
|
|
8
|
+
import type { SimEdge, SimNode } from './simulator/flow-sim-types';
|
|
9
|
+
export interface FlowVariableDecl {
|
|
10
|
+
name: string;
|
|
11
|
+
type?: string;
|
|
12
|
+
defaultValue?: unknown;
|
|
13
|
+
isInput?: boolean;
|
|
14
|
+
}
|
|
15
|
+
export interface FlowSimulatorPanelProps {
|
|
16
|
+
nodes: SimNode[];
|
|
17
|
+
edges: SimEdge[];
|
|
18
|
+
variables: FlowVariableDecl[];
|
|
19
|
+
onRunStateChange?: (s: {
|
|
20
|
+
activeNodeId: string | null;
|
|
21
|
+
visitedNodeIds: string[];
|
|
22
|
+
traversedEdgeIds: string[];
|
|
23
|
+
} | null) => void;
|
|
24
|
+
}
|
|
25
|
+
export declare function FlowSimulatorPanel({ nodes, edges, variables, onRunStateChange }: FlowSimulatorPanelProps): React.JSX.Element;
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
|
|
3
|
+
/**
|
|
4
|
+
* FlowSimulatorPanel — the designer-time debug runner UI. Drives a
|
|
5
|
+
* `FlowSimulator` (pure engine) and lifts its highlight state up so the canvas
|
|
6
|
+
* can paint the active node / traversed edges. Side effects are mocked; the
|
|
7
|
+
* panel only collects the flow's input variables as the run seed.
|
|
8
|
+
*/
|
|
9
|
+
import * as React from 'react';
|
|
10
|
+
import { Play, StepForward, RotateCcw, ChevronRight, AlertTriangle, CircleAlert, Plus, Trash2 } from 'lucide-react';
|
|
11
|
+
import { Button, Input, Label, cn } from '@object-ui/components';
|
|
12
|
+
import { FlowSimulator } from './simulator/flow-simulator';
|
|
13
|
+
/** Coerce a free-text seed value: number / boolean / JSON object|array / string. */
|
|
14
|
+
function parseSeed(raw) {
|
|
15
|
+
const s = raw.trim();
|
|
16
|
+
if (s === '')
|
|
17
|
+
return undefined;
|
|
18
|
+
if (s === 'true')
|
|
19
|
+
return true;
|
|
20
|
+
if (s === 'false')
|
|
21
|
+
return false;
|
|
22
|
+
if (/^-?\d+(\.\d+)?$/.test(s))
|
|
23
|
+
return Number(s);
|
|
24
|
+
if ((s.startsWith('{') && s.endsWith('}')) || (s.startsWith('[') && s.endsWith(']'))) {
|
|
25
|
+
try {
|
|
26
|
+
return JSON.parse(s);
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return raw;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return raw;
|
|
33
|
+
}
|
|
34
|
+
/** Node types whose side effects are mocked — authors can pin their output. */
|
|
35
|
+
const MOCKABLE = new Set([
|
|
36
|
+
'create_record',
|
|
37
|
+
'update_record',
|
|
38
|
+
'delete_record',
|
|
39
|
+
'get_record',
|
|
40
|
+
'http_request',
|
|
41
|
+
'connector_action',
|
|
42
|
+
'script',
|
|
43
|
+
]);
|
|
44
|
+
function mockableNodes(nodes) {
|
|
45
|
+
const out = [];
|
|
46
|
+
for (const n of nodes) {
|
|
47
|
+
if (!MOCKABLE.has(n.type))
|
|
48
|
+
continue;
|
|
49
|
+
const cfg = (n.config ?? {});
|
|
50
|
+
const outputs = [];
|
|
51
|
+
if (typeof cfg.outputVariable === 'string' && cfg.outputVariable)
|
|
52
|
+
outputs.push(cfg.outputVariable);
|
|
53
|
+
if (Array.isArray(cfg.outputVariables)) {
|
|
54
|
+
for (const o of cfg.outputVariables)
|
|
55
|
+
if (typeof o === 'string')
|
|
56
|
+
outputs.push(o);
|
|
57
|
+
}
|
|
58
|
+
out.push({ id: n.id, label: n.label || n.id, type: n.type, outputs });
|
|
59
|
+
}
|
|
60
|
+
return out;
|
|
61
|
+
}
|
|
62
|
+
const STATUS_TONE = {
|
|
63
|
+
ok: 'bg-emerald-100 text-emerald-700',
|
|
64
|
+
mocked: 'bg-violet-100 text-violet-700',
|
|
65
|
+
paused: 'bg-amber-100 text-amber-700',
|
|
66
|
+
skipped: 'bg-zinc-100 text-zinc-600',
|
|
67
|
+
error: 'bg-rose-100 text-rose-700',
|
|
68
|
+
};
|
|
69
|
+
export function FlowSimulatorPanel({ nodes, edges, variables, onRunStateChange }) {
|
|
70
|
+
const simRef = React.useRef(null);
|
|
71
|
+
const [snapshot, setSnapshot] = React.useState(null);
|
|
72
|
+
const [validation, setValidation] = React.useState(null);
|
|
73
|
+
const inputs = React.useMemo(() => variables.filter((v) => v.isInput), [variables]);
|
|
74
|
+
const mockNodes = React.useMemo(() => mockableNodes(nodes), [nodes]);
|
|
75
|
+
const [seed, setSeed] = React.useState({});
|
|
76
|
+
/** Free-form variable overrides so any branch can be exercised (e.g. a
|
|
77
|
+
* decision that reads a computed value no input declares). */
|
|
78
|
+
const [scratch, setScratch] = React.useState([]);
|
|
79
|
+
/** Per-node mock outputs, keyed by node id (raw text, parsed on run). */
|
|
80
|
+
const [mocks, setMocks] = React.useState({});
|
|
81
|
+
const sync = React.useCallback(() => {
|
|
82
|
+
const sim = simRef.current;
|
|
83
|
+
if (!sim)
|
|
84
|
+
return;
|
|
85
|
+
const st = sim.state;
|
|
86
|
+
setSnapshot({
|
|
87
|
+
...st,
|
|
88
|
+
steps: [...st.steps],
|
|
89
|
+
variables: { ...st.variables },
|
|
90
|
+
frontier: [...st.frontier],
|
|
91
|
+
visitedNodeIds: [...st.visitedNodeIds],
|
|
92
|
+
traversedEdgeIds: [...st.traversedEdgeIds],
|
|
93
|
+
});
|
|
94
|
+
onRunStateChange?.({
|
|
95
|
+
activeNodeId: st.activeNodeId,
|
|
96
|
+
visitedNodeIds: [...st.visitedNodeIds],
|
|
97
|
+
traversedEdgeIds: [...st.traversedEdgeIds],
|
|
98
|
+
});
|
|
99
|
+
}, [onRunStateChange]);
|
|
100
|
+
const buildSeed = React.useCallback(() => {
|
|
101
|
+
const out = {};
|
|
102
|
+
for (const v of inputs) {
|
|
103
|
+
const raw = seed[v.name];
|
|
104
|
+
const parsed = raw != null ? parseSeed(raw) : undefined;
|
|
105
|
+
out[v.name] = parsed !== undefined ? parsed : v.defaultValue;
|
|
106
|
+
}
|
|
107
|
+
// Scratch overrides win — they let an author drive any branch.
|
|
108
|
+
for (const row of scratch) {
|
|
109
|
+
const key = row.k.trim();
|
|
110
|
+
if (key)
|
|
111
|
+
out[key] = parseSeed(row.v);
|
|
112
|
+
}
|
|
113
|
+
return out;
|
|
114
|
+
}, [inputs, seed, scratch]);
|
|
115
|
+
const buildMocks = React.useCallback(() => {
|
|
116
|
+
const out = {};
|
|
117
|
+
for (const [id, raw] of Object.entries(mocks)) {
|
|
118
|
+
if (raw != null && raw.trim() !== '')
|
|
119
|
+
out[id] = parseSeed(raw);
|
|
120
|
+
}
|
|
121
|
+
return out;
|
|
122
|
+
}, [mocks]);
|
|
123
|
+
const reset = React.useCallback(() => {
|
|
124
|
+
const sim = new FlowSimulator(nodes, edges);
|
|
125
|
+
simRef.current = sim;
|
|
126
|
+
setValidation(sim.reset(buildSeed(), buildMocks()));
|
|
127
|
+
sync();
|
|
128
|
+
}, [nodes, edges, buildSeed, buildMocks, sync]);
|
|
129
|
+
const ensure = React.useCallback(() => {
|
|
130
|
+
if (!simRef.current)
|
|
131
|
+
reset();
|
|
132
|
+
return simRef.current;
|
|
133
|
+
}, [reset]);
|
|
134
|
+
const onRun = () => {
|
|
135
|
+
// A paused run (wait / screen) continues from where it halted. Any other
|
|
136
|
+
// state — fresh, done, or errored — starts a clean run that re-seeds with
|
|
137
|
+
// the current Set-variables and Mock-outputs editors, so editing them and
|
|
138
|
+
// pressing Run again always reflects the new values.
|
|
139
|
+
let sim = simRef.current;
|
|
140
|
+
if (sim && sim.state.status === 'paused') {
|
|
141
|
+
sim.resume();
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
reset();
|
|
145
|
+
sim = simRef.current;
|
|
146
|
+
}
|
|
147
|
+
sim.runToEnd();
|
|
148
|
+
sync();
|
|
149
|
+
};
|
|
150
|
+
const onStep = () => {
|
|
151
|
+
const sim = ensure();
|
|
152
|
+
sim.step();
|
|
153
|
+
sync();
|
|
154
|
+
};
|
|
155
|
+
const onResume = () => {
|
|
156
|
+
const sim = ensure();
|
|
157
|
+
sim.resume();
|
|
158
|
+
sim.runToEnd();
|
|
159
|
+
sync();
|
|
160
|
+
};
|
|
161
|
+
const onReset = () => {
|
|
162
|
+
simRef.current = null;
|
|
163
|
+
setSnapshot(null);
|
|
164
|
+
setValidation(null);
|
|
165
|
+
onRunStateChange?.(null);
|
|
166
|
+
};
|
|
167
|
+
const status = snapshot?.status ?? 'idle';
|
|
168
|
+
const blocked = (validation?.errors.length ?? 0) > 0;
|
|
169
|
+
return (_jsxs("div", { className: "flex h-full flex-col text-xs", children: [_jsxs("div", { className: "flex items-center gap-1.5 border-b bg-muted/30 px-3 py-2", children: [_jsxs(Button, { size: "sm", className: "h-7 gap-1 px-2", onClick: onRun, disabled: blocked, children: [_jsx(Play, { className: "h-3.5 w-3.5" }), " Run"] }), _jsxs(Button, { size: "sm", variant: "outline", className: "h-7 gap-1 px-2", onClick: onStep, disabled: blocked || status === 'done' || status === 'error', children: [_jsx(StepForward, { className: "h-3.5 w-3.5" }), " Step"] }), status === 'paused' && (_jsxs(Button, { size: "sm", variant: "outline", className: "h-7 gap-1 px-2", onClick: onResume, children: [_jsx(ChevronRight, { className: "h-3.5 w-3.5" }), " Continue"] })), _jsxs(Button, { size: "sm", variant: "ghost", className: "h-7 gap-1 px-2 text-muted-foreground", onClick: onReset, children: [_jsx(RotateCcw, { className: "h-3.5 w-3.5" }), " Reset"] }), _jsx("span", { className: cn('ml-auto rounded px-1.5 py-0.5 text-[10px] font-semibold uppercase', STATUS_TONE[status === 'idle' || status === 'running' ? 'ok' : status] ?? 'bg-muted'), children: status })] }), _jsxs("div", { className: "min-h-0 flex-1 space-y-3 overflow-auto p-3", children: [validation && (validation.errors.length > 0 || validation.warnings.length > 0) && (_jsxs("div", { className: "space-y-1", children: [validation.errors.map((d, i) => (_jsxs("div", { className: "flex items-start gap-1.5 rounded border border-rose-200 bg-rose-50 px-2 py-1 text-rose-700", children: [_jsx(CircleAlert, { className: "mt-0.5 h-3 w-3 shrink-0" }), _jsx("span", { children: d.message })] }, `e${i}`))), validation.warnings.map((d, i) => (_jsxs("div", { className: "flex items-start gap-1.5 rounded border border-amber-200 bg-amber-50 px-2 py-1 text-amber-700", children: [_jsx(AlertTriangle, { className: "mt-0.5 h-3 w-3 shrink-0" }), _jsx("span", { children: d.message })] }, `w${i}`)))] })), inputs.length > 0 && (_jsxs("section", { className: "space-y-1.5", children: [_jsx("div", { className: "font-medium text-muted-foreground", children: "Inputs" }), inputs.map((v) => (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Label, { className: "w-24 shrink-0 truncate font-mono text-[11px]", title: v.name, children: v.name }), _jsx(Input, { value: seed[v.name] ?? (v.defaultValue != null ? String(v.defaultValue) : ''), onChange: (e) => setSeed((p) => ({ ...p, [v.name]: e.target.value })), placeholder: v.type ?? 'value', className: "h-7 flex-1 text-xs" })] }, v.name)))] })), _jsxs("section", { className: "space-y-1.5", children: [_jsxs("div", { className: "flex items-center gap-1.5 font-medium text-muted-foreground", children: [_jsx("span", { children: "Set variables" }), _jsxs("button", { type: "button", className: "ml-auto inline-flex items-center gap-0.5 rounded border px-1.5 py-0.5 text-[10px] hover:bg-muted/50", onClick: () => setScratch((p) => [...p, { k: '', v: '' }]), children: [_jsx(Plus, { className: "h-3 w-3" }), " Add"] })] }), scratch.length === 0 ? (_jsx("div", { className: "italic text-muted-foreground", children: "Override or inject any variable (wins over inputs and mocks at start)." })) : (scratch.map((row, i) => (_jsxs("div", { className: "flex items-center gap-1.5", children: [_jsx(Input, { value: row.k, onChange: (e) => setScratch((p) => p.map((r, j) => (j === i ? { ...r, k: e.target.value } : r))), placeholder: "name", className: "h-7 w-24 shrink-0 font-mono text-[11px]" }), _jsx("span", { className: "text-muted-foreground", children: "=" }), _jsx(Input, { value: row.v, onChange: (e) => setScratch((p) => p.map((r, j) => (j === i ? { ...r, v: e.target.value } : r))), placeholder: "value", className: "h-7 flex-1 text-xs" }), _jsx("button", { type: "button", className: "shrink-0 rounded p-1 text-muted-foreground hover:bg-muted/50 hover:text-rose-600", onClick: () => setScratch((p) => p.filter((_, j) => j !== i)), "aria-label": "Remove variable", children: _jsx(Trash2, { className: "h-3 w-3" }) })] }, i))))] }), mockNodes.length > 0 && (_jsxs("section", { className: "space-y-1.5", children: [_jsx("div", { className: "font-medium text-muted-foreground", children: "Mock outputs" }), mockNodes.map((m) => (_jsxs("div", { className: "space-y-0.5", children: [_jsxs(Label, { className: "flex items-baseline gap-1.5 text-[11px]", title: m.id, children: [_jsx("span", { className: "truncate font-medium", children: m.label }), _jsx("span", { className: "text-[9px] uppercase text-muted-foreground", children: m.type.replace(/_/g, ' ') }), m.outputs.length > 0 && (_jsxs("span", { className: "truncate font-mono text-[10px] text-violet-600", children: ["\u2192 ", m.outputs.join(', ')] }))] }), _jsx(Input, { value: mocks[m.id] ?? '', onChange: (e) => setMocks((p) => ({ ...p, [m.id]: e.target.value })), placeholder: m.type === 'script' && m.outputs.length ? `{ "${m.outputs[0]}": … }` : 'mocked result (JSON)', className: "h-7 w-full font-mono text-[11px]" })] }, m.id)))] })), snapshot && (_jsxs("section", { className: "space-y-1.5", children: [_jsx("div", { className: "font-medium text-muted-foreground", children: "Variables" }), Object.keys(snapshot.variables).length === 0 ? (_jsx("div", { className: "italic text-muted-foreground", children: "No variables set." })) : (_jsx("ul", { className: "space-y-1", children: Object.entries(snapshot.variables).map(([k, val]) => (_jsxs("li", { className: "flex items-baseline gap-1.5 rounded border bg-background px-1.5 py-1", children: [_jsx("span", { className: "font-mono text-[11px]", children: k }), _jsxs("span", { className: "truncate font-mono text-[10px] text-muted-foreground", children: ["= ", typeof val === 'object' ? JSON.stringify(val) : String(val)] })] }, k))) }))] })), snapshot && snapshot.steps.length > 0 && (_jsxs("section", { className: "space-y-1.5", children: [_jsx("div", { className: "font-medium text-muted-foreground", children: "Timeline" }), _jsx("ol", { className: "space-y-1", children: snapshot.steps.map((s) => (_jsxs("li", { className: "rounded border bg-background p-1.5", children: [_jsxs("div", { className: "flex items-center gap-1.5", children: [_jsx("span", { className: "font-mono text-[10px] text-muted-foreground", children: s.seq + 1 }), _jsx("span", { className: "truncate font-medium", children: s.label }), _jsx("span", { className: "text-[10px] uppercase text-muted-foreground", children: s.type }), _jsx("span", { className: cn('ml-auto rounded px-1 py-0.5 text-[9px] font-semibold uppercase', STATUS_TONE[s.status]), children: s.status })] }), s.note && _jsx("div", { className: "mt-0.5 text-[10px] text-muted-foreground", children: s.note }), s.error && _jsx("div", { className: "mt-0.5 text-[10px] text-rose-600", children: s.error }), s.wrote && (_jsxs("div", { className: "mt-0.5 truncate font-mono text-[10px] text-violet-600", children: ["\u2192 ", Object.keys(s.wrote).join(', ')] })), s.edges && s.edges.length > 0 && (_jsx("ul", { className: "mt-0.5 space-y-0.5", children: s.edges.map((ed) => (_jsxs("li", { className: "space-y-0.5", children: [_jsxs("div", { className: cn('flex items-center gap-1 font-mono text-[10px]', ed.selected ? 'text-sky-700' : 'text-muted-foreground'), children: [_jsx("span", { children: ed.selected ? '▶' : '·' }), _jsx("span", { className: "truncate", children: ed.isDefault ? 'else' : ed.condition }), _jsx("span", { className: cn('ml-auto', ed.error && 'text-rose-600'), children: ed.error ? 'error' : ed.result ? 'true' : 'false' })] }), ed.error && _jsx("div", { className: "pl-3 text-[10px] text-rose-600", children: ed.error })] }, ed.edgeId))) }))] }, s.seq))) })] })), !snapshot && !blocked && (_jsx("p", { className: "italic text-muted-foreground", children: "Press Run to simulate, or Step to walk node by node. Side effects are mocked \u2014 no backend is called." }))] })] }));
|
|
170
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JobPreview — read-only summary of a Background Job draft.
|
|
3
|
+
*
|
|
4
|
+
* Canonical shape (see `packages/spec/src/system/job.zod.ts`):
|
|
5
|
+
* schedule: { type: 'cron', expression: string | { dialect:'cron', source:string }, timezone? }
|
|
6
|
+
* | { type: 'interval', intervalMs: number }
|
|
7
|
+
* | { type: 'once', at: string (ISO) }
|
|
8
|
+
* handler: string — function key registered in defineStack({ functions })
|
|
9
|
+
* retryPolicy?: { maxRetries, backoffMs, backoffMultiplier }
|
|
10
|
+
* timeout?: number (ms)
|
|
11
|
+
* enabled?: boolean
|
|
12
|
+
*
|
|
13
|
+
* Legacy / app-supplied flat shapes are also tolerated:
|
|
14
|
+
* • `cron` (string) — top-level cron expression
|
|
15
|
+
* • `every` / `interval` — interval like "5m" or millis number
|
|
16
|
+
* • `at` / `runAs` — one-shot ISO
|
|
17
|
+
* • `timezone` / `tz`
|
|
18
|
+
* • `active` / `enabled`
|
|
19
|
+
*
|
|
20
|
+
* For cron schedules we compute the **next 5 fire times** locally so
|
|
21
|
+
* operators can sanity-check the schedule without waiting for the
|
|
22
|
+
* runtime. The cron parser handles standard 5-field cron with `*`,
|
|
23
|
+
* `*\/N`, comma lists, and ranges (`a-b`). Special tokens like
|
|
24
|
+
* `@daily` / `@hourly` are also expanded.
|
|
25
|
+
*/
|
|
26
|
+
import * as React from 'react';
|
|
27
|
+
import type { MetadataPreviewProps } from '../preview-registry';
|
|
28
|
+
export declare function JobPreview({ name, draft }: MetadataPreviewProps): React.JSX.Element;
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
|
|
3
|
+
/**
|
|
4
|
+
* JobPreview — read-only summary of a Background Job draft.
|
|
5
|
+
*
|
|
6
|
+
* Canonical shape (see `packages/spec/src/system/job.zod.ts`):
|
|
7
|
+
* schedule: { type: 'cron', expression: string | { dialect:'cron', source:string }, timezone? }
|
|
8
|
+
* | { type: 'interval', intervalMs: number }
|
|
9
|
+
* | { type: 'once', at: string (ISO) }
|
|
10
|
+
* handler: string — function key registered in defineStack({ functions })
|
|
11
|
+
* retryPolicy?: { maxRetries, backoffMs, backoffMultiplier }
|
|
12
|
+
* timeout?: number (ms)
|
|
13
|
+
* enabled?: boolean
|
|
14
|
+
*
|
|
15
|
+
* Legacy / app-supplied flat shapes are also tolerated:
|
|
16
|
+
* • `cron` (string) — top-level cron expression
|
|
17
|
+
* • `every` / `interval` — interval like "5m" or millis number
|
|
18
|
+
* • `at` / `runAs` — one-shot ISO
|
|
19
|
+
* • `timezone` / `tz`
|
|
20
|
+
* • `active` / `enabled`
|
|
21
|
+
*
|
|
22
|
+
* For cron schedules we compute the **next 5 fire times** locally so
|
|
23
|
+
* operators can sanity-check the schedule without waiting for the
|
|
24
|
+
* runtime. The cron parser handles standard 5-field cron with `*`,
|
|
25
|
+
* `*\/N`, comma lists, and ranges (`a-b`). Special tokens like
|
|
26
|
+
* `@daily` / `@hourly` are also expanded.
|
|
27
|
+
*/
|
|
28
|
+
import * as React from 'react';
|
|
29
|
+
import { AlarmClock, Calendar, Clock, Code2, Globe2, PlayCircle, Power, RotateCcw, Timer, } from 'lucide-react';
|
|
30
|
+
import { PreviewShell, PreviewMessage, PreviewErrorBoundary } from './PreviewShell';
|
|
31
|
+
const CRON_ALIASES = {
|
|
32
|
+
'@yearly': '0 0 1 1 *',
|
|
33
|
+
'@annually': '0 0 1 1 *',
|
|
34
|
+
'@monthly': '0 0 1 * *',
|
|
35
|
+
'@weekly': '0 0 * * 0',
|
|
36
|
+
'@daily': '0 0 * * *',
|
|
37
|
+
'@midnight': '0 0 * * *',
|
|
38
|
+
'@hourly': '0 * * * *',
|
|
39
|
+
};
|
|
40
|
+
function parseCronField(raw, min, max) {
|
|
41
|
+
const out = { values: new Set(), any: false };
|
|
42
|
+
if (raw === '*') {
|
|
43
|
+
for (let i = min; i <= max; i++)
|
|
44
|
+
out.values.add(i);
|
|
45
|
+
out.any = true;
|
|
46
|
+
return out;
|
|
47
|
+
}
|
|
48
|
+
for (const part of raw.split(',')) {
|
|
49
|
+
let stepStr;
|
|
50
|
+
let body = part;
|
|
51
|
+
if (part.includes('/')) {
|
|
52
|
+
const [b, s] = part.split('/');
|
|
53
|
+
body = b;
|
|
54
|
+
stepStr = s;
|
|
55
|
+
}
|
|
56
|
+
const step = stepStr ? Math.max(1, parseInt(stepStr, 10) || 1) : 1;
|
|
57
|
+
let lo = min;
|
|
58
|
+
let hi = max;
|
|
59
|
+
if (body !== '*') {
|
|
60
|
+
if (body.includes('-')) {
|
|
61
|
+
const [a, b] = body.split('-').map((n) => parseInt(n, 10));
|
|
62
|
+
if (Number.isNaN(a) || Number.isNaN(b))
|
|
63
|
+
return null;
|
|
64
|
+
lo = a;
|
|
65
|
+
hi = b;
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
const v = parseInt(body, 10);
|
|
69
|
+
if (Number.isNaN(v))
|
|
70
|
+
return null;
|
|
71
|
+
lo = v;
|
|
72
|
+
hi = v;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
for (let i = lo; i <= hi; i += step) {
|
|
76
|
+
if (i >= min && i <= max)
|
|
77
|
+
out.values.add(i);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return out;
|
|
81
|
+
}
|
|
82
|
+
function parseCron(expr) {
|
|
83
|
+
const aliased = CRON_ALIASES[expr.trim()] ?? expr.trim();
|
|
84
|
+
const parts = aliased.split(/\s+/);
|
|
85
|
+
if (parts.length !== 5 && parts.length !== 6)
|
|
86
|
+
return null;
|
|
87
|
+
// Strip optional 6th seconds field — we ignore second-resolution for preview.
|
|
88
|
+
const fields = parts.length === 6 ? parts.slice(1) : parts;
|
|
89
|
+
const [m, h, dom, mon, dow] = fields;
|
|
90
|
+
const minute = parseCronField(m, 0, 59);
|
|
91
|
+
const hour = parseCronField(h, 0, 23);
|
|
92
|
+
const domF = parseCronField(dom, 1, 31);
|
|
93
|
+
const month = parseCronField(mon, 1, 12);
|
|
94
|
+
const dowF = parseCronField(dow === '7' ? '0' : dow, 0, 6);
|
|
95
|
+
if (!minute || !hour || !domF || !month || !dowF)
|
|
96
|
+
return null;
|
|
97
|
+
return { minute, hour, dom: domF, month, dow: dowF };
|
|
98
|
+
}
|
|
99
|
+
function nextCronFires(expr, from, count) {
|
|
100
|
+
const cron = parseCron(expr);
|
|
101
|
+
if (!cron)
|
|
102
|
+
return [];
|
|
103
|
+
const results = [];
|
|
104
|
+
// Walk minute by minute up to ~366 days; bail early once we hit count.
|
|
105
|
+
const cursor = new Date(from.getTime());
|
|
106
|
+
cursor.setSeconds(0, 0);
|
|
107
|
+
cursor.setMinutes(cursor.getMinutes() + 1);
|
|
108
|
+
const limitMs = 366 * 24 * 60 * 60 * 1000;
|
|
109
|
+
const endAt = from.getTime() + limitMs;
|
|
110
|
+
while (results.length < count && cursor.getTime() <= endAt) {
|
|
111
|
+
if (cron.minute.values.has(cursor.getMinutes()) &&
|
|
112
|
+
cron.hour.values.has(cursor.getHours()) &&
|
|
113
|
+
cron.month.values.has(cursor.getMonth() + 1) &&
|
|
114
|
+
// POSIX cron OR semantics: when both DOM and DOW are restricted,
|
|
115
|
+
// a match in EITHER triggers; when one is `*`, the other governs.
|
|
116
|
+
(cron.dom.any || cron.dow.any
|
|
117
|
+
? cron.dom.values.has(cursor.getDate()) && cron.dow.values.has(cursor.getDay())
|
|
118
|
+
: cron.dom.values.has(cursor.getDate()) || cron.dow.values.has(cursor.getDay()))) {
|
|
119
|
+
results.push(new Date(cursor.getTime()));
|
|
120
|
+
}
|
|
121
|
+
cursor.setMinutes(cursor.getMinutes() + 1);
|
|
122
|
+
}
|
|
123
|
+
return results;
|
|
124
|
+
}
|
|
125
|
+
function parseInterval(every) {
|
|
126
|
+
const m = /^(\d+)\s*(ms|s|m|h|d)$/.exec(every.trim());
|
|
127
|
+
if (!m)
|
|
128
|
+
return null;
|
|
129
|
+
const n = parseInt(m[1], 10);
|
|
130
|
+
switch (m[2]) {
|
|
131
|
+
case 'ms':
|
|
132
|
+
return n;
|
|
133
|
+
case 's':
|
|
134
|
+
return n * 1000;
|
|
135
|
+
case 'm':
|
|
136
|
+
return n * 60000;
|
|
137
|
+
case 'h':
|
|
138
|
+
return n * 3600000;
|
|
139
|
+
case 'd':
|
|
140
|
+
return n * 86400000;
|
|
141
|
+
default:
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
function nextIntervalFires(intervalMs, from, count) {
|
|
146
|
+
const out = [];
|
|
147
|
+
for (let i = 1; i <= count; i++)
|
|
148
|
+
out.push(new Date(from.getTime() + i * intervalMs));
|
|
149
|
+
return out;
|
|
150
|
+
}
|
|
151
|
+
function formatWhen(d) {
|
|
152
|
+
return d.toLocaleString(undefined, {
|
|
153
|
+
weekday: 'short',
|
|
154
|
+
month: 'short',
|
|
155
|
+
day: '2-digit',
|
|
156
|
+
hour: '2-digit',
|
|
157
|
+
minute: '2-digit',
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Normalize the canonical Schedule discriminated-union and legacy flat
|
|
162
|
+
* shapes into `{ cron?, every?, at?, timezone? }` for rendering.
|
|
163
|
+
*
|
|
164
|
+
* Supports:
|
|
165
|
+
* • d.schedule = { type:'cron', expression: string | {source}, timezone? }
|
|
166
|
+
* • d.schedule = { type:'interval', intervalMs: number }
|
|
167
|
+
* • d.schedule = { type:'once', at: string }
|
|
168
|
+
* • d.schedule = "0 9 * * 1-5" (legacy: string cron)
|
|
169
|
+
* • d.cron / d.every / d.interval / d.at / d.runAt / d.timezone / d.tz
|
|
170
|
+
*/
|
|
171
|
+
function normalizeSchedule(d) {
|
|
172
|
+
// Canonical discriminated-union schedule object.
|
|
173
|
+
if (d.schedule && typeof d.schedule === 'object') {
|
|
174
|
+
const s = d.schedule;
|
|
175
|
+
const t = String(s.type ?? '');
|
|
176
|
+
const tz = s.timezone ?? d.timezone ?? d.tz;
|
|
177
|
+
if (t === 'cron') {
|
|
178
|
+
const expr = s.expression;
|
|
179
|
+
const src = typeof expr === 'string'
|
|
180
|
+
? expr
|
|
181
|
+
: expr && typeof expr === 'object' && typeof expr.source === 'string'
|
|
182
|
+
? expr.source
|
|
183
|
+
: undefined;
|
|
184
|
+
return { cron: src, timezone: tz };
|
|
185
|
+
}
|
|
186
|
+
if (t === 'interval') {
|
|
187
|
+
const ms = Number(s.intervalMs);
|
|
188
|
+
return { every: Number.isFinite(ms) && ms > 0 ? humanizeMs(ms) : undefined, timezone: tz };
|
|
189
|
+
}
|
|
190
|
+
if (t === 'once') {
|
|
191
|
+
return { at: typeof s.at === 'string' ? s.at : undefined, timezone: tz };
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
// Flat legacy shapes.
|
|
195
|
+
const cron = typeof d.cron === 'string'
|
|
196
|
+
? d.cron
|
|
197
|
+
: typeof d.schedule === 'string'
|
|
198
|
+
? d.schedule
|
|
199
|
+
: undefined;
|
|
200
|
+
const everyRaw = d.every ?? d.interval;
|
|
201
|
+
const every = typeof everyRaw === 'string'
|
|
202
|
+
? everyRaw
|
|
203
|
+
: typeof everyRaw === 'number'
|
|
204
|
+
? humanizeMs(everyRaw)
|
|
205
|
+
: undefined;
|
|
206
|
+
const at = typeof d.at === 'string' ? d.at : typeof d.runAt === 'string' ? d.runAt : undefined;
|
|
207
|
+
const timezone = d.timezone ?? d.tz;
|
|
208
|
+
return { cron, every, at, timezone };
|
|
209
|
+
}
|
|
210
|
+
function humanizeMs(ms) {
|
|
211
|
+
if (ms % 86400000 === 0)
|
|
212
|
+
return `${ms / 86400000}d`;
|
|
213
|
+
if (ms % 3600000 === 0)
|
|
214
|
+
return `${ms / 3600000}h`;
|
|
215
|
+
if (ms % 60000 === 0)
|
|
216
|
+
return `${ms / 60000}m`;
|
|
217
|
+
if (ms % 1000 === 0)
|
|
218
|
+
return `${ms / 1000}s`;
|
|
219
|
+
return `${ms}ms`;
|
|
220
|
+
}
|
|
221
|
+
export function JobPreview({ name, draft }) {
|
|
222
|
+
const d = draft;
|
|
223
|
+
const jobName = String(d.name ?? name ?? '');
|
|
224
|
+
const label = String(d.label ?? jobName);
|
|
225
|
+
const description = d.description ?? '';
|
|
226
|
+
const { cron, every, at, timezone } = normalizeSchedule(d);
|
|
227
|
+
const handler = d.handler
|
|
228
|
+
?? d.target
|
|
229
|
+
?? d.function
|
|
230
|
+
?? d.functionName;
|
|
231
|
+
const active = d.active !== false && d.enabled !== false;
|
|
232
|
+
// Canonical: retryPolicy.{maxRetries,backoffMs,backoffMultiplier}; legacy: flat fields.
|
|
233
|
+
const retryPolicy = d.retryPolicy;
|
|
234
|
+
const maxRetries = retryPolicy?.maxRetries
|
|
235
|
+
?? d.maxRetries
|
|
236
|
+
?? d.retries;
|
|
237
|
+
const backoffMs = retryPolicy?.backoffMs;
|
|
238
|
+
const timeoutMs = d.timeout ?? d.timeoutMs;
|
|
239
|
+
const concurrency = d.concurrency;
|
|
240
|
+
const intervalMs = every ? parseInterval(every) : null;
|
|
241
|
+
const { nextFires, deltas } = React.useMemo(() => {
|
|
242
|
+
const now = new Date();
|
|
243
|
+
let fires = [];
|
|
244
|
+
if (cron)
|
|
245
|
+
fires = nextCronFires(cron, now, 5);
|
|
246
|
+
else if (intervalMs)
|
|
247
|
+
fires = nextIntervalFires(intervalMs, now, 5);
|
|
248
|
+
else if (at) {
|
|
249
|
+
const t = Date.parse(at);
|
|
250
|
+
if (!Number.isNaN(t))
|
|
251
|
+
fires = [new Date(t)];
|
|
252
|
+
}
|
|
253
|
+
return {
|
|
254
|
+
nextFires: fires,
|
|
255
|
+
deltas: fires.map((f) => humanDelta(f.getTime() - now.getTime())),
|
|
256
|
+
};
|
|
257
|
+
}, [cron, intervalMs, at]);
|
|
258
|
+
const scheduleInvalid = (cron && nextFires.length === 0) || (every && !intervalMs);
|
|
259
|
+
if (!jobName && !cron && !every && !at && !handler) {
|
|
260
|
+
return (_jsx(PreviewShell, { hint: "job", children: _jsx(PreviewMessage, { children: "Set a schedule (cron / every / at) and a handler to see the job preview." }) }));
|
|
261
|
+
}
|
|
262
|
+
return (_jsx(PreviewShell, { hint: "job", children: _jsx(PreviewErrorBoundary, { children: _jsxs("div", { className: "p-3 space-y-3", children: [_jsx("div", { className: "rounded border bg-muted/30 p-3", children: _jsxs("div", { className: "flex items-start gap-2", children: [_jsx(AlarmClock, { className: "h-4 w-4 mt-0.5 text-muted-foreground shrink-0" }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("div", { className: "flex flex-wrap items-baseline gap-x-2", children: [_jsx("span", { className: "text-sm font-medium truncate", children: label }), _jsx("span", { className: "font-mono text-[10px] text-muted-foreground", children: jobName })] }), description && _jsx("div", { className: "text-xs text-muted-foreground mt-0.5", children: description }), _jsxs("div", { className: "mt-1 flex flex-wrap items-center gap-x-3 gap-y-1 text-[11px]", children: [_jsx(Pill, { icon: Power, label: active ? 'Active' : 'Paused', tone: active ? 'green' : 'gray' }), timezone && _jsx(Pill, { icon: Globe2, label: timezone, mono: true }), maxRetries != null && _jsx(Pill, { icon: RotateCcw, label: `retries: ${maxRetries}${backoffMs ? ` (${humanizeMs(backoffMs)} backoff)` : ''}` }), timeoutMs != null && _jsx(Pill, { icon: Timer, label: `timeout: ${humanizeMs(timeoutMs)}` }), concurrency != null && _jsx(Pill, { label: `concurrency: ${concurrency}` })] })] })] }) }), _jsx(Section, { title: "Schedule", icon: Calendar, children: _jsxs("div", { className: "rounded border bg-background p-2.5 text-xs space-y-1", children: [cron && (_jsx(ScheduleLine, { label: "Cron", children: _jsx("code", { className: "font-mono", children: cron }) })), every && (_jsxs(ScheduleLine, { label: "Every", children: [_jsx("code", { className: "font-mono", children: every }), !intervalMs && _jsx("span", { className: "ml-2 text-amber-700", children: "unparseable" })] })), at && (_jsx(ScheduleLine, { label: "At", children: _jsx("code", { className: "font-mono", children: at }) })), !cron && !every && !at && (_jsx("div", { className: "text-muted-foreground italic", children: "No schedule set \u2014 runs only when triggered manually." }))] }) }), (cron || intervalMs || at) && (_jsx(Section, { title: `Next ${Math.max(nextFires.length, 1)} run${nextFires.length === 1 ? '' : 's'}`, icon: Clock, children: nextFires.length === 0 ? (_jsx("div", { className: "text-xs text-amber-700", children: scheduleInvalid
|
|
263
|
+
? 'Could not derive any future fire time. Check the schedule syntax.'
|
|
264
|
+
: 'No upcoming runs in the next 366 days.' })) : (_jsx("ul", { className: "rounded border bg-background divide-y text-xs", children: nextFires.map((d, i) => (_jsxs("li", { className: "flex items-center gap-2 px-2.5 py-1.5", children: [_jsx("span", { className: "w-4 text-right text-muted-foreground text-[10px]", children: i + 1 }), _jsx(Clock, { className: "h-3 w-3 text-muted-foreground" }), _jsx("span", { className: "font-mono", children: formatWhen(d) }), _jsxs("span", { className: "ml-auto text-[10px] text-muted-foreground", children: ["in ", deltas[i]] })] }, i))) })) })), _jsx(Section, { title: "Handler", icon: Code2, children: handler ? (_jsxs("div", { className: "rounded border bg-background px-2.5 py-1.5 text-xs flex items-center gap-2", children: [_jsx(PlayCircle, { className: "h-3.5 w-3.5 text-muted-foreground" }), _jsx("code", { className: "font-mono break-all", children: handler })] })) : (_jsx("div", { className: "text-xs text-amber-700", children: "No handler bound \u2014 the job will be a no-op." })) })] }) }) }));
|
|
265
|
+
}
|
|
266
|
+
function humanDelta(ms) {
|
|
267
|
+
if (ms <= 0)
|
|
268
|
+
return 'now';
|
|
269
|
+
const s = Math.round(ms / 1000);
|
|
270
|
+
if (s < 60)
|
|
271
|
+
return `${s}s`;
|
|
272
|
+
const m = Math.round(s / 60);
|
|
273
|
+
if (m < 60)
|
|
274
|
+
return `${m}m`;
|
|
275
|
+
const h = Math.round(m / 60);
|
|
276
|
+
if (h < 48)
|
|
277
|
+
return `${h}h`;
|
|
278
|
+
const days = Math.round(h / 24);
|
|
279
|
+
return `${days}d`;
|
|
280
|
+
}
|
|
281
|
+
function ScheduleLine({ label, children }) {
|
|
282
|
+
return (_jsxs("div", { className: "flex items-center gap-1.5", children: [_jsxs("span", { className: "text-muted-foreground w-12 shrink-0", children: [label, ":"] }), _jsx("span", { className: "break-all", children: children })] }));
|
|
283
|
+
}
|
|
284
|
+
function Section({ title, icon: Icon, children, }) {
|
|
285
|
+
return (_jsxs("div", { className: "space-y-1.5", children: [_jsxs("div", { className: "flex items-center gap-1.5 text-[11px] font-medium text-muted-foreground uppercase tracking-wider", children: [Icon && _jsx(Icon, { className: "h-3 w-3" }), _jsx("span", { children: title })] }), children] }));
|
|
286
|
+
}
|
|
287
|
+
function Pill({ icon: Icon, label, tone = 'gray', mono = false, }) {
|
|
288
|
+
const cls = tone === 'green' ? 'text-emerald-700' : 'text-foreground';
|
|
289
|
+
return (_jsxs("span", { className: "inline-flex items-center gap-1", children: [Icon && _jsx(Icon, { className: "h-3 w-3 text-muted-foreground" }), _jsx("span", { className: `${cls} ${mono ? 'font-mono' : ''}`, children: label })] }));
|
|
290
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ObjectFormCanvas — form-designer-style preview for an Object
|
|
3
|
+
* metadata draft. Replaces the legacy CRUD grid in DesignerMode.
|
|
4
|
+
*
|
|
5
|
+
* Each field renders as the labeled input it will become at runtime
|
|
6
|
+
* (via {@link FieldStub}). Clicking a row selects it and the host
|
|
7
|
+
* swaps the inspector to {@link ObjectFieldInspector}. The trailing
|
|
8
|
+
* "+ Add field" button opens a categorized type picker — picking a
|
|
9
|
+
* type appends a fresh field and immediately selects it so authors
|
|
10
|
+
* can fill in name/label in the inspector.
|
|
11
|
+
*
|
|
12
|
+
* All edits go through the host's `onPatch` callback. Read-only
|
|
13
|
+
* surfaces (legacy tier objects, builtin objects) still render the
|
|
14
|
+
* preview but suppress selection chrome + the add button.
|
|
15
|
+
*/
|
|
16
|
+
import * as React from 'react';
|
|
17
|
+
import type { MetadataSelection } from '../preview-registry';
|
|
18
|
+
import { toFieldName } from './object-fields-io';
|
|
19
|
+
export interface ObjectFormCanvasProps {
|
|
20
|
+
objectName: string;
|
|
21
|
+
draft: Record<string, unknown>;
|
|
22
|
+
/** Last published version, for the review/diff mode. */
|
|
23
|
+
baseline?: Record<string, unknown>;
|
|
24
|
+
onPatch?: (patch: Record<string, unknown>) => void;
|
|
25
|
+
selection?: MetadataSelection | null;
|
|
26
|
+
onSelectionChange?: (next: MetadataSelection | null) => void;
|
|
27
|
+
locale?: string;
|
|
28
|
+
}
|
|
29
|
+
export declare function ObjectFormCanvas({ objectName, draft, baseline, onPatch, selection, onSelectionChange, locale, }: ObjectFormCanvasProps): React.JSX.Element;
|
|
30
|
+
export { toFieldName };
|