@rakun-kit/manager-react 1.5.10 → 1.6.1

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.
Files changed (262) hide show
  1. package/README.md +349 -295
  2. package/dist/cjs/components/app-sidebar.js +10 -0
  3. package/dist/cjs/components/app-sidebar.js.map +1 -1
  4. package/dist/cjs/components/media/MediaLibrary.js +10 -1
  5. package/dist/cjs/components/media/MediaLibrary.js.map +1 -1
  6. package/dist/cjs/components/media/contexts/MediaLibraryContext.js +1 -1
  7. package/dist/cjs/components/media/contexts/MediaLibraryContext.js.map +1 -1
  8. package/dist/cjs/components/media/previews/MediaContextMenuContent.js +68 -15
  9. package/dist/cjs/components/media/previews/MediaContextMenuContent.js.map +1 -1
  10. package/dist/cjs/components/media/previews/Previews.js +89 -35
  11. package/dist/cjs/components/media/previews/Previews.js.map +1 -1
  12. package/dist/cjs/components/media/previews/context/MediaPreviewContext.js.map +1 -1
  13. package/dist/cjs/components/media/previews/dialogs/ExpandedPreviewDialog.js +7 -10
  14. package/dist/cjs/components/media/previews/dialogs/ExpandedPreviewDialog.js.map +1 -1
  15. package/dist/cjs/components/media/previews/hooks/useMediaPreviewRenderer.js +3 -1
  16. package/dist/cjs/components/media/previews/hooks/useMediaPreviewRenderer.js.map +1 -1
  17. package/dist/cjs/components/media/previews/toolbar/PreviewsToolbar.js +16 -9
  18. package/dist/cjs/components/media/previews/toolbar/PreviewsToolbar.js.map +1 -1
  19. package/dist/cjs/components/media/previews/utils/mediaDownload.js +54 -0
  20. package/dist/cjs/components/media/previews/utils/mediaDownload.js.map +1 -0
  21. package/dist/cjs/components/media/previews/views/PreviewsListView.js +1 -1
  22. package/dist/cjs/components/media/previews/views/PreviewsListView.js.map +1 -1
  23. package/dist/cjs/components/rakun-logo.js +4 -9
  24. package/dist/cjs/components/rakun-logo.js.map +1 -1
  25. package/dist/cjs/components/ui/context-menu.js +1 -1
  26. package/dist/cjs/components/ui/context-menu.js.map +1 -1
  27. package/dist/cjs/i18n/catalog.js +346 -9
  28. package/dist/cjs/i18n/catalog.js.map +1 -1
  29. package/dist/cjs/lib/media.js +1 -0
  30. package/dist/cjs/lib/media.js.map +1 -1
  31. package/dist/cjs/media.js +45 -0
  32. package/dist/cjs/media.js.map +1 -1
  33. package/dist/cjs/router/dashboard/[contentType]/[edit]/ContentTypeEdit.js +15 -4
  34. package/dist/cjs/router/dashboard/[contentType]/[edit]/ContentTypeEdit.js.map +1 -1
  35. package/dist/cjs/router/dashboard/[contentType]/[edit]/_components/ContentCommentsDrawer.js +11 -6
  36. package/dist/cjs/router/dashboard/[contentType]/[edit]/_components/ContentCommentsDrawer.js.map +1 -1
  37. package/dist/cjs/router/dashboard/[contentType]/[edit]/_components/EditTabPanels.js +2 -1
  38. package/dist/cjs/router/dashboard/[contentType]/[edit]/_components/EditTabPanels.js.map +1 -1
  39. package/dist/cjs/router/dashboard/[contentType]/[edit]/_components/EditToolbar.js +2 -1
  40. package/dist/cjs/router/dashboard/[contentType]/[edit]/_components/EditToolbar.js.map +1 -1
  41. package/dist/cjs/router/dashboard/[contentType]/[edit]/_components/PreviewPanel.js +1 -1
  42. package/dist/cjs/router/dashboard/[contentType]/[edit]/_components/PreviewPanel.js.map +1 -1
  43. package/dist/cjs/router/dashboard/[contentType]/[edit]/_components/SeoTabContent.js +290 -0
  44. package/dist/cjs/router/dashboard/[contentType]/[edit]/_components/SeoTabContent.js.map +1 -0
  45. package/dist/cjs/router/dashboard/[contentType]/[edit]/_components/seo-analysis.js +88 -0
  46. package/dist/cjs/router/dashboard/[contentType]/[edit]/_components/seo-analysis.js.map +1 -0
  47. package/dist/cjs/router/dashboard/[contentType]/[edit]/_context/EditPageContext.js +1 -1
  48. package/dist/cjs/router/dashboard/[contentType]/[edit]/_context/EditPageContext.js.map +1 -1
  49. package/dist/cjs/router/dashboard/[contentType]/[edit]/_fields/ContentReferenceField/ContentReferenceMultiSelectUI.js +15 -2
  50. package/dist/cjs/router/dashboard/[contentType]/[edit]/_fields/ContentReferenceField/ContentReferenceMultiSelectUI.js.map +1 -1
  51. package/dist/cjs/router/dashboard/[contentType]/[edit]/_fields/DynamicDataControl.js +222 -232
  52. package/dist/cjs/router/dashboard/[contentType]/[edit]/_fields/DynamicDataControl.js.map +1 -1
  53. package/dist/cjs/router/dashboard/[contentType]/[edit]/_fields/FileField/index.js +20 -1
  54. package/dist/cjs/router/dashboard/[contentType]/[edit]/_fields/FileField/index.js.map +1 -1
  55. package/dist/cjs/router/dashboard/[contentType]/[edit]/_fields/LinkField/LinkUI.js +27 -21
  56. package/dist/cjs/router/dashboard/[contentType]/[edit]/_fields/LinkField/LinkUI.js.map +1 -1
  57. package/dist/cjs/router/dashboard/[contentType]/[edit]/_fields/LinkField/index.js.map +1 -1
  58. package/dist/cjs/router/dashboard/[contentType]/[edit]/_fields/LinkField/linkValue.js +25 -0
  59. package/dist/cjs/router/dashboard/[contentType]/[edit]/_fields/LinkField/linkValue.js.map +1 -0
  60. package/dist/cjs/router/dashboard/[contentType]/[edit]/_fields/ListField/IteratorModulePicker.js +10 -1
  61. package/dist/cjs/router/dashboard/[contentType]/[edit]/_fields/ListField/IteratorModulePicker.js.map +1 -1
  62. package/dist/cjs/router/dashboard/[contentType]/[edit]/_fields/ListField/SimpleListUI.js +38 -11
  63. package/dist/cjs/router/dashboard/[contentType]/[edit]/_fields/ListField/SimpleListUI.js.map +1 -1
  64. package/dist/cjs/router/dashboard/[contentType]/[edit]/_fields/MenuField/MenuUI.js +135 -0
  65. package/dist/cjs/router/dashboard/[contentType]/[edit]/_fields/MenuField/MenuUI.js.map +1 -0
  66. package/dist/cjs/router/dashboard/[contentType]/[edit]/_fields/MenuField/index.js +10 -0
  67. package/dist/cjs/router/dashboard/[contentType]/[edit]/_fields/MenuField/index.js.map +1 -0
  68. package/dist/cjs/router/dashboard/[contentType]/[edit]/_fields/MenuField/menuTree.js +113 -0
  69. package/dist/cjs/router/dashboard/[contentType]/[edit]/_fields/MenuField/menuTree.js.map +1 -0
  70. package/dist/cjs/router/dashboard/[contentType]/[edit]/_fields/Select/MultiSelectUI.js +15 -2
  71. package/dist/cjs/router/dashboard/[contentType]/[edit]/_fields/Select/MultiSelectUI.js.map +1 -1
  72. package/dist/cjs/router/dashboard/[contentType]/[edit]/_fields/shared/ItemLimitStatus.js +22 -0
  73. package/dist/cjs/router/dashboard/[contentType]/[edit]/_fields/shared/ItemLimitStatus.js.map +1 -0
  74. package/dist/cjs/router/dashboard/[contentType]/[edit]/_fields/shared/index.js.map +1 -1
  75. package/dist/cjs/router/dashboard/[contentType]/[edit]/_hooks/useContentDocumentActions.js +1 -0
  76. package/dist/cjs/router/dashboard/[contentType]/[edit]/_hooks/useContentDocumentActions.js.map +1 -1
  77. package/dist/cjs/router/dashboard/[contentType]/[edit]/_hooks/useContentPreview.js +198 -0
  78. package/dist/cjs/router/dashboard/[contentType]/[edit]/_hooks/useContentPreview.js.map +1 -1
  79. package/dist/cjs/router/dashboard/[contentType]/[edit]/edit.js +10 -1
  80. package/dist/cjs/router/dashboard/[contentType]/[edit]/edit.js.map +1 -1
  81. package/dist/cjs/router/dashboard/debugging/api-routes/ApiTest.js +2 -2
  82. package/dist/cjs/router/dashboard/debugging/api-routes/ApiTest.js.map +1 -1
  83. package/dist/cjs/router/dashboard/debugging/api-routes/JsonViewer.js +17 -0
  84. package/dist/cjs/router/dashboard/debugging/api-routes/JsonViewer.js.map +1 -0
  85. package/dist/cjs/router/dashboard/debugging/api-routes/SchemaViewer.js +40 -26
  86. package/dist/cjs/router/dashboard/debugging/api-routes/SchemaViewer.js.map +1 -1
  87. package/dist/cjs/router/dashboard/debugging/api-routes/test.js +6 -5
  88. package/dist/cjs/router/dashboard/debugging/api-routes/test.js.map +1 -1
  89. package/dist/cjs/router/dashboard/seo/index.js +6 -0
  90. package/dist/cjs/router/dashboard/seo/index.js.map +1 -0
  91. package/dist/cjs/router/dashboard/seo/screen.js +234 -0
  92. package/dist/cjs/router/dashboard/seo/screen.js.map +1 -0
  93. package/dist/cjs/router/dashboard/seo/site-analysis.js +159 -0
  94. package/dist/cjs/router/dashboard/seo/site-analysis.js.map +1 -0
  95. package/dist/cjs/router/shared/route-list.js +10 -2
  96. package/dist/cjs/router/shared/route-list.js.map +1 -1
  97. package/dist/docs/index.md +285 -194
  98. package/dist/esm/components/app-sidebar.d.ts.map +1 -1
  99. package/dist/esm/components/app-sidebar.js +11 -1
  100. package/dist/esm/components/app-sidebar.js.map +1 -1
  101. package/dist/esm/components/media/MediaLibrary.d.ts.map +1 -1
  102. package/dist/esm/components/media/MediaLibrary.js +11 -2
  103. package/dist/esm/components/media/MediaLibrary.js.map +1 -1
  104. package/dist/esm/components/media/contexts/MediaLibraryContext.d.ts +2 -0
  105. package/dist/esm/components/media/contexts/MediaLibraryContext.d.ts.map +1 -1
  106. package/dist/esm/components/media/contexts/MediaLibraryContext.js +1 -1
  107. package/dist/esm/components/media/contexts/MediaLibraryContext.js.map +1 -1
  108. package/dist/esm/components/media/previews/MediaContextMenuContent.d.ts.map +1 -1
  109. package/dist/esm/components/media/previews/MediaContextMenuContent.js +70 -17
  110. package/dist/esm/components/media/previews/MediaContextMenuContent.js.map +1 -1
  111. package/dist/esm/components/media/previews/Previews.d.ts.map +1 -1
  112. package/dist/esm/components/media/previews/Previews.js +90 -36
  113. package/dist/esm/components/media/previews/Previews.js.map +1 -1
  114. package/dist/esm/components/media/previews/context/MediaPreviewContext.d.ts +2 -0
  115. package/dist/esm/components/media/previews/context/MediaPreviewContext.d.ts.map +1 -1
  116. package/dist/esm/components/media/previews/context/MediaPreviewContext.js.map +1 -1
  117. package/dist/esm/components/media/previews/dialogs/ExpandedPreviewDialog.d.ts.map +1 -1
  118. package/dist/esm/components/media/previews/dialogs/ExpandedPreviewDialog.js +7 -10
  119. package/dist/esm/components/media/previews/dialogs/ExpandedPreviewDialog.js.map +1 -1
  120. package/dist/esm/components/media/previews/hooks/useMediaPreviewRenderer.d.ts.map +1 -1
  121. package/dist/esm/components/media/previews/hooks/useMediaPreviewRenderer.js +3 -1
  122. package/dist/esm/components/media/previews/hooks/useMediaPreviewRenderer.js.map +1 -1
  123. package/dist/esm/components/media/previews/toolbar/PreviewsToolbar.d.ts +4 -1
  124. package/dist/esm/components/media/previews/toolbar/PreviewsToolbar.d.ts.map +1 -1
  125. package/dist/esm/components/media/previews/toolbar/PreviewsToolbar.js +17 -10
  126. package/dist/esm/components/media/previews/toolbar/PreviewsToolbar.js.map +1 -1
  127. package/dist/esm/components/media/previews/utils/mediaDownload.d.ts +13 -0
  128. package/dist/esm/components/media/previews/utils/mediaDownload.d.ts.map +1 -0
  129. package/dist/esm/components/media/previews/utils/mediaDownload.js +49 -0
  130. package/dist/esm/components/media/previews/utils/mediaDownload.js.map +1 -0
  131. package/dist/esm/components/media/previews/views/PreviewsListView.js +1 -1
  132. package/dist/esm/components/media/previews/views/PreviewsListView.js.map +1 -1
  133. package/dist/esm/components/rakun-logo.d.ts +1 -5
  134. package/dist/esm/components/rakun-logo.d.ts.map +1 -1
  135. package/dist/esm/components/rakun-logo.js +1 -6
  136. package/dist/esm/components/rakun-logo.js.map +1 -1
  137. package/dist/esm/components/ui/context-menu.js +1 -1
  138. package/dist/esm/components/ui/context-menu.js.map +1 -1
  139. package/dist/esm/i18n/catalog.d.ts +567 -9
  140. package/dist/esm/i18n/catalog.d.ts.map +1 -1
  141. package/dist/esm/i18n/catalog.js +330 -7
  142. package/dist/esm/i18n/catalog.js.map +1 -1
  143. package/dist/esm/lib/media.d.ts +8 -0
  144. package/dist/esm/lib/media.d.ts.map +1 -1
  145. package/dist/esm/lib/media.js +1 -0
  146. package/dist/esm/lib/media.js.map +1 -1
  147. package/dist/esm/media.d.ts +19 -1
  148. package/dist/esm/media.d.ts.map +1 -1
  149. package/dist/esm/media.js +44 -0
  150. package/dist/esm/media.js.map +1 -1
  151. package/dist/esm/router/dashboard/[contentType]/[edit]/ContentTypeEdit.d.ts.map +1 -1
  152. package/dist/esm/router/dashboard/[contentType]/[edit]/ContentTypeEdit.js +18 -7
  153. package/dist/esm/router/dashboard/[contentType]/[edit]/ContentTypeEdit.js.map +1 -1
  154. package/dist/esm/router/dashboard/[contentType]/[edit]/_components/EditTabPanels.d.ts.map +1 -1
  155. package/dist/esm/router/dashboard/[contentType]/[edit]/_components/EditTabPanels.js +2 -1
  156. package/dist/esm/router/dashboard/[contentType]/[edit]/_components/EditTabPanels.js.map +1 -1
  157. package/dist/esm/router/dashboard/[contentType]/[edit]/_components/EditToolbar.d.ts.map +1 -1
  158. package/dist/esm/router/dashboard/[contentType]/[edit]/_components/EditToolbar.js +2 -1
  159. package/dist/esm/router/dashboard/[contentType]/[edit]/_components/EditToolbar.js.map +1 -1
  160. package/dist/esm/router/dashboard/[contentType]/[edit]/_components/PreviewPanel.d.ts.map +1 -1
  161. package/dist/esm/router/dashboard/[contentType]/[edit]/_components/PreviewPanel.js +1 -1
  162. package/dist/esm/router/dashboard/[contentType]/[edit]/_components/PreviewPanel.js.map +1 -1
  163. package/dist/esm/router/dashboard/[contentType]/[edit]/_components/SeoTabContent.d.ts +2 -0
  164. package/dist/esm/router/dashboard/[contentType]/[edit]/_components/SeoTabContent.d.ts.map +1 -0
  165. package/dist/esm/router/dashboard/[contentType]/[edit]/_components/SeoTabContent.js +283 -0
  166. package/dist/esm/router/dashboard/[contentType]/[edit]/_components/SeoTabContent.js.map +1 -0
  167. package/dist/esm/router/dashboard/[contentType]/[edit]/_components/seo-analysis.d.ts +10 -0
  168. package/dist/esm/router/dashboard/[contentType]/[edit]/_components/seo-analysis.d.ts.map +1 -0
  169. package/dist/esm/router/dashboard/[contentType]/[edit]/_components/seo-analysis.js +83 -0
  170. package/dist/esm/router/dashboard/[contentType]/[edit]/_components/seo-analysis.js.map +1 -0
  171. package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/ContentReferenceField/ContentReferenceMultiSelectUI.d.ts.map +1 -1
  172. package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/ContentReferenceField/ContentReferenceMultiSelectUI.js +15 -2
  173. package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/ContentReferenceField/ContentReferenceMultiSelectUI.js.map +1 -1
  174. package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/DynamicDataControl.d.ts +6 -2
  175. package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/DynamicDataControl.d.ts.map +1 -1
  176. package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/DynamicDataControl.js +221 -234
  177. package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/DynamicDataControl.js.map +1 -1
  178. package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/FileField/index.d.ts.map +1 -1
  179. package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/FileField/index.js +20 -1
  180. package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/FileField/index.js.map +1 -1
  181. package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/LinkField/LinkUI.d.ts.map +1 -1
  182. package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/LinkField/LinkUI.js +16 -19
  183. package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/LinkField/LinkUI.js.map +1 -1
  184. package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/LinkField/index.d.ts +2 -0
  185. package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/LinkField/index.d.ts.map +1 -1
  186. package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/LinkField/index.js.map +1 -1
  187. package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/LinkField/linkValue.d.ts +4 -0
  188. package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/LinkField/linkValue.d.ts.map +1 -0
  189. package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/LinkField/linkValue.js +21 -0
  190. package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/LinkField/linkValue.js.map +1 -0
  191. package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/ListField/IteratorModulePicker.d.ts.map +1 -1
  192. package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/ListField/IteratorModulePicker.js +11 -2
  193. package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/ListField/IteratorModulePicker.js.map +1 -1
  194. package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/ListField/SimpleListUI.d.ts.map +1 -1
  195. package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/ListField/SimpleListUI.js +38 -11
  196. package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/ListField/SimpleListUI.js.map +1 -1
  197. package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/MenuField/MenuUI.d.ts +4 -0
  198. package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/MenuField/MenuUI.d.ts.map +1 -0
  199. package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/MenuField/MenuUI.js +130 -0
  200. package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/MenuField/MenuUI.js.map +1 -0
  201. package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/MenuField/index.d.ts +14 -0
  202. package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/MenuField/index.d.ts.map +1 -0
  203. package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/MenuField/index.js +5 -0
  204. package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/MenuField/index.js.map +1 -0
  205. package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/MenuField/menuTree.d.ts +23 -0
  206. package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/MenuField/menuTree.d.ts.map +1 -0
  207. package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/MenuField/menuTree.js +103 -0
  208. package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/MenuField/menuTree.js.map +1 -0
  209. package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/Select/MultiSelectUI.d.ts.map +1 -1
  210. package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/Select/MultiSelectUI.js +15 -2
  211. package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/Select/MultiSelectUI.js.map +1 -1
  212. package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/shared/ItemLimitStatus.d.ts +6 -0
  213. package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/shared/ItemLimitStatus.d.ts.map +1 -0
  214. package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/shared/ItemLimitStatus.js +18 -0
  215. package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/shared/ItemLimitStatus.js.map +1 -0
  216. package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/shared/index.d.ts +2 -1
  217. package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/shared/index.d.ts.map +1 -1
  218. package/dist/esm/router/dashboard/[contentType]/[edit]/_fields/shared/index.js.map +1 -1
  219. package/dist/esm/router/dashboard/[contentType]/[edit]/_hooks/useContentPreview.d.ts +43 -0
  220. package/dist/esm/router/dashboard/[contentType]/[edit]/_hooks/useContentPreview.d.ts.map +1 -1
  221. package/dist/esm/router/dashboard/[contentType]/[edit]/_hooks/useContentPreview.js +198 -0
  222. package/dist/esm/router/dashboard/[contentType]/[edit]/_hooks/useContentPreview.js.map +1 -1
  223. package/dist/esm/router/dashboard/[contentType]/[edit]/_hooks/useRouteLayoutData.d.ts.map +1 -1
  224. package/dist/esm/router/dashboard/[contentType]/[edit]/edit.d.ts.map +1 -1
  225. package/dist/esm/router/dashboard/[contentType]/[edit]/edit.js +10 -1
  226. package/dist/esm/router/dashboard/[contentType]/[edit]/edit.js.map +1 -1
  227. package/dist/esm/router/dashboard/debugging/api-routes/ApiTest.d.ts.map +1 -1
  228. package/dist/esm/router/dashboard/debugging/api-routes/ApiTest.js +2 -2
  229. package/dist/esm/router/dashboard/debugging/api-routes/ApiTest.js.map +1 -1
  230. package/dist/esm/router/dashboard/debugging/api-routes/JsonViewer.d.ts +5 -0
  231. package/dist/esm/router/dashboard/debugging/api-routes/JsonViewer.d.ts.map +1 -0
  232. package/dist/esm/router/dashboard/debugging/api-routes/JsonViewer.js +14 -0
  233. package/dist/esm/router/dashboard/debugging/api-routes/JsonViewer.js.map +1 -0
  234. package/dist/esm/router/dashboard/debugging/api-routes/SchemaViewer.d.ts.map +1 -1
  235. package/dist/esm/router/dashboard/debugging/api-routes/SchemaViewer.js +42 -28
  236. package/dist/esm/router/dashboard/debugging/api-routes/SchemaViewer.js.map +1 -1
  237. package/dist/esm/router/dashboard/debugging/api-routes/test.d.ts.map +1 -1
  238. package/dist/esm/router/dashboard/debugging/api-routes/test.js +6 -5
  239. package/dist/esm/router/dashboard/debugging/api-routes/test.js.map +1 -1
  240. package/dist/esm/router/dashboard/seo/index.d.ts +2 -0
  241. package/dist/esm/router/dashboard/seo/index.d.ts.map +1 -0
  242. package/dist/esm/router/dashboard/seo/index.js +2 -0
  243. package/dist/esm/router/dashboard/seo/index.js.map +1 -0
  244. package/dist/esm/router/dashboard/seo/screen.d.ts +6 -0
  245. package/dist/esm/router/dashboard/seo/screen.d.ts.map +1 -0
  246. package/dist/esm/router/dashboard/seo/screen.js +227 -0
  247. package/dist/esm/router/dashboard/seo/screen.js.map +1 -0
  248. package/dist/esm/router/dashboard/seo/site-analysis.d.ts +41 -0
  249. package/dist/esm/router/dashboard/seo/site-analysis.d.ts.map +1 -0
  250. package/dist/esm/router/dashboard/seo/site-analysis.js +154 -0
  251. package/dist/esm/router/dashboard/seo/site-analysis.js.map +1 -0
  252. package/dist/esm/router/shared/route-definitions.d.ts +4 -2
  253. package/dist/esm/router/shared/route-definitions.d.ts.map +1 -1
  254. package/dist/esm/router/shared/route-list.d.ts +1 -1
  255. package/dist/esm/router/shared/route-list.d.ts.map +1 -1
  256. package/dist/esm/router/shared/route-list.js +8 -0
  257. package/dist/esm/router/shared/route-list.js.map +1 -1
  258. package/dist/esm/router/shared/types.d.ts +2 -0
  259. package/dist/esm/router/shared/types.d.ts.map +1 -1
  260. package/dist/styles.css +237 -6
  261. package/dist/tsconfig.build.tsbuildinfo +1 -1
  262. 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, } from 'lucide-react';
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, } from '../../../../../components/ui/collapsible.js';
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, } from '../../../../../components/ui/tooltip.js';
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) => (bindings ? structuredClone(bindings) : undefined);
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
- ? bindings.fields
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.ui === 'List' || field.config.ui === 'Iterator';
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 asListField = (field) => field.config.ui === 'List' || field.config.ui === 'Iterator'
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 (contentType.dynamicData !== false &&
42
- isDynamicVisibleField(field));
65
+ return contentType.dynamicData !== false && isDynamicVisibleField(field);
43
66
  };
44
67
  const getFieldKind = (field) => {
45
- if (field.config.type === 'String') {
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 fileFieldOptions = (path, targetField) => {
101
- const options = [
102
- { label: fieldLabel(`${path}.url`), value: `${path}.url`, kind: 'string' },
103
- {
104
- label: fieldLabel(`${path}.previewUrl`),
105
- value: `${path}.previewUrl`,
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.type === 'Relation' && depth < 3) {
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
- if (field.config.type === 'File') {
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
- if (field.isMultiple)
170
- return fieldOption;
171
- return [...fieldOption, ...fileFieldOptions(path, targetField)];
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.ui === 'List' || field.config.ui === 'Iterator') {
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.ui === 'SimpleList') {
181
+ if (field.config.capabilities.dynamic?.collection === 'homogeneous' && 'field' in field) {
227
182
  const itemField = field.field;
228
- if (itemField.config.type !== 'Relation')
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, }) => (_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] }));
481
- 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 })] })] }));
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: '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) => {
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: '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 &&
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: 'grid gap-1.5', children: [t('dynamicData.item'), _jsxs(Select, { disabled: !sourceType || !hasItemOptions, value: sourceId, onValueChange: (value) => {
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: '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) => {
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: 'grid gap-1.5', children: [t('dynamicData.field'), _jsxs(Select, { disabled: !sourceType || !sourceId || fieldOptions.length === 0, value: fieldPath, onValueChange: (value) => {
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: '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))) }) })] })] })] }) }));
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
- const entry = field.fields.find((item) => item.name === itemName);
554
- if (!entry || entry.field.config.type !== 'Relation')
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.type === 'Relation') {
531
+ if (field.config.capabilities.dynamic?.relation) {
562
532
  return field.contentType;
563
533
  }
564
- if (field.config.ui === 'SimpleList') {
534
+ if (field.config.capabilities.dynamic?.collection === 'homogeneous' && 'field' in field) {
565
535
  const itemField = field.field;
566
- if (itemField.config.type === 'Relation') {
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 isSingleSelect = field.config.type === 'Select' &&
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) => (kind === 'boolean' ? 'true' : 'equals');
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 = asListField(targetField);
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?.fields.find((item) => item.name !== ITERATOR_FIELD_NAME)?.name;
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: '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) => {
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: '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) })] }));
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: '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) => {
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: '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
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: '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) => {
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: 'w-full', children: _jsx(SelectValue, { placeholder: relatedContentTypes.length > 0
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: '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
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: '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({
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
- ? undefined
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: 'w-full', children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: 'asc', children: t('dynamicData.ascending') }), _jsx(SelectItem, { value: 'desc', children: t('dynamicData.descending') })] })] })] })] })] }));
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.fields.filter((item) => item.name !== ITERATOR_FIELD_NAME);
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
- contentTypes.find((ct) => ct.name === sourceType);
771
- const targetContentType = getListTargetContentType(field, itemName);
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: '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) => {
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: 'w-full', children: _jsx(SelectValue, { placeholder: contentTypes.length > 0 || documentSourceOptions.length > 0
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: 'grid gap-1.5', children: [t('dynamicData.item'), _jsxs(Select, { disabled: !sourceType || itemOptions.length === 0, value: itemName, onValueChange: (value) => {
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: '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({
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: 'grid min-w-0 gap-1.5', children: [t('dynamicData.sortBy'), _jsxs(Select, { disabled: sortFieldOptions.length === 0, value: sortField || '__none__', onValueChange: (value) => emit({
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: 'w-full', children: _jsx(SelectValue, { placeholder: sortFieldOptions.length > 0
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: '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({
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: '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 ||
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: '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) => {
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: '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) => {
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: '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, {
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: '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, {
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: '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
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: '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' &&
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: '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({
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: 'h-4 w-4' }), _jsx("span", { className: 'sr-only', children: t('dynamicData.removeCondition') })] })] }, `${index}-${condition.field}`));
972
- }) }))] })] })), _jsx(PanelSection, { title: 'Mapping', children: _jsx("div", { className: 'grid gap-2', children: targetFields.map(([targetField, targetFieldConfig]) => {
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: '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
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 = isListField(field);
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 = list ? !!listBinding : !!fieldBinding;
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 clearBinding = () => list ? updateListBinding(undefined) : updateFieldBinding(undefined);
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: '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: [list ? (_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] }));
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: 'rounded-md border border-border bg-background p-4 shadow-sm', children: editor })) : null;
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: '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') })] })] }) }));
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: 'grid min-w-0 gap-2', children: [_jsx("div", { className: 'flex min-w-0 justify-end', children: trigger }), panel] }));
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