@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,547 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
|
|
3
|
+
/**
|
|
4
|
+
* ObjectFormCanvas — form-designer-style preview for an Object
|
|
5
|
+
* metadata draft. Replaces the legacy CRUD grid in DesignerMode.
|
|
6
|
+
*
|
|
7
|
+
* Each field renders as the labeled input it will become at runtime
|
|
8
|
+
* (via {@link FieldStub}). Clicking a row selects it and the host
|
|
9
|
+
* swaps the inspector to {@link ObjectFieldInspector}. The trailing
|
|
10
|
+
* "+ Add field" button opens a categorized type picker — picking a
|
|
11
|
+
* type appends a fresh field and immediately selects it so authors
|
|
12
|
+
* can fill in name/label in the inspector.
|
|
13
|
+
*
|
|
14
|
+
* All edits go through the host's `onPatch` callback. Read-only
|
|
15
|
+
* surfaces (legacy tier objects, builtin objects) still render the
|
|
16
|
+
* preview but suppress selection chrome + the add button.
|
|
17
|
+
*/
|
|
18
|
+
import * as React from 'react';
|
|
19
|
+
import { Badge, Button, cn, Popover, PopoverContent, PopoverTrigger, } from '@object-ui/components';
|
|
20
|
+
import { GripVertical, Plus, ChevronDown, ChevronRight, Trash2, ArrowUp, ArrowDown, FolderPlus, FolderInput, ChevronsDownUp, ChevronsUpDown, CheckSquare, GitCompareArrows, Sparkles, X, } from 'lucide-react';
|
|
21
|
+
import { requestAssistantOpen } from '../../../assistant/assistantBus';
|
|
22
|
+
import { readFields, writeFields, newField, toFieldName, groupEntries, readGroups, addGroup, renameGroup, removeGroup, moveGroup, clearFieldGroup, diffFields, } from './object-fields-io';
|
|
23
|
+
import { FIELD_TYPE_META, TYPES_BY_CATEGORY, CATEGORY_LABEL_EN, CATEGORY_LABEL_ZH, CATEGORY_TONE, } from './field-types';
|
|
24
|
+
import { FieldStub } from './FieldStub';
|
|
25
|
+
import { t, tFormat } from '../i18n';
|
|
26
|
+
/* ─── locale helpers ─── */
|
|
27
|
+
const isZh = (locale) => (locale ?? '').toLowerCase().startsWith('zh');
|
|
28
|
+
/** Field-type display label in the active locale (data carries both). */
|
|
29
|
+
const typeLabel = (meta, locale) => meta ? (isZh(locale) ? meta.labelZh : meta.label) : undefined;
|
|
30
|
+
const categoryLabel = (cat, locale) => (isZh(locale) ? CATEGORY_LABEL_ZH : CATEGORY_LABEL_EN)[cat];
|
|
31
|
+
export function ObjectFormCanvas({ objectName, draft, baseline, onPatch, selection, onSelectionChange, locale, }) {
|
|
32
|
+
const readOnly = !onPatch;
|
|
33
|
+
const view = React.useMemo(() => readFields(draft.fields), [draft]);
|
|
34
|
+
/* ─── Review/diff mode — draft vs last published ─── */
|
|
35
|
+
const diff = React.useMemo(() => (baseline ? diffFields(baseline.fields, draft.fields) : null), [baseline, draft]);
|
|
36
|
+
const changeCount = diff
|
|
37
|
+
? diff.counts.added + diff.counts.changed + diff.counts.removed
|
|
38
|
+
: 0;
|
|
39
|
+
const [reviewMode, setReviewMode] = React.useState(false);
|
|
40
|
+
// Auto-exit review when nothing differs anymore (e.g. user reverted edits).
|
|
41
|
+
React.useEffect(() => {
|
|
42
|
+
if (reviewMode && changeCount === 0)
|
|
43
|
+
setReviewMode(false);
|
|
44
|
+
}, [reviewMode, changeCount]);
|
|
45
|
+
const reviewing = reviewMode && changeCount > 0;
|
|
46
|
+
const statusOf = (name) => reviewing ? diff?.byName[name]?.status : undefined;
|
|
47
|
+
const changedKeysOf = (name) => reviewing ? diff?.byName[name]?.changedKeys ?? [] : [];
|
|
48
|
+
const declaredGroups = React.useMemo(() => readGroups(draft.fieldGroups), [draft]);
|
|
49
|
+
const hasGroups = declaredGroups.length > 0;
|
|
50
|
+
// While editing, keep empty declared sections visible as drop targets.
|
|
51
|
+
const groups = React.useMemo(() => groupEntries(view, declaredGroups, { includeEmptyDeclared: !readOnly }), [view, declaredGroups, readOnly]);
|
|
52
|
+
// Collapse state is local UI — keyed by group key (null bucket → "").
|
|
53
|
+
const [collapsed, setCollapsed] = React.useState({});
|
|
54
|
+
const collapseKey = (key) => key ?? '__ungrouped__';
|
|
55
|
+
const toggleCollapse = React.useCallback((key) => {
|
|
56
|
+
const k = key ?? '__ungrouped__';
|
|
57
|
+
setCollapsed((prev) => ({ ...prev, [k]: !prev[k] }));
|
|
58
|
+
}, []);
|
|
59
|
+
const allCollapsed = groups.length > 0 && groups.every((g) => collapsed[collapseKey(g.key)]);
|
|
60
|
+
const setAllCollapsed = React.useCallback((value) => {
|
|
61
|
+
setCollapsed(() => {
|
|
62
|
+
const next = {};
|
|
63
|
+
for (const g of groups)
|
|
64
|
+
next[collapseKey(g.key)] = value;
|
|
65
|
+
return next;
|
|
66
|
+
});
|
|
67
|
+
}, [groups]);
|
|
68
|
+
const selectedName = selection?.kind === 'field' ? String(selection.id) : null;
|
|
69
|
+
const requiredCount = view.entries.filter((e) => !!e.def.required).length;
|
|
70
|
+
const selectField = React.useCallback((entry) => {
|
|
71
|
+
if (!onSelectionChange)
|
|
72
|
+
return;
|
|
73
|
+
onSelectionChange({
|
|
74
|
+
kind: 'field',
|
|
75
|
+
id: entry.name,
|
|
76
|
+
label: typeof entry.def.label === 'string' ? entry.def.label : entry.name,
|
|
77
|
+
});
|
|
78
|
+
}, [onSelectionChange]);
|
|
79
|
+
/* ─── Multi-select (bulk ops) — canvas-local; no host coupling ─── */
|
|
80
|
+
const [multiSel, setMultiSel] = React.useState(() => new Set());
|
|
81
|
+
const anchorRef = React.useRef(null);
|
|
82
|
+
// Flat rendered order, for Shift-range selection.
|
|
83
|
+
const flatNames = React.useMemo(() => groups.flatMap((g) => g.entries.map((e) => e.name)), [groups]);
|
|
84
|
+
// Drop names that no longer exist (e.g. after a bulk delete elsewhere).
|
|
85
|
+
React.useEffect(() => {
|
|
86
|
+
setMultiSel((prev) => {
|
|
87
|
+
if (prev.size === 0)
|
|
88
|
+
return prev;
|
|
89
|
+
const live = new Set([...prev].filter((n) => view.entries.some((e) => e.name === n)));
|
|
90
|
+
return live.size === prev.size ? prev : live;
|
|
91
|
+
});
|
|
92
|
+
}, [view]);
|
|
93
|
+
const handleRowClick = React.useCallback((entry, e) => {
|
|
94
|
+
const name = entry.name;
|
|
95
|
+
if (!readOnly && e && (e.metaKey || e.ctrlKey)) {
|
|
96
|
+
setMultiSel((prev) => {
|
|
97
|
+
const next = new Set(prev);
|
|
98
|
+
if (next.has(name))
|
|
99
|
+
next.delete(name);
|
|
100
|
+
else
|
|
101
|
+
next.add(name);
|
|
102
|
+
return next;
|
|
103
|
+
});
|
|
104
|
+
anchorRef.current = name;
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
if (!readOnly && e && e.shiftKey && anchorRef.current && anchorRef.current !== name) {
|
|
108
|
+
const a = flatNames.indexOf(anchorRef.current);
|
|
109
|
+
const b = flatNames.indexOf(name);
|
|
110
|
+
if (a >= 0 && b >= 0) {
|
|
111
|
+
const [lo, hi] = a < b ? [a, b] : [b, a];
|
|
112
|
+
setMultiSel(new Set(flatNames.slice(lo, hi + 1)));
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
// Plain click — clear multi-selection, single-select.
|
|
117
|
+
if (multiSel.size)
|
|
118
|
+
setMultiSel(new Set());
|
|
119
|
+
anchorRef.current = name;
|
|
120
|
+
selectField(entry);
|
|
121
|
+
}, [readOnly, flatNames, multiSel, selectField]);
|
|
122
|
+
const clearMulti = React.useCallback(() => setMultiSel(new Set()), []);
|
|
123
|
+
const bulkDelete = React.useCallback(() => {
|
|
124
|
+
if (!onPatch || multiSel.size === 0)
|
|
125
|
+
return;
|
|
126
|
+
const entries = view.entries.filter((e) => !multiSel.has(e.name));
|
|
127
|
+
onPatch({ fields: writeFields({ shape: view.shape, entries }) });
|
|
128
|
+
if (selectedName && multiSel.has(selectedName))
|
|
129
|
+
onSelectionChange?.(null);
|
|
130
|
+
setMultiSel(new Set());
|
|
131
|
+
}, [onPatch, multiSel, view, selectedName, onSelectionChange]);
|
|
132
|
+
const bulkSetGroup = React.useCallback((groupKey) => {
|
|
133
|
+
if (!onPatch || multiSel.size === 0)
|
|
134
|
+
return;
|
|
135
|
+
const entries = view.entries.map((e) => multiSel.has(e.name)
|
|
136
|
+
? { name: e.name, def: { ...e.def, group: groupKey ?? undefined } }
|
|
137
|
+
: e);
|
|
138
|
+
onPatch({ fields: writeFields({ shape: view.shape, entries }) });
|
|
139
|
+
}, [onPatch, multiSel, view]);
|
|
140
|
+
const addField = React.useCallback((type, groupKey) => {
|
|
141
|
+
if (!onPatch)
|
|
142
|
+
return;
|
|
143
|
+
const existing = view.entries.map((e) => e.name);
|
|
144
|
+
const base = type === 'select' ? 'status' : type;
|
|
145
|
+
let i = 1;
|
|
146
|
+
let name = base;
|
|
147
|
+
while (existing.includes(name)) {
|
|
148
|
+
i += 1;
|
|
149
|
+
name = `${base}_${i}`;
|
|
150
|
+
}
|
|
151
|
+
const entry = newField(name, type);
|
|
152
|
+
if (groupKey)
|
|
153
|
+
entry.def = { ...entry.def, group: groupKey };
|
|
154
|
+
// Insert at the end of the target group's run so it lands in-section,
|
|
155
|
+
// otherwise append to the very end (ungrouped / no groups).
|
|
156
|
+
let insertAt = view.entries.length;
|
|
157
|
+
if (groupKey) {
|
|
158
|
+
for (let j = view.entries.length - 1; j >= 0; j -= 1) {
|
|
159
|
+
if (view.entries[j].def.group === groupKey) {
|
|
160
|
+
insertAt = j + 1;
|
|
161
|
+
break;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
const entries = view.entries.slice();
|
|
166
|
+
entries.splice(insertAt, 0, entry);
|
|
167
|
+
onPatch({ fields: writeFields({ shape: view.shape, entries }) });
|
|
168
|
+
onSelectionChange?.({
|
|
169
|
+
kind: 'field',
|
|
170
|
+
id: name,
|
|
171
|
+
label: String(entry.def.label ?? name),
|
|
172
|
+
});
|
|
173
|
+
}, [onPatch, onSelectionChange, view]);
|
|
174
|
+
/* ─── Section (field group) operations ─── */
|
|
175
|
+
const addSection = React.useCallback(() => {
|
|
176
|
+
if (!onPatch)
|
|
177
|
+
return;
|
|
178
|
+
const label = tFormat('designer.canvas.sectionN', locale, {
|
|
179
|
+
n: declaredGroups.length + 1,
|
|
180
|
+
});
|
|
181
|
+
const next = addGroup(declaredGroups, label);
|
|
182
|
+
const created = next[next.length - 1];
|
|
183
|
+
onPatch({ fieldGroups: next });
|
|
184
|
+
// Reveal the new (empty) section if everything was collapsed.
|
|
185
|
+
setCollapsed((prev) => ({ ...prev, [created.key]: false }));
|
|
186
|
+
}, [onPatch, declaredGroups, locale]);
|
|
187
|
+
const renameSection = React.useCallback((key, label) => {
|
|
188
|
+
if (!onPatch)
|
|
189
|
+
return;
|
|
190
|
+
onPatch({ fieldGroups: renameGroup(declaredGroups, key, label) });
|
|
191
|
+
}, [onPatch, declaredGroups]);
|
|
192
|
+
const removeSection = React.useCallback((key) => {
|
|
193
|
+
if (!onPatch)
|
|
194
|
+
return;
|
|
195
|
+
// Drop the declaration AND clear `group` from its members so they
|
|
196
|
+
// fall back to the Ungrouped bucket rather than vanishing.
|
|
197
|
+
const clearedView = clearFieldGroup(view, key);
|
|
198
|
+
onPatch({
|
|
199
|
+
fieldGroups: removeGroup(declaredGroups, key),
|
|
200
|
+
fields: writeFields(clearedView),
|
|
201
|
+
});
|
|
202
|
+
}, [onPatch, declaredGroups, view]);
|
|
203
|
+
const moveSection = React.useCallback((key, dir) => {
|
|
204
|
+
if (!onPatch)
|
|
205
|
+
return;
|
|
206
|
+
onPatch({ fieldGroups: moveGroup(declaredGroups, key, dir) });
|
|
207
|
+
}, [onPatch, declaredGroups]);
|
|
208
|
+
// Reorder fields by moving `fromName` to the position of `toName`.
|
|
209
|
+
// Uses native HTML5 DnD — no library, no animations, just a working
|
|
210
|
+
// reorder for the most common designer interaction.
|
|
211
|
+
// If `toName`'s field is in a different group than the dragged field,
|
|
212
|
+
// adopt that group so cross-group drops are intuitive.
|
|
213
|
+
const reorderField = React.useCallback((fromName, toName, position) => {
|
|
214
|
+
if (!onPatch)
|
|
215
|
+
return;
|
|
216
|
+
if (fromName === toName)
|
|
217
|
+
return;
|
|
218
|
+
const entries = view.entries.slice();
|
|
219
|
+
const fromIdx = entries.findIndex((e) => e.name === fromName);
|
|
220
|
+
if (fromIdx < 0)
|
|
221
|
+
return;
|
|
222
|
+
const [moved] = entries.splice(fromIdx, 1);
|
|
223
|
+
const toIdx = entries.findIndex((e) => e.name === toName);
|
|
224
|
+
const targetEntry = toIdx >= 0 ? entries[toIdx] : undefined;
|
|
225
|
+
if (targetEntry) {
|
|
226
|
+
const targetGroup = typeof targetEntry.def.group === 'string' ? targetEntry.def.group : undefined;
|
|
227
|
+
const fromGroup = typeof moved.def.group === 'string' ? moved.def.group : undefined;
|
|
228
|
+
if (targetGroup !== fromGroup) {
|
|
229
|
+
moved.def = { ...moved.def, group: targetGroup };
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
if (toIdx < 0) {
|
|
233
|
+
entries.push(moved);
|
|
234
|
+
}
|
|
235
|
+
else {
|
|
236
|
+
entries.splice(position === 'before' ? toIdx : toIdx + 1, 0, moved);
|
|
237
|
+
}
|
|
238
|
+
onPatch({ fields: writeFields({ shape: view.shape, entries }) });
|
|
239
|
+
}, [onPatch, view]);
|
|
240
|
+
// Keyboard reorder (Alt+↑/↓): swap a field with its nearest neighbour
|
|
241
|
+
// in the SAME group so a focused row moves predictably within its
|
|
242
|
+
// section without ever changing groups.
|
|
243
|
+
const moveFieldByOffset = React.useCallback((name, dir) => {
|
|
244
|
+
if (!onPatch)
|
|
245
|
+
return;
|
|
246
|
+
const entries = view.entries.slice();
|
|
247
|
+
const idx = entries.findIndex((e) => e.name === name);
|
|
248
|
+
if (idx < 0)
|
|
249
|
+
return;
|
|
250
|
+
const grp = typeof entries[idx].def.group === 'string' ? entries[idx].def.group : null;
|
|
251
|
+
let j = idx + dir;
|
|
252
|
+
while (j >= 0 && j < entries.length) {
|
|
253
|
+
const g = typeof entries[j].def.group === 'string' ? entries[j].def.group : null;
|
|
254
|
+
if (g === grp)
|
|
255
|
+
break;
|
|
256
|
+
j += dir;
|
|
257
|
+
}
|
|
258
|
+
if (j < 0 || j >= entries.length)
|
|
259
|
+
return;
|
|
260
|
+
const tmp = entries[idx];
|
|
261
|
+
entries[idx] = entries[j];
|
|
262
|
+
entries[j] = tmp;
|
|
263
|
+
onPatch({ fields: writeFields({ shape: view.shape, entries }) });
|
|
264
|
+
}, [onPatch, view]);
|
|
265
|
+
// Drop a field into a group section's empty space (or onto its header).
|
|
266
|
+
// Reassigns Field.group and moves the entry to the end of that group's
|
|
267
|
+
// run in the source order so it visually lands where it was dropped.
|
|
268
|
+
const moveToGroup = React.useCallback((fromName, groupKey) => {
|
|
269
|
+
if (!onPatch)
|
|
270
|
+
return;
|
|
271
|
+
const entries = view.entries.slice();
|
|
272
|
+
const fromIdx = entries.findIndex((e) => e.name === fromName);
|
|
273
|
+
if (fromIdx < 0)
|
|
274
|
+
return;
|
|
275
|
+
const [moved] = entries.splice(fromIdx, 1);
|
|
276
|
+
const currentGroup = typeof moved.def.group === 'string' ? moved.def.group : null;
|
|
277
|
+
if (currentGroup === groupKey) {
|
|
278
|
+
// No group change — re-insert at original position (effectively no-op).
|
|
279
|
+
entries.splice(fromIdx, 0, moved);
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
moved.def = { ...moved.def, group: groupKey ?? undefined };
|
|
283
|
+
// Find end of target group's run; if no members, append at end.
|
|
284
|
+
let insertAt = entries.length;
|
|
285
|
+
for (let i = entries.length - 1; i >= 0; i -= 1) {
|
|
286
|
+
const g = typeof entries[i].def.group === 'string' ? entries[i].def.group : null;
|
|
287
|
+
if (g === groupKey) {
|
|
288
|
+
insertAt = i + 1;
|
|
289
|
+
break;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
entries.splice(insertAt, 0, moved);
|
|
293
|
+
onPatch({ fields: writeFields({ shape: view.shape, entries }) });
|
|
294
|
+
}, [onPatch, view]);
|
|
295
|
+
// Inline label rename — used by double-click on the field card label.
|
|
296
|
+
const renameLabel = React.useCallback((name, nextLabel) => {
|
|
297
|
+
if (!onPatch)
|
|
298
|
+
return;
|
|
299
|
+
const entries = view.entries.map((e) => e.name === name
|
|
300
|
+
? { name, def: { ...e.def, label: nextLabel || undefined } }
|
|
301
|
+
: e);
|
|
302
|
+
onPatch({ fields: writeFields({ shape: view.shape, entries }) });
|
|
303
|
+
}, [onPatch, view]);
|
|
304
|
+
// Click anywhere on the empty canvas background to clear selection.
|
|
305
|
+
const handleBgClick = React.useCallback((e) => {
|
|
306
|
+
if (e.target === e.currentTarget && selectedName) {
|
|
307
|
+
onSelectionChange?.(null);
|
|
308
|
+
}
|
|
309
|
+
}, [onSelectionChange, selectedName]);
|
|
310
|
+
const emptyState = view.entries.length === 0;
|
|
311
|
+
// Section chrome (headers, collapse, drop-to-assign) only appears once
|
|
312
|
+
// groups exist — otherwise the canvas stays a flat field list.
|
|
313
|
+
const showSectionChrome = hasGroups || groups.length > 1;
|
|
314
|
+
return (_jsxs("div", { className: "h-full overflow-auto bg-muted/20", onClick: handleBgClick, "data-object-name": objectName, children: [!readOnly && multiSel.size > 0 && (_jsx(BulkActionBar, { count: multiSel.size, groups: declaredGroups, onMoveToGroup: bulkSetGroup, onDelete: bulkDelete, onClear: clearMulti, locale: locale })), _jsxs("div", { className: "mx-auto max-w-3xl px-6 py-6 space-y-4", onClick: handleBgClick, children: [!emptyState && (_jsx(CanvasToolbar, { fieldCount: view.entries.length, requiredCount: requiredCount, sectionCount: declaredGroups.length, allCollapsed: allCollapsed, onToggleAll: showSectionChrome ? () => setAllCollapsed(!allCollapsed) : undefined, reviewAvailable: changeCount > 0, reviewing: reviewing, diffCounts: diff?.counts, onToggleReview: () => setReviewMode((v) => !v), locale: locale })), emptyState ? (_jsx(EmptyCanvas, { onAdd: readOnly ? undefined : addField, locale: locale })) : (_jsx("div", { className: "space-y-5", children: groups.map((g) => {
|
|
315
|
+
const declaredIdx = g.key
|
|
316
|
+
? declaredGroups.findIndex((d) => d.key === g.key)
|
|
317
|
+
: -1;
|
|
318
|
+
return (_jsxs(GroupSection, { groupKey: g.key, label: g.key === null ? t('designer.canvas.ungrouped', locale) : g.label, count: g.entries.length, showHeader: showSectionChrome, collapsed: !!collapsed[collapseKey(g.key)], onToggleCollapse: () => toggleCollapse(g.key), readOnly: readOnly, locale: locale, canMoveUp: declaredIdx > 0, canMoveDown: declaredIdx >= 0 && declaredIdx < declaredGroups.length - 1, onRename: g.key ? (label) => renameSection(g.key, label) : undefined, onRemove: g.key ? () => removeSection(g.key) : undefined, onMove: g.key ? (dir) => moveSection(g.key, dir) : undefined, onAddField: readOnly ? undefined : (type) => addField(type, g.key), onDropField: readOnly ? undefined : moveToGroup, children: [g.entries.map((entry) => (_jsx(FieldRow, { entry: entry, selected: entry.name === selectedName, multiSelected: multiSel.has(entry.name), diffStatus: statusOf(entry.name), changedKeys: changedKeysOf(entry.name), readOnly: readOnly, locale: locale, onClick: (e) => handleRowClick(entry, e), onReorder: readOnly ? undefined : reorderField, onRenameLabel: readOnly ? undefined : renameLabel, onMoveOffset: readOnly ? undefined : (dir) => moveFieldByOffset(entry.name, dir) }, entry.name))), g.entries.length === 0 && (_jsx("div", { className: "rounded-md border border-dashed bg-background/40 px-3 py-4 text-center text-[11px] text-muted-foreground", children: readOnly
|
|
319
|
+
? t('designer.canvas.emptySection', locale)
|
|
320
|
+
: t('designer.canvas.dropHint', locale) }))] }, g.key ?? '__ungrouped__'));
|
|
321
|
+
}) })), reviewing && diff && diff.removed.length > 0 && (_jsxs("div", { className: "space-y-2.5", children: [_jsx("div", { className: "text-[11px] font-medium uppercase tracking-wider text-destructive/80 pl-1", children: t('designer.canvas.diffRemoved', locale) }), diff.removed.map((entry) => (_jsx(GhostFieldRow, { entry: entry, locale: locale }, entry.name)))] })), !emptyState && !readOnly && (_jsxs("div", { className: "flex items-center gap-2 pt-1", children: [_jsx(AddFieldButton, { onPick: (type) => addField(type), locale: locale }), _jsxs(Button, { variant: "ghost", size: "sm", className: "gap-1.5 text-muted-foreground hover:text-foreground", onClick: addSection, children: [_jsx(FolderPlus, { className: "h-3.5 w-3.5" }), t('designer.canvas.addSection', locale)] }), _jsxs(Button, { variant: "ghost", size: "sm", className: "gap-1.5 ml-auto text-primary/80 hover:text-primary", onClick: () => requestAssistantOpen(), children: [_jsx(Sparkles, { className: "h-3.5 w-3.5" }), t('designer.canvas.askAi', locale)] })] }))] })] }));
|
|
322
|
+
}
|
|
323
|
+
/* ─────────────── Review toolbar ─────────────── */
|
|
324
|
+
function CanvasToolbar({ fieldCount, requiredCount, sectionCount, allCollapsed, onToggleAll, reviewAvailable, reviewing, diffCounts, onToggleReview, locale, }) {
|
|
325
|
+
return (_jsxs("div", { className: "flex items-center justify-between gap-2 text-[11px] text-muted-foreground", children: [_jsx("div", { className: "flex items-center gap-1.5 flex-wrap", children: reviewing && diffCounts ? (_jsxs(_Fragment, { children: [_jsx("span", { className: "font-medium text-emerald-600 dark:text-emerald-400", children: diffCounts.added }), ' ', t('designer.canvas.diffAdded', locale), _jsx("span", { className: "text-muted-foreground/50", children: "\u00B7" }), _jsx("span", { className: "font-medium text-amber-600 dark:text-amber-400", children: diffCounts.changed }), ' ', t('designer.canvas.diffChanged', locale), _jsx("span", { className: "text-muted-foreground/50", children: "\u00B7" }), _jsx("span", { className: "font-medium text-destructive", children: diffCounts.removed }), ' ', t('designer.canvas.diffRemoved', locale), _jsx("span", { className: "text-muted-foreground/40 normal-case ml-1", children: t('designer.canvas.reviewVsPublished', locale) })] })) : (_jsxs(_Fragment, { children: [_jsx("span", { className: "font-medium text-foreground/80", children: fieldCount }), ' ', t('designer.canvas.fields', locale), _jsx("span", { className: "text-muted-foreground/50", children: "\u00B7" }), _jsx("span", { className: "font-medium text-foreground/80", children: requiredCount }), ' ', t('designer.canvas.required', locale), sectionCount > 0 && (_jsxs(_Fragment, { children: [_jsx("span", { className: "text-muted-foreground/50", children: "\u00B7" }), _jsx("span", { className: "font-medium text-foreground/80", children: sectionCount }), ' ', t('designer.canvas.sections', locale)] }))] })) }), _jsxs("div", { className: "flex items-center gap-1 shrink-0", children: [reviewAvailable && onToggleReview && (_jsxs("button", { type: "button", onClick: onToggleReview, className: cn('inline-flex items-center gap-1 rounded px-1.5 py-0.5 transition-colors', reviewing
|
|
326
|
+
? 'bg-primary/10 text-primary hover:bg-primary/15'
|
|
327
|
+
: 'hover:bg-accent hover:text-foreground'), children: [_jsx(GitCompareArrows, { className: "h-3 w-3" }), reviewing
|
|
328
|
+
? t('designer.canvas.reviewExit', locale)
|
|
329
|
+
: t('designer.canvas.reviewChanges', locale)] })), onToggleAll && (_jsxs("button", { type: "button", onClick: onToggleAll, className: "inline-flex items-center gap-1 rounded px-1.5 py-0.5 hover:bg-accent hover:text-foreground transition-colors", children: [allCollapsed ? (_jsx(ChevronsUpDown, { className: "h-3 w-3" })) : (_jsx(ChevronsDownUp, { className: "h-3 w-3" })), allCollapsed
|
|
330
|
+
? t('designer.canvas.expandAll', locale)
|
|
331
|
+
: t('designer.canvas.collapseAll', locale)] }))] })] }));
|
|
332
|
+
}
|
|
333
|
+
/* ─────────────── Bulk-action bar ─────────────── */
|
|
334
|
+
function BulkActionBar({ count, groups, onMoveToGroup, onDelete, onClear, locale, }) {
|
|
335
|
+
const [open, setOpen] = React.useState(false);
|
|
336
|
+
return (_jsxs("div", { className: "sticky top-0 z-20 flex items-center gap-2 border-b border-primary/20 bg-primary/10 backdrop-blur px-6 py-2 text-sm", children: [_jsx("span", { className: "font-medium text-foreground", children: tFormat('designer.canvas.bulkSelected', locale, { n: count }) }), _jsx("span", { className: "text-muted-foreground text-[11px] hidden md:inline", children: t('designer.canvas.bulkHint', locale) }), _jsxs("div", { className: "ml-auto flex items-center gap-1.5", children: [groups.length > 0 && (_jsxs(Popover, { open: open, onOpenChange: setOpen, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs(Button, { variant: "outline", size: "sm", className: "h-7 gap-1.5 bg-background/70", children: [_jsx(FolderInput, { className: "h-3.5 w-3.5" }), t('designer.canvas.bulkMoveTo', locale), _jsx(ChevronDown, { className: "h-3 w-3" })] }) }), _jsxs(PopoverContent, { align: "end", className: "w-52 p-1 max-h-[300px] overflow-auto", children: [_jsx("button", { type: "button", onClick: () => { onMoveToGroup(null); setOpen(false); }, className: "w-full text-left px-2 py-1.5 rounded text-sm hover:bg-accent", children: t('designer.canvas.ungrouped', locale) }), groups.map((g) => (_jsx("button", { type: "button", onClick: () => { onMoveToGroup(g.key); setOpen(false); }, className: "w-full text-left px-2 py-1.5 rounded text-sm hover:bg-accent truncate", children: g.label || g.key }, g.key)))] })] })), _jsxs(Button, { variant: "outline", size: "sm", className: "h-7 gap-1.5 bg-background/70 text-destructive hover:text-destructive", onClick: onDelete, children: [_jsx(Trash2, { className: "h-3.5 w-3.5" }), t('designer.canvas.bulkDelete', locale)] }), _jsxs(Button, { variant: "ghost", size: "sm", className: "h-7 gap-1.5", onClick: onClear, children: [_jsx(X, { className: "h-3.5 w-3.5" }), t('designer.canvas.bulkClear', locale)] })] })] }));
|
|
337
|
+
}
|
|
338
|
+
/* ─────────────── Building blocks ─────────────── */
|
|
339
|
+
function GroupSection({ groupKey, label, count, showHeader, collapsed, onToggleCollapse, readOnly, locale, canMoveUp, canMoveDown, onRename, onRemove, onMove, onAddField, onDropField, children, }) {
|
|
340
|
+
const [active, setActive] = React.useState(false);
|
|
341
|
+
const handleDragOver = (e) => {
|
|
342
|
+
if (!onDropField)
|
|
343
|
+
return;
|
|
344
|
+
const types = e.dataTransfer.types;
|
|
345
|
+
if (!types || !Array.from(types).includes('text/x-objectui-field'))
|
|
346
|
+
return;
|
|
347
|
+
e.preventDefault();
|
|
348
|
+
e.dataTransfer.dropEffect = 'move';
|
|
349
|
+
setActive(true);
|
|
350
|
+
};
|
|
351
|
+
const handleDragLeave = (e) => {
|
|
352
|
+
// Only deactivate when leaving the section container itself, not its children.
|
|
353
|
+
if (e.currentTarget === e.target)
|
|
354
|
+
setActive(false);
|
|
355
|
+
};
|
|
356
|
+
const handleDrop = (e) => {
|
|
357
|
+
if (!onDropField)
|
|
358
|
+
return;
|
|
359
|
+
// Let inner FieldRow drops win — only handle if no row already consumed it.
|
|
360
|
+
if (e.defaultPrevented) {
|
|
361
|
+
setActive(false);
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
e.preventDefault();
|
|
365
|
+
const from = e.dataTransfer.getData('text/x-objectui-field');
|
|
366
|
+
setActive(false);
|
|
367
|
+
if (from)
|
|
368
|
+
onDropField(from, groupKey);
|
|
369
|
+
};
|
|
370
|
+
return (_jsxs("section", { className: cn('space-y-2.5 rounded-md transition-colors', active && 'bg-primary/5 ring-1 ring-primary/30 -mx-1 px-1 py-1'), onDragOver: handleDragOver, onDragLeave: handleDragLeave, onDrop: handleDrop, children: [showHeader && (_jsx(SectionHeader, { label: label, count: count, collapsed: collapsed, onToggleCollapse: onToggleCollapse, readOnly: readOnly, locale: locale, canMoveUp: canMoveUp, canMoveDown: canMoveDown, dropActive: active, onRename: onRename, onRemove: onRemove, onMove: onMove, onAddField: onAddField })), !collapsed && _jsx("div", { className: "space-y-2.5", children: children })] }));
|
|
371
|
+
}
|
|
372
|
+
function SectionHeader({ label, count, collapsed, onToggleCollapse, readOnly, locale, canMoveUp, canMoveDown, dropActive, onRename, onRemove, onMove, onAddField, }) {
|
|
373
|
+
const [editing, setEditing] = React.useState(false);
|
|
374
|
+
const [draft, setDraft] = React.useState(label);
|
|
375
|
+
React.useEffect(() => { setDraft(label); }, [label]);
|
|
376
|
+
const commit = () => {
|
|
377
|
+
if (!onRename) {
|
|
378
|
+
setEditing(false);
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
const next = draft.trim();
|
|
382
|
+
if (next && next !== label)
|
|
383
|
+
onRename(next);
|
|
384
|
+
setEditing(false);
|
|
385
|
+
};
|
|
386
|
+
const Chevron = collapsed ? ChevronRight : ChevronDown;
|
|
387
|
+
return (_jsxs("div", { className: "group/sec flex items-center gap-1.5 pl-0.5 min-h-[24px]", children: [_jsx("button", { type: "button", onClick: onToggleCollapse, className: "flex items-center justify-center h-5 w-5 rounded text-muted-foreground hover:bg-accent hover:text-foreground transition-colors shrink-0", "aria-label": collapsed
|
|
388
|
+
? t('designer.canvas.expandSection', locale)
|
|
389
|
+
: t('designer.canvas.collapseSection', locale), "aria-expanded": !collapsed, children: _jsx(Chevron, { className: "h-3.5 w-3.5" }) }), editing ? (_jsx("input", { autoFocus: true, value: draft, onChange: (e) => setDraft(e.target.value), onClick: (e) => e.stopPropagation(), onKeyDown: (e) => {
|
|
390
|
+
e.stopPropagation();
|
|
391
|
+
if (e.key === 'Enter') {
|
|
392
|
+
e.preventDefault();
|
|
393
|
+
commit();
|
|
394
|
+
}
|
|
395
|
+
else if (e.key === 'Escape') {
|
|
396
|
+
e.preventDefault();
|
|
397
|
+
setDraft(label);
|
|
398
|
+
setEditing(false);
|
|
399
|
+
}
|
|
400
|
+
}, onBlur: commit, className: "text-[11px] font-medium uppercase tracking-wider px-1 py-0.5 -my-0.5 rounded border border-primary bg-background outline-none min-w-0 flex-1 max-w-[220px]" })) : (_jsx("span", { className: cn('text-[11px] font-medium uppercase tracking-wider text-muted-foreground truncate', onRename && 'cursor-text hover:text-foreground'), onDoubleClick: onRename ? () => { setDraft(label); setEditing(true); } : undefined, title: onRename ? t('designer.canvas.renameHint', locale) : undefined, children: label })), _jsx("span", { className: "text-[10px] text-muted-foreground/60 tabular-nums shrink-0", children: count }), dropActive && (_jsx("span", { className: "text-primary normal-case text-[10px] font-normal", children: t('designer.canvas.dropToAssign', locale) })), !readOnly && (onMove || onRemove || onAddField) && (_jsxs("div", { className: "ml-auto flex items-center gap-0.5 opacity-0 group-hover/sec:opacity-100 focus-within:opacity-100 transition-opacity", children: [onAddField && (_jsx(AddFieldButton, { onPick: onAddField, compact: true, locale: locale })), onMove && (_jsxs(_Fragment, { children: [_jsx("button", { type: "button", onClick: () => onMove(-1), disabled: !canMoveUp, className: "h-5 w-5 flex items-center justify-center rounded text-muted-foreground hover:bg-accent hover:text-foreground disabled:opacity-30 disabled:pointer-events-none", "aria-label": t('designer.canvas.moveSectionUp', locale), children: _jsx(ArrowUp, { className: "h-3 w-3" }) }), _jsx("button", { type: "button", onClick: () => onMove(1), disabled: !canMoveDown, className: "h-5 w-5 flex items-center justify-center rounded text-muted-foreground hover:bg-accent hover:text-foreground disabled:opacity-30 disabled:pointer-events-none", "aria-label": t('designer.canvas.moveSectionDown', locale), children: _jsx(ArrowDown, { className: "h-3 w-3" }) })] })), onRemove && (_jsx("button", { type: "button", onClick: onRemove, className: "h-5 w-5 flex items-center justify-center rounded text-muted-foreground hover:bg-destructive/10 hover:text-destructive", "aria-label": t('designer.canvas.removeSection', locale), title: t('designer.canvas.removeSectionHint', locale), children: _jsx(Trash2, { className: "h-3 w-3" }) }))] }))] }));
|
|
401
|
+
}
|
|
402
|
+
/** Read-only ghost of a field that exists in the baseline but was removed. */
|
|
403
|
+
function GhostFieldRow({ entry, locale }) {
|
|
404
|
+
const def = entry.def;
|
|
405
|
+
const typeStr = typeof def.type === 'string' ? def.type : 'text';
|
|
406
|
+
const meta = FIELD_TYPE_META[typeStr];
|
|
407
|
+
const Icon = meta?.Icon;
|
|
408
|
+
const label = typeof def.label === 'string' ? def.label : entry.name;
|
|
409
|
+
return (_jsx("div", { className: "rounded-md border border-dashed border-destructive/30 bg-destructive/[0.03] px-3.5 py-2.5 opacity-80", children: _jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsxs("div", { className: "flex items-center gap-1.5 min-w-0", children: [Icon && _jsx(Icon, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground/50" }), _jsx("span", { className: "text-sm font-medium truncate line-through text-muted-foreground", children: label }), _jsx("code", { className: "text-[10px] text-muted-foreground/60 font-mono truncate line-through", children: entry.name })] }), _jsx(Badge, { className: "text-[10px] font-medium border-transparent bg-destructive/15 text-destructive shrink-0", children: t('designer.canvas.diffRemoved', locale) })] }) }));
|
|
410
|
+
}
|
|
411
|
+
function FieldRow({ entry, selected, multiSelected, diffStatus, changedKeys, readOnly, locale, onClick, onReorder, onRenameLabel, onMoveOffset, }) {
|
|
412
|
+
const def = entry.def;
|
|
413
|
+
const typeStr = typeof def.type === 'string' ? def.type : 'text';
|
|
414
|
+
const meta = FIELD_TYPE_META[typeStr];
|
|
415
|
+
const Icon = meta?.Icon;
|
|
416
|
+
const tone = CATEGORY_TONE[meta?.category ?? 'advanced'];
|
|
417
|
+
const label = typeof def.label === 'string' ? def.label : entry.name;
|
|
418
|
+
const required = !!def.required;
|
|
419
|
+
const description = typeof def.description === 'string' ? def.description : null;
|
|
420
|
+
const options = Array.isArray(def.options)
|
|
421
|
+
? def.options.map((o) => ({
|
|
422
|
+
value: String(o.value ?? ''),
|
|
423
|
+
label: typeof o.label === 'string' ? o.label : undefined,
|
|
424
|
+
}))
|
|
425
|
+
: undefined;
|
|
426
|
+
const referenceTo = typeof def.reference === 'string' ? def.reference : undefined;
|
|
427
|
+
const formula = typeof def.formula === 'string' ? def.formula : undefined;
|
|
428
|
+
const placeholder = typeof def.placeholder === 'string' ? def.placeholder : undefined;
|
|
429
|
+
const [dropZone, setDropZone] = React.useState(null);
|
|
430
|
+
const draggable = !!onReorder;
|
|
431
|
+
const [editingLabel, setEditingLabel] = React.useState(false);
|
|
432
|
+
const [labelDraft, setLabelDraft] = React.useState(label);
|
|
433
|
+
React.useEffect(() => { setLabelDraft(label); }, [label]);
|
|
434
|
+
const beginEdit = (e) => {
|
|
435
|
+
if (!onRenameLabel)
|
|
436
|
+
return;
|
|
437
|
+
e.preventDefault();
|
|
438
|
+
e.stopPropagation();
|
|
439
|
+
setLabelDraft(label);
|
|
440
|
+
setEditingLabel(true);
|
|
441
|
+
};
|
|
442
|
+
const commitEdit = () => {
|
|
443
|
+
if (!onRenameLabel) {
|
|
444
|
+
setEditingLabel(false);
|
|
445
|
+
return;
|
|
446
|
+
}
|
|
447
|
+
const next = labelDraft.trim();
|
|
448
|
+
if (next && next !== label)
|
|
449
|
+
onRenameLabel(entry.name, next);
|
|
450
|
+
setEditingLabel(false);
|
|
451
|
+
};
|
|
452
|
+
const cancelEdit = () => {
|
|
453
|
+
setLabelDraft(label);
|
|
454
|
+
setEditingLabel(false);
|
|
455
|
+
};
|
|
456
|
+
const handleDragStart = (e) => {
|
|
457
|
+
e.dataTransfer.setData('text/x-objectui-field', entry.name);
|
|
458
|
+
e.dataTransfer.effectAllowed = 'move';
|
|
459
|
+
};
|
|
460
|
+
const handleDragOver = (e) => {
|
|
461
|
+
if (!draggable)
|
|
462
|
+
return;
|
|
463
|
+
const types = e.dataTransfer.types;
|
|
464
|
+
if (!types || !Array.from(types).includes('text/x-objectui-field'))
|
|
465
|
+
return;
|
|
466
|
+
e.preventDefault();
|
|
467
|
+
e.dataTransfer.dropEffect = 'move';
|
|
468
|
+
const rect = e.currentTarget.getBoundingClientRect();
|
|
469
|
+
const pos = e.clientY - rect.top < rect.height / 2 ? 'before' : 'after';
|
|
470
|
+
setDropZone(pos);
|
|
471
|
+
};
|
|
472
|
+
const handleDragLeave = () => setDropZone(null);
|
|
473
|
+
const handleDrop = (e) => {
|
|
474
|
+
if (!onReorder)
|
|
475
|
+
return;
|
|
476
|
+
e.preventDefault();
|
|
477
|
+
e.stopPropagation();
|
|
478
|
+
const from = e.dataTransfer.getData('text/x-objectui-field');
|
|
479
|
+
setDropZone(null);
|
|
480
|
+
if (from && from !== entry.name) {
|
|
481
|
+
onReorder(from, entry.name, dropZone ?? 'before');
|
|
482
|
+
}
|
|
483
|
+
};
|
|
484
|
+
return (_jsxs("div", { className: cn('relative', dropZone === 'before' && 'pt-1.5'), onDragOver: handleDragOver, onDragLeave: handleDragLeave, onDrop: handleDrop, children: [dropZone === 'before' && (_jsx("div", { className: "absolute left-0 right-0 -top-0.5 h-0.5 bg-primary rounded-full" })), _jsxs("div", { role: "button", tabIndex: readOnly ? -1 : 0, onClick: onClick, onKeyDown: (e) => {
|
|
485
|
+
if (e.target !== e.currentTarget)
|
|
486
|
+
return;
|
|
487
|
+
if (e.altKey && (e.key === 'ArrowUp' || e.key === 'ArrowDown')) {
|
|
488
|
+
if (onMoveOffset) {
|
|
489
|
+
e.preventDefault();
|
|
490
|
+
onMoveOffset(e.key === 'ArrowUp' ? -1 : 1);
|
|
491
|
+
}
|
|
492
|
+
return;
|
|
493
|
+
}
|
|
494
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
495
|
+
e.preventDefault();
|
|
496
|
+
onClick?.();
|
|
497
|
+
}
|
|
498
|
+
}, draggable: draggable, onDragStart: handleDragStart, className: cn('group block w-full text-left rounded-md border bg-card px-3.5 py-2.5 transition-colors', 'hover:border-primary/40 hover:bg-card outline-none focus-visible:ring-2 focus-visible:ring-primary/40', selected ? 'border-primary ring-2 ring-primary/30 shadow-sm' : 'border-border', multiSelected && 'border-primary/60 ring-2 ring-primary/40 bg-primary/[0.04]', diffStatus === 'added' && 'border-l-[3px] border-l-emerald-500', diffStatus === 'changed' && 'border-l-[3px] border-l-amber-500', readOnly && 'cursor-default', draggable && 'cursor-grab active:cursor-grabbing'), "aria-pressed": selected || multiSelected, children: [_jsxs("div", { className: "flex items-center justify-between gap-2 mb-1.5", children: [_jsxs("div", { className: "flex items-center gap-1.5 min-w-0", children: [multiSelected && (_jsx(CheckSquare, { className: "h-3.5 w-3.5 text-primary shrink-0", "aria-hidden": "true" })), draggable && !multiSelected && (_jsx(GripVertical, { className: "h-3.5 w-3.5 text-muted-foreground/40 shrink-0 group-hover:text-muted-foreground/80", "aria-hidden": "true" })), Icon && _jsx(Icon, { className: cn('h-3.5 w-3.5 shrink-0', tone.icon) }), editingLabel ? (_jsx("input", { autoFocus: true, value: labelDraft, onChange: (e) => setLabelDraft(e.target.value), onClick: (e) => e.stopPropagation(), onKeyDown: (e) => {
|
|
499
|
+
e.stopPropagation();
|
|
500
|
+
if (e.key === 'Enter') {
|
|
501
|
+
e.preventDefault();
|
|
502
|
+
commitEdit();
|
|
503
|
+
}
|
|
504
|
+
else if (e.key === 'Escape') {
|
|
505
|
+
e.preventDefault();
|
|
506
|
+
cancelEdit();
|
|
507
|
+
}
|
|
508
|
+
}, onBlur: commitEdit, className: "text-sm font-medium px-1 py-0.5 -mx-1 -my-0.5 rounded border border-primary bg-background outline-none min-w-0 flex-1" })) : (_jsx("span", { className: cn('text-sm font-medium truncate', onRenameLabel && 'cursor-text'), onDoubleClick: beginEdit, title: onRenameLabel ? t('designer.canvas.renameHint', locale) : undefined, children: label })), required && _jsx("span", { className: "text-destructive text-sm", children: "*" }), _jsx("code", { className: "text-[10px] text-muted-foreground/70 font-mono truncate", children: entry.name })] }), _jsxs("div", { className: "flex items-center gap-1.5 shrink-0", children: [diffStatus === 'added' && (_jsx(Badge, { className: "text-[10px] font-medium border-transparent bg-emerald-500/15 text-emerald-700 dark:text-emerald-300", children: t('designer.canvas.diffAdded', locale) })), diffStatus === 'changed' && (_jsx(Badge, { className: "text-[10px] font-medium border-transparent bg-amber-500/15 text-amber-700 dark:text-amber-300", title: changedKeys && changedKeys.length
|
|
509
|
+
? tFormat('designer.canvas.diffChangedKeys', locale, { keys: changedKeys.join(', ') })
|
|
510
|
+
: undefined, children: t('designer.canvas.diffChanged', locale) })), _jsx(Badge, { variant: "outline", className: cn('text-[10px] font-medium', tone.badge), children: typeLabel(meta, locale) ?? typeStr })] })] }), description && (_jsx("div", { className: "text-[11px] text-muted-foreground mb-1.5 line-clamp-1", children: description })), _jsx(FieldStub, { type: typeStr, label: label, placeholder: placeholder, options: options, referenceTo: referenceTo, formula: formula, locale: locale })] }), dropZone === 'after' && (_jsx("div", { className: "absolute left-0 right-0 -bottom-1 h-0.5 bg-primary rounded-full" }))] }));
|
|
511
|
+
}
|
|
512
|
+
function EmptyCanvas({ onAdd, locale }) {
|
|
513
|
+
return (_jsxs("div", { className: "rounded-lg border-2 border-dashed bg-background py-16 px-6 text-center space-y-3", children: [_jsx("div", { className: "text-sm font-medium", children: t('designer.canvas.noFields', locale) }), _jsx("div", { className: "text-xs text-muted-foreground", children: t('designer.canvas.noFieldsHint', locale) }), onAdd && (_jsxs("div", { className: "pt-2 flex items-center justify-center gap-2", children: [_jsx(AddFieldButton, { onPick: onAdd, locale: locale }), _jsxs(Button, { variant: "ghost", size: "sm", className: "gap-1.5 text-primary/80 hover:text-primary", onClick: () => requestAssistantOpen(), children: [_jsx(Sparkles, { className: "h-3.5 w-3.5" }), t('designer.canvas.askAiGenerate', locale)] })] }))] }));
|
|
514
|
+
}
|
|
515
|
+
function AddFieldButton({ onPick, compact, locale }) {
|
|
516
|
+
const [open, setOpen] = React.useState(false);
|
|
517
|
+
const [filter, setFilter] = React.useState('');
|
|
518
|
+
const q = filter.trim().toLowerCase();
|
|
519
|
+
const groups = React.useMemo(() => {
|
|
520
|
+
if (!q)
|
|
521
|
+
return TYPES_BY_CATEGORY;
|
|
522
|
+
return TYPES_BY_CATEGORY
|
|
523
|
+
.map((g) => ({
|
|
524
|
+
category: g.category,
|
|
525
|
+
types: g.types.filter((id) => {
|
|
526
|
+
const m = FIELD_TYPE_META[id];
|
|
527
|
+
return id.includes(q) || m.label.toLowerCase().includes(q) || m.labelZh.includes(filter.trim());
|
|
528
|
+
}),
|
|
529
|
+
}))
|
|
530
|
+
.filter((g) => g.types.length > 0);
|
|
531
|
+
}, [q, filter]);
|
|
532
|
+
return (_jsxs(Popover, { open: open, onOpenChange: (o) => {
|
|
533
|
+
setOpen(o);
|
|
534
|
+
if (!o)
|
|
535
|
+
setFilter('');
|
|
536
|
+
}, children: [_jsx(PopoverTrigger, { asChild: true, children: compact ? (_jsx("button", { type: "button", className: "h-5 w-5 flex items-center justify-center rounded text-muted-foreground hover:bg-accent hover:text-foreground", "aria-label": t('designer.canvas.addFieldToSection', locale), title: t('designer.canvas.addFieldToSection', locale), children: _jsx(Plus, { className: "h-3 w-3" }) })) : (_jsxs(Button, { variant: "outline", size: "sm", className: "gap-1.5 border-dashed", children: [_jsx(Plus, { className: "h-3.5 w-3.5" }), t('designer.canvas.addField', locale)] })) }), _jsxs(PopoverContent, { align: "start", className: "w-[320px] p-0 max-h-[480px] overflow-hidden flex flex-col", children: [_jsx("div", { className: "p-2 border-b", children: _jsx("input", { autoFocus: true, value: filter, onChange: (e) => setFilter(e.target.value), placeholder: t('designer.canvas.searchFieldType', locale), className: "h-7 w-full px-2 text-sm border rounded bg-background outline-none focus:ring-1 focus:ring-primary" }) }), _jsx("div", { className: "flex-1 overflow-auto p-1", children: groups.length === 0 ? (_jsx("div", { className: "text-xs text-muted-foreground p-4 text-center", children: t('designer.canvas.noMatchingTypes', locale) })) : (groups.map((g) => (_jsxs("div", { className: "mb-1", children: [_jsx("div", { className: "text-[10px] uppercase tracking-wider text-muted-foreground px-2 pt-2 pb-1", children: categoryLabel(g.category, locale) }), _jsx("div", { className: "grid grid-cols-2 gap-0.5", children: g.types.map((id) => {
|
|
537
|
+
const m = FIELD_TYPE_META[id];
|
|
538
|
+
const Icon = m.Icon;
|
|
539
|
+
return (_jsxs("button", { type: "button", onClick: () => {
|
|
540
|
+
onPick(id);
|
|
541
|
+
setOpen(false);
|
|
542
|
+
setFilter('');
|
|
543
|
+
}, className: "flex items-center gap-2 px-2 py-1.5 rounded text-left text-xs hover:bg-accent", children: [_jsx(Icon, { className: cn('h-3.5 w-3.5 shrink-0', CATEGORY_TONE[m.category].icon) }), _jsx("span", { className: "truncate", children: typeLabel(m, locale) })] }, id));
|
|
544
|
+
}) })] }, g.category)))) })] })] }));
|
|
545
|
+
}
|
|
546
|
+
// Internal helper for callers that want to normalize a name in their own UI.
|
|
547
|
+
export { toFieldName };
|
|
@@ -1,2 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ObjectPreview — form-designer canvas for an Object metadata draft.
|
|
3
|
+
*
|
|
4
|
+
* Each field renders as the labeled input control it will become at
|
|
5
|
+
* runtime. Clicking a field selects it and the host swaps the right
|
|
6
|
+
* panel to {@link ObjectFieldInspector}. Trailing "+ Add field"
|
|
7
|
+
* button opens a categorized type picker.
|
|
8
|
+
*
|
|
9
|
+
* Read/write of `draft.fields` is non-destructive: the original shape
|
|
10
|
+
* (array vs record) and any unknown properties on each field are
|
|
11
|
+
* preserved via `object-fields-io`.
|
|
12
|
+
*/
|
|
13
|
+
import * as React from 'react';
|
|
1
14
|
import type { MetadataPreviewProps } from '../preview-registry';
|
|
2
|
-
export declare function ObjectPreview({ name, draft }: MetadataPreviewProps):
|
|
15
|
+
export declare function ObjectPreview({ name, draft, baseline, onPatch, selection, onSelectionChange, locale, }: MetadataPreviewProps): React.JSX.Element;
|
|
@@ -1,36 +1,11 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
|
|
3
|
-
/**
|
|
4
|
-
* ObjectPreview — render the object exactly the way the console does it:
|
|
5
|
-
* via the same `object-view` SchemaRenderer the runtime route uses, with
|
|
6
|
-
* the live adapter behind it. Authors see real records, real localized
|
|
7
|
-
* column labels, real type-aware cell formatters (booleans → checkbox,
|
|
8
|
-
* dates → locale string, refs → links), real search / filter chrome.
|
|
9
|
-
*
|
|
10
|
-
* This is a deliberate change from the earlier hand-rolled table: keeping
|
|
11
|
-
* two implementations in sync was bound to drift, and the user explicitly
|
|
12
|
-
* asked for preview parity with the console.
|
|
13
|
-
*/
|
|
14
|
-
import * as React from 'react';
|
|
15
|
-
import { SchemaRenderer } from '@object-ui/react';
|
|
16
2
|
import { PreviewShell, PreviewMessage, PreviewErrorBoundary } from './PreviewShell';
|
|
17
|
-
|
|
3
|
+
import { ObjectFormCanvas } from './ObjectFormCanvas';
|
|
4
|
+
import { t } from '../i18n';
|
|
5
|
+
export function ObjectPreview({ name, draft, baseline, onPatch, selection, onSelectionChange, locale, }) {
|
|
18
6
|
const objectName = String(draft.name ?? name ?? '');
|
|
19
7
|
if (!objectName) {
|
|
20
|
-
return (_jsx(PreviewShell, { hint: "object", children: _jsx(PreviewMessage, { children:
|
|
8
|
+
return (_jsx(PreviewShell, { hint: "object", children: _jsx(PreviewMessage, { children: t('designer.canvas.nameToStart', locale) }) }));
|
|
21
9
|
}
|
|
22
|
-
|
|
23
|
-
// preview inherits localized headers, type-aware cell formatters, view
|
|
24
|
-
// switcher, search, filter, sort and pagination chrome out of the box.
|
|
25
|
-
const schema = React.useMemo(() => ({
|
|
26
|
-
type: 'object-view',
|
|
27
|
-
objectName,
|
|
28
|
-
defaultViewType: 'grid',
|
|
29
|
-
showSearch: true,
|
|
30
|
-
showFilters: true,
|
|
31
|
-
showCreate: false,
|
|
32
|
-
showRefresh: true,
|
|
33
|
-
showViewSwitcher: true,
|
|
34
|
-
}), [objectName]);
|
|
35
|
-
return (_jsx(PreviewShell, { hint: "object \u00B7 live data", children: _jsx(PreviewErrorBoundary, { fallbackHint: "The object metadata couldn't be rendered. Save the draft and reload to retry.", children: _jsx("div", { className: "max-h-[75vh] overflow-auto", children: _jsx(SchemaRenderer, { schema: schema }) }) }) }));
|
|
10
|
+
return (_jsx(PreviewShell, { hint: "object \u00B7 designer", children: _jsx(PreviewErrorBoundary, { fallbackHint: "The form designer couldn't be rendered. Check the Form tab.", children: _jsx(ObjectFormCanvas, { objectName: objectName, draft: draft, baseline: baseline, onPatch: onPatch, selection: selection, onSelectionChange: onSelectionChange, locale: locale }) }) }));
|
|
36
11
|
}
|