@rakun-kit/manager-react 1.5.10 → 1.6.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/README.md +348 -295
- package/dist/cjs/components/app-sidebar.js +10 -0
- package/dist/cjs/components/app-sidebar.js.map +1 -1
- package/dist/cjs/components/media/MediaLibrary.js +10 -1
- package/dist/cjs/components/media/MediaLibrary.js.map +1 -1
- package/dist/cjs/components/media/contexts/MediaLibraryContext.js +1 -1
- package/dist/cjs/components/media/contexts/MediaLibraryContext.js.map +1 -1
- package/dist/cjs/components/media/previews/MediaContextMenuContent.js +68 -15
- package/dist/cjs/components/media/previews/MediaContextMenuContent.js.map +1 -1
- package/dist/cjs/components/media/previews/Previews.js +89 -35
- package/dist/cjs/components/media/previews/Previews.js.map +1 -1
- package/dist/cjs/components/media/previews/context/MediaPreviewContext.js.map +1 -1
- package/dist/cjs/components/media/previews/dialogs/ExpandedPreviewDialog.js +7 -10
- package/dist/cjs/components/media/previews/dialogs/ExpandedPreviewDialog.js.map +1 -1
- package/dist/cjs/components/media/previews/hooks/useMediaPreviewRenderer.js +3 -1
- package/dist/cjs/components/media/previews/hooks/useMediaPreviewRenderer.js.map +1 -1
- package/dist/cjs/components/media/previews/toolbar/PreviewsToolbar.js +16 -9
- package/dist/cjs/components/media/previews/toolbar/PreviewsToolbar.js.map +1 -1
- package/dist/cjs/components/media/previews/utils/mediaDownload.js +54 -0
- package/dist/cjs/components/media/previews/utils/mediaDownload.js.map +1 -0
- package/dist/cjs/components/media/previews/views/PreviewsListView.js +1 -1
- package/dist/cjs/components/media/previews/views/PreviewsListView.js.map +1 -1
- package/dist/cjs/components/rakun-logo.js +4 -9
- package/dist/cjs/components/rakun-logo.js.map +1 -1
- package/dist/cjs/components/ui/context-menu.js +1 -1
- package/dist/cjs/components/ui/context-menu.js.map +1 -1
- package/dist/cjs/i18n/catalog.js +343 -9
- package/dist/cjs/i18n/catalog.js.map +1 -1
- package/dist/cjs/lib/media.js +1 -0
- package/dist/cjs/lib/media.js.map +1 -1
- package/dist/cjs/media.js +45 -0
- package/dist/cjs/media.js.map +1 -1
- package/dist/cjs/router/dashboard/[contentType]/[edit]/ContentTypeEdit.js +15 -4
- package/dist/cjs/router/dashboard/[contentType]/[edit]/ContentTypeEdit.js.map +1 -1
- package/dist/cjs/router/dashboard/[contentType]/[edit]/_components/ContentCommentsDrawer.js +11 -6
- package/dist/cjs/router/dashboard/[contentType]/[edit]/_components/ContentCommentsDrawer.js.map +1 -1
- package/dist/cjs/router/dashboard/[contentType]/[edit]/_components/EditTabPanels.js +2 -1
- package/dist/cjs/router/dashboard/[contentType]/[edit]/_components/EditTabPanels.js.map +1 -1
- package/dist/cjs/router/dashboard/[contentType]/[edit]/_components/EditToolbar.js +2 -1
- package/dist/cjs/router/dashboard/[contentType]/[edit]/_components/EditToolbar.js.map +1 -1
- package/dist/cjs/router/dashboard/[contentType]/[edit]/_components/PreviewPanel.js +1 -1
- package/dist/cjs/router/dashboard/[contentType]/[edit]/_components/PreviewPanel.js.map +1 -1
- package/dist/cjs/router/dashboard/[contentType]/[edit]/_components/SeoTabContent.js +290 -0
- package/dist/cjs/router/dashboard/[contentType]/[edit]/_components/SeoTabContent.js.map +1 -0
- package/dist/cjs/router/dashboard/[contentType]/[edit]/_components/seo-analysis.js +88 -0
- package/dist/cjs/router/dashboard/[contentType]/[edit]/_components/seo-analysis.js.map +1 -0
- package/dist/cjs/router/dashboard/[contentType]/[edit]/_context/EditPageContext.js +1 -1
- package/dist/cjs/router/dashboard/[contentType]/[edit]/_context/EditPageContext.js.map +1 -1
- package/dist/cjs/router/dashboard/[contentType]/[edit]/_fields/ContentReferenceField/ContentReferenceMultiSelectUI.js +15 -2
- package/dist/cjs/router/dashboard/[contentType]/[edit]/_fields/ContentReferenceField/ContentReferenceMultiSelectUI.js.map +1 -1
- package/dist/cjs/router/dashboard/[contentType]/[edit]/_fields/DynamicDataControl.js +222 -232
- package/dist/cjs/router/dashboard/[contentType]/[edit]/_fields/DynamicDataControl.js.map +1 -1
- package/dist/cjs/router/dashboard/[contentType]/[edit]/_fields/FileField/index.js +20 -1
- package/dist/cjs/router/dashboard/[contentType]/[edit]/_fields/FileField/index.js.map +1 -1
- package/dist/cjs/router/dashboard/[contentType]/[edit]/_fields/LinkField/LinkUI.js +27 -21
- package/dist/cjs/router/dashboard/[contentType]/[edit]/_fields/LinkField/LinkUI.js.map +1 -1
- package/dist/cjs/router/dashboard/[contentType]/[edit]/_fields/LinkField/index.js.map +1 -1
- package/dist/cjs/router/dashboard/[contentType]/[edit]/_fields/LinkField/linkValue.js +25 -0
- package/dist/cjs/router/dashboard/[contentType]/[edit]/_fields/LinkField/linkValue.js.map +1 -0
- package/dist/cjs/router/dashboard/[contentType]/[edit]/_fields/ListField/IteratorModulePicker.js +10 -1
- package/dist/cjs/router/dashboard/[contentType]/[edit]/_fields/ListField/IteratorModulePicker.js.map +1 -1
- package/dist/cjs/router/dashboard/[contentType]/[edit]/_fields/ListField/SimpleListUI.js +38 -11
- package/dist/cjs/router/dashboard/[contentType]/[edit]/_fields/ListField/SimpleListUI.js.map +1 -1
- package/dist/cjs/router/dashboard/[contentType]/[edit]/_fields/MenuField/MenuUI.js +135 -0
- package/dist/cjs/router/dashboard/[contentType]/[edit]/_fields/MenuField/MenuUI.js.map +1 -0
- package/dist/cjs/router/dashboard/[contentType]/[edit]/_fields/MenuField/index.js +10 -0
- package/dist/cjs/router/dashboard/[contentType]/[edit]/_fields/MenuField/index.js.map +1 -0
- package/dist/cjs/router/dashboard/[contentType]/[edit]/_fields/MenuField/menuTree.js +113 -0
- package/dist/cjs/router/dashboard/[contentType]/[edit]/_fields/MenuField/menuTree.js.map +1 -0
- package/dist/cjs/router/dashboard/[contentType]/[edit]/_fields/Select/MultiSelectUI.js +15 -2
- package/dist/cjs/router/dashboard/[contentType]/[edit]/_fields/Select/MultiSelectUI.js.map +1 -1
- package/dist/cjs/router/dashboard/[contentType]/[edit]/_fields/shared/ItemLimitStatus.js +22 -0
- package/dist/cjs/router/dashboard/[contentType]/[edit]/_fields/shared/ItemLimitStatus.js.map +1 -0
- package/dist/cjs/router/dashboard/[contentType]/[edit]/_fields/shared/index.js.map +1 -1
- package/dist/cjs/router/dashboard/[contentType]/[edit]/_hooks/useContentDocumentActions.js +1 -0
- package/dist/cjs/router/dashboard/[contentType]/[edit]/_hooks/useContentDocumentActions.js.map +1 -1
- package/dist/cjs/router/dashboard/[contentType]/[edit]/_hooks/useContentPreview.js +198 -0
- package/dist/cjs/router/dashboard/[contentType]/[edit]/_hooks/useContentPreview.js.map +1 -1
- package/dist/cjs/router/dashboard/[contentType]/[edit]/edit.js +10 -1
- package/dist/cjs/router/dashboard/[contentType]/[edit]/edit.js.map +1 -1
- package/dist/cjs/router/dashboard/debugging/api-routes/ApiTest.js +2 -2
- package/dist/cjs/router/dashboard/debugging/api-routes/ApiTest.js.map +1 -1
- package/dist/cjs/router/dashboard/debugging/api-routes/JsonViewer.js +17 -0
- package/dist/cjs/router/dashboard/debugging/api-routes/JsonViewer.js.map +1 -0
- package/dist/cjs/router/dashboard/debugging/api-routes/SchemaViewer.js +40 -26
- package/dist/cjs/router/dashboard/debugging/api-routes/SchemaViewer.js.map +1 -1
- package/dist/cjs/router/dashboard/debugging/api-routes/test.js +6 -5
- package/dist/cjs/router/dashboard/debugging/api-routes/test.js.map +1 -1
- package/dist/cjs/router/dashboard/seo/index.js +6 -0
- package/dist/cjs/router/dashboard/seo/index.js.map +1 -0
- package/dist/cjs/router/dashboard/seo/screen.js +219 -0
- package/dist/cjs/router/dashboard/seo/screen.js.map +1 -0
- package/dist/cjs/router/dashboard/seo/site-analysis.js +153 -0
- package/dist/cjs/router/dashboard/seo/site-analysis.js.map +1 -0
- package/dist/cjs/router/shared/route-list.js +10 -2
- package/dist/cjs/router/shared/route-list.js.map +1 -1
- package/dist/docs/index.md +283 -194
- package/dist/esm/components/app-sidebar.d.ts.map +1 -1
- package/dist/esm/components/app-sidebar.js +11 -1
- package/dist/esm/components/app-sidebar.js.map +1 -1
- package/dist/esm/components/media/MediaLibrary.d.ts.map +1 -1
- package/dist/esm/components/media/MediaLibrary.js +11 -2
- package/dist/esm/components/media/MediaLibrary.js.map +1 -1
- package/dist/esm/components/media/contexts/MediaLibraryContext.d.ts +2 -0
- package/dist/esm/components/media/contexts/MediaLibraryContext.d.ts.map +1 -1
- package/dist/esm/components/media/contexts/MediaLibraryContext.js +1 -1
- package/dist/esm/components/media/contexts/MediaLibraryContext.js.map +1 -1
- package/dist/esm/components/media/previews/MediaContextMenuContent.d.ts.map +1 -1
- package/dist/esm/components/media/previews/MediaContextMenuContent.js +70 -17
- package/dist/esm/components/media/previews/MediaContextMenuContent.js.map +1 -1
- package/dist/esm/components/media/previews/Previews.d.ts.map +1 -1
- package/dist/esm/components/media/previews/Previews.js +90 -36
- package/dist/esm/components/media/previews/Previews.js.map +1 -1
- package/dist/esm/components/media/previews/context/MediaPreviewContext.d.ts +2 -0
- package/dist/esm/components/media/previews/context/MediaPreviewContext.d.ts.map +1 -1
- package/dist/esm/components/media/previews/context/MediaPreviewContext.js.map +1 -1
- package/dist/esm/components/media/previews/dialogs/ExpandedPreviewDialog.d.ts.map +1 -1
- package/dist/esm/components/media/previews/dialogs/ExpandedPreviewDialog.js +7 -10
- package/dist/esm/components/media/previews/dialogs/ExpandedPreviewDialog.js.map +1 -1
- package/dist/esm/components/media/previews/hooks/useMediaPreviewRenderer.d.ts.map +1 -1
- package/dist/esm/components/media/previews/hooks/useMediaPreviewRenderer.js +3 -1
- package/dist/esm/components/media/previews/hooks/useMediaPreviewRenderer.js.map +1 -1
- package/dist/esm/components/media/previews/toolbar/PreviewsToolbar.d.ts +4 -1
- package/dist/esm/components/media/previews/toolbar/PreviewsToolbar.d.ts.map +1 -1
- package/dist/esm/components/media/previews/toolbar/PreviewsToolbar.js +17 -10
- package/dist/esm/components/media/previews/toolbar/PreviewsToolbar.js.map +1 -1
- package/dist/esm/components/media/previews/utils/mediaDownload.d.ts +13 -0
- package/dist/esm/components/media/previews/utils/mediaDownload.d.ts.map +1 -0
- package/dist/esm/components/media/previews/utils/mediaDownload.js +49 -0
- package/dist/esm/components/media/previews/utils/mediaDownload.js.map +1 -0
- package/dist/esm/components/media/previews/views/PreviewsListView.js +1 -1
- package/dist/esm/components/media/previews/views/PreviewsListView.js.map +1 -1
- package/dist/esm/components/rakun-logo.d.ts +1 -5
- package/dist/esm/components/rakun-logo.d.ts.map +1 -1
- package/dist/esm/components/rakun-logo.js +1 -6
- package/dist/esm/components/rakun-logo.js.map +1 -1
- package/dist/esm/components/ui/context-menu.js +1 -1
- package/dist/esm/components/ui/context-menu.js.map +1 -1
- package/dist/esm/i18n/catalog.d.ts +564 -9
- package/dist/esm/i18n/catalog.d.ts.map +1 -1
- package/dist/esm/i18n/catalog.js +327 -7
- package/dist/esm/i18n/catalog.js.map +1 -1
- package/dist/esm/lib/media.d.ts +8 -0
- package/dist/esm/lib/media.d.ts.map +1 -1
- package/dist/esm/lib/media.js +1 -0
- package/dist/esm/lib/media.js.map +1 -1
- package/dist/esm/media.d.ts +19 -1
- package/dist/esm/media.d.ts.map +1 -1
- package/dist/esm/media.js +44 -0
- package/dist/esm/media.js.map +1 -1
- package/dist/esm/router/dashboard/[contentType]/[edit]/ContentTypeEdit.d.ts.map +1 -1
- package/dist/esm/router/dashboard/[contentType]/[edit]/ContentTypeEdit.js +18 -7
- package/dist/esm/router/dashboard/[contentType]/[edit]/ContentTypeEdit.js.map +1 -1
- package/dist/esm/router/dashboard/[contentType]/[edit]/_components/EditTabPanels.d.ts.map +1 -1
- package/dist/esm/router/dashboard/[contentType]/[edit]/_components/EditTabPanels.js +2 -1
- package/dist/esm/router/dashboard/[contentType]/[edit]/_components/EditTabPanels.js.map +1 -1
- package/dist/esm/router/dashboard/[contentType]/[edit]/_components/EditToolbar.d.ts.map +1 -1
- package/dist/esm/router/dashboard/[contentType]/[edit]/_components/EditToolbar.js +2 -1
- package/dist/esm/router/dashboard/[contentType]/[edit]/_components/EditToolbar.js.map +1 -1
- package/dist/esm/router/dashboard/[contentType]/[edit]/_components/PreviewPanel.d.ts.map +1 -1
- package/dist/esm/router/dashboard/[contentType]/[edit]/_components/PreviewPanel.js +1 -1
- package/dist/esm/router/dashboard/[contentType]/[edit]/_components/PreviewPanel.js.map +1 -1
- package/dist/esm/router/dashboard/[contentType]/[edit]/_components/SeoTabContent.d.ts +2 -0
- package/dist/esm/router/dashboard/[contentType]/[edit]/_components/SeoTabContent.d.ts.map +1 -0
- package/dist/esm/router/dashboard/[contentType]/[edit]/_components/SeoTabContent.js +283 -0
- package/dist/esm/router/dashboard/[contentType]/[edit]/_components/SeoTabContent.js.map +1 -0
- package/dist/esm/router/dashboard/[contentType]/[edit]/_components/seo-analysis.d.ts +10 -0
- package/dist/esm/router/dashboard/[contentType]/[edit]/_components/seo-analysis.d.ts.map +1 -0
- package/dist/esm/router/dashboard/[contentType]/[edit]/_components/seo-analysis.js +83 -0
- package/dist/esm/router/dashboard/[contentType]/[edit]/_components/seo-analysis.js.map +1 -0
- package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/ContentReferenceField/ContentReferenceMultiSelectUI.d.ts.map +1 -1
- package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/ContentReferenceField/ContentReferenceMultiSelectUI.js +15 -2
- package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/ContentReferenceField/ContentReferenceMultiSelectUI.js.map +1 -1
- package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/DynamicDataControl.d.ts +6 -2
- package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/DynamicDataControl.d.ts.map +1 -1
- package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/DynamicDataControl.js +221 -234
- package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/DynamicDataControl.js.map +1 -1
- package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/FileField/index.d.ts.map +1 -1
- package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/FileField/index.js +20 -1
- package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/FileField/index.js.map +1 -1
- package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/LinkField/LinkUI.d.ts.map +1 -1
- package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/LinkField/LinkUI.js +16 -19
- package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/LinkField/LinkUI.js.map +1 -1
- package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/LinkField/index.d.ts +2 -0
- package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/LinkField/index.d.ts.map +1 -1
- package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/LinkField/index.js.map +1 -1
- package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/LinkField/linkValue.d.ts +4 -0
- package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/LinkField/linkValue.d.ts.map +1 -0
- package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/LinkField/linkValue.js +21 -0
- package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/LinkField/linkValue.js.map +1 -0
- package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/ListField/IteratorModulePicker.d.ts.map +1 -1
- package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/ListField/IteratorModulePicker.js +11 -2
- package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/ListField/IteratorModulePicker.js.map +1 -1
- package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/ListField/SimpleListUI.d.ts.map +1 -1
- package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/ListField/SimpleListUI.js +38 -11
- package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/ListField/SimpleListUI.js.map +1 -1
- package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/MenuField/MenuUI.d.ts +4 -0
- package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/MenuField/MenuUI.d.ts.map +1 -0
- package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/MenuField/MenuUI.js +130 -0
- package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/MenuField/MenuUI.js.map +1 -0
- package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/MenuField/index.d.ts +14 -0
- package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/MenuField/index.d.ts.map +1 -0
- package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/MenuField/index.js +5 -0
- package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/MenuField/index.js.map +1 -0
- package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/MenuField/menuTree.d.ts +23 -0
- package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/MenuField/menuTree.d.ts.map +1 -0
- package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/MenuField/menuTree.js +103 -0
- package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/MenuField/menuTree.js.map +1 -0
- package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/Select/MultiSelectUI.d.ts.map +1 -1
- package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/Select/MultiSelectUI.js +15 -2
- package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/Select/MultiSelectUI.js.map +1 -1
- package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/shared/ItemLimitStatus.d.ts +6 -0
- package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/shared/ItemLimitStatus.d.ts.map +1 -0
- package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/shared/ItemLimitStatus.js +18 -0
- package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/shared/ItemLimitStatus.js.map +1 -0
- package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/shared/index.d.ts +2 -1
- package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/shared/index.d.ts.map +1 -1
- package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/shared/index.js.map +1 -1
- package/dist/esm/router/dashboard/[contentType]/[edit]/_hooks/useContentPreview.d.ts +43 -0
- package/dist/esm/router/dashboard/[contentType]/[edit]/_hooks/useContentPreview.d.ts.map +1 -1
- package/dist/esm/router/dashboard/[contentType]/[edit]/_hooks/useContentPreview.js +198 -0
- package/dist/esm/router/dashboard/[contentType]/[edit]/_hooks/useContentPreview.js.map +1 -1
- package/dist/esm/router/dashboard/[contentType]/[edit]/edit.d.ts.map +1 -1
- package/dist/esm/router/dashboard/[contentType]/[edit]/edit.js +10 -1
- package/dist/esm/router/dashboard/[contentType]/[edit]/edit.js.map +1 -1
- package/dist/esm/router/dashboard/debugging/api-routes/ApiTest.d.ts.map +1 -1
- package/dist/esm/router/dashboard/debugging/api-routes/ApiTest.js +2 -2
- package/dist/esm/router/dashboard/debugging/api-routes/ApiTest.js.map +1 -1
- package/dist/esm/router/dashboard/debugging/api-routes/JsonViewer.d.ts +5 -0
- package/dist/esm/router/dashboard/debugging/api-routes/JsonViewer.d.ts.map +1 -0
- package/dist/esm/router/dashboard/debugging/api-routes/JsonViewer.js +14 -0
- package/dist/esm/router/dashboard/debugging/api-routes/JsonViewer.js.map +1 -0
- package/dist/esm/router/dashboard/debugging/api-routes/SchemaViewer.d.ts.map +1 -1
- package/dist/esm/router/dashboard/debugging/api-routes/SchemaViewer.js +42 -28
- package/dist/esm/router/dashboard/debugging/api-routes/SchemaViewer.js.map +1 -1
- package/dist/esm/router/dashboard/debugging/api-routes/test.d.ts.map +1 -1
- package/dist/esm/router/dashboard/debugging/api-routes/test.js +6 -5
- package/dist/esm/router/dashboard/debugging/api-routes/test.js.map +1 -1
- package/dist/esm/router/dashboard/seo/index.d.ts +2 -0
- package/dist/esm/router/dashboard/seo/index.d.ts.map +1 -0
- package/dist/esm/router/dashboard/seo/index.js +2 -0
- package/dist/esm/router/dashboard/seo/index.js.map +1 -0
- package/dist/esm/router/dashboard/seo/screen.d.ts +6 -0
- package/dist/esm/router/dashboard/seo/screen.d.ts.map +1 -0
- package/dist/esm/router/dashboard/seo/screen.js +212 -0
- package/dist/esm/router/dashboard/seo/screen.js.map +1 -0
- package/dist/esm/router/dashboard/seo/site-analysis.d.ts +40 -0
- package/dist/esm/router/dashboard/seo/site-analysis.d.ts.map +1 -0
- package/dist/esm/router/dashboard/seo/site-analysis.js +148 -0
- package/dist/esm/router/dashboard/seo/site-analysis.js.map +1 -0
- package/dist/esm/router/shared/route-definitions.d.ts +4 -2
- package/dist/esm/router/shared/route-definitions.d.ts.map +1 -1
- package/dist/esm/router/shared/route-list.d.ts +1 -1
- package/dist/esm/router/shared/route-list.d.ts.map +1 -1
- package/dist/esm/router/shared/route-list.js +8 -0
- package/dist/esm/router/shared/route-list.js.map +1 -1
- package/dist/esm/router/shared/types.d.ts +2 -0
- package/dist/esm/router/shared/types.d.ts.map +1 -1
- package/dist/styles.css +237 -6
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +3 -3
|
@@ -2,74 +2,70 @@
|
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useTranslations } from '../../../../../i18n/index.js';
|
|
4
4
|
import { DYNAMIC_QUERY_CURRENT_VALUE_KEY, DYNAMIC_QUERY_DOCUMENT_VALUE_KEY, ITERATOR_FIELD_NAME, getListField, isDynamicDataSourceContentTypeAllowed, isTranslatableObject, } from '@rakun-kit/core/client';
|
|
5
|
-
import { Cable, ChevronRight, HelpCircle, Link2, ListFilter, Plus, Trash2, X
|
|
5
|
+
import { Cable, ChevronRight, HelpCircle, Link2, ListFilter, Plus, Trash2, X } from 'lucide-react';
|
|
6
6
|
import { useEffect, useMemo, useRef, useState } from 'react';
|
|
7
7
|
import { Badge } from '../../../../../components/ui/badge.js';
|
|
8
8
|
import { Button } from '../../../../../components/ui/button.js';
|
|
9
|
-
import { Collapsible, CollapsibleContent, CollapsibleTrigger
|
|
9
|
+
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '../../../../../components/ui/collapsible.js';
|
|
10
10
|
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from '../../../../../components/ui/dialog.js';
|
|
11
11
|
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue, } from '../../../../../components/ui/select.js';
|
|
12
|
-
import { Tooltip, TooltipContent, TooltipTrigger
|
|
12
|
+
import { Tooltip, TooltipContent, TooltipTrigger } from '../../../../../components/ui/tooltip.js';
|
|
13
13
|
import { Input } from '../../../../../components/ui/input.js';
|
|
14
14
|
import { Label } from '../../../../../components/ui/label.js';
|
|
15
15
|
import { useManagerQuery } from '../../../../../client/react.js';
|
|
16
16
|
import { useLanguage } from '../../../../../lib/providers/language/LanguageClientProvider.js';
|
|
17
17
|
export const isDynamicFallbackRequired = (field, binding) => field.isRequired && !binding;
|
|
18
18
|
const CURRENT_DOCUMENT_ID = '__rakun_current_document__';
|
|
19
|
-
const cloneDynamicBindings = (bindings) =>
|
|
19
|
+
const cloneDynamicBindings = (bindings) => bindings ? structuredClone(bindings) : undefined;
|
|
20
20
|
const cleanDynamicBindings = (bindings) => {
|
|
21
21
|
if (!bindings)
|
|
22
22
|
return undefined;
|
|
23
|
-
const fields = bindings.fields && Object.keys(bindings.fields).length > 0
|
|
24
|
-
|
|
25
|
-
: undefined;
|
|
26
|
-
const lists = bindings.lists && Object.keys(bindings.lists).length > 0
|
|
27
|
-
? bindings.lists
|
|
28
|
-
: undefined;
|
|
23
|
+
const fields = bindings.fields && Object.keys(bindings.fields).length > 0 ? bindings.fields : undefined;
|
|
24
|
+
const lists = bindings.lists && Object.keys(bindings.lists).length > 0 ? bindings.lists : undefined;
|
|
29
25
|
return fields || lists ? { fields, lists } : undefined;
|
|
30
26
|
};
|
|
31
27
|
const isRecord = (value) => !!value && typeof value === 'object' && !Array.isArray(value);
|
|
32
|
-
const isListField = (field) => field.config.
|
|
28
|
+
const isListField = (field) => field.config.capabilities.dynamic?.collection === 'heterogeneous';
|
|
29
|
+
export const isMappableDynamicListField = (field) => {
|
|
30
|
+
if (isListField(field))
|
|
31
|
+
return true;
|
|
32
|
+
if (field.config.capabilities.dynamic?.collection !== 'homogeneous' || !('field' in field))
|
|
33
|
+
return false;
|
|
34
|
+
const itemField = field.field;
|
|
35
|
+
return !!(itemField.config.capabilities.dynamic?.relation ||
|
|
36
|
+
itemField.config.capabilities.dynamic?.mapProperties);
|
|
37
|
+
};
|
|
33
38
|
const isRelatedCollectionSource = (source) => !!source && 'kind' in source && source.kind === 'relatedCollection';
|
|
34
39
|
const isNestedListSource = (source) => !!source && 'kind' in source && source.kind === 'list';
|
|
35
|
-
const
|
|
36
|
-
? field
|
|
37
|
-
: undefined;
|
|
40
|
+
const asMappableListField = (field) => isMappableDynamicListField(field) ? field : undefined;
|
|
38
41
|
const isDynamicVisibleField = (field) => (field.visibility ?? 'all') === 'all' && field.isDynamic !== false;
|
|
39
42
|
const isSelectableDynamicField = (name, field) => name !== ITERATOR_FIELD_NAME && isDynamicVisibleField(field);
|
|
43
|
+
const propertyTargetField = (field, valueKind) => ({
|
|
44
|
+
...field,
|
|
45
|
+
config: {
|
|
46
|
+
...field.config,
|
|
47
|
+
capabilities: { valueKind },
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
const propertyMappingFields = (field) => Object.entries(field.config.capabilities.dynamic?.properties ?? {}).map(([property, valueKind]) => [property, propertyTargetField(field, valueKind)]);
|
|
51
|
+
export const targetMappingFields = (contentType) => contentType
|
|
52
|
+
? Object.entries(contentType.fields).flatMap(([name, field]) => {
|
|
53
|
+
if (!isSelectableDynamicField(name, field))
|
|
54
|
+
return [];
|
|
55
|
+
const properties = field.config.capabilities.dynamic?.mapProperties
|
|
56
|
+
? propertyMappingFields(field)
|
|
57
|
+
: [];
|
|
58
|
+
if (properties.length > 0) {
|
|
59
|
+
return properties.map(([property, propertyField]) => [`${name}.${property}`, propertyField]);
|
|
60
|
+
}
|
|
61
|
+
return [[name, field]];
|
|
62
|
+
})
|
|
63
|
+
: [];
|
|
40
64
|
export const isDynamicFieldEnabled = (contentType, field) => {
|
|
41
|
-
return
|
|
42
|
-
isDynamicVisibleField(field));
|
|
65
|
+
return contentType.dynamicData !== false && isDynamicVisibleField(field);
|
|
43
66
|
};
|
|
44
67
|
const getFieldKind = (field) => {
|
|
45
|
-
|
|
46
|
-
return field.config.ui === 'RichText' ? 'richText' : 'string';
|
|
47
|
-
}
|
|
48
|
-
if (field.config.type === 'Link')
|
|
49
|
-
return 'string';
|
|
50
|
-
if (field.config.type === 'Number')
|
|
51
|
-
return 'number';
|
|
52
|
-
if (field.config.type === 'Boolean')
|
|
53
|
-
return 'boolean';
|
|
54
|
-
if (field.config.type === 'Date') {
|
|
55
|
-
return field.config.ui === 'Time' ? 'string' : 'date';
|
|
56
|
-
}
|
|
57
|
-
if (field.config.type === 'Select') {
|
|
58
|
-
return field.isMultiple ? 'array' : 'string';
|
|
59
|
-
}
|
|
60
|
-
if (field.config.type === 'ContentReference') {
|
|
61
|
-
return field.isMultiple ? 'array' : 'string';
|
|
62
|
-
}
|
|
63
|
-
if (field.config.type === 'File') {
|
|
64
|
-
return field.isMultiple ? 'array' : 'object';
|
|
65
|
-
}
|
|
66
|
-
if (field.config.type === 'Relation')
|
|
67
|
-
return 'object';
|
|
68
|
-
if (field.config.ui === 'SimpleList')
|
|
69
|
-
return 'array';
|
|
70
|
-
if (isListField(field))
|
|
71
|
-
return 'array';
|
|
72
|
-
return 'unknown';
|
|
68
|
+
return field.config.capabilities.valueKind;
|
|
73
69
|
};
|
|
74
70
|
const isCompatibleSourceKind = (sourceKind, targetField) => {
|
|
75
71
|
if (!targetField)
|
|
@@ -97,35 +93,12 @@ const areFieldKindsCompatible = (sourceField, targetField) => {
|
|
|
97
93
|
};
|
|
98
94
|
const fieldLabel = (path) => path.startsWith('_seo.') ? `seo.${path.slice('_seo.'.length)}` : path;
|
|
99
95
|
const isSeoPath = (path) => path.split('.').some((segment) => segment === '_seo' || segment === 'seo');
|
|
100
|
-
const
|
|
101
|
-
const options = [
|
|
102
|
-
|
|
103
|
-
{
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
kind: 'string',
|
|
107
|
-
},
|
|
108
|
-
{ label: fieldLabel(`${path}.name`), value: `${path}.name`, kind: 'string' },
|
|
109
|
-
{
|
|
110
|
-
label: fieldLabel(`${path}.title`),
|
|
111
|
-
value: `${path}.title`,
|
|
112
|
-
kind: 'string',
|
|
113
|
-
},
|
|
114
|
-
{ label: fieldLabel(`${path}.alt`), value: `${path}.alt`, kind: 'string' },
|
|
115
|
-
{ label: fieldLabel(`${path}.mime`), value: `${path}.mime`, kind: 'string' },
|
|
116
|
-
{
|
|
117
|
-
label: fieldLabel(`${path}.srcSet`),
|
|
118
|
-
value: `${path}.srcSet`,
|
|
119
|
-
kind: 'string',
|
|
120
|
-
},
|
|
121
|
-
{ label: fieldLabel(`${path}.width`), value: `${path}.width`, kind: 'number' },
|
|
122
|
-
{
|
|
123
|
-
label: fieldLabel(`${path}.height`),
|
|
124
|
-
value: `${path}.height`,
|
|
125
|
-
kind: 'number',
|
|
126
|
-
},
|
|
127
|
-
{ label: fieldLabel(`${path}.size`), value: `${path}.size`, kind: 'number' },
|
|
128
|
-
];
|
|
96
|
+
const propertyFieldOptions = (path, field, targetField) => {
|
|
97
|
+
const options = Object.entries(field.config.capabilities.dynamic?.properties ?? {}).map(([property, kind]) => ({
|
|
98
|
+
label: fieldLabel(`${path}.${property}`),
|
|
99
|
+
value: `${path}.${property}`,
|
|
100
|
+
kind,
|
|
101
|
+
}));
|
|
129
102
|
return options.filter((option) => isCompatibleSourceKind(option.kind, targetField));
|
|
130
103
|
};
|
|
131
104
|
const nestedSourceFieldOptions = ({ contentType, prefix = '', targetField, depth = 0, }) => Object.entries(contentType.fields).flatMap(([name, field]) => {
|
|
@@ -135,7 +108,7 @@ const nestedSourceFieldOptions = ({ contentType, prefix = '', targetField, depth
|
|
|
135
108
|
const kind = getFieldKind(field);
|
|
136
109
|
if (isSeoPath(path))
|
|
137
110
|
return [];
|
|
138
|
-
if (field.config.
|
|
111
|
+
if (field.config.capabilities.dynamic?.relation && depth < 3) {
|
|
139
112
|
const relationContentType = field.contentType;
|
|
140
113
|
const idOption = isCompatibleSourceKind('string', targetField)
|
|
141
114
|
? [
|
|
@@ -156,7 +129,8 @@ const nestedSourceFieldOptions = ({ contentType, prefix = '', targetField, depth
|
|
|
156
129
|
}),
|
|
157
130
|
];
|
|
158
131
|
}
|
|
159
|
-
|
|
132
|
+
const properties = field.config.capabilities.dynamic?.properties;
|
|
133
|
+
if (properties) {
|
|
160
134
|
const fieldOption = areFieldKindsCompatible(field, targetField)
|
|
161
135
|
? [
|
|
162
136
|
{
|
|
@@ -166,25 +140,9 @@ const nestedSourceFieldOptions = ({ contentType, prefix = '', targetField, depth
|
|
|
166
140
|
},
|
|
167
141
|
]
|
|
168
142
|
: [];
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
}
|
|
173
|
-
if (field.config.type === 'Link') {
|
|
174
|
-
const fieldOption = targetField?.config.type === 'Link' &&
|
|
175
|
-
areFieldKindsCompatible(field, targetField)
|
|
176
|
-
? [{ label: fieldLabel(path), value: path, kind }]
|
|
177
|
-
: [];
|
|
178
|
-
const propertyOptions = ['href', 'title'].flatMap((property) => isCompatibleSourceKind('string', targetField)
|
|
179
|
-
? [
|
|
180
|
-
{
|
|
181
|
-
label: fieldLabel(`${path}.${property}`),
|
|
182
|
-
value: `${path}.${property}`,
|
|
183
|
-
kind: 'string',
|
|
184
|
-
},
|
|
185
|
-
]
|
|
186
|
-
: []);
|
|
187
|
-
return [...fieldOption, ...propertyOptions];
|
|
143
|
+
return kind === 'object'
|
|
144
|
+
? [...fieldOption, ...propertyFieldOptions(path, field, targetField)]
|
|
145
|
+
: fieldOption;
|
|
188
146
|
}
|
|
189
147
|
if (!areFieldKindsCompatible(field, targetField))
|
|
190
148
|
return [];
|
|
@@ -202,17 +160,14 @@ export const sourceFieldOptions = (contentType, targetField) => {
|
|
|
202
160
|
const fields = nestedSourceFieldOptions({ contentType, targetField });
|
|
203
161
|
const includeHref = contentType.routes?.some((route) => route.hasPage) &&
|
|
204
162
|
isCompatibleSourceKind('string', targetField);
|
|
205
|
-
return includeHref
|
|
206
|
-
? [{ label: 'href', value: '$href', kind: 'string' }, ...fields]
|
|
207
|
-
: fields;
|
|
163
|
+
return includeHref ? [{ label: 'href', value: '$href', kind: 'string' }, ...fields] : fields;
|
|
208
164
|
};
|
|
209
165
|
const currentDocumentListSourceValue = (path, itemName) => `current-document:${path}:${itemName ?? ''}`;
|
|
210
166
|
export const currentDocumentListSourceOptions = (contentType) => Object.entries(contentType.fields).flatMap(([name, field]) => {
|
|
211
167
|
if (!isSelectableDynamicField(name, field) || field.isTranslatable)
|
|
212
168
|
return [];
|
|
213
|
-
if (field.config.
|
|
214
|
-
const relationEntries = field.fields.filter((entry) => entry.name !== ITERATOR_FIELD_NAME &&
|
|
215
|
-
entry.field.config.type === 'Relation');
|
|
169
|
+
if (field.config.capabilities.dynamic?.collection === 'heterogeneous' && 'fields' in field) {
|
|
170
|
+
const relationEntries = field.fields.filter((entry) => entry.name !== ITERATOR_FIELD_NAME && entry.field.config.capabilities.dynamic?.relation);
|
|
216
171
|
return relationEntries.map((entry) => ({
|
|
217
172
|
label: relationEntries.length === 1
|
|
218
173
|
? `Current document · ${name}`
|
|
@@ -223,9 +178,9 @@ export const currentDocumentListSourceOptions = (contentType) => Object.entries(
|
|
|
223
178
|
itemName: entry.name,
|
|
224
179
|
}));
|
|
225
180
|
}
|
|
226
|
-
if (field.config.
|
|
181
|
+
if (field.config.capabilities.dynamic?.collection === 'homogeneous' && 'field' in field) {
|
|
227
182
|
const itemField = field.field;
|
|
228
|
-
if (itemField.config.
|
|
183
|
+
if (!itemField.config.capabilities.dynamic?.relation)
|
|
229
184
|
return [];
|
|
230
185
|
return [
|
|
231
186
|
{
|
|
@@ -238,9 +193,7 @@ export const currentDocumentListSourceOptions = (contentType) => Object.entries(
|
|
|
238
193
|
}
|
|
239
194
|
return [];
|
|
240
195
|
});
|
|
241
|
-
const createSource = (contentType, value, id) => value === '$href'
|
|
242
|
-
? { contentType, id, virtual: 'href' }
|
|
243
|
-
: { contentType, id, path: value };
|
|
196
|
+
const createSource = (contentType, value, id) => value === '$href' ? { contentType, id, virtual: 'href' } : { contentType, id, path: value };
|
|
244
197
|
const sourceValue = (source) => source?.virtual === 'href' ? '$href' : source?.path || '';
|
|
245
198
|
const sourceLabel = (source) => source?.virtual === 'href' ? 'href' : fieldLabel(source?.path || '');
|
|
246
199
|
const mappingSourceSummary = (source, currentSourceName) => {
|
|
@@ -285,15 +238,13 @@ const operatorByMongoOperator = {
|
|
|
285
238
|
$lte: 'lessThanOrEqual',
|
|
286
239
|
};
|
|
287
240
|
const readFilterOperand = (value) => {
|
|
288
|
-
if (isRecord(value) &&
|
|
289
|
-
typeof value[DYNAMIC_QUERY_CURRENT_VALUE_KEY] === 'string') {
|
|
241
|
+
if (isRecord(value) && typeof value[DYNAMIC_QUERY_CURRENT_VALUE_KEY] === 'string') {
|
|
290
242
|
return {
|
|
291
243
|
value: value[DYNAMIC_QUERY_CURRENT_VALUE_KEY],
|
|
292
244
|
valueSource: 'current',
|
|
293
245
|
};
|
|
294
246
|
}
|
|
295
|
-
if (isRecord(value) &&
|
|
296
|
-
typeof value[DYNAMIC_QUERY_DOCUMENT_VALUE_KEY] === 'string') {
|
|
247
|
+
if (isRecord(value) && typeof value[DYNAMIC_QUERY_DOCUMENT_VALUE_KEY] === 'string') {
|
|
297
248
|
return {
|
|
298
249
|
value: value[DYNAMIC_QUERY_DOCUMENT_VALUE_KEY],
|
|
299
250
|
valueSource: 'document',
|
|
@@ -309,8 +260,7 @@ const filterConditionFromEntry = (field, value) => {
|
|
|
309
260
|
if (value === false)
|
|
310
261
|
return { field, operator: 'false', value: '' };
|
|
311
262
|
const directOperand = readFilterOperand(value);
|
|
312
|
-
if (directOperand.valueSource === 'current' ||
|
|
313
|
-
directOperand.valueSource === 'document') {
|
|
263
|
+
if (directOperand.valueSource === 'current' || directOperand.valueSource === 'document') {
|
|
314
264
|
return { field, operator: 'equals', ...directOperand };
|
|
315
265
|
}
|
|
316
266
|
if (isRecord(value)) {
|
|
@@ -405,9 +355,7 @@ const buildFilterCondition = (condition, fieldOptions) => {
|
|
|
405
355
|
lessThanOrEqual: '$lte',
|
|
406
356
|
};
|
|
407
357
|
const operator = mongoOperator[condition.operator];
|
|
408
|
-
return operator
|
|
409
|
-
? { [condition.field]: { [operator]: value } }
|
|
410
|
-
: { [condition.field]: value };
|
|
358
|
+
return operator ? { [condition.field]: { [operator]: value } } : { [condition.field]: value };
|
|
411
359
|
};
|
|
412
360
|
export const buildFilter = (state, fieldOptions = []) => {
|
|
413
361
|
const conditions = state.conditions.flatMap((condition) => {
|
|
@@ -477,8 +425,8 @@ const bindingSummary = ({ list, fieldBinding, listBinding, documentContentTypeNa
|
|
|
477
425
|
return '';
|
|
478
426
|
return `${sourceContentTypeLabel(fieldBinding, documentContentTypeName)} -> ${sourceLabel(fieldBinding)}`;
|
|
479
427
|
};
|
|
480
|
-
const PanelSection = ({ title, children
|
|
481
|
-
const ControlLabel = ({ children, help
|
|
428
|
+
const PanelSection = ({ title, children }) => (_jsxs("div", { className: "grid gap-3 rounded-md border border-border bg-muted/20 p-3", children: [_jsx("div", { className: "text-xs font-semibold uppercase text-muted-foreground", children: title }), children] }));
|
|
429
|
+
const ControlLabel = ({ children, help }) => (_jsxs("div", { className: "flex items-center gap-1.5", children: [_jsx(Label, { children: children }), _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { type: "button", className: "rounded-sm text-muted-foreground outline-none hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring", "aria-label": help, children: _jsx(HelpCircle, { className: "h-3.5 w-3.5" }) }) }), _jsx(TooltipContent, { side: "top", sideOffset: 6, className: "max-w-xs", children: help })] })] }));
|
|
482
430
|
const FieldBindingEditor = ({ contentTypes, documentContentType, currentDocumentSourceEnabled, targetField, binding, onChange, }) => {
|
|
483
431
|
const t = useTranslations();
|
|
484
432
|
const { language } = useLanguage();
|
|
@@ -504,9 +452,7 @@ const FieldBindingEditor = ({ contentTypes, documentContentType, currentDocument
|
|
|
504
452
|
},
|
|
505
453
|
},
|
|
506
454
|
},
|
|
507
|
-
enabled: !!sourceType &&
|
|
508
|
-
!usesCurrentDocumentSource &&
|
|
509
|
-
selectedContentType?.dynamicDataSource === true,
|
|
455
|
+
enabled: !!sourceType && !usesCurrentDocumentSource && selectedContentType?.dynamicDataSource === true,
|
|
510
456
|
});
|
|
511
457
|
const items = (sourceItemsQuery.data?.items ?? []);
|
|
512
458
|
const hasCurrentDocumentItem = currentDocumentSourceEnabled && sourceType === documentContentType.name;
|
|
@@ -522,48 +468,72 @@ const FieldBindingEditor = ({ contentTypes, documentContentType, currentDocument
|
|
|
522
468
|
}
|
|
523
469
|
onChange(createSource(nextType, nextPath, usesCurrentDocument ? undefined : nextId));
|
|
524
470
|
};
|
|
525
|
-
return (_jsx(PanelSection, { title:
|
|
526
|
-
const nextId = currentDocumentSourceEnabled &&
|
|
527
|
-
value === documentContentType.name
|
|
471
|
+
return (_jsx(PanelSection, { title: "Source value", children: _jsxs("div", { className: "grid gap-3 md:grid-cols-[1fr_1.4fr_1fr]", children: [_jsxs(Label, { className: "grid gap-1.5", children: [t('dynamicData.source'), _jsxs(Select, { disabled: contentTypes.length === 0, value: sourceType, onValueChange: (value) => {
|
|
472
|
+
const nextId = currentDocumentSourceEnabled && value === documentContentType.name
|
|
528
473
|
? CURRENT_DOCUMENT_ID
|
|
529
474
|
: '';
|
|
530
475
|
setSourceType(value);
|
|
531
476
|
setSourceId(nextId);
|
|
532
477
|
setFieldPath('');
|
|
533
478
|
onChange(undefined);
|
|
534
|
-
}, children: [_jsx(SelectTrigger, { className:
|
|
535
|
-
ct.name === documentContentType.name
|
|
479
|
+
}, children: [_jsx(SelectTrigger, { className: "w-full", children: _jsx(SelectValue, { placeholder: contentTypes.length > 0 ? 'Content type' : 'No content types' }) }), _jsx(SelectContent, { children: _jsx(SelectGroup, { children: contentTypes.map((ct) => (_jsx(SelectItem, { value: ct.name, children: currentDocumentSourceEnabled && ct.name === documentContentType.name
|
|
536
480
|
? `${ct.name} (current document)`
|
|
537
|
-
: ct.name }, ct.name))) }) })] })] }), _jsxs(Label, { className:
|
|
481
|
+
: ct.name }, ct.name))) }) })] })] }), _jsxs(Label, { className: "grid gap-1.5", children: [t('dynamicData.item'), _jsxs(Select, { disabled: !sourceType || !hasItemOptions, value: sourceId, onValueChange: (value) => {
|
|
538
482
|
setSourceId(value);
|
|
539
483
|
emit(sourceType, value, fieldPath);
|
|
540
|
-
}, children: [_jsx(SelectTrigger, { className:
|
|
484
|
+
}, children: [_jsx(SelectTrigger, { className: "w-full", children: _jsx(SelectValue, { placeholder: hasItemOptions ? 'Item' : 'No items available' }) }), _jsx(SelectContent, { children: _jsxs(SelectGroup, { children: [hasCurrentDocumentItem ? (_jsx(SelectItem, { value: CURRENT_DOCUMENT_ID, children: t('dynamicData.currentDocument') })) : null, items.map((item) => {
|
|
541
485
|
const label = selectedContentType
|
|
542
486
|
? getListField(item, selectedContentType.listFields ?? [])
|
|
543
487
|
: item._id;
|
|
544
488
|
return (_jsx(SelectItem, { value: item._id, children: isTranslatableObject(label)
|
|
545
489
|
? label[language.code]
|
|
546
490
|
: String(label || item._id) }, item._id));
|
|
547
|
-
})] }) })] })] }), _jsxs(Label, { className:
|
|
491
|
+
})] }) })] })] }), _jsxs(Label, { className: "grid gap-1.5", children: [t('dynamicData.field'), _jsxs(Select, { disabled: !sourceType || !sourceId || fieldOptions.length === 0, value: fieldPath, onValueChange: (value) => {
|
|
548
492
|
setFieldPath(value);
|
|
549
493
|
emit(sourceType, sourceId, value);
|
|
550
|
-
}, children: [_jsx(SelectTrigger, { className:
|
|
494
|
+
}, children: [_jsx(SelectTrigger, { className: "w-full", children: _jsx(SelectValue, { placeholder: fieldOptions.length > 0 ? 'Field' : 'No compatible fields' }) }), _jsx(SelectContent, { children: _jsx(SelectGroup, { children: fieldOptions.map((field) => (_jsx(SelectItem, { value: field.value, children: field.label }, field.value))) }) })] })] })] }) }));
|
|
551
495
|
};
|
|
552
496
|
const getListTargetContentType = (field, itemName) => {
|
|
553
|
-
|
|
554
|
-
|
|
497
|
+
if (field.config.capabilities.dynamic?.collection === 'homogeneous') {
|
|
498
|
+
const itemField = field.field;
|
|
499
|
+
return itemField.config.capabilities.dynamic?.relation
|
|
500
|
+
? itemField.contentType
|
|
501
|
+
: undefined;
|
|
502
|
+
}
|
|
503
|
+
const listField = field;
|
|
504
|
+
const entry = listField.fields.find((item) => item.name === itemName);
|
|
505
|
+
if (!entry || !entry.field.config.capabilities.dynamic?.relation)
|
|
555
506
|
return undefined;
|
|
556
507
|
return entry.field.contentType;
|
|
557
508
|
};
|
|
509
|
+
const getListItemOptions = (field) => {
|
|
510
|
+
if (field.config.capabilities.dynamic?.collection !== 'homogeneous') {
|
|
511
|
+
return field.fields.filter((item) => item.name !== ITERATOR_FIELD_NAME);
|
|
512
|
+
}
|
|
513
|
+
const itemField = field.field;
|
|
514
|
+
const name = itemField.config.capabilities.dynamic?.relation
|
|
515
|
+
? itemField.contentType.name
|
|
516
|
+
: (itemField.config.editor ?? itemField.config.type);
|
|
517
|
+
return [{ name, field: itemField }];
|
|
518
|
+
};
|
|
519
|
+
export const listItemTargetFields = (field, itemName) => {
|
|
520
|
+
if (field.config.capabilities.dynamic?.collection === 'homogeneous') {
|
|
521
|
+
const itemField = field.field;
|
|
522
|
+
if (itemField.config.capabilities.dynamic?.mapProperties) {
|
|
523
|
+
return propertyMappingFields(itemField);
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
return targetMappingFields(getListTargetContentType(field, itemName));
|
|
527
|
+
};
|
|
558
528
|
const getRelationContentType = (field) => {
|
|
559
529
|
if (field.isTranslatable)
|
|
560
530
|
return undefined;
|
|
561
|
-
if (field.config.
|
|
531
|
+
if (field.config.capabilities.dynamic?.relation) {
|
|
562
532
|
return field.contentType;
|
|
563
533
|
}
|
|
564
|
-
if (field.config.
|
|
534
|
+
if (field.config.capabilities.dynamic?.collection === 'homogeneous' && 'field' in field) {
|
|
565
535
|
const itemField = field.field;
|
|
566
|
-
if (itemField.config.
|
|
536
|
+
if (itemField.config.capabilities.dynamic?.relation) {
|
|
567
537
|
return itemField.contentType;
|
|
568
538
|
}
|
|
569
539
|
}
|
|
@@ -584,13 +554,7 @@ const getSortFieldOptions = (contentType) => Object.entries(contentType.fields).
|
|
|
584
554
|
return [];
|
|
585
555
|
}
|
|
586
556
|
const kind = getFieldKind(field);
|
|
587
|
-
const
|
|
588
|
-
!field.isMultiple;
|
|
589
|
-
const isSortable = (field.config.type === 'String' && field.config.ui !== 'RichText') ||
|
|
590
|
-
field.config.type === 'Number' ||
|
|
591
|
-
field.config.type === 'Boolean' ||
|
|
592
|
-
field.config.type === 'Date' ||
|
|
593
|
-
isSingleSelect;
|
|
557
|
+
const isSortable = ['string', 'number', 'boolean', 'date'].includes(kind);
|
|
594
558
|
return isSortable ? [{ label: fieldLabel(name), value: name, kind }] : [];
|
|
595
559
|
});
|
|
596
560
|
const filterOperatorOptions = {
|
|
@@ -631,19 +595,11 @@ const getFilterOperatorOptions = (kind) => {
|
|
|
631
595
|
'notExists',
|
|
632
596
|
]
|
|
633
597
|
: kind === 'string' || kind === 'richText'
|
|
634
|
-
? [
|
|
635
|
-
'equals',
|
|
636
|
-
'notEquals',
|
|
637
|
-
'contains',
|
|
638
|
-
'in',
|
|
639
|
-
'notIn',
|
|
640
|
-
'exists',
|
|
641
|
-
'notExists',
|
|
642
|
-
]
|
|
598
|
+
? ['equals', 'notEquals', 'contains', 'in', 'notIn', 'exists', 'notExists']
|
|
643
599
|
: ['equals', 'notEquals', 'exists', 'notExists'];
|
|
644
600
|
return operators.map((operator) => filterOperatorOptions[operator]);
|
|
645
601
|
};
|
|
646
|
-
const defaultFilterOperator = (kind) =>
|
|
602
|
+
const defaultFilterOperator = (kind) => kind === 'boolean' ? 'true' : 'equals';
|
|
647
603
|
const createRelatedCollectionSource = ({ contentType, currentSource, targetField, }) => {
|
|
648
604
|
const relation = getRelatedRelationOptions(contentType, currentSource)[0];
|
|
649
605
|
const path = getRelatedPathOptions(contentType, targetField)[0]?.value;
|
|
@@ -659,12 +615,10 @@ const createRelatedCollectionSource = ({ contentType, currentSource, targetField
|
|
|
659
615
|
};
|
|
660
616
|
const MappingSourceEditor = ({ contentTypes, rootDocumentContentType, currentSource, targetField, source, onChange, }) => {
|
|
661
617
|
const t = useTranslations();
|
|
662
|
-
const nestedListTarget =
|
|
618
|
+
const nestedListTarget = asMappableListField(targetField);
|
|
663
619
|
const nestedSource = isNestedListSource(source) ? source : undefined;
|
|
664
620
|
const relatedSource = isRelatedCollectionSource(source) ? source : undefined;
|
|
665
|
-
const directSource = source && !isRelatedCollectionSource(source) && !isNestedListSource(source)
|
|
666
|
-
? source
|
|
667
|
-
: undefined;
|
|
621
|
+
const directSource = source && !isRelatedCollectionSource(source) && !isNestedListSource(source) ? source : undefined;
|
|
668
622
|
const directFieldOptions = sourceFieldOptions(currentSource, targetField);
|
|
669
623
|
const relatedContentTypes = contentTypes.filter((contentType) => getRelatedRelationOptions(contentType, currentSource).length > 0 &&
|
|
670
624
|
getRelatedPathOptions(contentType, targetField).length > 0);
|
|
@@ -684,7 +638,9 @@ const MappingSourceEditor = ({ contentTypes, rootDocumentContentType, currentSou
|
|
|
684
638
|
const sortField = sortEntry?.[0] ?? '';
|
|
685
639
|
const sortDirection = sortEntry?.[1] ?? 'desc';
|
|
686
640
|
const createNestedSource = () => {
|
|
687
|
-
const nestedItemName = nestedListTarget
|
|
641
|
+
const nestedItemName = nestedListTarget
|
|
642
|
+
? getListItemOptions(nestedListTarget)[0]?.name
|
|
643
|
+
: undefined;
|
|
688
644
|
if (!nestedItemName)
|
|
689
645
|
return undefined;
|
|
690
646
|
return {
|
|
@@ -696,13 +652,13 @@ const MappingSourceEditor = ({ contentTypes, rootDocumentContentType, currentSou
|
|
|
696
652
|
};
|
|
697
653
|
};
|
|
698
654
|
if (nestedSource && nestedListTarget) {
|
|
699
|
-
return (_jsxs("div", { className:
|
|
655
|
+
return (_jsxs("div", { className: "grid gap-3", children: [_jsxs("div", { className: "grid max-w-sm content-start gap-1.5", children: [_jsx(ControlLabel, { help: t('dynamicData.nestedListHelp'), children: t('dynamicData.mappingMode') }), _jsxs(Select, { value: "list", onValueChange: (value) => {
|
|
700
656
|
if (value === 'field')
|
|
701
657
|
onChange(undefined);
|
|
702
|
-
}, children: [_jsx(SelectTrigger, { className:
|
|
658
|
+
}, children: [_jsx(SelectTrigger, { className: "w-full", children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "field", children: t('dynamicData.directField') }), _jsx(SelectItem, { value: "list", children: t('dynamicData.nestedList') })] })] })] }), _jsx(ListBindingEditor, { contentTypes: contentTypes, documentContentType: currentSource, rootDocumentContentType: rootDocumentContentType, currentItemContentType: currentSource, currentDocumentSourceEnabled: true, field: nestedListTarget, binding: nestedSource, onChange: (binding) => onChange(binding ? { ...binding, kind: 'list' } : undefined) })] }));
|
|
703
659
|
}
|
|
704
660
|
if (!relatedSource) {
|
|
705
|
-
return (_jsxs("div", { className:
|
|
661
|
+
return (_jsxs("div", { className: "grid gap-3 md:grid-cols-[0.7fr_1.3fr]", children: [_jsxs("div", { className: "grid content-start gap-1.5", children: [_jsx(ControlLabel, { help: "Choose a direct field or query a related collection.", children: t('dynamicData.mappingMode') }), _jsxs(Select, { value: "field", onValueChange: (value) => {
|
|
706
662
|
if (value === 'list') {
|
|
707
663
|
onChange(createNestedSource());
|
|
708
664
|
return;
|
|
@@ -717,11 +673,9 @@ const MappingSourceEditor = ({ contentTypes, rootDocumentContentType, currentSou
|
|
|
717
673
|
}))
|
|
718
674
|
.find(Boolean);
|
|
719
675
|
onChange(next);
|
|
720
|
-
}, children: [_jsx(SelectTrigger, { className:
|
|
721
|
-
? 'Select a source field'
|
|
722
|
-
: 'No compatible fields' }) }), _jsx(SelectContent, { children: _jsx(SelectGroup, { children: directFieldOptions.map((item) => (_jsx(SelectItem, { value: item.value, children: item.label }, item.value))) }) })] })] })] }));
|
|
676
|
+
}, children: [_jsx(SelectTrigger, { className: "w-full", children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "field", children: t('dynamicData.directField') }), relatedContentTypes.length > 0 ? (_jsx(SelectItem, { value: "relatedCollection", children: t('dynamicData.relatedCollection') })) : null, nestedListTarget ? (_jsx(SelectItem, { value: "list", children: t('dynamicData.nestedList') })) : null] })] })] }), _jsxs("div", { className: "grid content-start gap-1.5", children: [_jsxs(ControlLabel, { help: "Its value will be assigned to this mapped property.", children: [t('dynamicData.fieldOn'), " ", currentSource.name] }), _jsxs(Select, { disabled: directFieldOptions.length === 0, value: sourceValue(directSource), onValueChange: (value) => onChange(createSource(currentSource.name, value)), children: [_jsx(SelectTrigger, { className: "w-full", children: _jsx(SelectValue, { placeholder: directFieldOptions.length > 0 ? 'Select a source field' : 'No compatible fields' }) }), _jsx(SelectContent, { children: _jsx(SelectGroup, { children: directFieldOptions.map((item) => (_jsx(SelectItem, { value: item.value, children: item.label }, item.value))) }) })] })] })] }));
|
|
723
677
|
}
|
|
724
|
-
return (_jsxs("div", { className:
|
|
678
|
+
return (_jsxs("div", { className: "grid gap-3", children: [_jsxs("div", { className: "grid gap-3 sm:grid-cols-2 lg:grid-cols-4", children: [_jsxs("div", { className: "grid content-start gap-1.5", children: [_jsx(ControlLabel, { help: "Query records related to the current source item.", children: t('dynamicData.mappingMode') }), _jsxs(Select, { value: "relatedCollection", onValueChange: (value) => onChange(value === 'list' ? createNestedSource() : undefined), children: [_jsx(SelectTrigger, { className: "w-full", children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "field", children: t('dynamicData.directField') }), _jsx(SelectItem, { value: "relatedCollection", children: t('dynamicData.relatedCollection') }), nestedListTarget ? (_jsx(SelectItem, { value: "list", children: t('dynamicData.nestedList') })) : null] })] })] }), _jsxs("div", { className: "grid content-start gap-1.5", children: [_jsx(ControlLabel, { help: "Content type whose records will be searched.", children: t('dynamicData.collectionToQuery') }), _jsxs(Select, { disabled: relatedContentTypes.length === 0, value: relatedSource.contentType, onValueChange: (value) => {
|
|
725
679
|
const contentType = relatedContentTypes.find((item) => item.name === value);
|
|
726
680
|
if (!contentType)
|
|
727
681
|
return;
|
|
@@ -730,66 +684,49 @@ const MappingSourceEditor = ({ contentTypes, rootDocumentContentType, currentSou
|
|
|
730
684
|
currentSource,
|
|
731
685
|
targetField,
|
|
732
686
|
}));
|
|
733
|
-
}, children: [_jsx(SelectTrigger, { className:
|
|
687
|
+
}, children: [_jsx(SelectTrigger, { className: "w-full", children: _jsx(SelectValue, { placeholder: relatedContentTypes.length > 0
|
|
734
688
|
? 'Select a content type'
|
|
735
|
-
: 'No compatible collections' }) }), _jsx(SelectContent, { children: relatedContentTypes.map((contentType) => (_jsx(SelectItem, { value: contentType.name, children: contentType.name }, contentType.name))) })] })] }), _jsxs("div", { className:
|
|
736
|
-
? 'Select a relation field'
|
|
737
|
-
: 'No compatible relations' }) }), _jsx(SelectContent, { children: relationOptions.map((relation) => (_jsx(SelectItem, { value: relation, children: relation }, relation))) })] })] }), _jsxs("div", { className: 'grid content-start gap-1.5', children: [_jsx(ControlLabel, { help: 'Arrays from matching records are flattened into one result.', children: t('dynamicData.arrayFieldToCollect') }), _jsxs(Select, { disabled: pathOptions.length === 0, value: relatedSource.path, onValueChange: (path) => onChange({ ...relatedSource, path }), children: [_jsx(SelectTrigger, { className: 'w-full', children: _jsx(SelectValue, { placeholder: pathOptions.length > 0
|
|
738
|
-
? 'Select an array field'
|
|
739
|
-
: 'No compatible array fields' }) }), _jsx(SelectContent, { children: pathOptions.map((option) => (_jsx(SelectItem, { value: option.value, children: option.label }, option.value))) })] })] })] }), _jsxs("div", { className: 'grid gap-3 sm:grid-cols-[0.7fr_1fr_0.7fr]', children: [_jsxs("div", { className: 'grid content-start gap-1.5', children: [_jsx(ControlLabel, { help: `Number of ${relatedSource.contentType} records queried per ${currentSource.name}. Minimum 1, maximum 100.`, children: t('dynamicData.maximumRelatedRecords') }), _jsx(Input, { type: 'number', min: 1, max: 100, value: String(relatedSource.limit), onChange: (event) => onChange({
|
|
689
|
+
: 'No compatible collections' }) }), _jsx(SelectContent, { children: relatedContentTypes.map((contentType) => (_jsx(SelectItem, { value: contentType.name, children: contentType.name }, contentType.name))) })] })] }), _jsxs("div", { className: "grid content-start gap-1.5", children: [_jsxs(ControlLabel, { help: `Field on ${relatedSource.contentType} that points to ${currentSource.name}.`, children: [t('dynamicData.relationTo'), " ", currentSource.name] }), _jsxs(Select, { disabled: relationOptions.length === 0, value: relatedSource.relation, onValueChange: (relation) => onChange({ ...relatedSource, relation }), children: [_jsx(SelectTrigger, { className: "w-full", children: _jsx(SelectValue, { placeholder: relationOptions.length > 0 ? 'Select a relation field' : 'No compatible relations' }) }), _jsx(SelectContent, { children: relationOptions.map((relation) => (_jsx(SelectItem, { value: relation, children: relation }, relation))) })] })] }), _jsxs("div", { className: "grid content-start gap-1.5", children: [_jsx(ControlLabel, { help: "Arrays from matching records are flattened into one result.", children: t('dynamicData.arrayFieldToCollect') }), _jsxs(Select, { disabled: pathOptions.length === 0, value: relatedSource.path, onValueChange: (path) => onChange({ ...relatedSource, path }), children: [_jsx(SelectTrigger, { className: "w-full", children: _jsx(SelectValue, { placeholder: pathOptions.length > 0 ? 'Select an array field' : 'No compatible array fields' }) }), _jsx(SelectContent, { children: pathOptions.map((option) => (_jsx(SelectItem, { value: option.value, children: option.label }, option.value))) })] })] })] }), _jsxs("div", { className: "grid gap-3 sm:grid-cols-[0.7fr_1fr_0.7fr]", children: [_jsxs("div", { className: "grid content-start gap-1.5", children: [_jsx(ControlLabel, { help: `Number of ${relatedSource.contentType} records queried per ${currentSource.name}. Minimum 1, maximum 100.`, children: t('dynamicData.maximumRelatedRecords') }), _jsx(Input, { type: "number", min: 1, max: 100, value: String(relatedSource.limit), onChange: (event) => onChange({
|
|
740
690
|
...relatedSource,
|
|
741
691
|
limit: Math.min(100, Math.max(1, Number(event.target.value || 10))),
|
|
742
|
-
}) })] }), _jsxs("div", { className:
|
|
692
|
+
}) })] }), _jsxs("div", { className: "grid content-start gap-1.5", children: [_jsx(ControlLabel, { help: "Optional. Only direct scalar fields can be used.", children: t('dynamicData.sortRelatedRecordsBy') }), _jsxs(Select, { value: sortField || '__none__', onValueChange: (value) => onChange({
|
|
743
693
|
...relatedSource,
|
|
744
|
-
sort: value === '__none__'
|
|
745
|
-
|
|
746
|
-
: { [value]: sortDirection },
|
|
747
|
-
}), children: [_jsx(SelectTrigger, { className: 'w-full', children: _jsx(SelectValue, { placeholder: t('dynamicData.noSort') }) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: '__none__', children: t('dynamicData.noSort') }), sortOptions.map((option) => (_jsx(SelectItem, { value: option.value, children: option.label }, option.value)))] })] })] }), _jsxs("div", { className: 'grid content-start gap-1.5', children: [_jsx(ControlLabel, { help: 'Applied before collecting and flattening the arrays.', children: t('dynamicData.sortDirection') }), _jsxs(Select, { disabled: !sortField, value: sortDirection, onValueChange: (direction) => sortField
|
|
694
|
+
sort: value === '__none__' ? undefined : { [value]: sortDirection },
|
|
695
|
+
}), children: [_jsx(SelectTrigger, { className: "w-full", children: _jsx(SelectValue, { placeholder: t('dynamicData.noSort') }) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "__none__", children: t('dynamicData.noSort') }), sortOptions.map((option) => (_jsx(SelectItem, { value: option.value, children: option.label }, option.value)))] })] })] }), _jsxs("div", { className: "grid content-start gap-1.5", children: [_jsx(ControlLabel, { help: "Applied before collecting and flattening the arrays.", children: t('dynamicData.sortDirection') }), _jsxs(Select, { disabled: !sortField, value: sortDirection, onValueChange: (direction) => sortField
|
|
748
696
|
? onChange({
|
|
749
697
|
...relatedSource,
|
|
750
698
|
sort: { [sortField]: direction },
|
|
751
699
|
})
|
|
752
|
-
: undefined, children: [_jsx(SelectTrigger, { className:
|
|
700
|
+
: undefined, children: [_jsx(SelectTrigger, { className: "w-full", children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "asc", children: t('dynamicData.ascending') }), _jsx(SelectItem, { value: "desc", children: t('dynamicData.descending') })] })] })] })] })] }));
|
|
753
701
|
};
|
|
754
702
|
const ListBindingEditor = ({ contentTypes, documentContentType, rootDocumentContentType, currentItemContentType, currentDocumentSourceEnabled, field, binding, onChange, }) => {
|
|
755
703
|
const t = useTranslations();
|
|
756
|
-
const itemOptions = field
|
|
704
|
+
const itemOptions = getListItemOptions(field);
|
|
757
705
|
const documentSourceOptions = currentDocumentSourceEnabled
|
|
758
706
|
? currentDocumentListSourceOptions(documentContentType)
|
|
759
707
|
: [];
|
|
760
708
|
const initialDocumentSource = binding?.source
|
|
761
|
-
? documentSourceOptions.find((option) => option.path === binding.source?.path &&
|
|
762
|
-
option.itemName === binding.source?.itemName)
|
|
709
|
+
? documentSourceOptions.find((option) => option.path === binding.source?.path && option.itemName === binding.source?.itemName)
|
|
763
710
|
: undefined;
|
|
764
711
|
const [sourceType, setSourceType] = useState(initialDocumentSource?.value || binding?.contentType || '');
|
|
765
712
|
const [itemName, setItemName] = useState(binding?.itemName || itemOptions[0]?.name || '');
|
|
766
713
|
const [filterState, setFilterState] = useState(readFilterState(binding?.query?.filter));
|
|
767
714
|
const [openMappingField, setOpenMappingField] = useState(null);
|
|
768
715
|
const selectedDocumentSource = documentSourceOptions.find((option) => option.value === sourceType);
|
|
769
|
-
const selectedSource = selectedDocumentSource?.contentType ??
|
|
770
|
-
|
|
771
|
-
const
|
|
772
|
-
const targetFields = useMemo(() => targetContentType
|
|
773
|
-
? Object.entries(targetContentType.fields).filter(([targetFieldName, targetField]) => isSelectableDynamicField(targetFieldName, targetField))
|
|
774
|
-
: [], [targetContentType]);
|
|
775
|
-
const sortFieldOptions = selectedSource
|
|
776
|
-
? getSortFieldOptions(selectedSource)
|
|
777
|
-
: [];
|
|
716
|
+
const selectedSource = selectedDocumentSource?.contentType ?? contentTypes.find((ct) => ct.name === sourceType);
|
|
717
|
+
const targetFields = useMemo(() => listItemTargetFields(field, itemName), [field, itemName]);
|
|
718
|
+
const sortFieldOptions = selectedSource ? getSortFieldOptions(selectedSource) : [];
|
|
778
719
|
const filterFieldOptions = selectedSource
|
|
779
720
|
? sourceFieldOptions(selectedSource).filter((item) => item.value !== '$href')
|
|
780
721
|
: [];
|
|
781
722
|
const currentDocumentFieldOptions = [
|
|
782
723
|
{ label: '_id', value: '_id', kind: 'string' },
|
|
783
|
-
...sourceFieldOptions(rootDocumentContentType).filter((item) => item.value !== '$href' &&
|
|
784
|
-
item.kind !== 'object' &&
|
|
785
|
-
item.kind !== 'array'),
|
|
724
|
+
...sourceFieldOptions(rootDocumentContentType).filter((item) => item.value !== '$href' && item.kind !== 'object' && item.kind !== 'array'),
|
|
786
725
|
];
|
|
787
726
|
const currentItemFieldOptions = currentItemContentType
|
|
788
727
|
? [
|
|
789
728
|
{ label: '_id', value: '_id', kind: 'string' },
|
|
790
|
-
...sourceFieldOptions(currentItemContentType).filter((item) => item.value !== '$href' &&
|
|
791
|
-
item.kind !== 'object' &&
|
|
792
|
-
item.kind !== 'array'),
|
|
729
|
+
...sourceFieldOptions(currentItemContentType).filter((item) => item.value !== '$href' && item.kind !== 'object' && item.kind !== 'array'),
|
|
793
730
|
]
|
|
794
731
|
: [];
|
|
795
732
|
const sortEntry = Object.entries(binding?.query?.options?.sort ?? {})[0];
|
|
@@ -809,9 +746,7 @@ const ListBindingEditor = ({ contentTypes, documentContentType, rootDocumentCont
|
|
|
809
746
|
source,
|
|
810
747
|
itemName,
|
|
811
748
|
map: binding?.map ?? {},
|
|
812
|
-
query: source
|
|
813
|
-
? undefined
|
|
814
|
-
: (binding?.query ?? { options: { limit: 10 } }),
|
|
749
|
+
query: source ? undefined : (binding?.query ?? { options: { limit: 10 } }),
|
|
815
750
|
...patch,
|
|
816
751
|
};
|
|
817
752
|
if (!next.contentType || !next.itemName) {
|
|
@@ -834,7 +769,7 @@ const ListBindingEditor = ({ contentTypes, documentContentType, rootDocumentCont
|
|
|
834
769
|
conditions[index] = nextCondition;
|
|
835
770
|
updateFilter({ ...filterState, conditions });
|
|
836
771
|
};
|
|
837
|
-
return (_jsxs("div", { className:
|
|
772
|
+
return (_jsxs("div", { className: "grid gap-3", children: [_jsx(PanelSection, { title: "Collection", children: _jsxs("div", { className: "grid gap-3 md:grid-cols-2", children: [_jsxs(Label, { className: "grid gap-1.5", children: [t('dynamicData.source'), _jsxs(Select, { disabled: contentTypes.length === 0 && documentSourceOptions.length === 0, value: sourceType, onValueChange: (value) => {
|
|
838
773
|
const documentSource = documentSourceOptions.find((option) => option.value === value);
|
|
839
774
|
setSourceType(value);
|
|
840
775
|
const nextFilterState = {
|
|
@@ -862,12 +797,12 @@ const ListBindingEditor = ({ contentTypes, documentContentType, rootDocumentCont
|
|
|
862
797
|
},
|
|
863
798
|
},
|
|
864
799
|
});
|
|
865
|
-
}, children: [_jsx(SelectTrigger, { className:
|
|
800
|
+
}, children: [_jsx(SelectTrigger, { className: "w-full", children: _jsx(SelectValue, { placeholder: contentTypes.length > 0 || documentSourceOptions.length > 0
|
|
866
801
|
? 'Content type or document list'
|
|
867
|
-
: 'No compatible sources' }) }), _jsx(SelectContent, { children: _jsxs(SelectGroup, { children: [documentSourceOptions.map((option) => (_jsx(SelectItem, { value: option.value, children: option.label }, option.value))), contentTypes.map((ct) => (_jsx(SelectItem, { value: ct.name, children: ct.name }, ct.name)))] }) })] })] }), _jsxs(Label, { className:
|
|
802
|
+
: 'No compatible sources' }) }), _jsx(SelectContent, { children: _jsxs(SelectGroup, { children: [documentSourceOptions.map((option) => (_jsx(SelectItem, { value: option.value, children: option.label }, option.value))), contentTypes.map((ct) => (_jsx(SelectItem, { value: ct.name, children: ct.name }, ct.name)))] }) })] })] }), _jsxs(Label, { className: "grid gap-1.5", children: [t('dynamicData.item'), _jsxs(Select, { disabled: !sourceType || itemOptions.length === 0, value: itemName, onValueChange: (value) => {
|
|
868
803
|
setItemName(value);
|
|
869
804
|
emit({ itemName: value, map: {} });
|
|
870
|
-
}, children: [_jsx(SelectTrigger, { className:
|
|
805
|
+
}, children: [_jsx(SelectTrigger, { className: "w-full", children: _jsx(SelectValue, { placeholder: itemOptions.length > 0 ? 'Item type' : 'No item types' }) }), _jsx(SelectContent, { children: _jsx(SelectGroup, { children: itemOptions.map((item) => (_jsx(SelectItem, { value: item.name, children: item.name }, item.name))) }) })] })] })] }) }), selectedDocumentSource ? null : (_jsxs(PanelSection, { title: "Query", children: [_jsxs("div", { className: "grid grid-cols-[minmax(5rem,0.4fr)_minmax(0,1.2fr)_minmax(8rem,0.6fr)] items-end gap-3", children: [_jsxs(Label, { className: "grid gap-1.5", children: [t('dynamicData.limit'), _jsx(Input, { type: "number", min: 1, max: 100, value: String(binding?.query?.options?.limit ?? 10), onChange: (event) => emit({
|
|
871
806
|
query: {
|
|
872
807
|
...binding?.query,
|
|
873
808
|
options: {
|
|
@@ -875,19 +810,15 @@ const ListBindingEditor = ({ contentTypes, documentContentType, rootDocumentCont
|
|
|
875
810
|
limit: Math.min(100, Math.max(1, Number(event.target.value || 10))),
|
|
876
811
|
},
|
|
877
812
|
},
|
|
878
|
-
}) })] }), _jsxs(Label, { className:
|
|
813
|
+
}) })] }), _jsxs(Label, { className: "grid min-w-0 gap-1.5", children: [t('dynamicData.sortBy'), _jsxs(Select, { disabled: sortFieldOptions.length === 0, value: sortField || '__none__', onValueChange: (value) => emit({
|
|
879
814
|
query: {
|
|
880
815
|
...binding?.query,
|
|
881
816
|
options: {
|
|
882
817
|
...binding?.query?.options,
|
|
883
|
-
sort: value === '__none__'
|
|
884
|
-
? undefined
|
|
885
|
-
: { [value]: sortDirection },
|
|
818
|
+
sort: value === '__none__' ? undefined : { [value]: sortDirection },
|
|
886
819
|
},
|
|
887
820
|
},
|
|
888
|
-
}), children: [_jsx(SelectTrigger, { className:
|
|
889
|
-
? 'Sort by field'
|
|
890
|
-
: 'No sortable fields' }) }), _jsx(SelectContent, { children: _jsxs(SelectGroup, { children: [_jsx(SelectItem, { value: '__none__', children: t('dynamicData.noSort') }), sortFieldOptions.map((item) => (_jsx(SelectItem, { value: item.value, children: item.label }, item.value)))] }) })] })] }), _jsxs(Label, { className: 'grid gap-1.5', children: [t('dynamicData.direction'), _jsxs(Select, { disabled: !sortField, value: sortDirection, onValueChange: (direction) => sortField
|
|
821
|
+
}), children: [_jsx(SelectTrigger, { className: "w-full", children: _jsx(SelectValue, { placeholder: sortFieldOptions.length > 0 ? 'Sort by field' : 'No sortable fields' }) }), _jsx(SelectContent, { children: _jsxs(SelectGroup, { children: [_jsx(SelectItem, { value: "__none__", children: t('dynamicData.noSort') }), sortFieldOptions.map((item) => (_jsx(SelectItem, { value: item.value, children: item.label }, item.value)))] }) })] })] }), _jsxs(Label, { className: "grid gap-1.5", children: [t('dynamicData.direction'), _jsxs(Select, { disabled: !sortField, value: sortDirection, onValueChange: (direction) => sortField
|
|
891
822
|
? emit({
|
|
892
823
|
query: {
|
|
893
824
|
...binding?.query,
|
|
@@ -899,17 +830,16 @@ const ListBindingEditor = ({ contentTypes, documentContentType, rootDocumentCont
|
|
|
899
830
|
},
|
|
900
831
|
},
|
|
901
832
|
})
|
|
902
|
-
: undefined, children: [_jsx(SelectTrigger, { className:
|
|
833
|
+
: undefined, children: [_jsx(SelectTrigger, { className: "w-full", children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "asc", children: t('dynamicData.ascending') }), _jsx(SelectItem, { value: "desc", children: t('dynamicData.descending') })] })] })] })] }), _jsxs("div", { className: "grid gap-3 rounded-md border border-border bg-background/60 p-3", children: [_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [_jsxs("div", { children: [_jsx("div", { className: "text-sm font-medium", children: t('dynamicData.conditions') }), _jsx("div", { className: "text-xs text-muted-foreground", children: t('dynamicData.conditionsDescription') })] }), _jsxs("div", { className: "flex items-center gap-2", children: [filterState.conditions.length > 1 ? (_jsxs(Select, { value: filterState.combinator, onValueChange: (combinator) => updateFilter({
|
|
903
834
|
...filterState,
|
|
904
835
|
combinator: combinator,
|
|
905
|
-
}), children: [_jsx(SelectTrigger, { className:
|
|
906
|
-
filterState.conditions.length >= 25, onClick: () => updateFilter({
|
|
836
|
+
}), children: [_jsx(SelectTrigger, { className: "h-8 w-36", children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "and", children: t('dynamicData.matchAll') }), _jsx(SelectItem, { value: "or", children: t('dynamicData.matchAny') })] })] })) : null, _jsxs(Button, { type: "button", size: "sm", variant: "outline", disabled: filterFieldOptions.length === 0 || filterState.conditions.length >= 25, onClick: () => updateFilter({
|
|
907
837
|
...filterState,
|
|
908
838
|
conditions: [
|
|
909
839
|
...filterState.conditions,
|
|
910
840
|
{ field: '', operator: 'equals', value: '' },
|
|
911
841
|
],
|
|
912
|
-
}), children: [_jsx(Plus, { className:
|
|
842
|
+
}), children: [_jsx(Plus, { className: "h-4 w-4" }), t('dynamicData.addCondition')] })] })] }), filterState.conditions.length === 0 ? (_jsx("div", { className: "rounded-md border border-dashed border-border px-3 py-5 text-center text-sm text-muted-foreground", children: t('dynamicData.noConditions') })) : (_jsx("div", { className: "grid gap-2", children: filterState.conditions.map((condition, index) => {
|
|
913
843
|
const fieldOption = filterFieldOptions.find((option) => option.value === condition.field);
|
|
914
844
|
const operatorOptions = getFilterOperatorOptions(fieldOption?.kind);
|
|
915
845
|
const needsValue = operatorNeedsValue(condition.operator);
|
|
@@ -927,14 +857,14 @@ const ListBindingEditor = ({ contentTypes, documentContentType, rootDocumentCont
|
|
|
927
857
|
condition.operator !== 'in' &&
|
|
928
858
|
condition.operator !== 'notIn' &&
|
|
929
859
|
currentItemValueOptions.length > 0;
|
|
930
|
-
return (_jsxs("div", { className:
|
|
860
|
+
return (_jsxs("div", { className: "grid items-center gap-2 rounded-md border border-border bg-background p-2 sm:grid-cols-[1.2fr_1fr_1.8fr_auto]", children: [_jsxs(Select, { disabled: filterFieldOptions.length === 0, value: condition.field, onValueChange: (value) => {
|
|
931
861
|
const kind = filterFieldOptions.find((option) => option.value === value)?.kind;
|
|
932
862
|
updateFilterCondition(index, {
|
|
933
863
|
field: value,
|
|
934
864
|
operator: defaultFilterOperator(kind),
|
|
935
865
|
value: '',
|
|
936
866
|
});
|
|
937
|
-
}, children: [_jsx(SelectTrigger, { className:
|
|
867
|
+
}, children: [_jsx(SelectTrigger, { className: "w-full", children: _jsx(SelectValue, { placeholder: t('dynamicData.field') }) }), _jsx(SelectContent, { children: _jsx(SelectGroup, { children: filterFieldOptions.map((item) => (_jsx(SelectItem, { value: item.value, children: item.label }, item.value))) }) })] }), _jsxs(Select, { disabled: !condition.field, value: condition.operator, onValueChange: (operator) => updateFilterCondition(index, {
|
|
938
868
|
...condition,
|
|
939
869
|
operator: operator,
|
|
940
870
|
valueSource: operator === 'in' || operator === 'notIn'
|
|
@@ -945,40 +875,35 @@ const ListBindingEditor = ({ contentTypes, documentContentType, rootDocumentCont
|
|
|
945
875
|
? ''
|
|
946
876
|
: condition.value
|
|
947
877
|
: '',
|
|
948
|
-
}), children: [_jsx(SelectTrigger, { className:
|
|
878
|
+
}), children: [_jsx(SelectTrigger, { className: "w-full", children: _jsx(SelectValue, { placeholder: t('dynamicData.operator') }) }), _jsx(SelectContent, { children: _jsx(SelectGroup, { children: operatorOptions.map((option) => (_jsx(SelectItem, { value: option.value, children: option.label }, option.value))) }) })] }), needsValue ? (_jsxs("div", { className: "grid grid-cols-[minmax(7rem,0.7fr)_minmax(0,1fr)] gap-2", children: [_jsxs(Select, { value: condition.valueSource ?? 'literal', onValueChange: (valueSource) => updateFilterCondition(index, {
|
|
949
879
|
...condition,
|
|
950
880
|
valueSource: valueSource,
|
|
951
881
|
value: '',
|
|
952
|
-
}), children: [_jsx(SelectTrigger, { className:
|
|
953
|
-
? 'document'
|
|
954
|
-
: 'current', children: t('dynamicData.currentDocument') })) : null, allowsCurrentItemValue ? (_jsx(SelectItem, { value: 'current', children: t('dynamicData.currentItem') })) : null] })] }), condition.valueSource === 'current' ||
|
|
882
|
+
}), children: [_jsx(SelectTrigger, { className: "w-full", "aria-label": "Value source", children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "literal", children: t('dynamicData.fixedValue') }), allowsCurrentDocumentValue ? (_jsx(SelectItem, { value: currentItemContentType ? 'document' : 'current', children: t('dynamicData.currentDocument') })) : null, allowsCurrentItemValue ? (_jsx(SelectItem, { value: "current", children: t('dynamicData.currentItem') })) : null] })] }), condition.valueSource === 'current' ||
|
|
955
883
|
condition.valueSource === 'document' ? (_jsxs(Select, { disabled: !condition.field, value: condition.value, onValueChange: (value) => updateFilterCondition(index, {
|
|
956
884
|
...condition,
|
|
957
885
|
value,
|
|
958
|
-
}), children: [_jsx(SelectTrigger, { className:
|
|
886
|
+
}), children: [_jsx(SelectTrigger, { className: "w-full", children: _jsx(SelectValue, { placeholder: t('dynamicData.currentField') }) }), _jsx(SelectContent, { children: _jsx(SelectGroup, { children: currentValueOptions.map((option) => (_jsx(SelectItem, { value: option.value, children: option.label }, option.value))) }) })] })) : (_jsx(Input, { type: fieldOption?.kind === 'number' &&
|
|
959
887
|
condition.operator !== 'in' &&
|
|
960
888
|
condition.operator !== 'notIn'
|
|
961
889
|
? 'number'
|
|
962
|
-
: 'text', value: condition.value, disabled: !condition.field, placeholder: condition.operator === 'in' ||
|
|
963
|
-
condition.operator === 'notIn'
|
|
890
|
+
: 'text', value: condition.value, disabled: !condition.field, placeholder: condition.operator === 'in' || condition.operator === 'notIn'
|
|
964
891
|
? 'Comma-separated values'
|
|
965
892
|
: 'Value', onChange: (event) => updateFilterCondition(index, {
|
|
966
893
|
...condition,
|
|
967
894
|
value: event.target.value,
|
|
968
|
-
}) }))] })) : (_jsx("div", { className:
|
|
895
|
+
}) }))] })) : (_jsx("div", { className: "h-9 rounded-md border border-dashed border-border bg-muted/30" })), _jsxs(Button, { type: "button", size: "icon", variant: "ghost", className: "size-9 text-muted-foreground hover:text-destructive", onClick: () => updateFilter({
|
|
969
896
|
...filterState,
|
|
970
897
|
conditions: filterState.conditions.filter((_, conditionIndex) => conditionIndex !== index),
|
|
971
|
-
}), children: [_jsx(Trash2, { className:
|
|
972
|
-
}) }))] })] })), _jsx(PanelSection, { title:
|
|
898
|
+
}), children: [_jsx(Trash2, { className: "h-4 w-4" }), _jsx("span", { className: "sr-only", children: t('dynamicData.removeCondition') })] })] }, `${index}-${condition.field}`));
|
|
899
|
+
}) }))] })] })), _jsx(PanelSection, { title: "Mapping", children: _jsx("div", { className: "grid gap-2", children: targetFields.map(([targetField, targetFieldConfig]) => {
|
|
973
900
|
const source = binding?.map?.[targetField];
|
|
974
901
|
const summary = mappingSourceSummary(source, selectedSource?.name ?? 'Source');
|
|
975
902
|
const summaryMode = isNestedListSource(source)
|
|
976
903
|
? t('dynamicData.nestedList')
|
|
977
904
|
: summary.mode;
|
|
978
905
|
const isOpen = openMappingField === targetField;
|
|
979
|
-
return (_jsx(Collapsible, { open: isOpen, onOpenChange: (open) => setOpenMappingField(open ? targetField : null), children: _jsxs("div", { className:
|
|
980
|
-
? summary.detail
|
|
981
|
-
: 'Select a source collection first' }), _jsx(ChevronRight, { className: 'h-4 w-4 text-muted-foreground transition-transform group-data-[state=open]:rotate-90' }), _jsx("span", { className: 'sr-only', children: t('dynamicData.configureMapping', { name: targetField }) })] }) }), _jsx(CollapsibleContent, { children: _jsx("div", { className: 'border-t border-border bg-muted/20 p-3', children: selectedSource ? (_jsx(MappingSourceEditor, { contentTypes: contentTypes, rootDocumentContentType: rootDocumentContentType, currentSource: selectedSource, targetField: targetFieldConfig, source: source, onChange: (nextSource) => {
|
|
906
|
+
return (_jsx(Collapsible, { open: isOpen, onOpenChange: (open) => setOpenMappingField(open ? targetField : null), children: _jsxs("div", { className: "overflow-hidden rounded-md border border-border bg-background/70 transition-colors hover:border-foreground/20", children: [_jsx(CollapsibleTrigger, { asChild: true, children: _jsxs("button", { type: "button", disabled: !selectedSource, className: "group grid w-full grid-cols-[minmax(6rem,0.45fr)_auto_minmax(0,1fr)_auto] items-center gap-3 px-3 py-2.5 text-left outline-none transition-colors hover:bg-muted/50 focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50", children: [_jsx("span", { className: "truncate text-sm font-semibold", children: targetField }), _jsx(Badge, { variant: source ? 'secondary' : 'outline', className: "max-w-40 truncate", children: summaryMode }), _jsx("span", { className: "truncate text-sm text-muted-foreground", children: selectedSource ? summary.detail : 'Select a source collection first' }), _jsx(ChevronRight, { className: "h-4 w-4 text-muted-foreground transition-transform group-data-[state=open]:rotate-90" }), _jsx("span", { className: "sr-only", children: t('dynamicData.configureMapping', { name: targetField }) })] }) }), _jsx(CollapsibleContent, { children: _jsx("div", { className: "border-t border-border bg-muted/20 p-3", children: selectedSource ? (_jsx(MappingSourceEditor, { contentTypes: contentTypes, rootDocumentContentType: rootDocumentContentType, currentSource: selectedSource, targetField: targetFieldConfig, source: source, onChange: (nextSource) => {
|
|
982
907
|
const map = { ...(binding?.map ?? {}) };
|
|
983
908
|
if (nextSource)
|
|
984
909
|
map[targetField] = nextSource;
|
|
@@ -988,12 +913,32 @@ const ListBindingEditor = ({ contentTypes, documentContentType, rootDocumentCont
|
|
|
988
913
|
} })) : null }) })] }) }, targetField));
|
|
989
914
|
}) }) })] }));
|
|
990
915
|
};
|
|
916
|
+
const StructuredArrayBindingEditor = ({ contentTypes, fieldContentTypes, documentContentType, currentDocumentSourceEnabled, field, fieldBinding, listBinding, onFieldChange, onListChange, }) => {
|
|
917
|
+
const t = useTranslations();
|
|
918
|
+
const [mode, setMode] = useState(listBinding ? 'list' : 'field');
|
|
919
|
+
useEffect(() => {
|
|
920
|
+
if (listBinding)
|
|
921
|
+
setMode('list');
|
|
922
|
+
else if (fieldBinding)
|
|
923
|
+
setMode('field');
|
|
924
|
+
}, [fieldBinding, listBinding]);
|
|
925
|
+
return (_jsxs("div", { className: "grid gap-3", children: [_jsxs("div", { className: "grid max-w-sm content-start gap-1.5", children: [_jsx(ControlLabel, { help: t('dynamicData.nestedListHelp'), children: t('dynamicData.mappingMode') }), _jsxs(Select, { value: mode, onValueChange: (value) => {
|
|
926
|
+
if (value === 'list') {
|
|
927
|
+
setMode('list');
|
|
928
|
+
onListChange(undefined);
|
|
929
|
+
return;
|
|
930
|
+
}
|
|
931
|
+
setMode('field');
|
|
932
|
+
onFieldChange(undefined);
|
|
933
|
+
}, children: [_jsx(SelectTrigger, { className: "w-full", children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "field", children: t('dynamicData.directField') }), _jsx(SelectItem, { value: "list", children: t('dynamicData.nestedList') })] })] })] }), mode === 'list' ? (_jsx(ListBindingEditor, { contentTypes: contentTypes, documentContentType: documentContentType, rootDocumentContentType: documentContentType, currentDocumentSourceEnabled: currentDocumentSourceEnabled, field: field, binding: listBinding, onChange: onListChange })) : (_jsx(FieldBindingEditor, { contentTypes: fieldContentTypes, documentContentType: documentContentType, currentDocumentSourceEnabled: currentDocumentSourceEnabled, targetField: field, binding: fieldBinding, onChange: onFieldChange }))] }));
|
|
934
|
+
};
|
|
991
935
|
export const DynamicDataControl = ({ contentType, documentContentType, fieldName, field, contentTypes, bindings, onChange, open, onOpenChange, mode = 'full', }) => {
|
|
992
936
|
const t = useTranslations();
|
|
993
937
|
const [internalOpen, setInternalOpen] = useState(false);
|
|
994
938
|
const [draftBindings, setDraftBindings] = useState(() => cloneDynamicBindings(bindings));
|
|
995
939
|
const wasOpenRef = useRef(open ?? internalOpen);
|
|
996
|
-
const list =
|
|
940
|
+
const list = isMappableDynamicListField(field);
|
|
941
|
+
const structuredArray = list && field.config.capabilities.dynamic?.collection === 'homogeneous';
|
|
997
942
|
const isOpen = open ?? internalOpen;
|
|
998
943
|
useEffect(() => {
|
|
999
944
|
if (mode !== 'dialog')
|
|
@@ -1029,9 +974,14 @@ export const DynamicDataControl = ({ contentType, documentContentType, fieldName
|
|
|
1029
974
|
: sourceContentTypes.filter((sourceContentType) => sourceContentType.name !== contentType.name);
|
|
1030
975
|
const fieldBinding = activeBindings?.fields?.[fieldName];
|
|
1031
976
|
const listBinding = activeBindings?.lists?.[fieldName];
|
|
1032
|
-
const bound =
|
|
977
|
+
const bound = structuredArray
|
|
978
|
+
? !!fieldBinding || !!listBinding
|
|
979
|
+
: list
|
|
980
|
+
? !!listBinding
|
|
981
|
+
: !!fieldBinding;
|
|
982
|
+
const usesListBinding = list && !!listBinding;
|
|
1033
983
|
const summary = bindingSummary({
|
|
1034
|
-
list,
|
|
984
|
+
list: usesListBinding,
|
|
1035
985
|
fieldBinding,
|
|
1036
986
|
listBinding,
|
|
1037
987
|
documentContentTypeName: currentDocumentContentType.name,
|
|
@@ -1058,7 +1008,44 @@ export const DynamicDataControl = ({ contentType, documentContentType, fieldName
|
|
|
1058
1008
|
lists: Object.keys(lists).length ? lists : undefined,
|
|
1059
1009
|
});
|
|
1060
1010
|
};
|
|
1061
|
-
const
|
|
1011
|
+
const updateStructuredFieldBinding = (binding) => {
|
|
1012
|
+
const fields = { ...(activeBindings?.fields ?? {}) };
|
|
1013
|
+
const lists = { ...(activeBindings?.lists ?? {}) };
|
|
1014
|
+
if (binding)
|
|
1015
|
+
fields[fieldName] = binding;
|
|
1016
|
+
else
|
|
1017
|
+
delete fields[fieldName];
|
|
1018
|
+
delete lists[fieldName];
|
|
1019
|
+
commitBindings({
|
|
1020
|
+
...(activeBindings ?? {}),
|
|
1021
|
+
fields: Object.keys(fields).length ? fields : undefined,
|
|
1022
|
+
lists: Object.keys(lists).length ? lists : undefined,
|
|
1023
|
+
});
|
|
1024
|
+
};
|
|
1025
|
+
const updateStructuredListBinding = (binding) => {
|
|
1026
|
+
const fields = { ...(activeBindings?.fields ?? {}) };
|
|
1027
|
+
const lists = { ...(activeBindings?.lists ?? {}) };
|
|
1028
|
+
delete fields[fieldName];
|
|
1029
|
+
if (binding)
|
|
1030
|
+
lists[fieldName] = binding;
|
|
1031
|
+
else
|
|
1032
|
+
delete lists[fieldName];
|
|
1033
|
+
commitBindings({
|
|
1034
|
+
...(activeBindings ?? {}),
|
|
1035
|
+
fields: Object.keys(fields).length ? fields : undefined,
|
|
1036
|
+
lists: Object.keys(lists).length ? lists : undefined,
|
|
1037
|
+
});
|
|
1038
|
+
};
|
|
1039
|
+
const clearBinding = () => {
|
|
1040
|
+
if (structuredArray) {
|
|
1041
|
+
updateStructuredListBinding(undefined);
|
|
1042
|
+
return;
|
|
1043
|
+
}
|
|
1044
|
+
if (list)
|
|
1045
|
+
updateListBinding(undefined);
|
|
1046
|
+
else
|
|
1047
|
+
updateFieldBinding(undefined);
|
|
1048
|
+
};
|
|
1062
1049
|
const triggerLabel = bound ? 'Edit dynamic data link' : 'Link dynamic data';
|
|
1063
1050
|
const helpDescription = list
|
|
1064
1051
|
? 'Dynamic data fills this list from another content source. Use it when modules should stay synced with page, route, or related content instead of being edited manually here.'
|
|
@@ -1071,22 +1058,22 @@ export const DynamicDataControl = ({ contentType, documentContentType, fieldName
|
|
|
1071
1058
|
onChange(cleanDynamicBindings(draftBindings));
|
|
1072
1059
|
setOpen(false);
|
|
1073
1060
|
};
|
|
1074
|
-
const trigger = (_jsxs("div", { className:
|
|
1075
|
-
const editor = list ? (_jsx(ListBindingEditor, { contentTypes: sourceContentTypes, documentContentType: currentDocumentContentType, rootDocumentContentType: currentDocumentContentType, currentDocumentSourceEnabled: currentDocumentSourceEnabled, field: field, binding: listBinding, onChange: updateListBinding })) : (_jsx(FieldBindingEditor, { contentTypes: fieldSourceContentTypes, documentContentType: currentDocumentContentType, currentDocumentSourceEnabled: currentDocumentSourceEnabled, targetField: field, binding: fieldBinding, onChange: updateFieldBinding }));
|
|
1076
|
-
const panel = isOpen ? (_jsx("div", { className:
|
|
1061
|
+
const trigger = (_jsxs("div", { className: "flex min-w-0 items-center gap-1.5", children: [_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { type: "button", className: "min-w-0 cursor-pointer rounded-md focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", onClick: () => setOpen((value) => !value), children: bound && summary ? (_jsxs(Badge, { variant: "secondary", className: "max-w-80 min-w-0 gap-1.5 rounded-md px-2 py-1 hover:bg-secondary/80", children: [usesListBinding ? (_jsx(ListFilter, { className: "h-3.5 w-3.5 shrink-0" })) : (_jsx(Link2, { className: "h-3.5 w-3.5 shrink-0" })), _jsx("span", { className: "truncate", children: summary })] })) : (_jsxs(Badge, { variant: "outline", className: "gap-1.5 rounded-md px-2 py-1 text-muted-foreground", children: [_jsx(Cable, { className: "h-3.5 w-3.5" }), t('dynamicData.notLinked')] })) }) }), _jsx(TooltipContent, { side: "top", sideOffset: 6, children: triggerLabel })] }), bound ? (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs(Button, { type: "button", size: "icon", variant: "ghost", className: "size-6", onClick: clearBinding, children: [_jsx(X, { className: "h-4 w-4" }), _jsx("span", { className: "sr-only", children: t('dynamicData.clear') })] }) }), _jsx(TooltipContent, { side: "top", sideOffset: 6, children: t('dynamicData.clearLink') })] })) : null] }));
|
|
1062
|
+
const editor = structuredArray ? (_jsx(StructuredArrayBindingEditor, { contentTypes: sourceContentTypes, fieldContentTypes: fieldSourceContentTypes, documentContentType: currentDocumentContentType, currentDocumentSourceEnabled: currentDocumentSourceEnabled, field: field, fieldBinding: fieldBinding, listBinding: listBinding, onFieldChange: updateStructuredFieldBinding, onListChange: updateStructuredListBinding })) : list ? (_jsx(ListBindingEditor, { contentTypes: sourceContentTypes, documentContentType: currentDocumentContentType, rootDocumentContentType: currentDocumentContentType, currentDocumentSourceEnabled: currentDocumentSourceEnabled, field: field, binding: listBinding, onChange: updateListBinding })) : (_jsx(FieldBindingEditor, { contentTypes: fieldSourceContentTypes, documentContentType: currentDocumentContentType, currentDocumentSourceEnabled: currentDocumentSourceEnabled, targetField: field, binding: fieldBinding, onChange: updateFieldBinding }));
|
|
1063
|
+
const panel = isOpen ? (_jsx("div", { className: "rounded-md border border-border bg-background p-4 shadow-sm", children: editor })) : null;
|
|
1077
1064
|
const dialog = (_jsx(Dialog, { open: isOpen, onOpenChange: (value) => {
|
|
1078
1065
|
if (value) {
|
|
1079
1066
|
setOpen(true);
|
|
1080
1067
|
return;
|
|
1081
1068
|
}
|
|
1082
1069
|
cancelDialogChanges();
|
|
1083
|
-
}, children: _jsxs(DialogContent, { className:
|
|
1070
|
+
}, children: _jsxs(DialogContent, { className: "max-h-[85vh] w-screen max-w-5xl! overflow-y-auto", children: [_jsxs(DialogHeader, { children: [_jsxs(DialogTitle, { className: "flex items-center gap-2", children: [t('dynamicData.title'), _jsx(HelpCircle, { className: "h-4 w-4 text-muted-foreground" })] }), _jsx(DialogDescription, { className: "max-w-2xl leading-relaxed", children: helpDescription })] }), editor, _jsxs(DialogFooter, { children: [_jsx(Button, { type: "button", variant: "outline", onClick: cancelDialogChanges, children: t('common.cancel') }), _jsx(Button, { type: "button", onClick: saveDialogChanges, children: t('common.save') })] })] }) }));
|
|
1084
1071
|
if (mode === 'trigger')
|
|
1085
1072
|
return trigger;
|
|
1086
1073
|
if (mode === 'panel')
|
|
1087
1074
|
return panel;
|
|
1088
1075
|
if (mode === 'dialog')
|
|
1089
1076
|
return dialog;
|
|
1090
|
-
return (_jsxs("div", { className:
|
|
1077
|
+
return (_jsxs("div", { className: "grid min-w-0 gap-2", children: [_jsx("div", { className: "flex min-w-0 justify-end", children: trigger }), panel] }));
|
|
1091
1078
|
};
|
|
1092
1079
|
//# sourceMappingURL=DynamicDataControl.js.map
|