@object-ui/app-shell 6.2.3 → 7.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1229 -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 +184 -39
- 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 +747 -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 +28 -0
- package/dist/console/ai/LiveCanvas.js +80 -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 +137 -4
- package/dist/hooks/useChatConversation.js +316 -25
- package/dist/hooks/useConsoleActionRuntime.d.ts +70 -0
- package/dist/hooks/useConsoleActionRuntime.js +564 -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 +18 -8
- package/dist/index.js +17 -5
- 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 +34 -2
- package/dist/layout/ConsoleFloatingChatbot.js +391 -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 +242 -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/layout/agentPicker.d.ts +56 -0
- package/dist/layout/agentPicker.js +40 -0
- 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/CommitTimeline.d.ts +15 -0
- package/dist/preview/CommitTimeline.js +82 -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 +83 -0
- package/dist/preview/commitHistory.d.ts +28 -0
- package/dist/preview/commitHistory.js +48 -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 +192 -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 +31 -0
- package/dist/views/FlowRunner.js +121 -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/ScreenView.d.ts +70 -0
- package/dist/views/ScreenView.js +73 -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 +101 -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 +39 -0
- package/dist/views/metadata-admin/JsonSourceEditor.js +196 -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 +403 -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 +1250 -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 +258 -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 +205 -0
- package/dist/views/metadata-admin/anchors.js +255 -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 +1252 -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 +221 -0
- package/dist/views/metadata-admin/inspectors/FlowEdgeInspector.d.ts +16 -0
- package/dist/views/metadata-admin/inspectors/FlowEdgeInspector.js +126 -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 +205 -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 +55 -0
- package/dist/views/metadata-admin/inspectors/ObjectFieldInspector.d.ts +23 -0
- package/dist/views/metadata-admin/inspectors/ObjectFieldInspector.js +365 -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 +218 -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 +128 -0
- package/dist/views/metadata-admin/inspectors/_shared.js +113 -0
- package/dist/views/metadata-admin/inspectors/datasetFilterCondition.d.ts +24 -0
- package/dist/views/metadata-admin/inspectors/datasetFilterCondition.js +97 -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 +506 -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/issuePath.d.ts +22 -0
- package/dist/views/metadata-admin/issuePath.js +65 -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/package-scope.d.ts +26 -0
- package/dist/views/metadata-admin/package-scope.js +43 -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 +105 -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 +49 -0
- package/dist/views/metadata-admin/previews/FlowCanvas.js +416 -0
- package/dist/views/metadata-admin/previews/FlowPreview.d.ts +20 -0
- package/dist/views/metadata-admin/previews/FlowPreview.js +120 -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 +204 -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 +200 -5
- 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/ScreenPreview.d.ts +38 -0
- package/dist/views/metadata-admin/previews/ScreenPreview.js +61 -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 +102 -0
- package/dist/views/metadata-admin/previews/flow-canvas-layout.js +227 -0
- package/dist/views/metadata-admin/previews/flow-canvas-parts.d.ts +96 -0
- package/dist/views/metadata-admin/previews/flow-canvas-parts.js +373 -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 +130 -0
- package/dist/views/metadata-admin/previews/object-fields-io.js +243 -0
- package/dist/views/metadata-admin/previews/screen-spec.d.ts +43 -0
- package/dist/views/metadata-admin/previews/screen-spec.js +108 -0
- package/dist/views/metadata-admin/previews/simulator/flow-sim-types.d.ts +102 -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 +15 -0
- package/dist/views/metadata-admin/previews/simulator/flow-sim-validate.js +185 -0
- package/dist/views/metadata-admin/previews/simulator/flow-simulator.d.ts +73 -0
- package/dist/views/metadata-admin/previews/simulator/flow-simulator.js +426 -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,221 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.
|
|
3
|
+
/**
|
|
4
|
+
* DatasetDefaultInspector — the curated designer for an analytics `dataset`
|
|
5
|
+
* (ADR-0021). Replaces the generic whole-draft JSON SchemaForm with structured,
|
|
6
|
+
* fool-proof editors for the dataset's parts:
|
|
7
|
+
*
|
|
8
|
+
* - base `object`,
|
|
9
|
+
* - `include` relationships (the join allowlist — D-C),
|
|
10
|
+
* - `dimensions` (name + field/`relationship.field` + type + granularity), and
|
|
11
|
+
* - `measures` (name + aggregate + field + format/currency/derived).
|
|
12
|
+
*
|
|
13
|
+
* The base object, the included relationships, and every `field` are picked
|
|
14
|
+
* from the live object graph (a searchable combo over {@link useDatasetFieldCatalog})
|
|
15
|
+
* — not recalled by hand — so authoring matches mainstream low-code dataset
|
|
16
|
+
* builders. The aggregate / type / granularity are closed dropdowns so an
|
|
17
|
+
* author can't type an unsupported value. Each combo still allows a custom
|
|
18
|
+
* value as an escape hatch (offline catalog, computed path). Edits flow through
|
|
19
|
+
* `onPatch`; the DatasetPreview on the canvas re-runs live as the draft changes.
|
|
20
|
+
*/
|
|
21
|
+
import * as React from 'react';
|
|
22
|
+
import { AlertTriangle, ArrowRight, ChevronDown, Plus, Trash2, X } from 'lucide-react';
|
|
23
|
+
import { Badge, Button, FilterBuilder, Label, Popover, PopoverContent, PopoverTrigger } from '@object-ui/components';
|
|
24
|
+
import { InspectorShell, InspectorTextField, InspectorSelectField, InspectorCheckboxField, appendArray, spliceArray, } from './_shared';
|
|
25
|
+
import { InspectorComboField } from './InspectorComboField';
|
|
26
|
+
import { toFieldName } from '../previews/object-fields-io';
|
|
27
|
+
import { formatMeasure } from '@object-ui/core';
|
|
28
|
+
import { conditionToGroup, groupToCondition } from './datasetFilterCondition';
|
|
29
|
+
import { useObjectOptions, useDatasetFieldCatalog, useDatasetUsage, fieldTypeToDimensionType, } from './useDatasetFields';
|
|
30
|
+
// Closed to what the dataset compiler supports (no array_agg/string_agg in v1).
|
|
31
|
+
const AGGREGATE_OPTIONS = [
|
|
32
|
+
{ value: 'count', label: 'count' },
|
|
33
|
+
{ value: 'sum', label: 'sum' },
|
|
34
|
+
{ value: 'avg', label: 'avg' },
|
|
35
|
+
{ value: 'min', label: 'min' },
|
|
36
|
+
{ value: 'max', label: 'max' },
|
|
37
|
+
{ value: 'count_distinct', label: 'count distinct' },
|
|
38
|
+
];
|
|
39
|
+
const DIMENSION_TYPE_OPTIONS = [
|
|
40
|
+
{ value: 'string', label: 'string' },
|
|
41
|
+
{ value: 'number', label: 'number' },
|
|
42
|
+
{ value: 'date', label: 'date' },
|
|
43
|
+
{ value: 'boolean', label: 'boolean' },
|
|
44
|
+
{ value: 'lookup', label: 'lookup' },
|
|
45
|
+
];
|
|
46
|
+
const DATE_GRANULARITY_OPTIONS = [
|
|
47
|
+
{ value: '', label: '— none —' },
|
|
48
|
+
{ value: 'day', label: 'day' },
|
|
49
|
+
{ value: 'week', label: 'week' },
|
|
50
|
+
{ value: 'month', label: 'month' },
|
|
51
|
+
{ value: 'quarter', label: 'quarter' },
|
|
52
|
+
{ value: 'year', label: 'year' },
|
|
53
|
+
];
|
|
54
|
+
const DERIVED_OP_OPTIONS = [
|
|
55
|
+
{ value: 'ratio', label: 'ratio (a ÷ b)' },
|
|
56
|
+
{ value: 'sum', label: 'sum (a + b)' },
|
|
57
|
+
{ value: 'difference', label: 'difference (a − b)' },
|
|
58
|
+
{ value: 'product', label: 'product (a × b)' },
|
|
59
|
+
];
|
|
60
|
+
// Display-format picker options — a business user shouldn't have to know numeral
|
|
61
|
+
// syntax (`$0,0.00`), so the inspector offers kind + decimals + currency and
|
|
62
|
+
// generates the `format`/`currency` strings.
|
|
63
|
+
const FORMAT_KIND_OPTIONS = [
|
|
64
|
+
{ value: 'raw', label: 'Raw number' },
|
|
65
|
+
{ value: 'number', label: 'Number — 1,234.5' },
|
|
66
|
+
{ value: 'currency', label: 'Currency — $1,234.50' },
|
|
67
|
+
{ value: 'percent', label: 'Percent — 12.3%' },
|
|
68
|
+
];
|
|
69
|
+
const DECIMALS_OPTIONS = [
|
|
70
|
+
{ value: '0', label: '0' },
|
|
71
|
+
{ value: '1', label: '1' },
|
|
72
|
+
{ value: '2', label: '2' },
|
|
73
|
+
];
|
|
74
|
+
const CURRENCY_OPTIONS = [
|
|
75
|
+
{ value: 'USD', label: 'USD ($)' },
|
|
76
|
+
{ value: 'EUR', label: 'EUR (€)' },
|
|
77
|
+
{ value: 'GBP', label: 'GBP (£)' },
|
|
78
|
+
{ value: 'CNY', label: 'CNY (¥)' },
|
|
79
|
+
{ value: 'JPY', label: 'JPY (¥)' },
|
|
80
|
+
{ value: 'INR', label: 'INR (₹)' },
|
|
81
|
+
{ value: 'CAD', label: 'CAD ($)' },
|
|
82
|
+
{ value: 'AUD', label: 'AUD ($)' },
|
|
83
|
+
];
|
|
84
|
+
function SectionHeader({ title, count, onAdd, addLabel }) {
|
|
85
|
+
return (_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { className: "flex items-center gap-1.5", children: [_jsx(Label, { className: "text-xs text-muted-foreground", children: title }), _jsx(Badge, { variant: "outline", className: "text-[10px]", children: count })] }), onAdd && (_jsxs(Button, { type: "button", variant: "ghost", size: "sm", className: "h-6 gap-1 px-1.5 text-[11px]", onClick: onAdd, children: [_jsx(Plus, { className: "h-3 w-3" }), " ", addLabel] }))] }));
|
|
86
|
+
}
|
|
87
|
+
/** Native disclosure for a row's optional / advanced fields. */
|
|
88
|
+
function Advanced({ children }) {
|
|
89
|
+
return (_jsxs("details", { className: "group", children: [_jsx("summary", { className: "cursor-pointer select-none list-none text-[11px] text-muted-foreground hover:text-foreground", children: _jsxs("span", { className: "inline-flex items-center gap-1", children: [_jsx(ArrowRight, { className: "h-3 w-3 transition-transform group-open:rotate-90" }), "Advanced"] }) }), _jsx("div", { className: "mt-1.5 space-y-1.5 border-l pl-2.5", children: children })] }));
|
|
90
|
+
}
|
|
91
|
+
/** Best-effort parse of a stored measure format into the picker's {kind, decimals}. */
|
|
92
|
+
function parseMeasureFormat(format, currency) {
|
|
93
|
+
const f = (format ?? '').trim();
|
|
94
|
+
const m = f.match(/\.(0+)/);
|
|
95
|
+
const decimals = m ? Math.min(m[1].length, 2) : 0;
|
|
96
|
+
if (currency || /[$£€¥₹]/.test(f))
|
|
97
|
+
return { kind: 'currency', decimals };
|
|
98
|
+
if (f.includes('%'))
|
|
99
|
+
return { kind: 'percent', decimals };
|
|
100
|
+
if (f)
|
|
101
|
+
return { kind: 'number', decimals };
|
|
102
|
+
return { kind: 'raw', decimals: 0 };
|
|
103
|
+
}
|
|
104
|
+
/** Generate {format, currency} from the picker selection. */
|
|
105
|
+
function buildMeasureFormat(kind, decimals, currency) {
|
|
106
|
+
const dp = decimals > 0 ? '.' + '0'.repeat(decimals) : '';
|
|
107
|
+
switch (kind) {
|
|
108
|
+
case 'number': return { format: `0,0${dp}`, currency: undefined };
|
|
109
|
+
case 'currency': return { format: `0,0${dp}`, currency: currency || 'USD' };
|
|
110
|
+
case 'percent': return { format: `0${dp}%`, currency: undefined };
|
|
111
|
+
default: return { format: undefined, currency: undefined };
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Structured display-format picker for a measure. Maps {kind, decimals, currency}
|
|
116
|
+
* ⇄ the spec's `format`/`currency` strings and shows a live sample so a business
|
|
117
|
+
* user never has to hand-write a numeral pattern.
|
|
118
|
+
*/
|
|
119
|
+
function MeasureFormatField({ measure, onPatch, disabled }) {
|
|
120
|
+
const { kind, decimals } = parseMeasureFormat(measure.format, measure.currency);
|
|
121
|
+
const currency = measure.currency || 'USD';
|
|
122
|
+
const apply = (k, d, c) => onPatch(buildMeasureFormat(k, d, c));
|
|
123
|
+
const sample = formatMeasure(kind === 'percent' ? 0.1234 : 1234.5, measure.format, measure.currency);
|
|
124
|
+
return (_jsxs("div", { className: "space-y-1.5", children: [_jsxs("div", { className: "grid grid-cols-2 gap-1.5", children: [_jsx(InspectorSelectField, { label: "Display format", value: kind, options: FORMAT_KIND_OPTIONS, onCommit: (v) => apply(v, decimals, currency), disabled: disabled }), kind !== 'raw' && (_jsx(InspectorSelectField, { label: "Decimals", value: String(decimals), options: DECIMALS_OPTIONS, onCommit: (v) => apply(kind, parseInt(v, 10) || 0, currency), disabled: disabled }))] }), kind === 'currency' && (_jsx(InspectorSelectField, { label: "Currency", value: currency, options: CURRENCY_OPTIONS, onCommit: (v) => apply(kind, decimals, v), disabled: disabled })), kind !== 'raw' && (_jsxs("p", { className: "text-[10px] text-muted-foreground", children: ["Sample: ", _jsx("span", { className: "font-mono tabular-nums", children: sample })] }))] }));
|
|
125
|
+
}
|
|
126
|
+
/** The relationship prefix of a `relationship.field` path that isn't yet in `include`, else null. */
|
|
127
|
+
function missingRelationship(field, include) {
|
|
128
|
+
if (!field || !field.includes('.'))
|
|
129
|
+
return null;
|
|
130
|
+
const rel = field.split('.')[0];
|
|
131
|
+
return rel && !include.includes(rel) ? rel : null;
|
|
132
|
+
}
|
|
133
|
+
/** Inline author-time warning: a `relationship.field` whose join isn't declared in `include`. */
|
|
134
|
+
function RelWarning({ rel, onAdd, disabled }) {
|
|
135
|
+
return (_jsxs("p", { className: "flex items-center gap-1 text-[10px] text-amber-600 dark:text-amber-400", children: [_jsx(AlertTriangle, { className: "h-3 w-3 shrink-0" }), _jsxs("span", { children: ["Relationship ", _jsx("code", { className: "font-mono", children: rel }), " isn't in Included relationships."] }), !disabled && onAdd && (_jsx("button", { type: "button", className: "underline hover:no-underline", onClick: onAdd, children: "Add it" }))] }));
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Visual filter editor for a dataset/measure `FilterCondition`. Wraps the shared
|
|
139
|
+
* {@link FilterBuilder} (a flat AND of `field op value` rows) and converts to/from
|
|
140
|
+
* the spec's Mongo-style `FilterCondition`. Filters it can't faithfully edit
|
|
141
|
+
* (nested / `$or` / multi-op) degrade to a "edit in Source" note rather than being
|
|
142
|
+
* silently rewritten. See {@link conditionToGroup} / {@link groupToCondition}.
|
|
143
|
+
*/
|
|
144
|
+
function DatasetFilterField({ label, help, value, onCommit, fields, disabled }) {
|
|
145
|
+
const { group, representable } = conditionToGroup(value);
|
|
146
|
+
const count = group.conditions.length;
|
|
147
|
+
return (_jsxs("div", { className: "space-y-1", children: [_jsx(Label, { className: "text-xs text-muted-foreground", children: label }), !representable ? (_jsxs("p", { className: "rounded-md border border-dashed bg-muted/30 px-2.5 py-1.5 text-[11px] text-muted-foreground", children: ["Advanced filter (nested / OR) \u2014 edit it in the ", _jsx("span", { className: "font-medium", children: "Source" }), " tab."] })) : (_jsxs(Popover, { children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs(Button, { type: "button", variant: "outline", size: "sm", disabled: disabled, className: "h-8 w-full justify-between text-xs font-normal", children: [_jsx("span", { className: "truncate text-left", children: count ? `${count} condition${count === 1 ? '' : 's'}` : _jsx("span", { className: "text-muted-foreground", children: "+ Add filter\u2026" }) }), _jsx(ChevronDown, { className: "h-3.5 w-3.5 opacity-60 shrink-0" })] }) }), _jsx(PopoverContent, { align: "start", className: "w-[440px] max-w-[90vw] p-3", children: fields.length === 0 ? (_jsx("p", { className: "text-xs text-muted-foreground", children: "Pick a base object to add filter conditions." })) : (_jsx(FilterBuilder, { fields: fields, value: group, onChange: (g) => onCommit(groupToCondition(g)) })) })] })), help && _jsx("p", { className: "text-[10px] text-muted-foreground", children: help })] }));
|
|
148
|
+
}
|
|
149
|
+
export function DatasetDefaultInspector({ draft, onPatch, readOnly, name }) {
|
|
150
|
+
const label = typeof draft.label === 'string' ? draft.label : '';
|
|
151
|
+
const description = typeof draft.description === 'string' ? draft.description : '';
|
|
152
|
+
const object = typeof draft.object === 'string' ? draft.object : '';
|
|
153
|
+
const include = Array.isArray(draft.include) ? draft.include : [];
|
|
154
|
+
const dimensions = Array.isArray(draft.dimensions) ? draft.dimensions : [];
|
|
155
|
+
const measures = Array.isArray(draft.measures) ? draft.measures : [];
|
|
156
|
+
const datasetName = typeof draft.name === 'string' ? draft.name : undefined;
|
|
157
|
+
// In create mode the host passes an empty `name` (the PK is assigned on first
|
|
158
|
+
// save). Mirror ReportDefaultInspector: expose an editable Name that auto-
|
|
159
|
+
// derives a snake_case slug from the label until the author edits it directly,
|
|
160
|
+
// so a dataset created through the canvas saves with a valid identifier instead
|
|
161
|
+
// of dead-ending on the empty-name identity rule.
|
|
162
|
+
const createMode = !name;
|
|
163
|
+
const nameTouched = React.useRef(false);
|
|
164
|
+
const nameValue = typeof draft.name === 'string' ? draft.name : '';
|
|
165
|
+
const { options: objectOptions, loading: objectsLoading } = useObjectOptions();
|
|
166
|
+
const { relationships, fieldOptions, loading: catalogLoading } = useDatasetFieldCatalog(object, include);
|
|
167
|
+
const usage = useDatasetUsage(datasetName);
|
|
168
|
+
const objectComboOptions = React.useMemo(() => objectOptions.map((o) => ({ value: o.name, label: o.label })), [objectOptions]);
|
|
169
|
+
const relationshipComboOptions = React.useMemo(() => relationships.map((r) => ({ value: r.name, label: r.label, hint: r.referenceTo ? `→ ${r.referenceTo}` : undefined })), [relationships]);
|
|
170
|
+
const fieldComboOptions = React.useMemo(() => fieldOptions.map((f) => ({ value: f.value, label: f.label, hint: f.type, group: f.group })), [fieldOptions]);
|
|
171
|
+
// Base-object fields for the filter builders (scope + measure filters operate on
|
|
172
|
+
// the base table; relationship-path filters are out of scope for v1).
|
|
173
|
+
const filterFields = React.useMemo(() => fieldOptions.filter((f) => !f.value.includes('.')).map((f) => ({ value: f.value, label: f.label, type: f.type })), [fieldOptions]);
|
|
174
|
+
const datasetFilter = draft.filter && typeof draft.filter === 'object' ? draft.filter : undefined;
|
|
175
|
+
const baseLabel = objectComboOptions.find((o) => o.value === object)?.label ?? object;
|
|
176
|
+
const patchDimension = (i, patch) => onPatch({ dimensions: dimensions.map((d, idx) => (idx === i ? { ...d, ...patch } : d)) });
|
|
177
|
+
const patchMeasure = (i, patch) => onPatch({ measures: measures.map((m, idx) => (idx === i ? { ...m, ...patch } : m)) });
|
|
178
|
+
// Picking a field auto-infers the dimension type from the field's framework
|
|
179
|
+
// type (region:string, close_date:date, …) — the BI "pick field, type follows"
|
|
180
|
+
// convention — while leaving the Type select free to override.
|
|
181
|
+
const leafName = (path) => (path.includes('.') ? path.split('.').pop() ?? path : path);
|
|
182
|
+
const pickDimensionField = (i, v) => {
|
|
183
|
+
const opt = fieldOptions.find((o) => o.value === v);
|
|
184
|
+
const patch = opt?.type ? { field: v, type: fieldTypeToDimensionType(opt.type) } : { field: v };
|
|
185
|
+
if (!dimensions[i]?.name)
|
|
186
|
+
patch.name = leafName(v); // auto-name from field when unnamed
|
|
187
|
+
patchDimension(i, patch);
|
|
188
|
+
};
|
|
189
|
+
const pickMeasureField = (i, v) => {
|
|
190
|
+
const patch = { field: v };
|
|
191
|
+
if (!measures[i]?.name)
|
|
192
|
+
patch.name = leafName(v); // auto-name from field when unnamed
|
|
193
|
+
patchMeasure(i, patch);
|
|
194
|
+
};
|
|
195
|
+
return (_jsxs(InspectorShell, { kindLabel: "Dataset", title: String(label || draft.name || 'Dataset'), onClose: () => { }, hideClose: true, children: [datasetName && !usage.loading && (_jsx("p", { className: usage.reports + usage.dashboards > 0
|
|
196
|
+
? 'rounded-md border border-amber-500/30 bg-amber-500/5 px-2.5 py-1.5 text-[11px] text-amber-700 dark:text-amber-300'
|
|
197
|
+
: 'text-[11px] text-muted-foreground', children: usage.reports + usage.dashboards > 0
|
|
198
|
+
? `Bound by ${usage.reports} report${usage.reports === 1 ? '' : 's'} · ${usage.dashboards} dashboard${usage.dashboards === 1 ? '' : 's'} — changes affect them.`
|
|
199
|
+
: 'Not yet bound by any report or dashboard.' })), createMode && (_jsx(InspectorTextField, { label: "Name", value: nameValue, onCommit: (v) => { nameTouched.current = true; onPatch({ name: toFieldName(v) }); }, placeholder: "snake_case identifier", disabled: readOnly, mono: true })), _jsx(InspectorTextField, { label: "Label", value: label, onCommit: (v) => {
|
|
200
|
+
// Live-derive the snake_case name from the label until the author edits
|
|
201
|
+
// the Name field directly (create mode only).
|
|
202
|
+
const patch = { label: v };
|
|
203
|
+
if (createMode && !nameTouched.current)
|
|
204
|
+
patch.name = toFieldName(v);
|
|
205
|
+
onPatch(patch);
|
|
206
|
+
}, disabled: readOnly }), _jsx(InspectorTextField, { label: "Description", value: description, onCommit: (v) => onPatch({ description: v }), disabled: readOnly }), _jsx(InspectorComboField, { label: "Base object", value: object, onCommit: (v) => onPatch({ object: v }), options: objectComboOptions, loading: objectsLoading, placeholder: "Select an object\u2026", searchPlaceholder: "Search objects\u2026", disabled: readOnly, mono: true }), _jsxs("div", { className: "border-t pt-3 space-y-1.5", children: [_jsx(SectionHeader, { title: "Included relationships", count: include.length, addLabel: "Add", onAdd: readOnly ? undefined : () => onPatch({ include: appendArray(include, '') }) }), include.length === 0 ? (_jsxs("p", { className: "rounded-md border border-dashed bg-muted/30 px-3 py-2 text-center text-[11px] text-muted-foreground", children: ["No joins. Add a relationship (a lookup field on ", _jsx("code", { children: baseLabel || 'the base object' }), ") to use ", _jsx("code", { children: "relationship.field" }), " dimensions/measures."] })) : (include.map((rel, i) => (_jsxs("div", { className: "flex items-center gap-1.5", children: [_jsx(InspectorComboField, { value: rel, onCommit: (v) => onPatch({ include: include.map((r, idx) => (idx === i ? v : r)) }), options: relationshipComboOptions, loading: catalogLoading, placeholder: "Select a relationship\u2026", searchPlaceholder: "Search relationships\u2026", disabled: readOnly, mono: true }), !readOnly && (_jsx(Button, { type: "button", variant: "ghost", size: "sm", className: "h-7 w-7 shrink-0 p-0", onClick: () => onPatch({ include: spliceArray(include, i, null) }), "aria-label": "Remove relationship", children: _jsx(X, { className: "h-3.5 w-3.5" }) }))] }, i)))), object && include.length > 0 && (_jsxs("div", { className: "flex flex-wrap items-center gap-x-1 gap-y-0.5 pt-0.5 text-[10px] text-muted-foreground", children: [_jsx("span", { className: "font-mono font-medium", children: baseLabel }), include.map((rel, i) => {
|
|
207
|
+
const r = relationships.find((x) => x.name === rel);
|
|
208
|
+
return (_jsxs("span", { className: "inline-flex items-center gap-1", children: [_jsx(ArrowRight, { className: "h-3 w-3 opacity-60" }), _jsxs("span", { className: "font-mono", children: [rel, r?.referenceTo ? ` (${r.referenceTo})` : ''] })] }, i));
|
|
209
|
+
})] }))] }), _jsx("div", { className: "border-t pt-3", children: _jsx(DatasetFilterField, { label: "Scope filter", help: "Intrinsic scope, ANDed into every query (e.g. exclude soft-deleted records).", value: datasetFilter, onCommit: (fc) => onPatch({ filter: fc }), fields: filterFields, disabled: readOnly }) }), _jsxs("div", { className: "border-t pt-3 space-y-2", children: [_jsx(SectionHeader, { title: "Dimensions", count: dimensions.length, addLabel: "Add dimension", onAdd: readOnly ? undefined : () => onPatch({ dimensions: appendArray(dimensions, { name: '', field: '', type: 'string' }) }) }), dimensions.map((d, i) => (_jsxs("div", { className: "rounded-md border p-2 space-y-1.5", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("span", { className: "text-[11px] font-medium text-muted-foreground", children: ["Dimension ", i + 1] }), !readOnly && (_jsx(Button, { type: "button", variant: "ghost", size: "sm", "aria-label": "Remove dimension", title: "Remove dimension", className: "h-6 w-6 shrink-0 p-0 text-muted-foreground hover:text-destructive", onClick: () => onPatch({ dimensions: spliceArray(dimensions, i, null) }), children: _jsx(Trash2, { className: "h-3.5 w-3.5" }) }))] }), _jsx(InspectorTextField, { label: "Name", value: d.name ?? '', onCommit: (v) => patchDimension(i, { name: v }), placeholder: "e.g. region", disabled: readOnly, mono: true }), _jsx(InspectorComboField, { label: "Field", value: d.field ?? '', onCommit: (v) => pickDimensionField(i, v), options: fieldComboOptions, loading: catalogLoading, placeholder: "field or relationship.field", searchPlaceholder: "Search fields\u2026", disabled: readOnly, mono: true }), (() => { const rel = missingRelationship(d.field, include); return rel ? _jsx(RelWarning, { rel: rel, disabled: readOnly, onAdd: () => onPatch({ include: appendArray(include, rel) }) }) : null; })(), _jsx(InspectorSelectField, { label: "Type", value: d.type, options: DIMENSION_TYPE_OPTIONS, onCommit: (v) => patchDimension(i, { type: v }), disabled: readOnly }), _jsxs(Advanced, { children: [_jsx(InspectorTextField, { label: "Label (optional)", value: d.label ?? '', onCommit: (v) => patchDimension(i, { label: v || undefined }), placeholder: d.name || 'Display label', disabled: readOnly }), d.type === 'date' && (_jsx(InspectorSelectField, { label: "Date bucket", value: d.dateGranularity ?? '', options: DATE_GRANULARITY_OPTIONS, onCommit: (v) => patchDimension(i, { dateGranularity: v || undefined }), disabled: readOnly }))] })] }, i)))] }), _jsxs("div", { className: "border-t pt-3 space-y-2", children: [_jsx(SectionHeader, { title: "Measures", count: measures.length, addLabel: "Add measure", onAdd: readOnly ? undefined : () => onPatch({ measures: appendArray(measures, { name: '', aggregate: 'sum', field: '' }) }) }), measures.map((m, i) => {
|
|
210
|
+
const otherMeasures = measures.filter((_, idx) => idx !== i).map((x) => x.name).filter((n) => !!n);
|
|
211
|
+
const derived = m.derived;
|
|
212
|
+
return (_jsxs("div", { className: "rounded-md border p-2 space-y-1.5", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("span", { className: "text-[11px] font-medium text-muted-foreground", children: ["Measure ", i + 1] }), !readOnly && (_jsx(Button, { type: "button", variant: "ghost", size: "sm", "aria-label": "Remove measure", title: "Remove measure", className: "h-6 w-6 shrink-0 p-0 text-muted-foreground hover:text-destructive", onClick: () => onPatch({ measures: spliceArray(measures, i, null) }), children: _jsx(Trash2, { className: "h-3.5 w-3.5" }) }))] }), _jsx(InspectorTextField, { label: "Name", value: m.name ?? '', onCommit: (v) => patchMeasure(i, { name: v }), placeholder: "e.g. revenue", disabled: readOnly, mono: true }), _jsx(InspectorSelectField, { label: "Aggregate", value: m.aggregate, options: AGGREGATE_OPTIONS, onCommit: (v) => patchMeasure(i, { aggregate: v }), disabled: readOnly }), _jsx(InspectorComboField, { label: "Field", value: m.field ?? '', onCommit: (v) => pickMeasureField(i, v), options: fieldComboOptions, loading: catalogLoading, placeholder: "field (optional for count)", searchPlaceholder: "Search fields\u2026", disabled: readOnly, mono: true }), (() => { const rel = missingRelationship(m.field, include); return rel ? _jsx(RelWarning, { rel: rel, disabled: readOnly, onAdd: () => onPatch({ include: appendArray(include, rel) }) }) : null; })(), _jsxs(Advanced, { children: [_jsx(InspectorTextField, { label: "Label (optional)", value: m.label ?? '', onCommit: (v) => patchMeasure(i, { label: v || undefined }), placeholder: m.name || 'Display label', disabled: readOnly }), _jsx(MeasureFormatField, { measure: m, onPatch: (pp) => patchMeasure(i, pp), disabled: readOnly }), _jsx(DatasetFilterField, { label: "Filter (measure-scoped)", help: "Only rows matching this filter feed this measure (e.g. won_amount = sum(amount) where stage = won).", value: m.filter, onCommit: (fc) => patchMeasure(i, { filter: fc }), fields: filterFields, disabled: readOnly }), _jsx(InspectorCheckboxField, { label: "Derived \u2014 computed from other measures", value: !!derived, onCommit: (v) => patchMeasure(i, { derived: v ? { op: 'ratio', of: [] } : undefined }), disabled: readOnly }), derived && (_jsxs("div", { className: "space-y-1.5 rounded-md border border-dashed p-2", children: [_jsx(InspectorSelectField, { label: "Operation", value: derived.op, options: DERIVED_OP_OPTIONS, onCommit: (v) => patchMeasure(i, { derived: { ...derived, op: v } }), disabled: readOnly }), _jsx(Label, { className: "text-xs text-muted-foreground", children: "Operands (other measures)" }), (() => { const need = derived.op === 'ratio' || derived.op === 'difference' ? 2 : 1; const have = Array.isArray(derived.of) ? derived.of.length : 0; return have < need ? _jsxs("p", { className: "text-[10px] text-amber-600 dark:text-amber-400", children: ["Select ", need === 2 ? 'exactly 2 measures' : 'at least 1 measure', " for ", derived.op, "."] }) : null; })(), otherMeasures.length === 0 ? (_jsx("p", { className: "text-[11px] italic text-muted-foreground", children: "Add other measures first." })) : (_jsx("div", { className: "space-y-1", children: otherMeasures.map((nm) => {
|
|
213
|
+
const checked = Array.isArray(derived.of) && derived.of.includes(nm);
|
|
214
|
+
return (_jsx(InspectorCheckboxField, { label: nm, value: checked, disabled: readOnly, onCommit: (v) => {
|
|
215
|
+
const current = Array.isArray(derived.of) ? derived.of : [];
|
|
216
|
+
const next = v ? [...current, nm] : current.filter((x) => x !== nm);
|
|
217
|
+
patchMeasure(i, { derived: { ...derived, of: next } });
|
|
218
|
+
} }, nm));
|
|
219
|
+
}) }))] }))] })] }, i));
|
|
220
|
+
})] })] }));
|
|
221
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FlowEdgeInspector — scoped editor for the selected flow connection (edge).
|
|
3
|
+
*
|
|
4
|
+
* Selection shape: { kind: 'edge', id: <edgeKey> }
|
|
5
|
+
* Patches: draft.edges[i] = {...edge, ...updates}
|
|
6
|
+
*
|
|
7
|
+
* An edge carries the flow's routing semantics between two nodes: an optional
|
|
8
|
+
* branch `label` (e.g. an Approval node's `approve` / `reject` out-edge, a
|
|
9
|
+
* Decision branch name), a guard `condition` (a CEL expression the engine
|
|
10
|
+
* evaluates to pick the branch), and an `isDefault` flag marking the fallback
|
|
11
|
+
* ("else") branch. Source / target are shown read-only — rewiring is done on
|
|
12
|
+
* the canvas, not here — so the edge's identity key stays stable across edits.
|
|
13
|
+
*/
|
|
14
|
+
import * as React from 'react';
|
|
15
|
+
import type { MetadataInspectorProps } from '../inspector-registry';
|
|
16
|
+
export declare function FlowEdgeInspector({ selection, draft, onPatch, onClearSelection, locale, readOnly }: MetadataInspectorProps): React.JSX.Element;
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { t } from '../i18n';
|
|
3
|
+
import { InspectorShell, InspectorTextField, InspectorSelectField, InspectorCheckboxField, InspectorRemoveButton, InspectorEmptyState, spliceArray, } from './_shared';
|
|
4
|
+
import { Label } from '@object-ui/components';
|
|
5
|
+
import { edgeKey, conditionText } from '../previews/flow-canvas-layout';
|
|
6
|
+
import { validateExpressionClient } from './expression-validate';
|
|
7
|
+
/** Read-only display of an edge endpoint (source / target node id). */
|
|
8
|
+
function EndpointRow({ label, value }) {
|
|
9
|
+
return (_jsxs("div", { className: "space-y-1", children: [_jsx(Label, { className: "text-xs text-muted-foreground", children: label }), _jsx("div", { className: "flex h-8 items-center rounded border bg-muted/30 px-2 font-mono text-sm text-muted-foreground", children: value })] }));
|
|
10
|
+
}
|
|
11
|
+
export function FlowEdgeInspector({ selection, draft, onPatch, onClearSelection, locale, readOnly }) {
|
|
12
|
+
const edges = Array.isArray(draft.edges) ? draft.edges : [];
|
|
13
|
+
const index = edges.findIndex((e, i) => edgeKey(e, i) === selection.id);
|
|
14
|
+
const edge = index >= 0 ? edges[index] : null;
|
|
15
|
+
if (!edge) {
|
|
16
|
+
return (_jsx(InspectorShell, { kindLabel: t('engine.inspector.flowEdge.kind', locale), title: selection.label ?? selection.id, onClose: onClearSelection, closeLabel: t('engine.inspector.flowEdge.close', locale), children: _jsx(InspectorEmptyState, { message: t('engine.inspector.flowEdge.missing', locale) }) }));
|
|
17
|
+
}
|
|
18
|
+
// Splice an updated edge in place. A field edit never moves the edge in the
|
|
19
|
+
// array, so the row index is stable; but an edge without an explicit `id`
|
|
20
|
+
// keys off `source->target#index`, so we re-point the selection to the fresh
|
|
21
|
+
// key after the patch to keep the panel attached to the same edge.
|
|
22
|
+
const patchEdge = (updates) => {
|
|
23
|
+
const next = { ...edge, ...updates };
|
|
24
|
+
// Prune empty optional keys so a cleared field doesn't linger in the draft.
|
|
25
|
+
for (const k of ['label', 'condition', 'isDefault']) {
|
|
26
|
+
const v = next[k];
|
|
27
|
+
if (v === undefined || v === '' || v === false)
|
|
28
|
+
delete next[k];
|
|
29
|
+
}
|
|
30
|
+
// `type` defaults to 'default' (FlowEdgeSchema) — don't persist the noise so
|
|
31
|
+
// a normal edge stays `{ source, target }`; only `back`/`fault`/`conditional`
|
|
32
|
+
// are written.
|
|
33
|
+
if (next.type === 'default' || next.type === '' || next.type === undefined)
|
|
34
|
+
delete next.type;
|
|
35
|
+
onPatch({ edges: spliceArray(edges, index, next) });
|
|
36
|
+
};
|
|
37
|
+
const isDefault = edge.isDefault === true;
|
|
38
|
+
// Decision out-edges can bind EXPLICITLY to one of the source decision's
|
|
39
|
+
// branches (vs the implicit by-order auto-wire): picking a branch writes its
|
|
40
|
+
// expression / label (or marks the default) onto this edge, so routing stays
|
|
41
|
+
// correct even when edges are connected out of branch order.
|
|
42
|
+
const nodes = Array.isArray(draft.nodes)
|
|
43
|
+
? (draft.nodes)
|
|
44
|
+
: [];
|
|
45
|
+
const sourceNode = nodes.find((n) => n.id === edge.source);
|
|
46
|
+
const branches = sourceNode?.type === 'decision' &&
|
|
47
|
+
Array.isArray(sourceNode.config?.conditions)
|
|
48
|
+
? (sourceNode.config.conditions)
|
|
49
|
+
: [];
|
|
50
|
+
const branchExpr = (b) => (typeof b.expression === 'string' ? b.expression.trim() : '');
|
|
51
|
+
const branchName = (b) => (typeof b.label === 'string' ? b.label.trim() : '');
|
|
52
|
+
// Which branch this edge currently represents: the default edge maps to the
|
|
53
|
+
// `true`/empty branch; otherwise match by condition, then by label. '' = custom.
|
|
54
|
+
const selectedBranch = (() => {
|
|
55
|
+
if (!branches.length)
|
|
56
|
+
return '';
|
|
57
|
+
if (isDefault) {
|
|
58
|
+
const i = branches.findIndex((b) => { const e = branchExpr(b); return e === '' || e === 'true'; });
|
|
59
|
+
return i >= 0 ? String(i) : '';
|
|
60
|
+
}
|
|
61
|
+
const cond = conditionText(edge.condition);
|
|
62
|
+
let i = cond ? branches.findIndex((b) => branchExpr(b) === cond) : -1;
|
|
63
|
+
if (i < 0 && edge.label)
|
|
64
|
+
i = branches.findIndex((b) => branchName(b) === edge.label);
|
|
65
|
+
return i >= 0 ? String(i) : '';
|
|
66
|
+
})();
|
|
67
|
+
const applyBranch = (key) => {
|
|
68
|
+
if (key === '')
|
|
69
|
+
return; // keep current custom values
|
|
70
|
+
const b = branches[Number(key)];
|
|
71
|
+
if (!b)
|
|
72
|
+
return;
|
|
73
|
+
const expr = branchExpr(b);
|
|
74
|
+
const lbl = branchName(b) || undefined;
|
|
75
|
+
if (expr === '' || expr === 'true')
|
|
76
|
+
patchEdge({ isDefault: true, condition: undefined, label: lbl });
|
|
77
|
+
else
|
|
78
|
+
patchEdge({ isDefault: false, condition: expr, label: lbl });
|
|
79
|
+
};
|
|
80
|
+
// Approval out-edges (ADR-0019/0044) route by branch *label*: the engine
|
|
81
|
+
// resumes down the out-edge whose label matches the decision — `approve` /
|
|
82
|
+
// `reject`, or `revise` (ADR-0044 send-back-for-revision). Offer those as a
|
|
83
|
+
// picker (mirrors APPROVAL_BRANCH_LABELS in @objectstack/spec) so the author
|
|
84
|
+
// need not recall the exact keyword; a free-text label is still allowed.
|
|
85
|
+
const isApprovalSource = sourceNode?.type === 'approval';
|
|
86
|
+
const APPROVAL_BRANCHES = ['approve', 'reject', 'revise'];
|
|
87
|
+
const currentApprovalBranch = (() => {
|
|
88
|
+
const l = (edge.label ?? '').trim().toLowerCase();
|
|
89
|
+
return APPROVAL_BRANCHES.includes(l) ? l : '';
|
|
90
|
+
})();
|
|
91
|
+
const edgeType = (typeof edge.type === 'string' && edge.type) || 'default';
|
|
92
|
+
return (_jsxs(InspectorShell, { kindLabel: t('engine.inspector.flowEdge.kind', locale), title: selection.label ?? `${edge.source} → ${edge.target}`, onClose: onClearSelection, closeLabel: t('engine.inspector.flowEdge.close', locale), footer: _jsx(InspectorRemoveButton, { label: t('engine.inspector.flowEdge.remove', locale), onClick: () => {
|
|
93
|
+
onPatch({ edges: spliceArray(edges, index, null) });
|
|
94
|
+
onClearSelection();
|
|
95
|
+
}, disabled: readOnly }), children: [_jsx(EndpointRow, { label: t('engine.inspector.flowEdge.source', locale), value: edge.source }), _jsx(EndpointRow, { label: t('engine.inspector.flowEdge.target', locale), value: edge.target }), _jsxs("div", { className: "flex items-center gap-2 pt-1", children: [_jsx("span", { className: "text-[11px] font-semibold uppercase tracking-wide text-muted-foreground", children: t('engine.inspector.flowEdge.routing', locale) }), _jsx("span", { className: "h-px flex-1 bg-border", "aria-hidden": true })] }), branches.length > 0 && (_jsx(InspectorSelectField, { label: t('engine.inspector.flowEdge.branch', locale), value: selectedBranch, options: [
|
|
96
|
+
...branches.map((b, i) => {
|
|
97
|
+
const expr = branchExpr(b);
|
|
98
|
+
const nm = branchName(b) || `Branch ${i + 1}`;
|
|
99
|
+
const suffix = expr === '' || expr === 'true' ? ' \u00b7 default' : ` \u00b7 ${expr}`;
|
|
100
|
+
return { value: String(i), label: `${nm}${suffix}` };
|
|
101
|
+
}),
|
|
102
|
+
{ value: '', label: '\u2014 Custom \u2014' },
|
|
103
|
+
], onCommit: applyBranch, disabled: readOnly })), isApprovalSource && (_jsx(InspectorSelectField, { label: t('engine.inspector.flowEdge.approvalBranch', locale), value: currentApprovalBranch, options: [
|
|
104
|
+
{ value: 'approve', label: t('engine.inspector.flowEdge.branchApprove', locale) },
|
|
105
|
+
{ value: 'reject', label: t('engine.inspector.flowEdge.branchReject', locale) },
|
|
106
|
+
{ value: 'revise', label: t('engine.inspector.flowEdge.branchRevise', locale) },
|
|
107
|
+
{ value: '', label: t('engine.inspector.flowEdge.branchCustom', locale) },
|
|
108
|
+
],
|
|
109
|
+
// Picking a branch writes the matching label; "Custom" keeps the
|
|
110
|
+
// free-text label the author typed below.
|
|
111
|
+
onCommit: (v) => { if (v)
|
|
112
|
+
patchEdge({ label: v }); }, disabled: readOnly })), _jsx(InspectorTextField, { label: t('engine.inspector.flowEdge.label', locale), value: edge.label ?? '', onCommit: (v) => patchEdge({ label: v }), placeholder: t('engine.inspector.flowEdge.labelHint', locale), disabled: readOnly || isDefault }), _jsx(InspectorTextField, { label: t('engine.inspector.flowEdge.condition', locale), value: conditionText(edge.condition) ?? '', onCommit: (v) => patchEdge({ condition: v || undefined }), placeholder: t('engine.inspector.flowEdge.conditionHint', locale), disabled: readOnly || isDefault, mono: true }), (() => {
|
|
113
|
+
// ADR-0032 — flag a malformed edge guard (e.g. `{record.x}` brace-in-CEL)
|
|
114
|
+
// inline, with the same corrective message as build/agent validation.
|
|
115
|
+
const issue = isDefault ? null : validateExpressionClient('predicate', edge.condition);
|
|
116
|
+
return issue ? (_jsx("p", { className: "text-[11px] leading-snug text-destructive", role: "alert", children: issue.message })) : null;
|
|
117
|
+
})(), _jsx(InspectorCheckboxField, { label: t('engine.inspector.flowEdge.isDefault', locale), value: isDefault,
|
|
118
|
+
// The default ("else") branch is taken when no other guard matches, so
|
|
119
|
+
// it carries neither a condition nor a branch label — clear both.
|
|
120
|
+
onCommit: (v) => patchEdge(v ? { isDefault: true, condition: undefined, label: undefined } : { isDefault: false }), disabled: readOnly }), _jsx("p", { className: "text-[11px] leading-snug text-muted-foreground", children: t('engine.inspector.flowEdge.hint', locale) }), _jsxs("div", { className: "flex items-center gap-2 pt-1", children: [_jsx("span", { className: "text-[11px] font-semibold uppercase tracking-wide text-muted-foreground", children: t('engine.inspector.flowEdge.connection', locale) }), _jsx("span", { className: "h-px flex-1 bg-border", "aria-hidden": true })] }), _jsx(InspectorSelectField, { label: t('engine.inspector.flowEdge.type', locale), value: edgeType, options: [
|
|
121
|
+
{ value: 'default', label: t('engine.inspector.flowEdge.typeDefault', locale) },
|
|
122
|
+
{ value: 'conditional', label: t('engine.inspector.flowEdge.typeConditional', locale) },
|
|
123
|
+
{ value: 'fault', label: t('engine.inspector.flowEdge.typeFault', locale) },
|
|
124
|
+
{ value: 'back', label: t('engine.inspector.flowEdge.typeBack', locale) },
|
|
125
|
+
], onCommit: (v) => patchEdge({ type: v }), disabled: readOnly }), edge.type === 'back' && (_jsx("p", { className: "text-[11px] leading-snug text-amber-600 dark:text-amber-400", role: "note", children: t('engine.inspector.flowEdge.backHint', locale) }))] }));
|
|
126
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FlowInspector — the single inspector registered for the `flow` metadata type.
|
|
3
|
+
*
|
|
4
|
+
* The flow canvas emits two kinds of selection (see `FlowPreview` /
|
|
5
|
+
* `FlowCanvas`): a node (`{ kind: 'node' }`) or a connection edge
|
|
6
|
+
* (`{ kind: 'edge' }`). This thin router forwards each to its focused editor so
|
|
7
|
+
* neither component has to know about the other. Anything else falls through to
|
|
8
|
+
* the node inspector (which renders an empty-state for an unknown id).
|
|
9
|
+
*/
|
|
10
|
+
import * as React from 'react';
|
|
11
|
+
import type { MetadataInspectorProps } from '../inspector-registry';
|
|
12
|
+
export declare function FlowInspector(props: MetadataInspectorProps): React.JSX.Element;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { FlowNodeInspector } from './FlowNodeInspector';
|
|
3
|
+
import { FlowEdgeInspector } from './FlowEdgeInspector';
|
|
4
|
+
export function FlowInspector(props) {
|
|
5
|
+
if (props.selection.kind === 'edge') {
|
|
6
|
+
return _jsx(FlowEdgeInspector, { ...props });
|
|
7
|
+
}
|
|
8
|
+
return _jsx(FlowNodeInspector, { ...props });
|
|
9
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FlowKeyValueField — a small repeatable key/value editor for object-map
|
|
3
|
+
* config (e.g. an action's `params`, a subflow's `input`, request `headers`).
|
|
4
|
+
*
|
|
5
|
+
* Design notes (why local draft state instead of commit-on-keystroke):
|
|
6
|
+
* - The host inspector owns the draft and re-renders from the top on every
|
|
7
|
+
* `onPatch`. Committing each keystroke would rehydrate rows mid-edit and
|
|
8
|
+
* drop focus / collapse half-typed keys. So rows live in LOCAL state and
|
|
9
|
+
* only flush to `onCommit` on blur, Enter, add, or remove.
|
|
10
|
+
* - Rows carry a STABLE `id` (not the editable key) so renaming a key never
|
|
11
|
+
* remounts the row — caret and focus are preserved.
|
|
12
|
+
* - Values are smart-parsed on commit (number / boolean / else string) so an
|
|
13
|
+
* author can type `3` or `true` without writing JSON. Empty and duplicate
|
|
14
|
+
* keys are skipped when flushing (last non-empty wins is avoided — earlier
|
|
15
|
+
* rows take precedence).
|
|
16
|
+
*/
|
|
17
|
+
import * as React from 'react';
|
|
18
|
+
export interface FlowKeyValueFieldProps {
|
|
19
|
+
label: string;
|
|
20
|
+
value: unknown;
|
|
21
|
+
onCommit: (value: Record<string, unknown> | undefined) => void;
|
|
22
|
+
disabled?: boolean;
|
|
23
|
+
help?: string;
|
|
24
|
+
addLabel: string;
|
|
25
|
+
keyLabel: string;
|
|
26
|
+
valueLabel: string;
|
|
27
|
+
removeLabel: string;
|
|
28
|
+
emptyLabel: string;
|
|
29
|
+
}
|
|
30
|
+
export declare function FlowKeyValueField({ label, value, onCommit, disabled, help, addLabel, keyLabel, valueLabel, removeLabel, emptyLabel, }: FlowKeyValueFieldProps): React.JSX.Element;
|
|
@@ -0,0 +1,125 @@
|
|
|
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
|
+
* FlowKeyValueField — a small repeatable key/value editor for object-map
|
|
5
|
+
* config (e.g. an action's `params`, a subflow's `input`, request `headers`).
|
|
6
|
+
*
|
|
7
|
+
* Design notes (why local draft state instead of commit-on-keystroke):
|
|
8
|
+
* - The host inspector owns the draft and re-renders from the top on every
|
|
9
|
+
* `onPatch`. Committing each keystroke would rehydrate rows mid-edit and
|
|
10
|
+
* drop focus / collapse half-typed keys. So rows live in LOCAL state and
|
|
11
|
+
* only flush to `onCommit` on blur, Enter, add, or remove.
|
|
12
|
+
* - Rows carry a STABLE `id` (not the editable key) so renaming a key never
|
|
13
|
+
* remounts the row — caret and focus are preserved.
|
|
14
|
+
* - Values are smart-parsed on commit (number / boolean / else string) so an
|
|
15
|
+
* author can type `3` or `true` without writing JSON. Empty and duplicate
|
|
16
|
+
* keys are skipped when flushing (last non-empty wins is avoided — earlier
|
|
17
|
+
* rows take precedence).
|
|
18
|
+
*/
|
|
19
|
+
import * as React from 'react';
|
|
20
|
+
import { Plus, X } from 'lucide-react';
|
|
21
|
+
import { Button, Input, Label } from '@object-ui/components';
|
|
22
|
+
import { uniqueId } from './_shared';
|
|
23
|
+
function isPlainObject(v) {
|
|
24
|
+
return typeof v === 'object' && v !== null && !Array.isArray(v);
|
|
25
|
+
}
|
|
26
|
+
/** Render a stored value as an editable string. */
|
|
27
|
+
function toRaw(v) {
|
|
28
|
+
if (v == null)
|
|
29
|
+
return '';
|
|
30
|
+
if (typeof v === 'string')
|
|
31
|
+
return v;
|
|
32
|
+
if (typeof v === 'number' || typeof v === 'boolean')
|
|
33
|
+
return String(v);
|
|
34
|
+
return JSON.stringify(v);
|
|
35
|
+
}
|
|
36
|
+
/** Smart-parse an edited value string back to a scalar (no hand-written JSON). */
|
|
37
|
+
function parseValue(raw) {
|
|
38
|
+
const s = raw.trim();
|
|
39
|
+
if (s === '')
|
|
40
|
+
return '';
|
|
41
|
+
if (s === 'true')
|
|
42
|
+
return true;
|
|
43
|
+
if (s === 'false')
|
|
44
|
+
return false;
|
|
45
|
+
if (/^-?\d+(\.\d+)?$/.test(s))
|
|
46
|
+
return Number(s);
|
|
47
|
+
// Round-trip non-scalar values losslessly: a filter operator like
|
|
48
|
+
// `{"$ne": null}` or an array must parse back to its object/array form, not
|
|
49
|
+
// be flattened to a string. Template refs like `{leadId}` are not valid JSON
|
|
50
|
+
// and correctly fall through to a plain string.
|
|
51
|
+
if ((s.startsWith('{') && s.endsWith('}')) || (s.startsWith('[') && s.endsWith(']'))) {
|
|
52
|
+
try {
|
|
53
|
+
return JSON.parse(s);
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
return raw;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return raw;
|
|
60
|
+
}
|
|
61
|
+
function toRows(obj, existingIds) {
|
|
62
|
+
const ids = [...existingIds];
|
|
63
|
+
return Object.entries(obj).map(([key, value]) => {
|
|
64
|
+
const id = uniqueId('kv', ids);
|
|
65
|
+
ids.push(id);
|
|
66
|
+
return { id, key, raw: toRaw(value) };
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
/** Flush rows to an object, skipping empty/duplicate keys (first wins). */
|
|
70
|
+
function rowsToObject(rows) {
|
|
71
|
+
const out = {};
|
|
72
|
+
for (const r of rows) {
|
|
73
|
+
const k = r.key.trim();
|
|
74
|
+
if (!k || k in out)
|
|
75
|
+
continue;
|
|
76
|
+
out[k] = parseValue(r.raw);
|
|
77
|
+
}
|
|
78
|
+
return out;
|
|
79
|
+
}
|
|
80
|
+
function serialize(obj) {
|
|
81
|
+
const sorted = Object.keys(obj).sort().reduce((acc, k) => {
|
|
82
|
+
acc[k] = obj[k];
|
|
83
|
+
return acc;
|
|
84
|
+
}, {});
|
|
85
|
+
return JSON.stringify(sorted);
|
|
86
|
+
}
|
|
87
|
+
export function FlowKeyValueField({ label, value, onCommit, disabled, help, addLabel, keyLabel, valueLabel, removeLabel, emptyLabel, }) {
|
|
88
|
+
const external = isPlainObject(value) ? value : {};
|
|
89
|
+
const [rows, setRows] = React.useState(() => toRows(external, []));
|
|
90
|
+
// Track the last value we committed so an external change (node switch) can
|
|
91
|
+
// resync rows without clobbering an in-progress edit of the same node.
|
|
92
|
+
const lastCommitted = React.useRef(serialize(external));
|
|
93
|
+
React.useEffect(() => {
|
|
94
|
+
const next = serialize(external);
|
|
95
|
+
if (next !== lastCommitted.current) {
|
|
96
|
+
setRows(toRows(external, []));
|
|
97
|
+
lastCommitted.current = next;
|
|
98
|
+
}
|
|
99
|
+
}, [external]);
|
|
100
|
+
const flush = (nextRows) => {
|
|
101
|
+
const obj = rowsToObject(nextRows);
|
|
102
|
+
lastCommitted.current = serialize(obj);
|
|
103
|
+
onCommit(Object.keys(obj).length ? obj : undefined);
|
|
104
|
+
};
|
|
105
|
+
const setRowField = (id, patch) => {
|
|
106
|
+
setRows((rs) => rs.map((r) => (r.id === id ? { ...r, ...patch } : r)));
|
|
107
|
+
};
|
|
108
|
+
const addRow = () => {
|
|
109
|
+
setRows((rs) => [...rs, { id: uniqueId('kv', rs.map((r) => r.id)), key: '', raw: '' }]);
|
|
110
|
+
};
|
|
111
|
+
const removeRow = (id) => {
|
|
112
|
+
setRows((rs) => {
|
|
113
|
+
const next = rs.filter((r) => r.id !== id);
|
|
114
|
+
flush(next);
|
|
115
|
+
return next;
|
|
116
|
+
});
|
|
117
|
+
};
|
|
118
|
+
return (_jsxs("div", { className: "space-y-1.5", children: [_jsx(Label, { className: "text-xs text-muted-foreground", children: label }), _jsxs("div", { className: "space-y-1.5", children: [rows.length === 0 && (_jsx("p", { className: "text-[11px] italic text-muted-foreground", children: emptyLabel })), rows.map((row) => (_jsxs("div", { className: "flex items-center gap-1.5", children: [_jsx(Input, { value: row.key, onChange: (e) => setRowField(row.id, { key: e.target.value }), onBlur: () => flush(rows), onKeyDown: (e) => {
|
|
119
|
+
if (e.key === 'Enter')
|
|
120
|
+
e.target.blur();
|
|
121
|
+
}, placeholder: keyLabel, disabled: disabled, className: "h-8 flex-1 font-mono text-xs" }), _jsx(Input, { value: row.raw, onChange: (e) => setRowField(row.id, { raw: e.target.value }), onBlur: () => flush(rows), onKeyDown: (e) => {
|
|
122
|
+
if (e.key === 'Enter')
|
|
123
|
+
e.target.blur();
|
|
124
|
+
}, placeholder: valueLabel, disabled: disabled, className: "h-8 flex-1 text-xs" }), _jsx(Button, { type: "button", variant: "ghost", size: "sm", className: "h-8 w-8 shrink-0 p-0 text-muted-foreground", onClick: () => removeRow(row.id), disabled: disabled, "aria-label": removeLabel, title: removeLabel, children: _jsx(X, { className: "h-3.5 w-3.5" }) })] }, row.id)))] }), _jsxs(Button, { type: "button", variant: "outline", size: "sm", className: "h-7 w-full text-xs", onClick: addRow, disabled: disabled, children: [_jsx(Plus, { className: "mr-1 h-3.5 w-3.5" }), addLabel] }), help && _jsx("p", { className: "text-[11px] leading-snug text-muted-foreground", children: help })] }));
|
|
125
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FlowNodeConfigField — renders one scalar config control for a flow node,
|
|
3
|
+
* driven by a `FlowConfigField` descriptor. Bridges descriptor "kind" to the
|
|
4
|
+
* shared inspector field primitives and writes back to `node.config[key]`.
|
|
5
|
+
*/
|
|
6
|
+
import * as React from 'react';
|
|
7
|
+
import type { FlowConfigField } from './flow-node-config';
|
|
8
|
+
import { type FlowReferenceContext } from './FlowReferenceField';
|
|
9
|
+
export interface FlowNodeConfigFieldProps {
|
|
10
|
+
field: FlowConfigField;
|
|
11
|
+
value: unknown;
|
|
12
|
+
onCommit: (value: unknown) => void;
|
|
13
|
+
disabled?: boolean;
|
|
14
|
+
locale?: string;
|
|
15
|
+
/** Draft + node context so `reference` fields can resolve their options. */
|
|
16
|
+
context?: FlowReferenceContext;
|
|
17
|
+
}
|
|
18
|
+
export declare function FlowNodeConfigField({ field, value, onCommit, disabled, locale, context }: FlowNodeConfigFieldProps): React.JSX.Element;
|