@webiny/app-headless-cms 6.6.0-alpha.0 → 6.6.0-alpha.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 (211) hide show
  1. package/ContentEntriesModule.js +3 -3
  2. package/ContentEntriesModule.js.map +1 -1
  3. package/HeadlessCMS.js +7 -2
  4. package/HeadlessCMS.js.map +1 -1
  5. package/admin/RoutesConfig.js +14 -1
  6. package/admin/RoutesConfig.js.map +1 -1
  7. package/admin/components/ContentEntries/BulkActions/ActionDelete.d.ts +2 -2
  8. package/admin/components/ContentEntries/BulkActions/ActionDelete.js.map +1 -1
  9. package/admin/components/ContentEntries/BulkActions/ActionMove.d.ts +2 -2
  10. package/admin/components/ContentEntries/BulkActions/ActionMove.js.map +1 -1
  11. package/admin/components/ContentEntries/BulkActions/ActionPublish.d.ts +2 -2
  12. package/admin/components/ContentEntries/BulkActions/ActionPublish.js.map +1 -1
  13. package/admin/components/ContentEntries/BulkActions/ActionUnpublish.d.ts +2 -2
  14. package/admin/components/ContentEntries/BulkActions/ActionUnpublish.js.map +1 -1
  15. package/admin/components/ContentModelEditor/ContentModelEditorProvider.js +1 -0
  16. package/admin/components/ContentModelEditor/ContentModelEditorProvider.js.map +1 -1
  17. package/admin/components/ContentModelEditor/FieldsSidebar.js +12 -2
  18. package/admin/components/ContentModelEditor/FieldsSidebar.js.map +1 -1
  19. package/admin/components/ContentModelEditor/evaluateExpression.js +4 -0
  20. package/admin/components/ContentModelEditor/evaluateExpression.js.map +1 -1
  21. package/admin/components/Dialogs/PublishEntryConfirmDialog.d.ts +26 -1
  22. package/admin/components/Dialogs/PublishEntryConfirmDialog.js +4 -3
  23. package/admin/components/Dialogs/PublishEntryConfirmDialog.js.map +1 -1
  24. package/admin/components/Dialogs/UnpublishEntryConfirmDialog.d.ts +26 -1
  25. package/admin/components/Dialogs/UnpublishEntryConfirmDialog.js +4 -3
  26. package/admin/components/Dialogs/UnpublishEntryConfirmDialog.js.map +1 -1
  27. package/admin/components/FieldEditor/EditFieldDialog/PermissionsEditor/PermissionsEditor.js +3 -3
  28. package/admin/components/FieldEditor/EditFieldDialog/PermissionsEditor/PermissionsEditor.js.map +1 -1
  29. package/admin/components/FieldEditor/EditFieldDialog.d.ts +2 -2
  30. package/admin/components/FieldEditor/EditFieldDialog.js +5 -2
  31. package/admin/components/FieldEditor/EditFieldDialog.js.map +1 -1
  32. package/admin/components/FieldEditor/Field.js +1 -1
  33. package/admin/components/FieldEditor/Field.js.map +1 -1
  34. package/admin/components/FieldEditor/FieldEditor.js +2 -2
  35. package/admin/components/FieldEditor/FieldEditor.js.map +1 -1
  36. package/admin/components/FieldEditor/FieldEditorContext.d.ts +1 -1
  37. package/admin/components/FieldEditor/FieldEditorContext.js +6 -1
  38. package/admin/components/FieldEditor/FieldEditorContext.js.map +1 -1
  39. package/admin/components/LexicalCmsEditor/LexicalEditor.js +10 -6
  40. package/admin/components/LexicalCmsEditor/LexicalEditor.js.map +1 -1
  41. package/admin/components/LexicalCmsEditor/TypographyDropDown.js +3 -2
  42. package/admin/components/LexicalCmsEditor/TypographyDropDown.js.map +1 -1
  43. package/admin/config/contentEntries/editor/ContentEntryEditorConfig.d.ts +60 -2
  44. package/admin/config/contentEntries/editor/ContentEntryEditorConfig.js +18 -5
  45. package/admin/config/contentEntries/editor/ContentEntryEditorConfig.js.map +1 -1
  46. package/admin/config/contentEntries/editor/NewEntryWizard.d.ts +8 -1
  47. package/admin/config/contentEntries/editor/NewEntryWizard.js +20 -5
  48. package/admin/config/contentEntries/editor/NewEntryWizard.js.map +1 -1
  49. package/admin/config/contentEntries/list/Browser/BreadcrumbRoot.d.ts +38 -0
  50. package/admin/config/contentEntries/list/Browser/BreadcrumbRoot.js +23 -0
  51. package/admin/config/contentEntries/list/Browser/BreadcrumbRoot.js.map +1 -0
  52. package/admin/config/contentEntries/list/Browser/index.d.ts +21 -0
  53. package/admin/config/contentEntries/list/Browser/index.js +2 -0
  54. package/admin/config/contentEntries/list/Browser/index.js.map +1 -1
  55. package/admin/config/contentEntries/list/ContentEntryListConfig.d.ts +39 -0
  56. package/admin/config/contentEntries/list/ContentEntryListConfig.js +2 -1
  57. package/admin/config/contentEntries/list/ContentEntryListConfig.js.map +1 -1
  58. package/admin/graphql/contentModels.d.ts +1 -1
  59. package/admin/graphql/contentModels.js +2 -1
  60. package/admin/graphql/contentModels.js.map +1 -1
  61. package/admin/plugins/editor/formSettings/components/GeneralSettings.js +24 -1
  62. package/admin/plugins/editor/formSettings/components/GeneralSettings.js.map +1 -1
  63. package/exports/admin/cms/entry/editor.d.ts +1 -0
  64. package/exports/admin/cms/entry/editor.js +1 -0
  65. package/exports/admin/cms/entry/list.d.ts +2 -0
  66. package/exports/admin/cms/entry/list.js +2 -0
  67. package/exports/admin/cms.d.ts +2 -0
  68. package/exports/admin/cms.js +2 -0
  69. package/features/contentEntry/EntryGraphQLFields.js +1 -1
  70. package/features/contentEntry/EntryGraphQLFields.js.map +1 -1
  71. package/features/contentEntry/createEntry/CreateEntryRepository.d.ts +3 -1
  72. package/features/contentEntry/createEntry/CreateEntryRepository.js +10 -2
  73. package/features/contentEntry/createEntry/CreateEntryRepository.js.map +1 -1
  74. package/features/contentEntry/deleteEntry/DeleteEntryRepository.d.ts +3 -1
  75. package/features/contentEntry/deleteEntry/DeleteEntryRepository.js +12 -2
  76. package/features/contentEntry/deleteEntry/DeleteEntryRepository.js.map +1 -1
  77. package/features/contentEntry/refTypes.d.ts +7 -0
  78. package/features/contentEntry/refTypes.js.map +1 -1
  79. package/features/contentEntry/updateEntry/UpdateEntryRepository.d.ts +3 -1
  80. package/features/contentEntry/updateEntry/UpdateEntryRepository.js +10 -2
  81. package/features/contentEntry/updateEntry/UpdateEntryRepository.js.map +1 -1
  82. package/features/formModel/mappers/AssetFieldMapper.d.ts +12 -0
  83. package/features/formModel/mappers/AssetFieldMapper.js +13 -0
  84. package/features/formModel/mappers/AssetFieldMapper.js.map +1 -0
  85. package/features/formModel/mappers/index.js +2 -0
  86. package/features/formModel/mappers/index.js.map +1 -1
  87. package/features/model/updateModel/UpdateModelGateway.js +1 -0
  88. package/features/model/updateModel/UpdateModelGateway.js.map +1 -1
  89. package/index.d.ts +1 -1
  90. package/index.js +1 -1
  91. package/package.json +24 -24
  92. package/presentation/contentEntries/list/ContentEntriesPresenter.test.js +4 -0
  93. package/presentation/contentEntries/list/ContentEntriesPresenter.test.js.map +1 -1
  94. package/presentation/contentEntries/preview/ComponentDiscoveryIframe.d.ts +6 -0
  95. package/presentation/contentEntries/preview/ComponentDiscoveryIframe.js +47 -0
  96. package/presentation/contentEntries/preview/ComponentDiscoveryIframe.js.map +1 -0
  97. package/presentation/contentEntries/preview/LivePreviewPresenter.d.ts +14 -0
  98. package/presentation/contentEntries/preview/LivePreviewPresenter.js +33 -0
  99. package/presentation/contentEntries/preview/LivePreviewPresenter.js.map +1 -0
  100. package/presentation/contentEntries/preview/ModelEditorComponentDiscovery.d.ts +2 -0
  101. package/presentation/contentEntries/preview/ModelEditorComponentDiscovery.js +27 -0
  102. package/presentation/contentEntries/preview/ModelEditorComponentDiscovery.js.map +1 -0
  103. package/presentation/contentEntries/preview/PreviewComponentsContext.d.ts +15 -0
  104. package/presentation/contentEntries/preview/PreviewComponentsContext.js +43 -0
  105. package/presentation/contentEntries/preview/PreviewComponentsContext.js.map +1 -0
  106. package/presentation/contentEntries/preview/PreviewDecorator.d.ts +2 -0
  107. package/presentation/contentEntries/preview/PreviewDecorator.js +48 -0
  108. package/presentation/contentEntries/preview/PreviewDecorator.js.map +1 -0
  109. package/presentation/contentEntries/preview/PreviewPane.d.ts +9 -0
  110. package/presentation/contentEntries/preview/PreviewPane.js +181 -0
  111. package/presentation/contentEntries/preview/PreviewPane.js.map +1 -0
  112. package/presentation/contentEntries/preview/abstractions.d.ts +16 -0
  113. package/presentation/contentEntries/preview/abstractions.js +5 -0
  114. package/presentation/contentEntries/preview/abstractions.js.map +1 -0
  115. package/presentation/contentEntries/preview/feature.d.ts +3 -0
  116. package/presentation/contentEntries/preview/feature.js +17 -0
  117. package/presentation/contentEntries/preview/feature.js.map +1 -0
  118. package/presentation/contentEntries/preview/resolvePreviewUrl.d.ts +5 -0
  119. package/presentation/contentEntries/preview/resolvePreviewUrl.js +29 -0
  120. package/presentation/contentEntries/preview/resolvePreviewUrl.js.map +1 -0
  121. package/presentation/contentEntries/preview/useLivePreviewPresenter.d.ts +1 -0
  122. package/presentation/contentEntries/preview/useLivePreviewPresenter.js +8 -0
  123. package/presentation/contentEntries/preview/useLivePreviewPresenter.js.map +1 -0
  124. package/presentation/contentEntries/trashBin/CmsTrashBin.d.ts +2 -2
  125. package/presentation/contentEntries/views/CmsAdvancedSearch.d.ts +2 -2
  126. package/presentation/contentEntries/views/ContentEntriesBreadcrumbs.d.ts +13 -0
  127. package/presentation/contentEntries/views/ContentEntriesBreadcrumbs.js +54 -0
  128. package/presentation/contentEntries/views/ContentEntriesBreadcrumbs.js.map +1 -0
  129. package/presentation/contentEntries/views/ContentEntriesListLayout.d.ts +2 -2
  130. package/presentation/contentEntries/views/ContentEntriesListLayout.js +3 -2
  131. package/presentation/contentEntries/views/ContentEntriesListLayout.js.map +1 -1
  132. package/presentation/contentEntries/views/ContentEntryFormView.d.ts +2 -2
  133. package/presentation/contentEntries/views/ContentEntryFormView.js +5 -6
  134. package/presentation/contentEntries/views/ContentEntryFormView.js.map +1 -1
  135. package/presentation/contentEntries/views/RevisionDrawer.d.ts +2 -2
  136. package/presentation/contentEntries/views/RevisionsList.d.ts +2 -2
  137. package/presentation/contentEntries/views/SingleEntryLayout.d.ts +2 -2
  138. package/presentation/contentEntries/views/Table/Table.d.ts +2 -2
  139. package/presentation/contentEntries/views/actions/CreateNewRevisionButton.d.ts +2 -2
  140. package/presentation/contentEntries/views/actions/DeleteEntryMenuItem.d.ts +2 -2
  141. package/presentation/contentEntries/views/actions/PublishOnlyButton.d.ts +2 -2
  142. package/presentation/contentEntries/views/actions/RevisionSelector.d.ts +2 -2
  143. package/presentation/contentEntries/views/actions/SaveAndPublishButton.d.ts +2 -2
  144. package/presentation/contentEntries/views/actions/SaveContentButton.d.ts +2 -2
  145. package/presentation/contentEntries/views/actions/ShowRevisionListMenuItem.d.ts +2 -2
  146. package/presentation/contentEntries/views/layout/ContentEntryForm.d.ts +12 -12
  147. package/presentation/contentEntries/views/layout/ContentEntryFormContent.d.ts +10 -6
  148. package/presentation/contentEntries/views/layout/ContentEntryFormContent.js +7 -2
  149. package/presentation/contentEntries/views/layout/ContentEntryFormContent.js.map +1 -1
  150. package/presentation/contentModels/components/CloneContentModelDialog.d.ts +2 -2
  151. package/presentation/contentModels/components/ContentModels.d.ts +2 -2
  152. package/presentation/contentModels/components/ContentModelsDataList.d.ts +2 -2
  153. package/presentation/contentModels/components/NewContentModelDialog.d.ts +2 -2
  154. package/presentation/contentModels/components/fullDelete/types.js.map +1 -1
  155. package/presentation/fieldEditor/FieldEditorPresenter.js +1 -1
  156. package/presentation/fieldEditor/FieldEditorPresenter.js.map +1 -1
  157. package/presentation/fieldEditor/groups/ValidationsGroup.js +1 -1
  158. package/presentation/fieldEditor/groups/ValidationsGroup.js.map +1 -1
  159. package/presentation/fieldEditor/renderers/CmsAccessControlRulesRenderer.js +3 -3
  160. package/presentation/fieldEditor/renderers/CmsAccessControlRulesRenderer.js.map +1 -1
  161. package/presentation/fieldRenderers/ref/CmsRefDetailedMultipleRenderer.js +8 -0
  162. package/presentation/fieldRenderers/ref/CmsRefDetailedMultipleRenderer.js.map +1 -1
  163. package/presentation/fieldRenderers/ref/CmsRefDetailedSingleRenderer.js +8 -0
  164. package/presentation/fieldRenderers/ref/CmsRefDetailedSingleRenderer.js.map +1 -1
  165. package/presentation/fieldRenderers/ref/components/EditEntryDrawer.d.ts +10 -0
  166. package/presentation/fieldRenderers/ref/components/EditEntryDrawer.js +94 -0
  167. package/presentation/fieldRenderers/ref/components/EditEntryDrawer.js.map +1 -0
  168. package/presentation/fieldRenderers/ref/components/EntryCard.d.ts +2 -0
  169. package/presentation/fieldRenderers/ref/components/EntryCard.js +13 -3
  170. package/presentation/fieldRenderers/ref/components/EntryCard.js.map +1 -1
  171. package/presentation/fieldRenderers/ref/components/RefFieldOptions.d.ts +2 -2
  172. package/presentation/fieldRenderers/ref/detailed/RefDetailedPresenter.d.ts +2 -1
  173. package/presentation/fieldRenderers/ref/detailed/RefDetailedPresenter.js +6 -0
  174. package/presentation/fieldRenderers/ref/detailed/RefDetailedPresenter.js.map +1 -1
  175. package/presentation/fieldRenderers/ref/detailed/abstractions.d.ts +2 -1
  176. package/presentation/fieldRenderers/ref/detailed/abstractions.js.map +1 -1
  177. package/presentation/fieldRenderers/ref/editEntry/EditEntryPresenter.d.ts +13 -0
  178. package/presentation/fieldRenderers/ref/editEntry/EditEntryPresenter.js +25 -0
  179. package/presentation/fieldRenderers/ref/editEntry/EditEntryPresenter.js.map +1 -0
  180. package/presentation/fieldRenderers/ref/editEntry/abstractions.d.ts +10 -0
  181. package/presentation/fieldRenderers/ref/editEntry/abstractions.js +5 -0
  182. package/presentation/fieldRenderers/ref/editEntry/abstractions.js.map +1 -0
  183. package/presentation/fieldRenderers/ref/editEntry/feature.d.ts +3 -0
  184. package/presentation/fieldRenderers/ref/editEntry/feature.js +17 -0
  185. package/presentation/fieldRenderers/ref/editEntry/feature.js.map +1 -0
  186. package/presentation/fieldTypes/abstractions.d.ts +12 -0
  187. package/presentation/fieldTypes/abstractions.js.map +1 -1
  188. package/presentation/fieldTypes/renderers/common/SelectBoxRenderer.js +1 -1
  189. package/presentation/fieldTypes/renderers/common/SelectBoxRenderer.js.map +1 -1
  190. package/presentation/fieldTypes/renderers/dynamicZone/DynamicZoneRenderer.js +6 -2
  191. package/presentation/fieldTypes/renderers/dynamicZone/DynamicZoneRenderer.js.map +1 -1
  192. package/presentation/fieldTypes/renderers/object/ObjectAccordionRenderer.js +2 -0
  193. package/presentation/fieldTypes/renderers/object/ObjectAccordionRenderer.js.map +1 -1
  194. package/presentation/fieldTypes/renderers/object/ObjectsAccordionRenderer.js +6 -0
  195. package/presentation/fieldTypes/renderers/object/ObjectsAccordionRenderer.js.map +1 -1
  196. package/presentation/fieldTypes/types/DynamicZoneFieldType.d.ts +3 -6
  197. package/presentation/fieldTypes/types/DynamicZoneFieldType.js +2 -12
  198. package/presentation/fieldTypes/types/DynamicZoneFieldType.js.map +1 -1
  199. package/presentation/fieldTypes/types/dynamicZone/TemplateDialog.js +25 -3
  200. package/presentation/fieldTypes/types/dynamicZone/TemplateDialog.js.map +1 -1
  201. package/presentation/importContentModels/ImportContentModelsDialog.d.ts +2 -2
  202. package/presentation/importContentModels/components/DataList.d.ts +2 -2
  203. package/presentation/importContentModels/components/FileUpload.d.ts +2 -2
  204. package/presentation/importContentModels/components/Model/DataListModels.d.ts +2 -2
  205. package/presentation/menus/ContentGroupsMenuItems.d.ts +2 -2
  206. package/presentation/modelGroup/ModelGroupPresenter.d.ts +3 -1
  207. package/presentation/modelGroup/ModelGroupPresenter.js +7 -9
  208. package/presentation/modelGroup/ModelGroupPresenter.js.map +1 -1
  209. package/presentation/modelGroup/components/ContentModelGroups.d.ts +2 -2
  210. package/presentation/modelGroup/components/ContentModelGroupsDataList.d.ts +6 -2
  211. package/presentation/modelGroup/components/ContentModelGroupsForm.d.ts +8 -2
@@ -1 +1 @@
1
- {"version":3,"file":"admin/components/ContentModelEditor/evaluateExpression.js","sources":["../../../../src/admin/components/ContentModelEditor/evaluateExpression.ts"],"sourcesContent":["export type Operator =\n | \"==\"\n | \"!=\"\n | \">\"\n | \"<\"\n | \">=\"\n | \"<=\"\n | \"contains\"\n | \"startsWith\"\n | \"endsWith\"\n | \"isEmpty\"\n | \"isNotEmpty\";\n\nexport interface ParsedExpression {\n target: string;\n operator: Operator;\n value: string | number | boolean | null;\n}\n\n/**\n * Resolve a fieldPath that may contain `$` placeholders using the bindParentName.\n *\n * The bindParentName gives us the concrete indices for the current list context.\n * For example, if fieldPath is `panorama.hotspots.$.title` and bindParentName\n * is `panorama.hotspots.2`, the result is `panorama.hotspots.2.title`.\n *\n * Supports multiple nested `$` segments for deeply nested list objects.\n */\nexport function resolveFieldPath(fieldPath: string, bindParentName?: string): string {\n if (!fieldPath.includes(\"$\")) {\n return fieldPath;\n }\n\n if (!bindParentName) {\n // No parent context, replace $ with 0 as fallback\n return fieldPath.replace(/\\$/g, \"0\");\n }\n\n const pathParts = fieldPath.split(\".\");\n const parentParts = bindParentName.split(\".\");\n\n // Build a map of prefix -> index from the parent path.\n // E.g., parentName \"panorama.hotspots.2.items.1\" gives us:\n // \"panorama.hotspots\" -> \"2\"\n // \"panorama.hotspots.2.items\" -> \"1\"\n const indexMap = new Map<string, string>();\n const prefixParts: string[] = [];\n for (const part of parentParts) {\n if (/^\\d+$/.test(part)) {\n indexMap.set(prefixParts.join(\".\"), part);\n } else {\n prefixParts.push(part);\n }\n }\n\n // Walk through pathParts and replace each `$` with the corresponding index\n const resolved: string[] = [];\n const currentPrefix: string[] = [];\n for (const part of pathParts) {\n if (part === \"$\") {\n const key = currentPrefix.join(\".\");\n const index = indexMap.get(key) ?? \"0\";\n resolved.push(index);\n } else {\n currentPrefix.push(part);\n resolved.push(part);\n }\n }\n\n return resolved.join(\".\");\n}\n\nfunction compareValues(\n operator: string,\n val: unknown,\n rhs: string | number | boolean | null\n): boolean {\n switch (operator) {\n case \"==\":\n return val == rhs;\n case \"!=\":\n return val != rhs;\n case \">\":\n return Number(val) > Number(rhs);\n case \"<\":\n return Number(val) < Number(rhs);\n case \">=\":\n return Number(val) >= Number(rhs);\n case \"<=\":\n return Number(val) <= Number(rhs);\n case \"contains\":\n return String(val ?? \"\").includes(String(rhs ?? \"\"));\n case \"startsWith\":\n return String(val ?? \"\").startsWith(String(rhs ?? \"\"));\n case \"endsWith\":\n return String(val ?? \"\").endsWith(String(rhs ?? \"\"));\n case \"isEmpty\":\n return val == null || val === \"\" || (Array.isArray(val) && val.length === 0);\n case \"isNotEmpty\":\n return val != null && val !== \"\" && !(Array.isArray(val) && val.length === 0);\n default:\n return false;\n }\n}\n\n/**\n * Evaluate a parsed expression against form values.\n *\n * If the resolved fieldPath ends with `.length`, it reads the array at the parent\n * path and uses its length as the left-hand value.\n */\nexport function evaluateExpression(\n parsed: ParsedExpression,\n getFormValue: (path: string) => unknown\n): boolean {\n const { target, operator, value: rhs } = parsed;\n\n let val: unknown;\n if (target.endsWith(\".length\")) {\n const arrayPath = target.slice(0, -\".length\".length);\n const arr = getFormValue(arrayPath);\n val = Array.isArray(arr) ? arr.length : 0;\n } else {\n val = getFormValue(target);\n }\n\n return compareValues(operator, val, rhs);\n}\n"],"names":["resolveFieldPath","fieldPath","bindParentName","pathParts","parentParts","indexMap","Map","prefixParts","part","resolved","currentPrefix","key","index","compareValues","operator","val","rhs","Number","String","Array","evaluateExpression","parsed","getFormValue","target","arrayPath","arr"],"mappings":"AA4BO,SAASA,iBAAiBC,SAAiB,EAAEC,cAAuB;IACvE,IAAI,CAACD,UAAU,QAAQ,CAAC,MACpB,OAAOA;IAGX,IAAI,CAACC,gBAED,OAAOD,UAAU,OAAO,CAAC,OAAO;IAGpC,MAAME,YAAYF,UAAU,KAAK,CAAC;IAClC,MAAMG,cAAcF,eAAe,KAAK,CAAC;IAMzC,MAAMG,WAAW,IAAIC;IACrB,MAAMC,cAAwB,EAAE;IAChC,KAAK,MAAMC,QAAQJ,YACf,IAAI,QAAQ,IAAI,CAACI,OACbH,SAAS,GAAG,CAACE,YAAY,IAAI,CAAC,MAAMC;SAEpCD,YAAY,IAAI,CAACC;IAKzB,MAAMC,WAAqB,EAAE;IAC7B,MAAMC,gBAA0B,EAAE;IAClC,KAAK,MAAMF,QAAQL,UACf,IAAIK,AAAS,QAATA,MAAc;QACd,MAAMG,MAAMD,cAAc,IAAI,CAAC;QAC/B,MAAME,QAAQP,SAAS,GAAG,CAACM,QAAQ;QACnCF,SAAS,IAAI,CAACG;IAClB,OAAO;QACHF,cAAc,IAAI,CAACF;QACnBC,SAAS,IAAI,CAACD;IAClB;IAGJ,OAAOC,SAAS,IAAI,CAAC;AACzB;AAEA,SAASI,cACLC,QAAgB,EAChBC,GAAY,EACZC,GAAqC;IAErC,OAAQF;QACJ,KAAK;YACD,OAAOC,OAAOC;QAClB,KAAK;YACD,OAAOD,OAAOC;QAClB,KAAK;YACD,OAAOC,OAAOF,OAAOE,OAAOD;QAChC,KAAK;YACD,OAAOC,OAAOF,OAAOE,OAAOD;QAChC,KAAK;YACD,OAAOC,OAAOF,QAAQE,OAAOD;QACjC,KAAK;YACD,OAAOC,OAAOF,QAAQE,OAAOD;QACjC,KAAK;YACD,OAAOE,OAAOH,OAAO,IAAI,QAAQ,CAACG,OAAOF,OAAO;QACpD,KAAK;YACD,OAAOE,OAAOH,OAAO,IAAI,UAAU,CAACG,OAAOF,OAAO;QACtD,KAAK;YACD,OAAOE,OAAOH,OAAO,IAAI,QAAQ,CAACG,OAAOF,OAAO;QACpD,KAAK;YACD,OAAOD,AAAO,QAAPA,OAAeA,AAAQ,OAARA,OAAeI,MAAM,OAAO,CAACJ,QAAQA,AAAe,MAAfA,IAAI,MAAM;QACzE,KAAK;YACD,OAAOA,AAAO,QAAPA,OAAeA,AAAQ,OAARA,OAAc,CAAEI,CAAAA,MAAM,OAAO,CAACJ,QAAQA,AAAe,MAAfA,IAAI,MAAM,AAAK;QAC/E;YACI,OAAO;IACf;AACJ;AAQO,SAASK,mBACZC,MAAwB,EACxBC,YAAuC;IAEvC,MAAM,EAAEC,MAAM,EAAET,QAAQ,EAAE,OAAOE,GAAG,EAAE,GAAGK;IAEzC,IAAIN;IACJ,IAAIQ,OAAO,QAAQ,CAAC,YAAY;QAC5B,MAAMC,YAAYD,OAAO,KAAK,CAAC,GAAG;QAClC,MAAME,MAAMH,aAAaE;QACzBT,MAAMI,MAAM,OAAO,CAACM,OAAOA,IAAI,MAAM,GAAG;IAC5C,OACIV,MAAMO,aAAaC;IAGvB,OAAOV,cAAcC,UAAUC,KAAKC;AACxC"}
1
+ {"version":3,"file":"admin/components/ContentModelEditor/evaluateExpression.js","sources":["../../../../src/admin/components/ContentModelEditor/evaluateExpression.ts"],"sourcesContent":["export type Operator =\n | \"==\"\n | \"!=\"\n | \">\"\n | \"<\"\n | \">=\"\n | \"<=\"\n | \"contains\"\n | \"startsWith\"\n | \"endsWith\"\n | \"isEmpty\"\n | \"isNotEmpty\";\n\nexport interface ParsedExpression {\n target: string;\n operator: Operator;\n value: string | number | boolean | null;\n}\n\n/**\n * Resolve a fieldPath that may contain `$` placeholders using the bindParentName.\n *\n * The bindParentName gives us the concrete indices for the current list context.\n * For example, if fieldPath is `panorama.hotspots.$.title` and bindParentName\n * is `panorama.hotspots.2`, the result is `panorama.hotspots.2.title`.\n *\n * Supports multiple nested `$` segments for deeply nested list objects.\n */\nexport function resolveFieldPath(fieldPath: string, bindParentName?: string): string {\n if (!fieldPath.includes(\"$\")) {\n return fieldPath;\n }\n\n if (fieldPath.startsWith(\"$.\")) {\n const relative = fieldPath.slice(2);\n return bindParentName ? `${bindParentName}.${relative}` : relative;\n }\n\n if (!bindParentName) {\n // No parent context, replace $ with 0 as fallback\n return fieldPath.replace(/\\$/g, \"0\");\n }\n\n const pathParts = fieldPath.split(\".\");\n const parentParts = bindParentName.split(\".\");\n\n // Build a map of prefix -> index from the parent path.\n // E.g., parentName \"panorama.hotspots.2.items.1\" gives us:\n // \"panorama.hotspots\" -> \"2\"\n // \"panorama.hotspots.2.items\" -> \"1\"\n const indexMap = new Map<string, string>();\n const prefixParts: string[] = [];\n for (const part of parentParts) {\n if (/^\\d+$/.test(part)) {\n indexMap.set(prefixParts.join(\".\"), part);\n } else {\n prefixParts.push(part);\n }\n }\n\n // Walk through pathParts and replace each `$` with the corresponding index\n const resolved: string[] = [];\n const currentPrefix: string[] = [];\n for (const part of pathParts) {\n if (part === \"$\") {\n const key = currentPrefix.join(\".\");\n const index = indexMap.get(key) ?? \"0\";\n resolved.push(index);\n } else {\n currentPrefix.push(part);\n resolved.push(part);\n }\n }\n\n return resolved.join(\".\");\n}\n\nfunction compareValues(\n operator: string,\n val: unknown,\n rhs: string | number | boolean | null\n): boolean {\n switch (operator) {\n case \"==\":\n return val == rhs;\n case \"!=\":\n return val != rhs;\n case \">\":\n return Number(val) > Number(rhs);\n case \"<\":\n return Number(val) < Number(rhs);\n case \">=\":\n return Number(val) >= Number(rhs);\n case \"<=\":\n return Number(val) <= Number(rhs);\n case \"contains\":\n return String(val ?? \"\").includes(String(rhs ?? \"\"));\n case \"startsWith\":\n return String(val ?? \"\").startsWith(String(rhs ?? \"\"));\n case \"endsWith\":\n return String(val ?? \"\").endsWith(String(rhs ?? \"\"));\n case \"isEmpty\":\n return val == null || val === \"\" || (Array.isArray(val) && val.length === 0);\n case \"isNotEmpty\":\n return val != null && val !== \"\" && !(Array.isArray(val) && val.length === 0);\n default:\n return false;\n }\n}\n\n/**\n * Evaluate a parsed expression against form values.\n *\n * If the resolved fieldPath ends with `.length`, it reads the array at the parent\n * path and uses its length as the left-hand value.\n */\nexport function evaluateExpression(\n parsed: ParsedExpression,\n getFormValue: (path: string) => unknown\n): boolean {\n const { target, operator, value: rhs } = parsed;\n\n let val: unknown;\n if (target.endsWith(\".length\")) {\n const arrayPath = target.slice(0, -\".length\".length);\n const arr = getFormValue(arrayPath);\n val = Array.isArray(arr) ? arr.length : 0;\n } else {\n val = getFormValue(target);\n }\n\n return compareValues(operator, val, rhs);\n}\n"],"names":["resolveFieldPath","fieldPath","bindParentName","relative","pathParts","parentParts","indexMap","Map","prefixParts","part","resolved","currentPrefix","key","index","compareValues","operator","val","rhs","Number","String","Array","evaluateExpression","parsed","getFormValue","target","arrayPath","arr"],"mappings":"AA4BO,SAASA,iBAAiBC,SAAiB,EAAEC,cAAuB;IACvE,IAAI,CAACD,UAAU,QAAQ,CAAC,MACpB,OAAOA;IAGX,IAAIA,UAAU,UAAU,CAAC,OAAO;QAC5B,MAAME,WAAWF,UAAU,KAAK,CAAC;QACjC,OAAOC,iBAAiB,GAAGA,eAAe,CAAC,EAAEC,UAAU,GAAGA;IAC9D;IAEA,IAAI,CAACD,gBAED,OAAOD,UAAU,OAAO,CAAC,OAAO;IAGpC,MAAMG,YAAYH,UAAU,KAAK,CAAC;IAClC,MAAMI,cAAcH,eAAe,KAAK,CAAC;IAMzC,MAAMI,WAAW,IAAIC;IACrB,MAAMC,cAAwB,EAAE;IAChC,KAAK,MAAMC,QAAQJ,YACf,IAAI,QAAQ,IAAI,CAACI,OACbH,SAAS,GAAG,CAACE,YAAY,IAAI,CAAC,MAAMC;SAEpCD,YAAY,IAAI,CAACC;IAKzB,MAAMC,WAAqB,EAAE;IAC7B,MAAMC,gBAA0B,EAAE;IAClC,KAAK,MAAMF,QAAQL,UACf,IAAIK,AAAS,QAATA,MAAc;QACd,MAAMG,MAAMD,cAAc,IAAI,CAAC;QAC/B,MAAME,QAAQP,SAAS,GAAG,CAACM,QAAQ;QACnCF,SAAS,IAAI,CAACG;IAClB,OAAO;QACHF,cAAc,IAAI,CAACF;QACnBC,SAAS,IAAI,CAACD;IAClB;IAGJ,OAAOC,SAAS,IAAI,CAAC;AACzB;AAEA,SAASI,cACLC,QAAgB,EAChBC,GAAY,EACZC,GAAqC;IAErC,OAAQF;QACJ,KAAK;YACD,OAAOC,OAAOC;QAClB,KAAK;YACD,OAAOD,OAAOC;QAClB,KAAK;YACD,OAAOC,OAAOF,OAAOE,OAAOD;QAChC,KAAK;YACD,OAAOC,OAAOF,OAAOE,OAAOD;QAChC,KAAK;YACD,OAAOC,OAAOF,QAAQE,OAAOD;QACjC,KAAK;YACD,OAAOC,OAAOF,QAAQE,OAAOD;QACjC,KAAK;YACD,OAAOE,OAAOH,OAAO,IAAI,QAAQ,CAACG,OAAOF,OAAO;QACpD,KAAK;YACD,OAAOE,OAAOH,OAAO,IAAI,UAAU,CAACG,OAAOF,OAAO;QACtD,KAAK;YACD,OAAOE,OAAOH,OAAO,IAAI,QAAQ,CAACG,OAAOF,OAAO;QACpD,KAAK;YACD,OAAOD,AAAO,QAAPA,OAAeA,AAAQ,OAARA,OAAeI,MAAM,OAAO,CAACJ,QAAQA,AAAe,MAAfA,IAAI,MAAM;QACzE,KAAK;YACD,OAAOA,AAAO,QAAPA,OAAeA,AAAQ,OAARA,OAAc,CAAEI,CAAAA,MAAM,OAAO,CAACJ,QAAQA,AAAe,MAAfA,IAAI,MAAM,AAAK;QAC/E;YACI,OAAO;IACf;AACJ;AAQO,SAASK,mBACZC,MAAwB,EACxBC,YAAuC;IAEvC,MAAM,EAAEC,MAAM,EAAET,QAAQ,EAAE,OAAOE,GAAG,EAAE,GAAGK;IAEzC,IAAIN;IACJ,IAAIQ,OAAO,QAAQ,CAAC,YAAY;QAC5B,MAAMC,YAAYD,OAAO,KAAK,CAAC,GAAG;QAClC,MAAME,MAAMH,aAAaE;QACzBT,MAAMI,MAAM,OAAO,CAACM,OAAOA,IAAI,MAAM,GAAG;IAC5C,OACIV,MAAMO,aAAaC;IAGvB,OAAOV,cAAcC,UAAUC,KAAKC;AACxC"}
@@ -1,2 +1,27 @@
1
1
  import React from "react";
2
- export declare const PublishEntryConfirmDialog: () => React.JSX.Element;
2
+ export interface PublishEntryConfirmDialogProps {
3
+ /**
4
+ * Arbitrary content rendered at the top of the dialog body. Features (e.g. the scheduler)
5
+ * decorate this component and pass a notice here.
6
+ */
7
+ intro?: React.ReactNode;
8
+ }
9
+ export declare const PublishEntryConfirmDialog: (({ intro }: PublishEntryConfirmDialogProps) => React.JSX.Element) & {
10
+ original: ({ intro }: PublishEntryConfirmDialogProps) => React.JSX.Element;
11
+ originalName: string;
12
+ displayName: string;
13
+ } & {
14
+ original: (({ intro }: PublishEntryConfirmDialogProps) => React.JSX.Element) & {
15
+ original: ({ intro }: PublishEntryConfirmDialogProps) => React.JSX.Element;
16
+ originalName: string;
17
+ displayName: string;
18
+ };
19
+ originalName: string;
20
+ displayName: string;
21
+ } & {
22
+ createDecorator: (decorator: import("@webiny/react-composition").ComponentDecorator<(({ intro }: PublishEntryConfirmDialogProps) => React.JSX.Element) & {
23
+ original: ({ intro }: PublishEntryConfirmDialogProps) => React.JSX.Element;
24
+ originalName: string;
25
+ displayName: string;
26
+ }>) => (props: unknown) => React.JSX.Element;
27
+ };
@@ -1,8 +1,9 @@
1
1
  import react, { useCallback, useState } from "react";
2
+ import { makeDecoratable } from "@webiny/react-composition";
2
3
  import { Text, Textarea } from "@webiny/admin-ui";
3
4
  import { ConfirmationDialog } from "@webiny/app-admin/components/ConfirmationDialog/index.js";
4
5
  import { useNamedConfirmationDialog } from "@webiny/app-admin";
5
- const PublishEntryConfirmDialog = ()=>{
6
+ const PublishEntryConfirmDialog = makeDecoratable("PublishEntryConfirmDialog", ({ intro })=>{
6
7
  const { onConfirm, onCancel, closeDialog, params } = useNamedConfirmationDialog();
7
8
  const [description, setDescription] = useState("");
8
9
  const handleChange = useCallback((value)=>{
@@ -22,7 +23,7 @@ const PublishEntryConfirmDialog = ()=>{
22
23
  onCancel();
23
24
  closeDialog();
24
25
  }
25
- }, /*#__PURE__*/ react.createElement(Text, {
26
+ }, intro, /*#__PURE__*/ react.createElement(Text, {
26
27
  as: "div",
27
28
  size: "md",
28
29
  className: "mb-md"
@@ -33,7 +34,7 @@ const PublishEntryConfirmDialog = ()=>{
33
34
  onChange: handleChange,
34
35
  value: description
35
36
  }));
36
- };
37
+ });
37
38
  export { PublishEntryConfirmDialog };
38
39
 
39
40
  //# sourceMappingURL=PublishEntryConfirmDialog.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"admin/components/Dialogs/PublishEntryConfirmDialog.js","sources":["../../../../src/admin/components/Dialogs/PublishEntryConfirmDialog.tsx"],"sourcesContent":["import React, { useCallback, useState } from \"react\";\nimport { Text, Textarea } from \"@webiny/admin-ui\";\nimport { ConfirmationDialog } from \"@webiny/app-admin/components/ConfirmationDialog/index.js\";\nimport { useNamedConfirmationDialog } from \"@webiny/app-admin\";\nimport type { CmsContentEntry } from \"@webiny/app-headless-cms-common/types/index.js\";\n\nexport const PublishEntryConfirmDialog = () => {\n const { onConfirm, onCancel, closeDialog, params } = useNamedConfirmationDialog<\n { entry: CmsContentEntry },\n { revisionDescription: string }\n >();\n\n const [description, setDescription] = useState(\"\");\n\n const handleChange = useCallback((value: string) => {\n setDescription(value);\n }, []);\n\n return (\n <ConfirmationDialog\n title=\"Publish entry\"\n confirmLabel=\"Yes, publish!\"\n loadingLabel=\"Publishing...\"\n onConfirm={async () => {\n await onConfirm({ revisionDescription: description });\n closeDialog();\n }}\n onCancel={() => {\n onCancel();\n closeDialog();\n }}\n >\n <Text as={\"div\"} size={\"md\"} className={\"mb-md\"}>\n You are about to publish a record titled{\" \"}\n <span className={\"font-bold\"}>{params.entry.meta.title}</span>.<br />\n Are you sure you want to continue?\n </Text>\n <Textarea\n description={\"Write a revision description (optional):\"}\n onChange={handleChange}\n value={description}\n />\n </ConfirmationDialog>\n );\n};\n"],"names":["PublishEntryConfirmDialog","onConfirm","onCancel","closeDialog","params","useNamedConfirmationDialog","description","setDescription","useState","handleChange","useCallback","value","ConfirmationDialog","Text","Textarea"],"mappings":";;;;AAMO,MAAMA,4BAA4B;IACrC,MAAM,EAAEC,SAAS,EAAEC,QAAQ,EAAEC,WAAW,EAAEC,MAAM,EAAE,GAAGC;IAKrD,MAAM,CAACC,aAAaC,eAAe,GAAGC,SAAS;IAE/C,MAAMC,eAAeC,YAAY,CAACC;QAC9BJ,eAAeI;IACnB,GAAG,EAAE;IAEL,OAAO,WAAP,GACI,oBAACC,oBAAkBA;QACf,OAAM;QACN,cAAa;QACb,cAAa;QACb,WAAW;YACP,MAAMX,UAAU;gBAAE,qBAAqBK;YAAY;YACnDH;QACJ;QACA,UAAU;YACND;YACAC;QACJ;qBAEA,oBAACU,MAAIA;QAAC,IAAI;QAAO,MAAM;QAAM,WAAW;OAAS,4CACJ,mBACzC,oBAAC;QAAK,WAAW;OAAcT,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,GAAQ,mBAAC,oBAAC,aAAK,qDAGzE,oBAACU,UAAQA;QACL,aAAa;QACb,UAAUL;QACV,OAAOH;;AAIvB"}
1
+ {"version":3,"file":"admin/components/Dialogs/PublishEntryConfirmDialog.js","sources":["../../../../src/admin/components/Dialogs/PublishEntryConfirmDialog.tsx"],"sourcesContent":["import React, { useCallback, useState } from \"react\";\nimport { makeDecoratable } from \"@webiny/react-composition\";\nimport { Text, Textarea } from \"@webiny/admin-ui\";\nimport { ConfirmationDialog } from \"@webiny/app-admin/components/ConfirmationDialog/index.js\";\nimport { useNamedConfirmationDialog } from \"@webiny/app-admin\";\nimport type { CmsContentEntry } from \"@webiny/app-headless-cms-common/types/index.js\";\n\nexport interface PublishEntryConfirmDialogProps {\n /**\n * Arbitrary content rendered at the top of the dialog body. Features (e.g. the scheduler)\n * decorate this component and pass a notice here.\n */\n intro?: React.ReactNode;\n}\n\nexport const PublishEntryConfirmDialog = makeDecoratable(\n \"PublishEntryConfirmDialog\",\n ({ intro }: PublishEntryConfirmDialogProps) => {\n const { onConfirm, onCancel, closeDialog, params } = useNamedConfirmationDialog<\n { entry: CmsContentEntry },\n { revisionDescription: string }\n >();\n\n const [description, setDescription] = useState(\"\");\n\n const handleChange = useCallback((value: string) => {\n setDescription(value);\n }, []);\n\n return (\n <ConfirmationDialog\n title=\"Publish entry\"\n confirmLabel=\"Yes, publish!\"\n loadingLabel=\"Publishing...\"\n onConfirm={async () => {\n await onConfirm({ revisionDescription: description });\n closeDialog();\n }}\n onCancel={() => {\n onCancel();\n closeDialog();\n }}\n >\n {intro}\n <Text as={\"div\"} size={\"md\"} className={\"mb-md\"}>\n You are about to publish a record titled{\" \"}\n <span className={\"font-bold\"}>{params.entry.meta.title}</span>.<br />\n Are you sure you want to continue?\n </Text>\n <Textarea\n description={\"Write a revision description (optional):\"}\n onChange={handleChange}\n value={description}\n />\n </ConfirmationDialog>\n );\n }\n);\n"],"names":["PublishEntryConfirmDialog","makeDecoratable","intro","onConfirm","onCancel","closeDialog","params","useNamedConfirmationDialog","description","setDescription","useState","handleChange","useCallback","value","ConfirmationDialog","Text","Textarea"],"mappings":";;;;;AAeO,MAAMA,4BAA4BC,gBACrC,6BACA,CAAC,EAAEC,KAAK,EAAkC;IACtC,MAAM,EAAEC,SAAS,EAAEC,QAAQ,EAAEC,WAAW,EAAEC,MAAM,EAAE,GAAGC;IAKrD,MAAM,CAACC,aAAaC,eAAe,GAAGC,SAAS;IAE/C,MAAMC,eAAeC,YAAY,CAACC;QAC9BJ,eAAeI;IACnB,GAAG,EAAE;IAEL,OAAO,WAAP,GACI,oBAACC,oBAAkBA;QACf,OAAM;QACN,cAAa;QACb,cAAa;QACb,WAAW;YACP,MAAMX,UAAU;gBAAE,qBAAqBK;YAAY;YACnDH;QACJ;QACA,UAAU;YACND;YACAC;QACJ;OAECH,OAAAA,WAAAA,GACD,oBAACa,MAAIA;QAAC,IAAI;QAAO,MAAM;QAAM,WAAW;OAAS,4CACJ,mBACzC,oBAAC;QAAK,WAAW;OAAcT,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,GAAQ,mBAAC,oBAAC,aAAK,qDAGzE,oBAACU,UAAQA;QACL,aAAa;QACb,UAAUL;QACV,OAAOH;;AAIvB"}
@@ -1,2 +1,27 @@
1
1
  import React from "react";
2
- export declare const UnpublishEntryConfirmDialog: () => React.JSX.Element;
2
+ export interface UnpublishEntryConfirmDialogProps {
3
+ /**
4
+ * Arbitrary content rendered at the top of the dialog body. Features (e.g. the scheduler)
5
+ * decorate this component and pass a notice here.
6
+ */
7
+ intro?: React.ReactNode;
8
+ }
9
+ export declare const UnpublishEntryConfirmDialog: (({ intro }: UnpublishEntryConfirmDialogProps) => React.JSX.Element) & {
10
+ original: ({ intro }: UnpublishEntryConfirmDialogProps) => React.JSX.Element;
11
+ originalName: string;
12
+ displayName: string;
13
+ } & {
14
+ original: (({ intro }: UnpublishEntryConfirmDialogProps) => React.JSX.Element) & {
15
+ original: ({ intro }: UnpublishEntryConfirmDialogProps) => React.JSX.Element;
16
+ originalName: string;
17
+ displayName: string;
18
+ };
19
+ originalName: string;
20
+ displayName: string;
21
+ } & {
22
+ createDecorator: (decorator: import("@webiny/react-composition").ComponentDecorator<(({ intro }: UnpublishEntryConfirmDialogProps) => React.JSX.Element) & {
23
+ original: ({ intro }: UnpublishEntryConfirmDialogProps) => React.JSX.Element;
24
+ originalName: string;
25
+ displayName: string;
26
+ }>) => (props: unknown) => React.JSX.Element;
27
+ };
@@ -1,7 +1,8 @@
1
1
  import react from "react";
2
+ import { makeDecoratable } from "@webiny/react-composition";
2
3
  import { ConfirmationDialog } from "@webiny/app-admin/components/ConfirmationDialog/index.js";
3
4
  import { useNamedConfirmationDialog } from "@webiny/app-admin";
4
- const UnpublishEntryConfirmDialog = ()=>{
5
+ const UnpublishEntryConfirmDialog = makeDecoratable("UnpublishEntryConfirmDialog", ({ intro })=>{
5
6
  const { onConfirm, onCancel, closeDialog } = useNamedConfirmationDialog();
6
7
  return /*#__PURE__*/ react.createElement(ConfirmationDialog, {
7
8
  title: "Unpublish entry",
@@ -15,8 +16,8 @@ const UnpublishEntryConfirmDialog = ()=>{
15
16
  onCancel();
16
17
  closeDialog();
17
18
  }
18
- }, /*#__PURE__*/ react.createElement("p", null, "Are you sure you want to unpublish this entry?"));
19
- };
19
+ }, intro, /*#__PURE__*/ react.createElement("p", null, "Are you sure you want to unpublish this entry?"));
20
+ });
20
21
  export { UnpublishEntryConfirmDialog };
21
22
 
22
23
  //# sourceMappingURL=UnpublishEntryConfirmDialog.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"admin/components/Dialogs/UnpublishEntryConfirmDialog.js","sources":["../../../../src/admin/components/Dialogs/UnpublishEntryConfirmDialog.tsx"],"sourcesContent":["import React from \"react\";\nimport { ConfirmationDialog } from \"@webiny/app-admin/components/ConfirmationDialog/index.js\";\nimport { useNamedConfirmationDialog } from \"@webiny/app-admin\";\n\nexport const UnpublishEntryConfirmDialog = () => {\n const { onConfirm, onCancel, closeDialog } = useNamedConfirmationDialog<{ entryId: string }>();\n\n return (\n <ConfirmationDialog\n title=\"Unpublish entry\"\n confirmLabel=\"Yes, unpublish!\"\n loadingLabel=\"Unpublishing...\"\n onConfirm={async () => {\n await onConfirm();\n closeDialog();\n }}\n onCancel={() => {\n onCancel();\n closeDialog();\n }}\n >\n <p>Are you sure you want to unpublish this entry?</p>\n </ConfirmationDialog>\n );\n};\n"],"names":["UnpublishEntryConfirmDialog","onConfirm","onCancel","closeDialog","useNamedConfirmationDialog","ConfirmationDialog"],"mappings":";;;AAIO,MAAMA,8BAA8B;IACvC,MAAM,EAAEC,SAAS,EAAEC,QAAQ,EAAEC,WAAW,EAAE,GAAGC;IAE7C,OAAO,WAAP,GACI,oBAACC,oBAAkBA;QACf,OAAM;QACN,cAAa;QACb,cAAa;QACb,WAAW;YACP,MAAMJ;YACNE;QACJ;QACA,UAAU;YACND;YACAC;QACJ;qBAEA,oBAAC,WAAE;AAGf"}
1
+ {"version":3,"file":"admin/components/Dialogs/UnpublishEntryConfirmDialog.js","sources":["../../../../src/admin/components/Dialogs/UnpublishEntryConfirmDialog.tsx"],"sourcesContent":["import React from \"react\";\nimport { makeDecoratable } from \"@webiny/react-composition\";\nimport { ConfirmationDialog } from \"@webiny/app-admin/components/ConfirmationDialog/index.js\";\nimport { useNamedConfirmationDialog } from \"@webiny/app-admin\";\n\nexport interface UnpublishEntryConfirmDialogProps {\n /**\n * Arbitrary content rendered at the top of the dialog body. Features (e.g. the scheduler)\n * decorate this component and pass a notice here.\n */\n intro?: React.ReactNode;\n}\n\nexport const UnpublishEntryConfirmDialog = makeDecoratable(\n \"UnpublishEntryConfirmDialog\",\n ({ intro }: UnpublishEntryConfirmDialogProps) => {\n const { onConfirm, onCancel, closeDialog } = useNamedConfirmationDialog<{\n entryId: string;\n }>();\n\n return (\n <ConfirmationDialog\n title=\"Unpublish entry\"\n confirmLabel=\"Yes, unpublish!\"\n loadingLabel=\"Unpublishing...\"\n onConfirm={async () => {\n await onConfirm();\n closeDialog();\n }}\n onCancel={() => {\n onCancel();\n closeDialog();\n }}\n >\n {intro}\n <p>Are you sure you want to unpublish this entry?</p>\n </ConfirmationDialog>\n );\n }\n);\n"],"names":["UnpublishEntryConfirmDialog","makeDecoratable","intro","onConfirm","onCancel","closeDialog","useNamedConfirmationDialog","ConfirmationDialog"],"mappings":";;;;AAaO,MAAMA,8BAA8BC,gBACvC,+BACA,CAAC,EAAEC,KAAK,EAAoC;IACxC,MAAM,EAAEC,SAAS,EAAEC,QAAQ,EAAEC,WAAW,EAAE,GAAGC;IAI7C,OAAO,WAAP,GACI,oBAACC,oBAAkBA;QACf,OAAM;QACN,cAAa;QACb,cAAa;QACb,WAAW;YACP,MAAMJ;YACNE;QACJ;QACA,UAAU;YACND;YACAC;QACJ;OAECH,OAAAA,WAAAA,GACD,oBAAC,WAAE;AAGf"}
@@ -2,13 +2,13 @@ import react, { useEffect, useState } from "react";
2
2
  import { useFeature } from "@webiny/app";
3
3
  import { Grid } from "@webiny/admin-ui";
4
4
  import { useBind } from "@webiny/form";
5
- import { useWcp } from "@webiny/app-admin";
5
+ import { useFeatureFlags } from "@webiny/app-admin";
6
6
  import { UsersTeamsMultiAutocomplete } from "@webiny/app-aco";
7
7
  import { ListFolderPermissionsTargetsFeature } from "../../../../../features/listFolderPermissionsTargets/feature.js";
8
8
  import { FieldPermissionsSelection } from "./FieldPermissionsSelection.js";
9
9
  import { CannotUsePermissions } from "./CannotUsePermissions.js";
10
10
  const PermissionsEditor = ()=>{
11
- const wcp = useWcp();
11
+ const featureFlags = useFeatureFlags();
12
12
  const { useCase } = useFeature(ListFolderPermissionsTargetsFeature);
13
13
  const bind = useBind({
14
14
  name: "rules"
@@ -52,7 +52,7 @@ const PermissionsEditor = ()=>{
52
52
  ...updatedAccessRules
53
53
  ]);
54
54
  };
55
- if (!wcp.canUseHcmsFieldPermissions()) return /*#__PURE__*/ react.createElement(Grid, null, /*#__PURE__*/ react.createElement(Grid.Column, {
55
+ if (!featureFlags.isEnabled("advancedAccessControlLayer.hcmsFieldPermissions")) return /*#__PURE__*/ react.createElement(Grid, null, /*#__PURE__*/ react.createElement(Grid.Column, {
56
56
  span: 12
57
57
  }, /*#__PURE__*/ react.createElement(CannotUsePermissions, null)));
58
58
  return /*#__PURE__*/ react.createElement(Grid, null, /*#__PURE__*/ react.createElement(Grid.Column, {
@@ -1 +1 @@
1
- {"version":3,"file":"admin/components/FieldEditor/EditFieldDialog/PermissionsEditor/PermissionsEditor.js","sources":["../../../../../../src/admin/components/FieldEditor/EditFieldDialog/PermissionsEditor/PermissionsEditor.tsx"],"sourcesContent":["import React, { useEffect, useState } from \"react\";\nimport { useFeature } from \"@webiny/app\";\nimport { Grid } from \"@webiny/admin-ui\";\nimport { useBind } from \"@webiny/form\";\nimport { useWcp } from \"@webiny/app-admin\";\nimport { UsersTeamsMultiAutocomplete } from \"@webiny/app-aco\";\nimport type { FolderLevelPermissionsTarget } from \"@webiny/app-aco\";\nimport { ListFolderPermissionsTargetsFeature } from \"~/features/listFolderPermissionsTargets/feature.js\";\nimport type { FieldRule } from \"~/types.js\";\nimport { FieldPermissionsSelection } from \"./FieldPermissionsSelection.js\";\nimport { CannotUsePermissions } from \"./CannotUsePermissions.js\";\n\nexport const PermissionsEditor = () => {\n const wcp = useWcp();\n const { useCase } = useFeature(ListFolderPermissionsTargetsFeature);\n const bind = useBind({ name: \"rules\" });\n const allRules: FieldRule[] = bind.value || [];\n const accessRules = allRules.filter(r => r.type === \"accessControl\");\n const otherRules = allRules.filter(r => r.type !== \"accessControl\");\n\n const [targetsList, setTargetsList] = useState<FolderLevelPermissionsTarget[]>([]);\n\n useEffect(() => {\n useCase.execute().then(setTargetsList).catch(console.error);\n }, []);\n\n const addPermission = (value: string[]) => {\n const selectedUserOrTeam = value[value.length - 1];\n const newRule: FieldRule = {\n type: \"accessControl\",\n target: \"identity\",\n operator: \"matches\",\n value: selectedUserOrTeam,\n action: \"disable\"\n };\n\n bind.onChange([...otherRules, ...accessRules, newRule]);\n };\n\n const updatePermission = ({ rule: updatedRule }: { rule: FieldRule }) => {\n const updatedAccessRules = accessRules.map(rule => {\n if (rule.value === updatedRule.value) {\n return updatedRule;\n }\n return rule;\n });\n bind.onChange([...otherRules, ...updatedAccessRules]);\n };\n\n const removeUserTeam = ({ rule: removedRule }: { rule: FieldRule }) => {\n const updatedAccessRules = accessRules.filter(rule => rule.value !== removedRule.value);\n bind.onChange([...otherRules, ...updatedAccessRules]);\n };\n\n if (!wcp.canUseHcmsFieldPermissions()) {\n return (\n <Grid>\n <Grid.Column span={12}>\n <CannotUsePermissions />\n </Grid.Column>\n </Grid>\n );\n }\n\n return (\n <Grid>\n <Grid.Column span={12}>\n <UsersTeamsMultiAutocomplete\n options={targetsList}\n value={accessRules.map(\n rule => String(rule.value) as `admin:${string}` | `team:${string}`\n )}\n onChange={addPermission}\n />\n </Grid.Column>\n <Grid.Column span={12}>\n <FieldPermissionsSelection\n rules={accessRules}\n targetsList={targetsList}\n onRemoveAccess={removeUserTeam}\n onUpdatePermission={updatePermission}\n />\n </Grid.Column>\n </Grid>\n );\n};\n"],"names":["PermissionsEditor","wcp","useWcp","useCase","useFeature","ListFolderPermissionsTargetsFeature","bind","useBind","allRules","accessRules","r","otherRules","targetsList","setTargetsList","useState","useEffect","console","addPermission","value","selectedUserOrTeam","newRule","updatePermission","updatedRule","updatedAccessRules","rule","removeUserTeam","removedRule","Grid","CannotUsePermissions","UsersTeamsMultiAutocomplete","String","FieldPermissionsSelection"],"mappings":";;;;;;;;;AAYO,MAAMA,oBAAoB;IAC7B,MAAMC,MAAMC;IACZ,MAAM,EAAEC,OAAO,EAAE,GAAGC,WAAWC;IAC/B,MAAMC,OAAOC,QAAQ;QAAE,MAAM;IAAQ;IACrC,MAAMC,WAAwBF,KAAK,KAAK,IAAI,EAAE;IAC9C,MAAMG,cAAcD,SAAS,MAAM,CAACE,CAAAA,IAAKA,AAAW,oBAAXA,EAAE,IAAI;IAC/C,MAAMC,aAAaH,SAAS,MAAM,CAACE,CAAAA,IAAKA,AAAW,oBAAXA,EAAE,IAAI;IAE9C,MAAM,CAACE,aAAaC,eAAe,GAAGC,SAAyC,EAAE;IAEjFC,UAAU;QACNZ,QAAQ,OAAO,GAAG,IAAI,CAACU,gBAAgB,KAAK,CAACG,QAAQ,KAAK;IAC9D,GAAG,EAAE;IAEL,MAAMC,gBAAgB,CAACC;QACnB,MAAMC,qBAAqBD,KAAK,CAACA,MAAM,MAAM,GAAG,EAAE;QAClD,MAAME,UAAqB;YACvB,MAAM;YACN,QAAQ;YACR,UAAU;YACV,OAAOD;YACP,QAAQ;QACZ;QAEAb,KAAK,QAAQ,CAAC;eAAIK;eAAeF;YAAaW;SAAQ;IAC1D;IAEA,MAAMC,mBAAmB,CAAC,EAAE,MAAMC,WAAW,EAAuB;QAChE,MAAMC,qBAAqBd,YAAY,GAAG,CAACe,CAAAA;YACvC,IAAIA,KAAK,KAAK,KAAKF,YAAY,KAAK,EAChC,OAAOA;YAEX,OAAOE;QACX;QACAlB,KAAK,QAAQ,CAAC;eAAIK;eAAeY;SAAmB;IACxD;IAEA,MAAME,iBAAiB,CAAC,EAAE,MAAMC,WAAW,EAAuB;QAC9D,MAAMH,qBAAqBd,YAAY,MAAM,CAACe,CAAAA,OAAQA,KAAK,KAAK,KAAKE,YAAY,KAAK;QACtFpB,KAAK,QAAQ,CAAC;eAAIK;eAAeY;SAAmB;IACxD;IAEA,IAAI,CAACtB,IAAI,0BAA0B,IAC/B,OAAO,WAAP,GACI,oBAAC0B,MAAIA,MAAAA,WAAAA,GACD,oBAACA,KAAK,MAAM;QAAC,MAAM;qBACf,oBAACC,sBAAoBA;IAMrC,OAAO,WAAP,GACI,oBAACD,MAAIA,MAAAA,WAAAA,GACD,oBAACA,KAAK,MAAM;QAAC,MAAM;qBACf,oBAACE,6BAA2BA;QACxB,SAASjB;QACT,OAAOH,YAAY,GAAG,CAClBe,CAAAA,OAAQM,OAAON,KAAK,KAAK;QAE7B,UAAUP;uBAGlB,oBAACU,KAAK,MAAM;QAAC,MAAM;qBACf,oBAACI,2BAAyBA;QACtB,OAAOtB;QACP,aAAaG;QACb,gBAAgBa;QAChB,oBAAoBJ;;AAKxC"}
1
+ {"version":3,"file":"admin/components/FieldEditor/EditFieldDialog/PermissionsEditor/PermissionsEditor.js","sources":["../../../../../../src/admin/components/FieldEditor/EditFieldDialog/PermissionsEditor/PermissionsEditor.tsx"],"sourcesContent":["import React, { useEffect, useState } from \"react\";\nimport { useFeature } from \"@webiny/app\";\nimport { Grid } from \"@webiny/admin-ui\";\nimport { useBind } from \"@webiny/form\";\nimport { useFeatureFlags } from \"@webiny/app-admin\";\nimport { UsersTeamsMultiAutocomplete } from \"@webiny/app-aco\";\nimport type { FolderLevelPermissionsTarget } from \"@webiny/app-aco\";\nimport { ListFolderPermissionsTargetsFeature } from \"~/features/listFolderPermissionsTargets/feature.js\";\nimport type { FieldRule } from \"~/types.js\";\nimport { FieldPermissionsSelection } from \"./FieldPermissionsSelection.js\";\nimport { CannotUsePermissions } from \"./CannotUsePermissions.js\";\n\nexport const PermissionsEditor = () => {\n const featureFlags = useFeatureFlags();\n const { useCase } = useFeature(ListFolderPermissionsTargetsFeature);\n const bind = useBind({ name: \"rules\" });\n const allRules: FieldRule[] = bind.value || [];\n const accessRules = allRules.filter(r => r.type === \"accessControl\");\n const otherRules = allRules.filter(r => r.type !== \"accessControl\");\n\n const [targetsList, setTargetsList] = useState<FolderLevelPermissionsTarget[]>([]);\n\n useEffect(() => {\n useCase.execute().then(setTargetsList).catch(console.error);\n }, []);\n\n const addPermission = (value: string[]) => {\n const selectedUserOrTeam = value[value.length - 1];\n const newRule: FieldRule = {\n type: \"accessControl\",\n target: \"identity\",\n operator: \"matches\",\n value: selectedUserOrTeam,\n action: \"disable\"\n };\n\n bind.onChange([...otherRules, ...accessRules, newRule]);\n };\n\n const updatePermission = ({ rule: updatedRule }: { rule: FieldRule }) => {\n const updatedAccessRules = accessRules.map(rule => {\n if (rule.value === updatedRule.value) {\n return updatedRule;\n }\n return rule;\n });\n bind.onChange([...otherRules, ...updatedAccessRules]);\n };\n\n const removeUserTeam = ({ rule: removedRule }: { rule: FieldRule }) => {\n const updatedAccessRules = accessRules.filter(rule => rule.value !== removedRule.value);\n bind.onChange([...otherRules, ...updatedAccessRules]);\n };\n\n if (!featureFlags.isEnabled(\"advancedAccessControlLayer.hcmsFieldPermissions\")) {\n return (\n <Grid>\n <Grid.Column span={12}>\n <CannotUsePermissions />\n </Grid.Column>\n </Grid>\n );\n }\n\n return (\n <Grid>\n <Grid.Column span={12}>\n <UsersTeamsMultiAutocomplete\n options={targetsList}\n value={accessRules.map(\n rule => String(rule.value) as `admin:${string}` | `team:${string}`\n )}\n onChange={addPermission}\n />\n </Grid.Column>\n <Grid.Column span={12}>\n <FieldPermissionsSelection\n rules={accessRules}\n targetsList={targetsList}\n onRemoveAccess={removeUserTeam}\n onUpdatePermission={updatePermission}\n />\n </Grid.Column>\n </Grid>\n );\n};\n"],"names":["PermissionsEditor","featureFlags","useFeatureFlags","useCase","useFeature","ListFolderPermissionsTargetsFeature","bind","useBind","allRules","accessRules","r","otherRules","targetsList","setTargetsList","useState","useEffect","console","addPermission","value","selectedUserOrTeam","newRule","updatePermission","updatedRule","updatedAccessRules","rule","removeUserTeam","removedRule","Grid","CannotUsePermissions","UsersTeamsMultiAutocomplete","String","FieldPermissionsSelection"],"mappings":";;;;;;;;;AAYO,MAAMA,oBAAoB;IAC7B,MAAMC,eAAeC;IACrB,MAAM,EAAEC,OAAO,EAAE,GAAGC,WAAWC;IAC/B,MAAMC,OAAOC,QAAQ;QAAE,MAAM;IAAQ;IACrC,MAAMC,WAAwBF,KAAK,KAAK,IAAI,EAAE;IAC9C,MAAMG,cAAcD,SAAS,MAAM,CAACE,CAAAA,IAAKA,AAAW,oBAAXA,EAAE,IAAI;IAC/C,MAAMC,aAAaH,SAAS,MAAM,CAACE,CAAAA,IAAKA,AAAW,oBAAXA,EAAE,IAAI;IAE9C,MAAM,CAACE,aAAaC,eAAe,GAAGC,SAAyC,EAAE;IAEjFC,UAAU;QACNZ,QAAQ,OAAO,GAAG,IAAI,CAACU,gBAAgB,KAAK,CAACG,QAAQ,KAAK;IAC9D,GAAG,EAAE;IAEL,MAAMC,gBAAgB,CAACC;QACnB,MAAMC,qBAAqBD,KAAK,CAACA,MAAM,MAAM,GAAG,EAAE;QAClD,MAAME,UAAqB;YACvB,MAAM;YACN,QAAQ;YACR,UAAU;YACV,OAAOD;YACP,QAAQ;QACZ;QAEAb,KAAK,QAAQ,CAAC;eAAIK;eAAeF;YAAaW;SAAQ;IAC1D;IAEA,MAAMC,mBAAmB,CAAC,EAAE,MAAMC,WAAW,EAAuB;QAChE,MAAMC,qBAAqBd,YAAY,GAAG,CAACe,CAAAA;YACvC,IAAIA,KAAK,KAAK,KAAKF,YAAY,KAAK,EAChC,OAAOA;YAEX,OAAOE;QACX;QACAlB,KAAK,QAAQ,CAAC;eAAIK;eAAeY;SAAmB;IACxD;IAEA,MAAME,iBAAiB,CAAC,EAAE,MAAMC,WAAW,EAAuB;QAC9D,MAAMH,qBAAqBd,YAAY,MAAM,CAACe,CAAAA,OAAQA,KAAK,KAAK,KAAKE,YAAY,KAAK;QACtFpB,KAAK,QAAQ,CAAC;eAAIK;eAAeY;SAAmB;IACxD;IAEA,IAAI,CAACtB,aAAa,SAAS,CAAC,oDACxB,OAAO,WAAP,GACI,oBAAC0B,MAAIA,MAAAA,WAAAA,GACD,oBAACA,KAAK,MAAM;QAAC,MAAM;qBACf,oBAACC,sBAAoBA;IAMrC,OAAO,WAAP,GACI,oBAACD,MAAIA,MAAAA,WAAAA,GACD,oBAACA,KAAK,MAAM;QAAC,MAAM;qBACf,oBAACE,6BAA2BA;QACxB,SAASjB;QACT,OAAOH,YAAY,GAAG,CAClBe,CAAAA,OAAQM,OAAON,KAAK,KAAK;QAE7B,UAAUP;uBAGlB,oBAACU,KAAK,MAAM;QAAC,MAAM;qBACf,oBAACI,2BAAyBA;QACtB,OAAOtB;QACP,aAAaG;QACb,gBAAgBa;QAChB,oBAAoBJ;;AAKxC"}
@@ -4,7 +4,7 @@ interface EditFieldDialogProps {
4
4
  onClose: () => void;
5
5
  onSubmit: (data: CmsModelField) => void;
6
6
  }
7
- declare const EditFieldDialog: ((props: EditFieldDialogProps) => React.JSX.Element) & {
8
- displayName: string;
7
+ declare const EditFieldDialog: ((props: EditFieldDialogProps) => React.JSX.Element) & React.NamedExoticComponent<EditFieldDialogProps> & {
8
+ readonly type: (props: EditFieldDialogProps) => React.JSX.Element;
9
9
  };
10
10
  export default EditFieldDialog;
@@ -15,9 +15,12 @@ const EditFieldDialog = observer((props)=>{
15
15
  const presenter = useMemo(()=>container.resolve(FieldEditorPresenter), [
16
16
  container
17
17
  ]);
18
- const fieldType = useMemo(()=>container.resolveAll(CmsFieldType).find((ft)=>ft.type === field.type), [
18
+ const fieldType = useMemo(()=>{
19
+ const all = container.resolveAll(CmsFieldType);
20
+ return all.find((ft)=>ft.matches?.(field)) ?? all.find((ft)=>ft.type === field.type);
21
+ }, [
19
22
  container,
20
- field.type
23
+ field
21
24
  ]);
22
25
  useEffect(()=>{
23
26
  presenter.init(field, contentModel);
@@ -1 +1 @@
1
- {"version":3,"file":"admin/components/FieldEditor/EditFieldDialog.js","sources":["../../../../src/admin/components/FieldEditor/EditFieldDialog.tsx"],"sourcesContent":["import React, { useEffect, useMemo } from \"react\";\nimport { observer } from \"mobx-react-lite\";\nimport { i18n } from \"@webiny/app/i18n/index.js\";\nimport { FormView, FormErrors } from \"@webiny/app-admin\";\nimport { useContainer } from \"@webiny/app\";\nimport { Drawer } from \"@webiny/admin-ui\";\nimport type { CmsModelField } from \"~/types.js\";\nimport { useModelEditor, useModelField } from \"~/admin/hooks/index.js\";\nimport { FieldEditorPresenter } from \"~/presentation/fieldEditor/abstractions.js\";\nimport { CmsFieldType } from \"~/presentation/fieldTypes/abstractions.js\";\n\nconst t = i18n.namespace(\"app-headless-cms/admin/components/editor\");\n\ninterface EditFieldDialogProps {\n onClose: () => void;\n onSubmit: (data: CmsModelField) => void;\n}\n\nconst EditFieldDialog = observer((props: EditFieldDialogProps) => {\n const { field } = useModelField();\n const { data: contentModel, setData: setContentModelData } = useModelEditor();\n\n const container = useContainer();\n const presenter = useMemo(() => container.resolve(FieldEditorPresenter), [container]);\n const fieldType = useMemo(() => {\n return container.resolveAll(CmsFieldType).find(ft => ft.type === field.type);\n }, [container, field.type]);\n\n useEffect(() => {\n presenter.init(field, contentModel);\n }, []);\n\n const headerTitle = t`Field Settings - {fieldTypeLabel}`({\n fieldTypeLabel: fieldType ? fieldType.label : field.type\n });\n\n const isTitleField = contentModel.titleFieldId === field.fieldId;\n\n const handleSubmit = async () => {\n const result = await presenter.submit();\n if (!result) {\n return;\n }\n\n if (isTitleField && contentModel.titleFieldId !== result.fieldId) {\n setContentModelData(prev => ({\n ...prev,\n titleFieldId: result.fieldId\n }));\n }\n\n props.onSubmit(result);\n };\n\n return (\n <Drawer\n title={headerTitle}\n open={true}\n modal={true}\n onClose={props.onClose}\n bodyPadding={false}\n footerSeparator={true}\n size={\"lg\"}\n actions={\n <>\n <Drawer.CancelButton\n text={t`Cancel`}\n data-testid=\"cms.editor.field.settings.cancel\"\n />\n <Drawer.ConfirmButton\n text={t`Save Field`}\n onClick={handleSubmit}\n data-testid=\"cms.editor.field.settings.save\"\n />\n </>\n }\n data-testid={\"cms-editor-edit-fields-dialog\"}\n >\n {presenter.vm.form ? (\n <>\n <FormErrors form={presenter.vm.form} />\n <FormView name=\"CmsFieldEditor\" form={presenter.vm.form} />\n </>\n ) : null}\n </Drawer>\n );\n});\n\nexport default EditFieldDialog;\n"],"names":["t","i18n","EditFieldDialog","observer","props","field","useModelField","contentModel","setContentModelData","useModelEditor","container","useContainer","presenter","useMemo","FieldEditorPresenter","fieldType","CmsFieldType","ft","useEffect","headerTitle","isTitleField","handleSubmit","result","prev","Drawer","FormErrors","FormView"],"mappings":";;;;;;;;;AAWA,MAAMA,IAAIC,KAAK,SAAS,CAAC;AAOzB,MAAMC,kBAAkBC,SAAS,CAACC;IAC9B,MAAM,EAAEC,KAAK,EAAE,GAAGC;IAClB,MAAM,EAAE,MAAMC,YAAY,EAAE,SAASC,mBAAmB,EAAE,GAAGC;IAE7D,MAAMC,YAAYC;IAClB,MAAMC,YAAYC,QAAQ,IAAMH,UAAU,OAAO,CAACI,uBAAuB;QAACJ;KAAU;IACpF,MAAMK,YAAYF,QAAQ,IACfH,UAAU,UAAU,CAACM,cAAc,IAAI,CAACC,CAAAA,KAAMA,GAAG,IAAI,KAAKZ,MAAM,IAAI,GAC5E;QAACK;QAAWL,MAAM,IAAI;KAAC;IAE1Ba,UAAU;QACNN,UAAU,IAAI,CAACP,OAAOE;IAC1B,GAAG,EAAE;IAEL,MAAMY,cAAcnB,CAAC,CAAC,iCAAiC,CAAC,CAAC;QACrD,gBAAgBe,YAAYA,UAAU,KAAK,GAAGV,MAAM,IAAI;IAC5D;IAEA,MAAMe,eAAeb,aAAa,YAAY,KAAKF,MAAM,OAAO;IAEhE,MAAMgB,eAAe;QACjB,MAAMC,SAAS,MAAMV,UAAU,MAAM;QACrC,IAAI,CAACU,QACD;QAGJ,IAAIF,gBAAgBb,aAAa,YAAY,KAAKe,OAAO,OAAO,EAC5Dd,oBAAoBe,CAAAA,OAAS;gBACzB,GAAGA,IAAI;gBACP,cAAcD,OAAO,OAAO;YAChC;QAGJlB,MAAM,QAAQ,CAACkB;IACnB;IAEA,OAAO,WAAP,GACI,oBAACE,QAAMA;QACH,OAAOL;QACP,MAAM;QACN,OAAO;QACP,SAASf,MAAM,OAAO;QACtB,aAAa;QACb,iBAAiB;QACjB,MAAM;QACN,uBACI,wDACI,oBAACoB,OAAO,YAAY;YAChB,MAAMxB,CAAC,CAAC,MAAM,CAAC;YACf,eAAY;0BAEhB,oBAACwB,OAAO,aAAa;YACjB,MAAMxB,CAAC,CAAC,UAAU,CAAC;YACnB,SAASqB;YACT,eAAY;;QAIxB,eAAa;OAEZT,UAAU,EAAE,CAAC,IAAI,GAAG,WAAH,GACd,wDACI,oBAACa,YAAUA;QAAC,MAAMb,UAAU,EAAE,CAAC,IAAI;sBACnC,oBAACc,UAAQA;QAAC,MAAK;QAAiB,MAAMd,UAAU,EAAE,CAAC,IAAI;UAE3D;AAGhB;AAEA,oCAAeV"}
1
+ {"version":3,"file":"admin/components/FieldEditor/EditFieldDialog.js","sources":["../../../../src/admin/components/FieldEditor/EditFieldDialog.tsx"],"sourcesContent":["import React, { useEffect, useMemo } from \"react\";\nimport { observer } from \"mobx-react-lite\";\nimport { i18n } from \"@webiny/app/i18n/index.js\";\nimport { FormView, FormErrors } from \"@webiny/app-admin\";\nimport { useContainer } from \"@webiny/app\";\nimport { Drawer } from \"@webiny/admin-ui\";\nimport type { CmsModelField } from \"~/types.js\";\nimport { useModelEditor, useModelField } from \"~/admin/hooks/index.js\";\nimport { FieldEditorPresenter } from \"~/presentation/fieldEditor/abstractions.js\";\nimport { CmsFieldType } from \"~/presentation/fieldTypes/abstractions.js\";\n\nconst t = i18n.namespace(\"app-headless-cms/admin/components/editor\");\n\ninterface EditFieldDialogProps {\n onClose: () => void;\n onSubmit: (data: CmsModelField) => void;\n}\n\nconst EditFieldDialog = observer((props: EditFieldDialogProps) => {\n const { field } = useModelField();\n const { data: contentModel, setData: setContentModelData } = useModelEditor();\n\n const container = useContainer();\n const presenter = useMemo(() => container.resolve(FieldEditorPresenter), [container]);\n const fieldType = useMemo(() => {\n const all = container.resolveAll(CmsFieldType);\n return all.find(ft => ft.matches?.(field)) ?? all.find(ft => ft.type === field.type);\n }, [container, field]);\n\n useEffect(() => {\n presenter.init(field, contentModel);\n }, []);\n\n const headerTitle = t`Field Settings - {fieldTypeLabel}`({\n fieldTypeLabel: fieldType ? fieldType.label : field.type\n });\n\n const isTitleField = contentModel.titleFieldId === field.fieldId;\n\n const handleSubmit = async () => {\n const result = await presenter.submit();\n if (!result) {\n return;\n }\n\n if (isTitleField && contentModel.titleFieldId !== result.fieldId) {\n setContentModelData(prev => ({\n ...prev,\n titleFieldId: result.fieldId\n }));\n }\n\n props.onSubmit(result);\n };\n\n return (\n <Drawer\n title={headerTitle}\n open={true}\n modal={true}\n onClose={props.onClose}\n bodyPadding={false}\n footerSeparator={true}\n size={\"lg\"}\n actions={\n <>\n <Drawer.CancelButton\n text={t`Cancel`}\n data-testid=\"cms.editor.field.settings.cancel\"\n />\n <Drawer.ConfirmButton\n text={t`Save Field`}\n onClick={handleSubmit}\n data-testid=\"cms.editor.field.settings.save\"\n />\n </>\n }\n data-testid={\"cms-editor-edit-fields-dialog\"}\n >\n {presenter.vm.form ? (\n <>\n <FormErrors form={presenter.vm.form} />\n <FormView name=\"CmsFieldEditor\" form={presenter.vm.form} />\n </>\n ) : null}\n </Drawer>\n );\n});\n\nexport default EditFieldDialog;\n"],"names":["t","i18n","EditFieldDialog","observer","props","field","useModelField","contentModel","setContentModelData","useModelEditor","container","useContainer","presenter","useMemo","FieldEditorPresenter","fieldType","all","CmsFieldType","ft","useEffect","headerTitle","isTitleField","handleSubmit","result","prev","Drawer","FormErrors","FormView"],"mappings":";;;;;;;;;AAWA,MAAMA,IAAIC,KAAK,SAAS,CAAC;AAOzB,MAAMC,kBAAkBC,SAAS,CAACC;IAC9B,MAAM,EAAEC,KAAK,EAAE,GAAGC;IAClB,MAAM,EAAE,MAAMC,YAAY,EAAE,SAASC,mBAAmB,EAAE,GAAGC;IAE7D,MAAMC,YAAYC;IAClB,MAAMC,YAAYC,QAAQ,IAAMH,UAAU,OAAO,CAACI,uBAAuB;QAACJ;KAAU;IACpF,MAAMK,YAAYF,QAAQ;QACtB,MAAMG,MAAMN,UAAU,UAAU,CAACO;QACjC,OAAOD,IAAI,IAAI,CAACE,CAAAA,KAAMA,GAAG,OAAO,GAAGb,WAAWW,IAAI,IAAI,CAACE,CAAAA,KAAMA,GAAG,IAAI,KAAKb,MAAM,IAAI;IACvF,GAAG;QAACK;QAAWL;KAAM;IAErBc,UAAU;QACNP,UAAU,IAAI,CAACP,OAAOE;IAC1B,GAAG,EAAE;IAEL,MAAMa,cAAcpB,CAAC,CAAC,iCAAiC,CAAC,CAAC;QACrD,gBAAgBe,YAAYA,UAAU,KAAK,GAAGV,MAAM,IAAI;IAC5D;IAEA,MAAMgB,eAAed,aAAa,YAAY,KAAKF,MAAM,OAAO;IAEhE,MAAMiB,eAAe;QACjB,MAAMC,SAAS,MAAMX,UAAU,MAAM;QACrC,IAAI,CAACW,QACD;QAGJ,IAAIF,gBAAgBd,aAAa,YAAY,KAAKgB,OAAO,OAAO,EAC5Df,oBAAoBgB,CAAAA,OAAS;gBACzB,GAAGA,IAAI;gBACP,cAAcD,OAAO,OAAO;YAChC;QAGJnB,MAAM,QAAQ,CAACmB;IACnB;IAEA,OAAO,WAAP,GACI,oBAACE,QAAMA;QACH,OAAOL;QACP,MAAM;QACN,OAAO;QACP,SAAShB,MAAM,OAAO;QACtB,aAAa;QACb,iBAAiB;QACjB,MAAM;QACN,uBACI,wDACI,oBAACqB,OAAO,YAAY;YAChB,MAAMzB,CAAC,CAAC,MAAM,CAAC;YACf,eAAY;0BAEhB,oBAACyB,OAAO,aAAa;YACjB,MAAMzB,CAAC,CAAC,UAAU,CAAC;YACnB,SAASsB;YACT,eAAY;;QAIxB,eAAa;OAEZV,UAAU,EAAE,CAAC,IAAI,GAAG,WAAH,GACd,wDACI,oBAACc,YAAUA;QAAC,MAAMd,UAAU,EAAE,CAAC,IAAI;sBACnC,oBAACe,UAAQA;QAAC,MAAK;QAAiB,MAAMf,UAAU,EAAE,CAAC,IAAI;UAE3D;AAGhB;AAEA,oCAAeV"}
@@ -104,7 +104,7 @@ const Field = (props)=>{
104
104
  field.fieldId,
105
105
  setModel
106
106
  ]);
107
- const fieldType = getFieldType(field.type);
107
+ const fieldType = getFieldType(field);
108
108
  const editorFieldOptionPlugins = plugins.byType("cms-editor-field-option");
109
109
  if (!fieldType) return null;
110
110
  const renderer = getFieldRenderer(field.renderer.name);
@@ -1 +1 @@
1
- {"version":3,"file":"admin/components/FieldEditor/Field.js","sources":["../../../../src/admin/components/FieldEditor/Field.tsx"],"sourcesContent":["import React, { Fragment, useCallback, useMemo } from \"react\";\nimport capitalize from \"lodash/capitalize.js\";\nimport { ReactComponent as EditIcon } from \"@webiny/icons/edit.svg\";\nimport { ReactComponent as DeleteIcon } from \"@webiny/icons/delete.svg\";\nimport { ReactComponent as TitleIcon } from \"@webiny/icons/title.svg\";\nimport { ReactComponent as MoreVerticalIcon } from \"@webiny/icons/more_vert.svg\";\nimport { plugins } from \"@webiny/plugins\";\nimport type { CmsModelField, CmsEditorFieldOptionPlugin, CmsModel } from \"~/types.js\";\nimport { i18n } from \"@webiny/app/i18n/index.js\";\nimport { useModelEditor } from \"~/admin/hooks/index.js\";\nimport { useModelFieldEditor } from \"~/admin/components/FieldEditor/useModelFieldEditor.js\";\nimport { useSnackbar } from \"@webiny/app-admin\";\nimport { Icon, IconButton, Text, DropdownMenu, Tag } from \"@webiny/admin-ui\";\n\nconst t = i18n.ns(\"app-headless-cms/admin/components/editor/field\");\n\nconst allowedTitleFieldTypes: string[] = [\"text\", \"number\"];\n\nconst isFieldAllowedToBeTitle = (model: CmsModel, field: CmsModelField, parent?: CmsModelField) => {\n if (field.list || parent) {\n return false;\n } else if (allowedTitleFieldTypes.includes(field.type) === false) {\n return false;\n } else if (model.titleFieldId === field.fieldId) {\n return false;\n }\n return true;\n};\nconst isFieldAllowedToBeDescription = (\n model: CmsModel,\n field: CmsModelField,\n parent?: CmsModelField\n) => {\n if (field.list || parent) {\n return false;\n } else if (model.descriptionFieldId === field.fieldId) {\n return false;\n }\n return field.type === \"long-text\";\n};\n\nconst isFieldAllowedToBeImage = (model: CmsModel, field: CmsModelField, parent?: CmsModelField) => {\n if (field.list || parent) {\n return false;\n } else if (model.imageFieldId === field.fieldId) {\n return false;\n }\n return field.type === \"file\" && field.settings?.imagesOnly;\n};\n\nconst getFieldTypeName = (\n model: CmsModel,\n field: CmsModelField,\n parent?: CmsModelField\n): string | null => {\n if (parent) {\n return null;\n }\n const isTitleField = field.fieldId === model?.titleFieldId && !parent;\n const isDescriptionField = field.fieldId === model?.descriptionFieldId && !parent;\n const isImageField = field.fieldId === model?.imageFieldId && !parent;\n\n return (\n [\n isTitleField ? \"entry title\" : null,\n isDescriptionField ? \"entry description\" : null,\n isImageField ? \"entry image\" : null\n ]\n .filter(Boolean)\n .join(\"\") || null\n );\n};\n\nexport interface FieldProps {\n field: CmsModelField;\n onDelete: (field: CmsModelField) => void;\n onEdit: (field: CmsModelField) => void;\n parent?: CmsModelField;\n}\n\nconst Field = (props: FieldProps) => {\n const { field, onEdit, parent } = props;\n const { showSnackbar, showErrorSnackbar } = useSnackbar();\n const { setData: setModel, data: model } = useModelEditor();\n const { getFieldType, getFieldRenderer } = useModelFieldEditor();\n\n const removeFieldFromSelected = useCallback(async () => {\n if (model.titleFieldId === field.fieldId) {\n await setModel(data => {\n return {\n ...data,\n titleFieldId: null\n };\n });\n } else if (model.descriptionFieldId === field.fieldId) {\n await setModel(data => {\n return {\n ...data,\n descriptionFieldId: null\n };\n });\n } else if (model.imageFieldId === field.fieldId) {\n await setModel(data => {\n return {\n ...data,\n imageFieldId: null\n };\n });\n }\n }, [field.id, setModel, model]);\n\n const onDelete = useCallback(async () => {\n await removeFieldFromSelected();\n props.onDelete(field);\n return;\n }, [field.fieldId]);\n\n const setAsTitle = useCallback(async (): Promise<void> => {\n const response = await setModel(data => {\n return { ...data, titleFieldId: field.fieldId };\n });\n\n if (response && response.error) {\n return showErrorSnackbar(response.error.message);\n }\n\n showSnackbar(t`Title field set successfully.`);\n }, [field.fieldId, setModel]);\n\n const setAsDescription = useCallback(async (): Promise<void> => {\n const response = await setModel(data => {\n return { ...data, descriptionFieldId: field.fieldId };\n });\n\n if (response && response.error) {\n return showErrorSnackbar(response.error.message);\n }\n\n showSnackbar(t`Description field set successfully.`);\n }, [field.fieldId, setModel]);\n\n const setAsImage = useCallback(async (): Promise<void> => {\n const response = await setModel(data => {\n return { ...data, imageFieldId: field.fieldId };\n });\n\n if (response && response.error) {\n return showErrorSnackbar(response.error.message);\n }\n\n showSnackbar(t`Image field set successfully.`);\n }, [field.fieldId, setModel]);\n\n const fieldType = getFieldType(field.type);\n const editorFieldOptionPlugins =\n plugins.byType<CmsEditorFieldOptionPlugin>(\"cms-editor-field-option\");\n\n if (!fieldType) {\n return null;\n }\n\n const renderer = getFieldRenderer(field.renderer.name);\n const canEdit = fieldType.canEditSettings !== false;\n\n const defaultInformationRenderer = useMemo(() => {\n const fieldTypeName = getFieldTypeName(model, field, parent);\n const fn = () => {\n if (!fieldTypeName) {\n return null;\n }\n return <Tag content={capitalize(fieldTypeName)} variant={\"neutral-light\"} />;\n };\n\n fn.displayName = \"FieldTypeRenderer\";\n\n return fn;\n }, [field.id]);\n\n const fieldInformationRenderer = fieldType.renderInfo;\n\n const info = [renderer?.name, field.list ? \"multiple values\" : null].filter(Boolean).join(\", \");\n\n return (\n <Fragment>\n <div className={\"flex items-center justify-between gap-sm-extra\"}>\n <div className={\"flex items-center gap-sm-extra flex-1 min-w-0\"}>\n <Icon\n icon={fieldType.icon}\n label={fieldType.label}\n size={\"md\"}\n color={\"neutral-light\"}\n />\n <div className={\"flex flex-col gap-xxs min-w-0\"}>\n <span\n className={\n \"text-md font-semibold text-neutral-primary truncate leading-5\"\n }\n >\n {field.label}\n </span>\n <Text size={\"sm\"} className={\"text-neutral-muted truncate\"}>\n {fieldType.label}\n {info && <span> / {info}</span>}\n </Text>\n </div>\n </div>\n <div className={\"flex items-center justify-end gap-xs shrink-0\"}>\n {fieldInformationRenderer\n ? fieldInformationRenderer({ model, field })\n : defaultInformationRenderer()}\n <DropdownMenu\n trigger={\n <IconButton icon={<MoreVerticalIcon />} variant={\"ghost\"} size={\"sm\"} />\n }\n >\n {canEdit && (\n <DropdownMenu.Item\n onClick={() => onEdit(field)}\n text={t`Edit`}\n icon={\n <DropdownMenu.Item.Icon\n element={<EditIcon />}\n label={t`Edit field`}\n />\n }\n />\n )}\n {editorFieldOptionPlugins.map(pl =>\n React.cloneElement(pl.render(), { key: pl.name })\n )}\n {/* We only allow this action for top-level fields. */}\n <DropdownMenu.Item\n disabled={!isFieldAllowedToBeTitle(model, field, parent)}\n onClick={setAsTitle}\n text={t`Use as title`}\n icon={\n <DropdownMenu.Item.Icon\n element={<TitleIcon />}\n label={t`Use as title`}\n />\n }\n />\n <DropdownMenu.Item\n disabled={!isFieldAllowedToBeDescription(model, field, parent)}\n onClick={setAsDescription}\n text={t`Use as description`}\n icon={\n <DropdownMenu.Item.Icon\n element={<TitleIcon />}\n label={t`Use as description`}\n />\n }\n />\n <DropdownMenu.Item\n disabled={!isFieldAllowedToBeImage(model, field, parent)}\n onClick={setAsImage}\n text={t`Use as image`}\n icon={\n <DropdownMenu.Item.Icon\n element={<TitleIcon />}\n label={t`Use as image`}\n />\n }\n />\n <DropdownMenu.Item\n onClick={onDelete}\n text={t`Delete`}\n icon={\n <DropdownMenu.Item.Icon\n element={<DeleteIcon />}\n label={t`Delete`}\n />\n }\n variant={\"destructive\"}\n />\n </DropdownMenu>\n </div>\n </div>\n {fieldType.renderEditor && (\n <div className={\"pt-md\"}>{fieldType.renderEditor({ field, model })}</div>\n )}\n </Fragment>\n );\n};\n\nexport default React.memo(Field);\n"],"names":["t","i18n","allowedTitleFieldTypes","isFieldAllowedToBeTitle","model","field","parent","isFieldAllowedToBeDescription","isFieldAllowedToBeImage","getFieldTypeName","isTitleField","isDescriptionField","isImageField","Boolean","Field","props","onEdit","showSnackbar","showErrorSnackbar","useSnackbar","setModel","useModelEditor","getFieldType","getFieldRenderer","useModelFieldEditor","removeFieldFromSelected","useCallback","data","onDelete","setAsTitle","response","setAsDescription","setAsImage","fieldType","editorFieldOptionPlugins","plugins","renderer","canEdit","defaultInformationRenderer","useMemo","fieldTypeName","fn","Tag","capitalize","fieldInformationRenderer","info","Fragment","Icon","Text","DropdownMenu","IconButton","MoreVerticalIcon","EditIcon","pl","React","TitleIcon","DeleteIcon"],"mappings":"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"}
1
+ {"version":3,"file":"admin/components/FieldEditor/Field.js","sources":["../../../../src/admin/components/FieldEditor/Field.tsx"],"sourcesContent":["import React, { Fragment, useCallback, useMemo } from \"react\";\nimport capitalize from \"lodash/capitalize.js\";\nimport { ReactComponent as EditIcon } from \"@webiny/icons/edit.svg\";\nimport { ReactComponent as DeleteIcon } from \"@webiny/icons/delete.svg\";\nimport { ReactComponent as TitleIcon } from \"@webiny/icons/title.svg\";\nimport { ReactComponent as MoreVerticalIcon } from \"@webiny/icons/more_vert.svg\";\nimport { plugins } from \"@webiny/plugins\";\nimport type { CmsModelField, CmsEditorFieldOptionPlugin, CmsModel } from \"~/types.js\";\nimport { i18n } from \"@webiny/app/i18n/index.js\";\nimport { useModelEditor } from \"~/admin/hooks/index.js\";\nimport { useModelFieldEditor } from \"~/admin/components/FieldEditor/useModelFieldEditor.js\";\nimport { useSnackbar } from \"@webiny/app-admin\";\nimport { Icon, IconButton, Text, DropdownMenu, Tag } from \"@webiny/admin-ui\";\n\nconst t = i18n.ns(\"app-headless-cms/admin/components/editor/field\");\n\nconst allowedTitleFieldTypes: string[] = [\"text\", \"number\"];\n\nconst isFieldAllowedToBeTitle = (model: CmsModel, field: CmsModelField, parent?: CmsModelField) => {\n if (field.list || parent) {\n return false;\n } else if (allowedTitleFieldTypes.includes(field.type) === false) {\n return false;\n } else if (model.titleFieldId === field.fieldId) {\n return false;\n }\n return true;\n};\nconst isFieldAllowedToBeDescription = (\n model: CmsModel,\n field: CmsModelField,\n parent?: CmsModelField\n) => {\n if (field.list || parent) {\n return false;\n } else if (model.descriptionFieldId === field.fieldId) {\n return false;\n }\n return field.type === \"long-text\";\n};\n\nconst isFieldAllowedToBeImage = (model: CmsModel, field: CmsModelField, parent?: CmsModelField) => {\n if (field.list || parent) {\n return false;\n } else if (model.imageFieldId === field.fieldId) {\n return false;\n }\n return field.type === \"file\" && field.settings?.imagesOnly;\n};\n\nconst getFieldTypeName = (\n model: CmsModel,\n field: CmsModelField,\n parent?: CmsModelField\n): string | null => {\n if (parent) {\n return null;\n }\n const isTitleField = field.fieldId === model?.titleFieldId && !parent;\n const isDescriptionField = field.fieldId === model?.descriptionFieldId && !parent;\n const isImageField = field.fieldId === model?.imageFieldId && !parent;\n\n return (\n [\n isTitleField ? \"entry title\" : null,\n isDescriptionField ? \"entry description\" : null,\n isImageField ? \"entry image\" : null\n ]\n .filter(Boolean)\n .join(\"\") || null\n );\n};\n\nexport interface FieldProps {\n field: CmsModelField;\n onDelete: (field: CmsModelField) => void;\n onEdit: (field: CmsModelField) => void;\n parent?: CmsModelField;\n}\n\nconst Field = (props: FieldProps) => {\n const { field, onEdit, parent } = props;\n const { showSnackbar, showErrorSnackbar } = useSnackbar();\n const { setData: setModel, data: model } = useModelEditor();\n const { getFieldType, getFieldRenderer } = useModelFieldEditor();\n\n const removeFieldFromSelected = useCallback(async () => {\n if (model.titleFieldId === field.fieldId) {\n await setModel(data => {\n return {\n ...data,\n titleFieldId: null\n };\n });\n } else if (model.descriptionFieldId === field.fieldId) {\n await setModel(data => {\n return {\n ...data,\n descriptionFieldId: null\n };\n });\n } else if (model.imageFieldId === field.fieldId) {\n await setModel(data => {\n return {\n ...data,\n imageFieldId: null\n };\n });\n }\n }, [field.id, setModel, model]);\n\n const onDelete = useCallback(async () => {\n await removeFieldFromSelected();\n props.onDelete(field);\n return;\n }, [field.fieldId]);\n\n const setAsTitle = useCallback(async (): Promise<void> => {\n const response = await setModel(data => {\n return { ...data, titleFieldId: field.fieldId };\n });\n\n if (response && response.error) {\n return showErrorSnackbar(response.error.message);\n }\n\n showSnackbar(t`Title field set successfully.`);\n }, [field.fieldId, setModel]);\n\n const setAsDescription = useCallback(async (): Promise<void> => {\n const response = await setModel(data => {\n return { ...data, descriptionFieldId: field.fieldId };\n });\n\n if (response && response.error) {\n return showErrorSnackbar(response.error.message);\n }\n\n showSnackbar(t`Description field set successfully.`);\n }, [field.fieldId, setModel]);\n\n const setAsImage = useCallback(async (): Promise<void> => {\n const response = await setModel(data => {\n return { ...data, imageFieldId: field.fieldId };\n });\n\n if (response && response.error) {\n return showErrorSnackbar(response.error.message);\n }\n\n showSnackbar(t`Image field set successfully.`);\n }, [field.fieldId, setModel]);\n\n const fieldType = getFieldType(field);\n const editorFieldOptionPlugins =\n plugins.byType<CmsEditorFieldOptionPlugin>(\"cms-editor-field-option\");\n\n if (!fieldType) {\n return null;\n }\n\n const renderer = getFieldRenderer(field.renderer.name);\n const canEdit = fieldType.canEditSettings !== false;\n\n const defaultInformationRenderer = useMemo(() => {\n const fieldTypeName = getFieldTypeName(model, field, parent);\n const fn = () => {\n if (!fieldTypeName) {\n return null;\n }\n return <Tag content={capitalize(fieldTypeName)} variant={\"neutral-light\"} />;\n };\n\n fn.displayName = \"FieldTypeRenderer\";\n\n return fn;\n }, [field.id]);\n\n const fieldInformationRenderer = fieldType.renderInfo;\n\n const info = [renderer?.name, field.list ? \"multiple values\" : null].filter(Boolean).join(\", \");\n\n return (\n <Fragment>\n <div className={\"flex items-center justify-between gap-sm-extra\"}>\n <div className={\"flex items-center gap-sm-extra flex-1 min-w-0\"}>\n <Icon\n icon={fieldType.icon}\n label={fieldType.label}\n size={\"md\"}\n color={\"neutral-light\"}\n />\n <div className={\"flex flex-col gap-xxs min-w-0\"}>\n <span\n className={\n \"text-md font-semibold text-neutral-primary truncate leading-5\"\n }\n >\n {field.label}\n </span>\n <Text size={\"sm\"} className={\"text-neutral-muted truncate\"}>\n {fieldType.label}\n {info && <span> / {info}</span>}\n </Text>\n </div>\n </div>\n <div className={\"flex items-center justify-end gap-xs shrink-0\"}>\n {fieldInformationRenderer\n ? fieldInformationRenderer({ model, field })\n : defaultInformationRenderer()}\n <DropdownMenu\n trigger={\n <IconButton icon={<MoreVerticalIcon />} variant={\"ghost\"} size={\"sm\"} />\n }\n >\n {canEdit && (\n <DropdownMenu.Item\n onClick={() => onEdit(field)}\n text={t`Edit`}\n icon={\n <DropdownMenu.Item.Icon\n element={<EditIcon />}\n label={t`Edit field`}\n />\n }\n />\n )}\n {editorFieldOptionPlugins.map(pl =>\n React.cloneElement(pl.render(), { key: pl.name })\n )}\n {/* We only allow this action for top-level fields. */}\n <DropdownMenu.Item\n disabled={!isFieldAllowedToBeTitle(model, field, parent)}\n onClick={setAsTitle}\n text={t`Use as title`}\n icon={\n <DropdownMenu.Item.Icon\n element={<TitleIcon />}\n label={t`Use as title`}\n />\n }\n />\n <DropdownMenu.Item\n disabled={!isFieldAllowedToBeDescription(model, field, parent)}\n onClick={setAsDescription}\n text={t`Use as description`}\n icon={\n <DropdownMenu.Item.Icon\n element={<TitleIcon />}\n label={t`Use as description`}\n />\n }\n />\n <DropdownMenu.Item\n disabled={!isFieldAllowedToBeImage(model, field, parent)}\n onClick={setAsImage}\n text={t`Use as image`}\n icon={\n <DropdownMenu.Item.Icon\n element={<TitleIcon />}\n label={t`Use as image`}\n />\n }\n />\n <DropdownMenu.Item\n onClick={onDelete}\n text={t`Delete`}\n icon={\n <DropdownMenu.Item.Icon\n element={<DeleteIcon />}\n label={t`Delete`}\n />\n }\n variant={\"destructive\"}\n />\n </DropdownMenu>\n </div>\n </div>\n {fieldType.renderEditor && (\n <div className={\"pt-md\"}>{fieldType.renderEditor({ field, model })}</div>\n )}\n </Fragment>\n );\n};\n\nexport default React.memo(Field);\n"],"names":["t","i18n","allowedTitleFieldTypes","isFieldAllowedToBeTitle","model","field","parent","isFieldAllowedToBeDescription","isFieldAllowedToBeImage","getFieldTypeName","isTitleField","isDescriptionField","isImageField","Boolean","Field","props","onEdit","showSnackbar","showErrorSnackbar","useSnackbar","setModel","useModelEditor","getFieldType","getFieldRenderer","useModelFieldEditor","removeFieldFromSelected","useCallback","data","onDelete","setAsTitle","response","setAsDescription","setAsImage","fieldType","editorFieldOptionPlugins","plugins","renderer","canEdit","defaultInformationRenderer","useMemo","fieldTypeName","fn","Tag","capitalize","fieldInformationRenderer","info","Fragment","Icon","Text","DropdownMenu","IconButton","MoreVerticalIcon","EditIcon","pl","React","TitleIcon","DeleteIcon"],"mappings":";;;;;;;;;;;;AAcA,MAAMA,IAAIC,KAAK,EAAE,CAAC;AAElB,MAAMC,yBAAmC;IAAC;IAAQ;CAAS;AAE3D,MAAMC,0BAA0B,CAACC,OAAiBC,OAAsBC;IACpE,IAAID,MAAM,IAAI,IAAIC,QACd,OAAO;IACJ,IAAIJ,AAAgD,UAAhDA,uBAAuB,QAAQ,CAACG,MAAM,IAAI,GACjD,OAAO;IACJ,IAAID,MAAM,YAAY,KAAKC,MAAM,OAAO,EAC3C,OAAO;IAEX,OAAO;AACX;AACA,MAAME,gCAAgC,CAClCH,OACAC,OACAC;IAEA,IAAID,MAAM,IAAI,IAAIC,QACd,OAAO;IACJ,IAAIF,MAAM,kBAAkB,KAAKC,MAAM,OAAO,EACjD,OAAO;IAEX,OAAOA,AAAe,gBAAfA,MAAM,IAAI;AACrB;AAEA,MAAMG,0BAA0B,CAACJ,OAAiBC,OAAsBC;IACpE,IAAID,MAAM,IAAI,IAAIC,QACd,OAAO;IACJ,IAAIF,MAAM,YAAY,KAAKC,MAAM,OAAO,EAC3C,OAAO;IAEX,OAAOA,AAAe,WAAfA,MAAM,IAAI,IAAeA,MAAM,QAAQ,EAAE;AACpD;AAEA,MAAMI,mBAAmB,CACrBL,OACAC,OACAC;IAEA,IAAIA,QACA,OAAO;IAEX,MAAMI,eAAeL,MAAM,OAAO,KAAKD,OAAO,gBAAgB,CAACE;IAC/D,MAAMK,qBAAqBN,MAAM,OAAO,KAAKD,OAAO,sBAAsB,CAACE;IAC3E,MAAMM,eAAeP,MAAM,OAAO,KAAKD,OAAO,gBAAgB,CAACE;IAE/D,OACI;QACII,eAAe,gBAAgB;QAC/BC,qBAAqB,sBAAsB;QAC3CC,eAAe,gBAAgB;KAClC,CACI,MAAM,CAACC,SACP,IAAI,CAAC,OAAO;AAEzB;AASA,MAAMC,QAAQ,CAACC;IACX,MAAM,EAAEV,KAAK,EAAEW,MAAM,EAAEV,MAAM,EAAE,GAAGS;IAClC,MAAM,EAAEE,YAAY,EAAEC,iBAAiB,EAAE,GAAGC;IAC5C,MAAM,EAAE,SAASC,QAAQ,EAAE,MAAMhB,KAAK,EAAE,GAAGiB;IAC3C,MAAM,EAAEC,YAAY,EAAEC,gBAAgB,EAAE,GAAGC;IAE3C,MAAMC,0BAA0BC,YAAY;QACxC,IAAItB,MAAM,YAAY,KAAKC,MAAM,OAAO,EACpC,MAAMe,SAASO,CAAAA,OACJ;gBACH,GAAGA,IAAI;gBACP,cAAc;YAClB;aAED,IAAIvB,MAAM,kBAAkB,KAAKC,MAAM,OAAO,EACjD,MAAMe,SAASO,CAAAA,OACJ;gBACH,GAAGA,IAAI;gBACP,oBAAoB;YACxB;aAED,IAAIvB,MAAM,YAAY,KAAKC,MAAM,OAAO,EAC3C,MAAMe,SAASO,CAAAA,OACJ;gBACH,GAAGA,IAAI;gBACP,cAAc;YAClB;IAGZ,GAAG;QAACtB,MAAM,EAAE;QAAEe;QAAUhB;KAAM;IAE9B,MAAMwB,WAAWF,YAAY;QACzB,MAAMD;QACNV,MAAM,QAAQ,CAACV;IAEnB,GAAG;QAACA,MAAM,OAAO;KAAC;IAElB,MAAMwB,aAAaH,YAAY;QAC3B,MAAMI,WAAW,MAAMV,SAASO,CAAAA,OACrB;gBAAE,GAAGA,IAAI;gBAAE,cAActB,MAAM,OAAO;YAAC;QAGlD,IAAIyB,YAAYA,SAAS,KAAK,EAC1B,OAAOZ,kBAAkBY,SAAS,KAAK,CAAC,OAAO;QAGnDb,aAAajB,CAAC,CAAC,6BAA6B,CAAC;IACjD,GAAG;QAACK,MAAM,OAAO;QAAEe;KAAS;IAE5B,MAAMW,mBAAmBL,YAAY;QACjC,MAAMI,WAAW,MAAMV,SAASO,CAAAA,OACrB;gBAAE,GAAGA,IAAI;gBAAE,oBAAoBtB,MAAM,OAAO;YAAC;QAGxD,IAAIyB,YAAYA,SAAS,KAAK,EAC1B,OAAOZ,kBAAkBY,SAAS,KAAK,CAAC,OAAO;QAGnDb,aAAajB,CAAC,CAAC,mCAAmC,CAAC;IACvD,GAAG;QAACK,MAAM,OAAO;QAAEe;KAAS;IAE5B,MAAMY,aAAaN,YAAY;QAC3B,MAAMI,WAAW,MAAMV,SAASO,CAAAA,OACrB;gBAAE,GAAGA,IAAI;gBAAE,cAActB,MAAM,OAAO;YAAC;QAGlD,IAAIyB,YAAYA,SAAS,KAAK,EAC1B,OAAOZ,kBAAkBY,SAAS,KAAK,CAAC,OAAO;QAGnDb,aAAajB,CAAC,CAAC,6BAA6B,CAAC;IACjD,GAAG;QAACK,MAAM,OAAO;QAAEe;KAAS;IAE5B,MAAMa,YAAYX,aAAajB;IAC/B,MAAM6B,2BACFC,QAAQ,MAAM,CAA6B;IAE/C,IAAI,CAACF,WACD,OAAO;IAGX,MAAMG,WAAWb,iBAAiBlB,MAAM,QAAQ,CAAC,IAAI;IACrD,MAAMgC,UAAUJ,AAA8B,UAA9BA,UAAU,eAAe;IAEzC,MAAMK,6BAA6BC,QAAQ;QACvC,MAAMC,gBAAgB/B,iBAAiBL,OAAOC,OAAOC;QACrD,MAAMmC,KAAK;YACP,IAAI,CAACD,eACD,OAAO;YAEX,OAAO,WAAP,GAAO,oBAACE,KAAGA;gBAAC,SAASC,WAAWH;gBAAgB,SAAS;;QAC7D;QAEAC,GAAG,WAAW,GAAG;QAEjB,OAAOA;IACX,GAAG;QAACpC,MAAM,EAAE;KAAC;IAEb,MAAMuC,2BAA2BX,UAAU,UAAU;IAErD,MAAMY,OAAO;QAACT,UAAU;QAAM/B,MAAM,IAAI,GAAG,oBAAoB;KAAK,CAAC,MAAM,CAACQ,SAAS,IAAI,CAAC;IAE1F,OAAO,WAAP,GACI,oBAACiC,UAAQA,MAAAA,WAAAA,GACL,oBAAC;QAAI,WAAW;qBACZ,oBAAC;QAAI,WAAW;qBACZ,oBAACC,MAAIA;QACD,MAAMd,UAAU,IAAI;QACpB,OAAOA,UAAU,KAAK;QACtB,MAAM;QACN,OAAO;sBAEX,oBAAC;QAAI,WAAW;qBACZ,oBAAC;QACG,WACI;OAGH5B,MAAM,KAAK,iBAEhB,oBAAC2C,MAAIA;QAAC,MAAM;QAAM,WAAW;OACxBf,UAAU,KAAK,EACfY,QAAQ,WAARA,GAAQ,oBAAC,cAAK,OAAIA,UAAAA,WAAAA,GAI/B,oBAAC;QAAI,WAAW;OACXD,2BACKA,yBAAyB;QAAExC;QAAOC;IAAM,KACxCiC,8BAAAA,WAAAA,GACN,oBAACW,cAAYA;QACT,uBACI,oBAACC,YAAUA;YAAC,oBAAM,oBAACC,8BAAgBA;YAAK,SAAS;YAAS,MAAM;;OAGnEd,WAAW,WAAXA,GACG,oBAACY,aAAa,IAAI;QACd,SAAS,IAAMjC,OAAOX;QACtB,MAAML,CAAC,CAAC,IAAI,CAAC;QACb,oBACI,oBAACiD,aAAa,IAAI,CAAC,IAAI;YACnB,uBAAS,oBAACG,gBAAQA;YAClB,OAAOpD,CAAC,CAAC,UAAU,CAAC;;QAKnCkC,yBAAyB,GAAG,CAACmB,CAAAA,KAAAA,WAAAA,GAC1BC,MAAAA,YAAkB,CAACD,GAAG,MAAM,IAAI;YAAE,KAAKA,GAAG,IAAI;QAAC,mBAGnD,oBAACJ,aAAa,IAAI;QACd,UAAU,CAAC9C,wBAAwBC,OAAOC,OAAOC;QACjD,SAASuB;QACT,MAAM7B,CAAC,CAAC,YAAY,CAAC;QACrB,oBACI,oBAACiD,aAAa,IAAI,CAAC,IAAI;YACnB,uBAAS,oBAACM,0BAASA;YACnB,OAAOvD,CAAC,CAAC,YAAY,CAAC;;sBAIlC,oBAACiD,aAAa,IAAI;QACd,UAAU,CAAC1C,8BAA8BH,OAAOC,OAAOC;QACvD,SAASyB;QACT,MAAM/B,CAAC,CAAC,kBAAkB,CAAC;QAC3B,oBACI,oBAACiD,aAAa,IAAI,CAAC,IAAI;YACnB,uBAAS,oBAACM,0BAASA;YACnB,OAAOvD,CAAC,CAAC,kBAAkB,CAAC;;sBAIxC,oBAACiD,aAAa,IAAI;QACd,UAAU,CAACzC,wBAAwBJ,OAAOC,OAAOC;QACjD,SAAS0B;QACT,MAAMhC,CAAC,CAAC,YAAY,CAAC;QACrB,oBACI,oBAACiD,aAAa,IAAI,CAAC,IAAI;YACnB,uBAAS,oBAACM,0BAASA;YACnB,OAAOvD,CAAC,CAAC,YAAY,CAAC;;sBAIlC,oBAACiD,aAAa,IAAI;QACd,SAASrB;QACT,MAAM5B,CAAC,CAAC,MAAM,CAAC;QACf,oBACI,oBAACiD,aAAa,IAAI,CAAC,IAAI;YACnB,uBAAS,oBAACO,2BAAUA;YACpB,OAAOxD,CAAC,CAAC,MAAM,CAAC;;QAGxB,SAAS;WAKxBiC,UAAU,YAAY,IAAI,WAAJ,GACnB,oBAAC;QAAI,WAAW;OAAUA,UAAU,YAAY,CAAC;QAAE5B;QAAOD;IAAM;AAIhF;AAEA,wCAAekD,MAAAA,IAAU,CAACxC"}
@@ -30,14 +30,14 @@ const Editor = ()=>{
30
30
  });
31
31
  };
32
32
  const canDropIntoField = (field, draggable)=>{
33
- const ft = getFieldType(field.type);
33
+ const ft = getFieldType(field);
34
34
  if (ft && "function" == typeof ft.canAccept && !ft.canAccept(field, draggable)) return false;
35
35
  return true;
36
36
  };
37
37
  const isVerticalDropzoneVisible = (cb)=>(item)=>{
38
38
  if ("newLayoutField" === item.type || "layoutField" === item.type) return false;
39
39
  if (!parent) return cb(item);
40
- const parentFieldType = getFieldType(parent.type);
40
+ const parentFieldType = getFieldType(parent);
41
41
  if (parentFieldType) {
42
42
  const allowLayout = parentFieldType.allowLayout ?? true;
43
43
  if (!allowLayout) return false;
@@ -1 +1 @@
1
- {"version":3,"file":"admin/components/FieldEditor/FieldEditor.js","sources":["../../../../src/admin/components/FieldEditor/FieldEditor.tsx"],"sourcesContent":["import React, { Fragment } from \"react\";\nimport get from \"lodash/get.js\";\nimport { i18n } from \"@webiny/app/i18n/index.js\";\nimport { ReactComponent as DragIcon } from \"@webiny/icons/drag_indicator.svg\";\nimport { Center, Horizontal, Vertical } from \"../DropZone/index.js\";\nimport Draggable from \"../Draggable.js\";\nimport EditFieldDialog from \"./EditFieldDialog.js\";\nimport Field from \"./Field.js\";\nimport { LayoutCell } from \"./LayoutCell.js\";\nimport { useModelFieldEditor } from \"./useModelFieldEditor.js\";\nimport type { IsVisibleCallable } from \"./FieldEditorContext.js\";\nimport { FieldEditorProvider } from \"./FieldEditorContext.js\";\nimport type { CmsEditorFieldsLayout, CmsModelField, CmsLayoutField, DragSource } from \"~/types.js\";\nimport { isLayoutField } from \"~/types.js\";\nimport { ModelFieldProvider } from \"~/admin/components/ModelFieldProvider/index.js\";\nimport { IconButton } from \"@webiny/admin-ui\";\n\nconst t = i18n.namespace(\"app-headless-cms/admin/components/editor\");\n\nconst fieldTypes: string[] = [\"field\", \"newField\"];\n\nconst Editor = () => {\n const {\n parent,\n depth,\n insertField,\n updateField,\n deleteField,\n fields,\n noConflict,\n editField,\n onFieldDrop,\n onEndDrag,\n field,\n dropTarget,\n getFieldType,\n getLayoutFieldType,\n getField\n } = useModelFieldEditor();\n\n /**\n * Collect all data fields referenced inside a layout descriptor (e.g. fields inside tabs).\n * Delegates to the layout field type's `collectFields` method if available.\n */\n const collectLayoutFieldFields = (layoutField: CmsLayoutField): CmsModelField[] => {\n const lft = getLayoutFieldType(layoutField.type);\n if (!lft || !lft.collectFields) {\n return [];\n }\n return lft.collectFields({\n field: layoutField,\n getField: (id: string) => getField({ id })\n });\n };\n\n const canDropIntoField = (field: CmsModelField, draggable: DragSource) => {\n const ft = getFieldType(field.type);\n if (ft && typeof ft.canAccept === \"function\" && !ft.canAccept(field, draggable)) {\n return false;\n }\n return true;\n };\n\n const isVerticalDropzoneVisible = (cb: IsVisibleCallable) => {\n return (item: DragSource) => {\n // Layout fields always occupy full row — no side-by-side layout\n if (item.type === \"newLayoutField\" || item.type === \"layoutField\") {\n return false;\n }\n\n if (!parent) {\n return cb(item);\n }\n\n const parentFieldType = getFieldType(parent.type);\n if (parentFieldType) {\n const allowLayout = parentFieldType.allowLayout ?? true;\n if (!allowLayout) {\n return false;\n }\n }\n\n if (!canDropIntoField(parent, item)) {\n return false;\n }\n\n return cb(item);\n };\n };\n\n const isHorizontalDropzoneVisible = (cb: IsVisibleCallable) => {\n return (item: DragSource) => {\n if (!parent) {\n return cb(item);\n }\n\n if (!canDropIntoField(parent, item)) {\n return false;\n }\n\n return cb(item);\n };\n };\n\n return (\n <Fragment>\n {fields.length === 0 && (\n <Center\n isDroppable={isHorizontalDropzoneVisible(() => true)}\n onDrop={item =>\n onFieldDrop(item, {\n row: 0,\n index: 0\n })\n }\n >\n {t`Drop your first field here`}\n </Center>\n )}\n\n {fields.map((row, index) => {\n // Build a stable key for the row\n const rowKey = row\n .map(cell => (isLayoutField(cell) ? cell.id : (cell as CmsModelField).fieldId))\n .join(\".\");\n\n return (\n <Draggable\n beginDrag={{\n parent: parent ? parent.fieldId : null,\n type: \"row\",\n fields: row.filter(cell => !isLayoutField(cell)) as CmsModelField[],\n pos: { row: index }\n }}\n endDrag={onEndDrag}\n key={rowKey}\n >\n {(\n {\n drag,\n isDragging\n } /* RowContainer start - includes drag handle, drop zones and the Row itself. */\n ) => (\n <div\n className={`group flex flex-column relative mb-sm-extra last-of-type:mb-none ${isDragging ? \"opacity-50\" : \"opacity-100\"}`}\n >\n <div\n className={\n \"cursor-grab absolute left-[0] top-1/2 -translate-y-1/2 z-10 invisible group-hover:visible\"\n }\n ref={element => {\n drag(element);\n }}\n >\n <IconButton\n icon={<DragIcon />}\n variant={\"secondary\"}\n size={\"xs\"}\n />\n </div>\n <Horizontal\n isVisible={isHorizontalDropzoneVisible(noConflict())}\n data-testid={`cms-editor-row-droppable-top-${index}`}\n onDrop={item => onFieldDrop(item, { row: index, index: null })}\n />\n {/* Row start - includes field drop zones and fields */}\n <div\n className={\"w-full flex justify-between gap-x-sm-extra\"}\n data-testid={\"cms.editor.field-row\"}\n >\n {row.map((cell, fieldIndex) => {\n if (isLayoutField(cell)) {\n return (\n <Draggable\n key={cell.id}\n beginDrag={{\n parent: parent ? parent.fieldId : null,\n type: \"layoutField\",\n layoutField: cell,\n fields: collectLayoutFieldFields(cell)\n }}\n endDrag={onEndDrag}\n >\n {({ drag }) => (\n <div\n ref={element => {\n drag(element);\n }}\n className={\"relative flex-1 min-w-0\"}\n >\n <div\n className={\n \"cursor-grab bg-neutral-base drop-shadow-[0px_1px_2px_rgba(0,0,0,0.05)] rounded-lg pl-md pr-sm py-sm\"\n }\n >\n <LayoutCell\n field={cell}\n rowIndex={index}\n cellIndex={fieldIndex}\n />\n </div>\n </div>\n )}\n </Draggable>\n );\n }\n\n const field = cell as CmsModelField;\n return (\n <ModelFieldProvider field={field} key={field.fieldId}>\n <Draggable\n beginDrag={{\n parent: parent ? parent.fieldId : null,\n type: \"field\",\n field,\n pos: {\n row: index,\n index: fieldIndex\n }\n }}\n endDrag={onEndDrag}\n >\n {({ drag }) => (\n <div\n className={\"relative flex-1 min-w-0\"}\n ref={element => {\n drag(element);\n }}\n >\n <Vertical\n depth={depth}\n onDrop={item =>\n onFieldDrop(item, {\n row: index,\n index: fieldIndex\n })\n }\n isVisible={isVerticalDropzoneVisible(\n noConflict(\n item =>\n fieldTypes.includes(\n item.type\n ) &&\n (row.length < 4 ||\n get(\n item,\n \"pos.row\"\n ) === index)\n )\n )}\n />\n\n <div\n className={\n \"cursor-grab bg-neutral-base drop-shadow-[0px_1px_2px_rgba(0,0,0,0.05)] rounded-lg pl-md pr-sm py-sm\"\n }\n >\n <Field\n parent={parent}\n field={field}\n onEdit={editField}\n onDelete={deleteField}\n />\n </div>\n\n {/* Field end */}\n {fieldIndex === row.length - 1 && (\n <Vertical\n last\n depth={depth}\n isVisible={isVerticalDropzoneVisible(\n noConflict(item => {\n return (\n fieldTypes.includes(\n item.type\n ) &&\n (row.length < 4 ||\n get(\n item,\n \"pos.row\"\n ) === index)\n );\n })\n )}\n onDrop={item =>\n onFieldDrop(item, {\n row: index,\n index: fieldIndex + 1\n })\n }\n />\n )}\n </div>\n )}\n </Draggable>\n </ModelFieldProvider>\n );\n })}\n </div>\n {/* Row end */}\n {index === fields.length - 1 ? (\n <Horizontal\n data-testid={`cms-editor-row-droppable-bottom-${index}`}\n last\n isVisible={isHorizontalDropzoneVisible(noConflict())}\n onDrop={item =>\n onFieldDrop(item, {\n row: index + 1,\n index: null\n })\n }\n />\n ) : null}\n </div>\n )}\n </Draggable>\n );\n })}\n\n {field ? (\n <ModelFieldProvider field={field}>\n <EditFieldDialog\n onClose={() => editField(null)}\n onSubmit={field => {\n if (field.id) {\n updateField(field);\n editField(null);\n return;\n }\n insertField({ field, position: dropTarget });\n\n editField(null);\n }}\n />\n </ModelFieldProvider>\n ) : null}\n </Fragment>\n );\n};\n\nexport interface FieldEditorProps {\n parent?: CmsModelField;\n layout: CmsEditorFieldsLayout;\n fields: CmsModelField[];\n onChange: (params: { fields: CmsModelField[]; layout: CmsEditorFieldsLayout }) => void;\n}\n\nexport const FieldEditor = (props: FieldEditorProps) => {\n return (\n <FieldEditorProvider {...props}>\n <Editor />\n </FieldEditorProvider>\n );\n};\n"],"names":["t","i18n","fieldTypes","Editor","parent","depth","insertField","updateField","deleteField","fields","noConflict","editField","onFieldDrop","onEndDrag","field","dropTarget","getFieldType","getLayoutFieldType","getField","useModelFieldEditor","collectLayoutFieldFields","layoutField","lft","id","canDropIntoField","draggable","ft","isVerticalDropzoneVisible","cb","item","parentFieldType","allowLayout","isHorizontalDropzoneVisible","Fragment","Center","row","index","rowKey","cell","isLayoutField","Draggable","drag","isDragging","element","IconButton","DragIcon","Horizontal","fieldIndex","LayoutCell","ModelFieldProvider","Vertical","get","Field","EditFieldDialog","FieldEditor","props","FieldEditorProvider"],"mappings":"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"}
1
+ {"version":3,"file":"admin/components/FieldEditor/FieldEditor.js","sources":["../../../../src/admin/components/FieldEditor/FieldEditor.tsx"],"sourcesContent":["import React, { Fragment } from \"react\";\nimport get from \"lodash/get.js\";\nimport { i18n } from \"@webiny/app/i18n/index.js\";\nimport { ReactComponent as DragIcon } from \"@webiny/icons/drag_indicator.svg\";\nimport { Center, Horizontal, Vertical } from \"../DropZone/index.js\";\nimport Draggable from \"../Draggable.js\";\nimport EditFieldDialog from \"./EditFieldDialog.js\";\nimport Field from \"./Field.js\";\nimport { LayoutCell } from \"./LayoutCell.js\";\nimport { useModelFieldEditor } from \"./useModelFieldEditor.js\";\nimport type { IsVisibleCallable } from \"./FieldEditorContext.js\";\nimport { FieldEditorProvider } from \"./FieldEditorContext.js\";\nimport type { CmsEditorFieldsLayout, CmsModelField, CmsLayoutField, DragSource } from \"~/types.js\";\nimport { isLayoutField } from \"~/types.js\";\nimport { ModelFieldProvider } from \"~/admin/components/ModelFieldProvider/index.js\";\nimport { IconButton } from \"@webiny/admin-ui\";\n\nconst t = i18n.namespace(\"app-headless-cms/admin/components/editor\");\n\nconst fieldTypes: string[] = [\"field\", \"newField\"];\n\nconst Editor = () => {\n const {\n parent,\n depth,\n insertField,\n updateField,\n deleteField,\n fields,\n noConflict,\n editField,\n onFieldDrop,\n onEndDrag,\n field,\n dropTarget,\n getFieldType,\n getLayoutFieldType,\n getField\n } = useModelFieldEditor();\n\n /**\n * Collect all data fields referenced inside a layout descriptor (e.g. fields inside tabs).\n * Delegates to the layout field type's `collectFields` method if available.\n */\n const collectLayoutFieldFields = (layoutField: CmsLayoutField): CmsModelField[] => {\n const lft = getLayoutFieldType(layoutField.type);\n if (!lft || !lft.collectFields) {\n return [];\n }\n return lft.collectFields({\n field: layoutField,\n getField: (id: string) => getField({ id })\n });\n };\n\n const canDropIntoField = (field: CmsModelField, draggable: DragSource) => {\n const ft = getFieldType(field);\n if (ft && typeof ft.canAccept === \"function\" && !ft.canAccept(field, draggable)) {\n return false;\n }\n return true;\n };\n\n const isVerticalDropzoneVisible = (cb: IsVisibleCallable) => {\n return (item: DragSource) => {\n // Layout fields always occupy full row — no side-by-side layout\n if (item.type === \"newLayoutField\" || item.type === \"layoutField\") {\n return false;\n }\n\n if (!parent) {\n return cb(item);\n }\n\n const parentFieldType = getFieldType(parent);\n if (parentFieldType) {\n const allowLayout = parentFieldType.allowLayout ?? true;\n if (!allowLayout) {\n return false;\n }\n }\n\n if (!canDropIntoField(parent, item)) {\n return false;\n }\n\n return cb(item);\n };\n };\n\n const isHorizontalDropzoneVisible = (cb: IsVisibleCallable) => {\n return (item: DragSource) => {\n if (!parent) {\n return cb(item);\n }\n\n if (!canDropIntoField(parent, item)) {\n return false;\n }\n\n return cb(item);\n };\n };\n\n return (\n <Fragment>\n {fields.length === 0 && (\n <Center\n isDroppable={isHorizontalDropzoneVisible(() => true)}\n onDrop={item =>\n onFieldDrop(item, {\n row: 0,\n index: 0\n })\n }\n >\n {t`Drop your first field here`}\n </Center>\n )}\n\n {fields.map((row, index) => {\n // Build a stable key for the row\n const rowKey = row\n .map(cell => (isLayoutField(cell) ? cell.id : (cell as CmsModelField).fieldId))\n .join(\".\");\n\n return (\n <Draggable\n beginDrag={{\n parent: parent ? parent.fieldId : null,\n type: \"row\",\n fields: row.filter(cell => !isLayoutField(cell)) as CmsModelField[],\n pos: { row: index }\n }}\n endDrag={onEndDrag}\n key={rowKey}\n >\n {(\n {\n drag,\n isDragging\n } /* RowContainer start - includes drag handle, drop zones and the Row itself. */\n ) => (\n <div\n className={`group flex flex-column relative mb-sm-extra last-of-type:mb-none ${isDragging ? \"opacity-50\" : \"opacity-100\"}`}\n >\n <div\n className={\n \"cursor-grab absolute left-[0] top-1/2 -translate-y-1/2 z-10 invisible group-hover:visible\"\n }\n ref={element => {\n drag(element);\n }}\n >\n <IconButton\n icon={<DragIcon />}\n variant={\"secondary\"}\n size={\"xs\"}\n />\n </div>\n <Horizontal\n isVisible={isHorizontalDropzoneVisible(noConflict())}\n data-testid={`cms-editor-row-droppable-top-${index}`}\n onDrop={item => onFieldDrop(item, { row: index, index: null })}\n />\n {/* Row start - includes field drop zones and fields */}\n <div\n className={\"w-full flex justify-between gap-x-sm-extra\"}\n data-testid={\"cms.editor.field-row\"}\n >\n {row.map((cell, fieldIndex) => {\n if (isLayoutField(cell)) {\n return (\n <Draggable\n key={cell.id}\n beginDrag={{\n parent: parent ? parent.fieldId : null,\n type: \"layoutField\",\n layoutField: cell,\n fields: collectLayoutFieldFields(cell)\n }}\n endDrag={onEndDrag}\n >\n {({ drag }) => (\n <div\n ref={element => {\n drag(element);\n }}\n className={\"relative flex-1 min-w-0\"}\n >\n <div\n className={\n \"cursor-grab bg-neutral-base drop-shadow-[0px_1px_2px_rgba(0,0,0,0.05)] rounded-lg pl-md pr-sm py-sm\"\n }\n >\n <LayoutCell\n field={cell}\n rowIndex={index}\n cellIndex={fieldIndex}\n />\n </div>\n </div>\n )}\n </Draggable>\n );\n }\n\n const field = cell as CmsModelField;\n return (\n <ModelFieldProvider field={field} key={field.fieldId}>\n <Draggable\n beginDrag={{\n parent: parent ? parent.fieldId : null,\n type: \"field\",\n field,\n pos: {\n row: index,\n index: fieldIndex\n }\n }}\n endDrag={onEndDrag}\n >\n {({ drag }) => (\n <div\n className={\"relative flex-1 min-w-0\"}\n ref={element => {\n drag(element);\n }}\n >\n <Vertical\n depth={depth}\n onDrop={item =>\n onFieldDrop(item, {\n row: index,\n index: fieldIndex\n })\n }\n isVisible={isVerticalDropzoneVisible(\n noConflict(\n item =>\n fieldTypes.includes(\n item.type\n ) &&\n (row.length < 4 ||\n get(\n item,\n \"pos.row\"\n ) === index)\n )\n )}\n />\n\n <div\n className={\n \"cursor-grab bg-neutral-base drop-shadow-[0px_1px_2px_rgba(0,0,0,0.05)] rounded-lg pl-md pr-sm py-sm\"\n }\n >\n <Field\n parent={parent}\n field={field}\n onEdit={editField}\n onDelete={deleteField}\n />\n </div>\n\n {/* Field end */}\n {fieldIndex === row.length - 1 && (\n <Vertical\n last\n depth={depth}\n isVisible={isVerticalDropzoneVisible(\n noConflict(item => {\n return (\n fieldTypes.includes(\n item.type\n ) &&\n (row.length < 4 ||\n get(\n item,\n \"pos.row\"\n ) === index)\n );\n })\n )}\n onDrop={item =>\n onFieldDrop(item, {\n row: index,\n index: fieldIndex + 1\n })\n }\n />\n )}\n </div>\n )}\n </Draggable>\n </ModelFieldProvider>\n );\n })}\n </div>\n {/* Row end */}\n {index === fields.length - 1 ? (\n <Horizontal\n data-testid={`cms-editor-row-droppable-bottom-${index}`}\n last\n isVisible={isHorizontalDropzoneVisible(noConflict())}\n onDrop={item =>\n onFieldDrop(item, {\n row: index + 1,\n index: null\n })\n }\n />\n ) : null}\n </div>\n )}\n </Draggable>\n );\n })}\n\n {field ? (\n <ModelFieldProvider field={field}>\n <EditFieldDialog\n onClose={() => editField(null)}\n onSubmit={field => {\n if (field.id) {\n updateField(field);\n editField(null);\n return;\n }\n insertField({ field, position: dropTarget });\n\n editField(null);\n }}\n />\n </ModelFieldProvider>\n ) : null}\n </Fragment>\n );\n};\n\nexport interface FieldEditorProps {\n parent?: CmsModelField;\n layout: CmsEditorFieldsLayout;\n fields: CmsModelField[];\n onChange: (params: { fields: CmsModelField[]; layout: CmsEditorFieldsLayout }) => void;\n}\n\nexport const FieldEditor = (props: FieldEditorProps) => {\n return (\n <FieldEditorProvider {...props}>\n <Editor />\n </FieldEditorProvider>\n );\n};\n"],"names":["t","i18n","fieldTypes","Editor","parent","depth","insertField","updateField","deleteField","fields","noConflict","editField","onFieldDrop","onEndDrag","field","dropTarget","getFieldType","getLayoutFieldType","getField","useModelFieldEditor","collectLayoutFieldFields","layoutField","lft","id","canDropIntoField","draggable","ft","isVerticalDropzoneVisible","cb","item","parentFieldType","allowLayout","isHorizontalDropzoneVisible","Fragment","Center","row","index","rowKey","cell","isLayoutField","Draggable","drag","isDragging","element","IconButton","DragIcon","Horizontal","fieldIndex","LayoutCell","ModelFieldProvider","Vertical","get","Field","EditFieldDialog","FieldEditor","props","FieldEditorProvider"],"mappings":"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"}
@@ -87,7 +87,7 @@ export interface FieldEditorContext {
87
87
  layout: CmsEditorFieldsLayout;
88
88
  onChange?: (data: any) => void;
89
89
  getFieldsInLayout: GetFieldsInLayoutCallable;
90
- getFieldType: (type: string) => ICmsFieldType | undefined;
90
+ getFieldType: (typeOrField: string | CmsModelField) => ICmsFieldType | undefined;
91
91
  getField: GetFieldCallable;
92
92
  getFieldRenderer: GetFieldRendererCallable;
93
93
  editField: (field: CmsModelField | null) => void;
@@ -335,7 +335,12 @@ const FieldEditorProvider = ({ parent, fields, layout, onChange, children })=>{
335
335
  parentEditorContext,
336
336
  depth,
337
337
  getFieldsInLayout,
338
- getFieldType: (type)=>fieldTypesMap.get(type),
338
+ getFieldType: (typeOrField)=>{
339
+ if ("string" == typeof typeOrField) return fieldTypesMap.get(typeOrField);
340
+ const field = typeOrField;
341
+ for (const ft of fieldTypesMap.values())if (ft.matches?.(field)) return ft;
342
+ return fieldTypesMap.get(field.type);
343
+ },
339
344
  getFieldRenderer,
340
345
  getField,
341
346
  editField,