@strapi/admin 4.5.0-alpha.0 → 4.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (317) hide show
  1. package/admin/src/StrapiApp.js +21 -18
  2. package/admin/src/assets/images/hot-air-balloon.png +0 -0
  3. package/admin/src/assets/images/icon_offline-cloud.svg +3 -3
  4. package/admin/src/assets/images/logo-strapi-2022.svg +7 -0
  5. package/admin/src/assets/images/upgrade-details.png +0 -0
  6. package/admin/src/components/Providers/index.js +14 -10
  7. package/admin/src/content-manager/components/CollectionTypeFormWrapper/index.js +24 -0
  8. package/admin/src/content-manager/components/DynamicTable/CellContent/CellValue.js +1 -1
  9. package/admin/src/content-manager/components/DynamicTable/CellContent/RelationMultiple/index.js +5 -4
  10. package/admin/src/content-manager/components/DynamicTable/CellContent/index.js +10 -0
  11. package/admin/src/content-manager/components/DynamicTable/TableRows/index.js +20 -15
  12. package/admin/src/content-manager/components/DynamicTable/index.js +21 -4
  13. package/admin/src/content-manager/components/DynamicZone/components/Component/index.js +19 -9
  14. package/admin/src/content-manager/components/DynamicZone/index.js +6 -2
  15. package/admin/src/content-manager/components/EditViewDataManagerProvider/index.js +153 -63
  16. package/admin/src/content-manager/components/EditViewDataManagerProvider/reducer.js +180 -132
  17. package/admin/src/content-manager/components/EditViewDataManagerProvider/utils/cleanData.js +70 -16
  18. package/admin/src/content-manager/components/EditViewDataManagerProvider/utils/findLeafByPathAndReplace.js +52 -0
  19. package/admin/src/content-manager/components/EditViewDataManagerProvider/utils/index.js +2 -0
  20. package/admin/src/content-manager/components/EditViewDataManagerProvider/utils/recursivelyFindPathsBasedOnCondition.js +72 -0
  21. package/admin/src/content-manager/components/FieldComponent/index.js +9 -2
  22. package/admin/src/content-manager/components/FieldTypeIcon/index.js +31 -1
  23. package/admin/src/content-manager/components/Inputs/index.js +36 -14
  24. package/admin/src/content-manager/components/NonRepeatableComponent/index.js +2 -0
  25. package/admin/src/content-manager/components/PreviewWysiwyg/index.js +1 -1
  26. package/admin/src/content-manager/components/RelationInput/RelationInput.js +163 -96
  27. package/admin/src/content-manager/components/RelationInput/components/RelationItem.js +2 -2
  28. package/admin/src/content-manager/components/RelationInput/constants.js +1 -1
  29. package/admin/src/content-manager/components/RelationInputDataManager/RelationInputDataManager.js +116 -73
  30. package/admin/src/content-manager/components/RelationInputDataManager/utils/diffRelations.js +24 -0
  31. package/admin/src/content-manager/components/RelationInputDataManager/utils/index.js +3 -1
  32. package/admin/src/content-manager/components/RelationInputDataManager/utils/normalizeRelations.js +17 -31
  33. package/admin/src/content-manager/components/RelationInputDataManager/utils/normalizeSearchResults.js +16 -0
  34. package/admin/src/content-manager/components/RelationInputDataManager/utils/select.js +35 -11
  35. package/admin/src/content-manager/components/RepeatableComponent/DraggedItem/index.js +5 -0
  36. package/admin/src/content-manager/components/RepeatableComponent/index.js +4 -3
  37. package/admin/src/content-manager/components/SingleTypeFormWrapper/index.js +23 -0
  38. package/admin/src/content-manager/hooks/__test__/usePrev.test.js +26 -0
  39. package/admin/src/content-manager/hooks/index.js +1 -0
  40. package/admin/src/content-manager/hooks/useFetchContentTypeLayout/utils/formatLayouts.js +19 -48
  41. package/admin/src/content-manager/hooks/usePrev.js +14 -0
  42. package/admin/src/content-manager/hooks/useRelation/useRelation.js +116 -15
  43. package/admin/src/content-manager/pages/App/reducer.js +3 -0
  44. package/admin/src/content-manager/pages/EditSettingsView/components/FormModal.js +7 -2
  45. package/admin/src/content-manager/pages/EditSettingsView/index.js +2 -1
  46. package/admin/src/content-manager/pages/EditView/Header/index.js +118 -50
  47. package/admin/src/content-manager/pages/EditView/Header/utils/select.js +4 -0
  48. package/admin/src/content-manager/pages/EditView/index.js +102 -93
  49. package/admin/src/content-manager/pages/ListSettingsView/components/DraggableCard.js +3 -3
  50. package/admin/src/content-manager/pages/ListSettingsView/components/Settings.js +2 -2
  51. package/admin/src/content-manager/pages/ListSettingsView/components/SortDisplayedFields.js +1 -1
  52. package/admin/src/content-manager/pages/ListView/index.js +24 -15
  53. package/admin/src/content-manager/pages/ListView/utils/buildQueryString.js +14 -2
  54. package/admin/src/contexts/ApiTokenPermissions/index.js +24 -0
  55. package/admin/src/core/apis/CustomFields.js +79 -0
  56. package/admin/src/core/apis/index.js +1 -0
  57. package/admin/src/core/store/configureStore.js +17 -2
  58. package/admin/src/favicon.png +0 -0
  59. package/admin/src/hooks/index.js +1 -0
  60. package/admin/src/hooks/useFetchMarketplacePlugins/index.js +2 -2
  61. package/admin/src/hooks/useFetchMarketplacePlugins/utils/api.js +4 -2
  62. package/admin/src/hooks/useFetchMarketplaceProviders/index.js +3 -3
  63. package/admin/src/hooks/useFetchMarketplaceProviders/utils/api.js +5 -3
  64. package/admin/src/hooks/useRegenerate/index.js +34 -0
  65. package/admin/src/index.js +1 -0
  66. package/admin/src/pages/App/index.js +1 -1
  67. package/admin/src/pages/HomePage/SocialLinks.js +1 -1
  68. package/admin/src/pages/HomePage/assets/corner-ornament.svg +48 -0
  69. package/admin/src/pages/HomePage/index.js +3 -2
  70. package/admin/src/pages/MarketplacePage/components/NpmPackageCard/CardButton.js +110 -0
  71. package/admin/src/pages/MarketplacePage/components/NpmPackageCard/InstallPluginButton.js +32 -21
  72. package/admin/src/pages/MarketplacePage/components/NpmPackageCard/PackageStats.js +79 -0
  73. package/admin/src/pages/MarketplacePage/components/NpmPackageCard/index.js +28 -11
  74. package/admin/src/pages/MarketplacePage/components/NpmPackagesFilters/FilterSelect.js +41 -0
  75. package/admin/src/pages/MarketplacePage/components/NpmPackagesFilters/FiltersPopover.js +96 -0
  76. package/admin/src/pages/MarketplacePage/components/NpmPackagesFilters/index.js +106 -0
  77. package/admin/src/pages/MarketplacePage/components/NpmPackagesGrid/index.js +4 -0
  78. package/admin/src/pages/MarketplacePage/components/SortSelect/index.js +70 -0
  79. package/admin/src/pages/MarketplacePage/index.js +68 -8
  80. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/ActionBoundRoutes/index.js +56 -0
  81. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/BoundRoute/getMethodColor.js +41 -0
  82. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/BoundRoute/index.js +72 -0
  83. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/CollapsableContentType/CheckBoxWrapper.js +30 -0
  84. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/CollapsableContentType/index.js +150 -0
  85. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/ContenTypesSection/index.js +37 -0
  86. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/FormApiTokenContainer/index.js +255 -0
  87. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/FormBody/index.js +78 -0
  88. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/FormHead/index.js +89 -0
  89. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/Permissions/index.js +40 -0
  90. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/Regenerate/index.js +68 -0
  91. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/index.js +216 -197
  92. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/init.js +13 -0
  93. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/reducer.js +72 -0
  94. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/utils/getDateOfExpiration.js +16 -0
  95. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/utils/index.js +5 -0
  96. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/utils/schema.js +2 -1
  97. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/utils/transformPermissionsData.js +36 -0
  98. package/admin/src/pages/SettingsPage/pages/ApiTokens/ListView/DynamicTable/DefaultButton/index.js +63 -0
  99. package/admin/src/pages/SettingsPage/pages/ApiTokens/ListView/DynamicTable/DeleteButton/index.js +1 -0
  100. package/admin/src/pages/SettingsPage/pages/ApiTokens/ListView/DynamicTable/ReadButton/index.js +19 -0
  101. package/admin/src/pages/SettingsPage/pages/ApiTokens/ListView/DynamicTable/UpdateButton/index.js +3 -36
  102. package/admin/src/pages/SettingsPage/pages/ApiTokens/ListView/DynamicTable/index.js +13 -11
  103. package/admin/src/pages/SettingsPage/pages/ApiTokens/ListView/index.js +3 -2
  104. package/admin/src/pages/SettingsPage/pages/ApiTokens/ListView/utils/tableHeaders.js +8 -8
  105. package/admin/src/pages/SettingsPage/pages/ApiTokens/ProtectedEditView/index.js +1 -1
  106. package/admin/src/pages/SettingsPage/pages/Roles/EditPage/components/ConditionsModal/ActionRow/index.js +7 -38
  107. package/admin/src/pages/SettingsPage/pages/Roles/EditPage/components/ConditionsModal/ActionRow/utils/options.js +31 -0
  108. package/admin/src/pages/SettingsPage/pages/Roles/EditPage/components/ConditionsModal/index.js +32 -43
  109. package/admin/src/pages/SettingsPage/pages/Roles/EditPage/components/ContentTypeCollapse/Collapse/index.js +1 -1
  110. package/admin/src/pages/SettingsPage/pages/Roles/ListPage/components/RoleRow/index.js +3 -1
  111. package/admin/src/pages/SettingsPage/pages/Roles/ListPage/index.js +2 -1
  112. package/admin/src/pages/SettingsPage/pages/Users/ListPage/ModalForm/index.js +2 -2
  113. package/admin/src/pages/SettingsPage/pages/Webhooks/EditView/components/EventInput/index.js +2 -2
  114. package/admin/src/permissions/defaultPermissions.js +2 -6
  115. package/admin/src/translations/ca.json +4 -2
  116. package/admin/src/translations/de.json +5 -2
  117. package/admin/src/translations/dk.json +4 -1
  118. package/admin/src/translations/en.json +38 -3
  119. package/admin/src/translations/es.json +157 -158
  120. package/admin/src/translations/fr.json +4 -1
  121. package/admin/src/translations/gu.json +608 -606
  122. package/admin/src/translations/he.json +1 -1
  123. package/admin/src/translations/hi.json +689 -687
  124. package/admin/src/translations/hu.json +3 -1
  125. package/admin/src/translations/id.json +3 -1
  126. package/admin/src/translations/it.json +3 -1
  127. package/admin/src/translations/ja.json +3 -1
  128. package/admin/src/translations/ko.json +3 -1
  129. package/admin/src/translations/ml.json +689 -687
  130. package/admin/src/translations/nl.json +4 -1
  131. package/admin/src/translations/no.json +1 -1
  132. package/admin/src/translations/pl.json +3 -1
  133. package/admin/src/translations/pt-BR.json +4 -1
  134. package/admin/src/translations/ru.json +489 -491
  135. package/admin/src/translations/sa.json +86 -83
  136. package/admin/src/translations/sk.json +4 -1
  137. package/admin/src/translations/sv.json +4 -1
  138. package/admin/src/translations/th.json +1 -1
  139. package/admin/src/translations/zh-Hans.json +5 -2
  140. package/admin/src/translations/zh.json +4 -1
  141. package/build/1856.172d5fa0.chunk.js +174 -0
  142. package/build/2077.058590f4.chunk.js +206 -0
  143. package/build/2912.2c42c07b.chunk.js +259 -0
  144. package/build/4318.5e670740.chunk.js +30 -0
  145. package/build/4715.22747b59.chunk.js +387 -0
  146. package/build/{4800.d09f1225.chunk.js → 4800.a6935af6.chunk.js} +1 -1
  147. package/build/4982.1b75ddb1.chunk.js +325 -0
  148. package/build/617f9c948fa79e6d73bd.png +0 -0
  149. package/build/6d21938306785f176538.png +0 -0
  150. package/build/70674f63fc3904c20de0.svg +7 -0
  151. package/build/7379.d246dd38.chunk.js +1 -0
  152. package/build/7692.a36fb2c2.chunk.js +470 -0
  153. package/build/7841.c50e9509.chunk.js +259 -0
  154. package/build/7866.ba215f99.chunk.js +505 -0
  155. package/build/7e9af4fb7e723fcebf1f.svg +48 -0
  156. package/build/8380.e53e7207.chunk.js +299 -0
  157. package/build/8549.832ed79d.chunk.js +159 -0
  158. package/build/8738.0fe8a61e.chunk.js +463 -0
  159. package/build/{9066.08049eb1.chunk.js → 9066.eaf76ff3.chunk.js} +5 -5
  160. package/build/{9166.037339e0.chunk.js → 9166.90876521.chunk.js} +16 -15
  161. package/build/{9420.43a86e7c.chunk.js → 9420.5292d1d2.chunk.js} +38 -37
  162. package/build/9649.468667d9.chunk.js +199 -0
  163. package/build/9d5d788027e86620c234.svg +5 -0
  164. package/build/{Admin-authenticatedApp.e39f36c9.chunk.js → Admin-authenticatedApp.c4f68103.chunk.js} +3 -3
  165. package/build/{Admin_homePage.118926e0.chunk.js → Admin_homePage.26d32e30.chunk.js} +6 -5
  166. package/build/Admin_marketplace.32375885.chunk.js +22 -0
  167. package/build/{Admin_profilePage.9d50ac44.chunk.js → Admin_profilePage.da32abbc.chunk.js} +1 -1
  168. package/build/Admin_settingsPage.bf2234e1.chunk.js +178 -0
  169. package/build/admin-app.9049056c.chunk.js +112 -0
  170. package/build/admin-edit-roles-page.69d9fcb2.chunk.js +1 -0
  171. package/build/{admin-users.97a08630.chunk.js → admin-users.d71f198a.chunk.js} +3 -3
  172. package/build/api-tokens-create-page.93dd0689.chunk.js +1 -0
  173. package/build/api-tokens-edit-page.b0adac81.chunk.js +1 -0
  174. package/build/api-tokens-list-page.bb36535f.chunk.js +16 -0
  175. package/build/ca-json.07ae0f2c.chunk.js +1 -0
  176. package/build/content-manager.ff998bed.chunk.js +1204 -0
  177. package/build/content-type-builder-list-view.5b3cd768.chunk.js +194 -0
  178. package/build/content-type-builder-translation-en-json.f985c9c4.chunk.js +1 -0
  179. package/build/content-type-builder-translation-sv-json.6deff030.chunk.js +1 -0
  180. package/build/content-type-builder.16af63a6.chunk.js +145 -0
  181. package/build/de-json.6b3e1894.chunk.js +1 -0
  182. package/build/dk-json.144c6a8e.chunk.js +1 -0
  183. package/build/{email-settings-page.64037147.chunk.js → email-settings-page.c3469093.chunk.js} +6 -6
  184. package/build/en-json.4a269f6b.chunk.js +1 -0
  185. package/build/es-json.6d123a82.chunk.js +1 -0
  186. package/build/fr-json.28ab54cb.chunk.js +1 -0
  187. package/build/gu-json.9a50ea64.chunk.js +1 -0
  188. package/build/he-json.72f18790.chunk.js +1 -0
  189. package/build/hi-json.0301b7ba.chunk.js +1 -0
  190. package/build/hu-json.c4b641bb.chunk.js +1 -0
  191. package/build/{i18n-settings-page.0b73785d.chunk.js → i18n-settings-page.46d894ff.chunk.js} +5 -5
  192. package/build/id-json.86035797.chunk.js +1 -0
  193. package/build/index.html +1 -1
  194. package/build/it-json.bbdc8993.chunk.js +1 -0
  195. package/build/ja-json.1c9eeeec.chunk.js +1 -0
  196. package/build/ko-json.e1f66398.chunk.js +1 -0
  197. package/build/main.91328e7a.js +9381 -0
  198. package/build/ml-json.963c889f.chunk.js +1 -0
  199. package/build/nl-json.2b8cc3a0.chunk.js +1 -0
  200. package/build/no-json.a58c28bd.chunk.js +1 -0
  201. package/build/pl-json.249626b3.chunk.js +1 -0
  202. package/build/pt-BR-json.7852f808.chunk.js +1 -0
  203. package/build/ru-json.d7cfc2ff.chunk.js +1 -0
  204. package/build/runtime~main.c9c319c0.js +2 -0
  205. package/build/sa-json.44e95991.chunk.js +1 -0
  206. package/build/sk-json.7ba4b330.chunk.js +1 -0
  207. package/build/sso-settings-page.9ceb0140.chunk.js +1 -0
  208. package/build/sv-json.8e5a7911.chunk.js +1 -0
  209. package/build/th-json.a67309b1.chunk.js +1 -0
  210. package/build/{upload-settings.80ff0974.chunk.js → upload-settings.53b690f3.chunk.js} +5 -5
  211. package/build/{upload-translation-en-json.004a86c1.chunk.js → upload-translation-en-json.86da7b0a.chunk.js} +1 -1
  212. package/build/{users-advanced-settings-page.a02f4806.chunk.js → users-advanced-settings-page.3f4ee86e.chunk.js} +5 -5
  213. package/build/{webhook-edit-page.d2ea3351.chunk.js → webhook-edit-page.dc9442ce.chunk.js} +2 -2
  214. package/build/webhook-list-page.02191138.chunk.js +134 -0
  215. package/build/zh-Hans-json.21617c24.chunk.js +1 -0
  216. package/build/zh-json.608aaf24.chunk.js +1 -0
  217. package/ee/admin/pages/SettingsPage/pages/Roles/ListPage/index.js +3 -2
  218. package/ee/server/controllers/user.js +5 -3
  219. package/env.js +1 -0
  220. package/package.json +13 -11
  221. package/scripts/build.js +11 -0
  222. package/server/bootstrap.js +19 -1
  223. package/server/config/admin-actions.js +20 -0
  224. package/server/content-types/api-token-permission.js +36 -0
  225. package/server/content-types/api-token.js +25 -1
  226. package/server/content-types/index.js +1 -0
  227. package/server/controllers/admin.js +3 -0
  228. package/server/controllers/api-token.js +24 -1
  229. package/server/controllers/content-api.js +15 -0
  230. package/server/controllers/index.js +1 -0
  231. package/server/controllers/user.js +3 -2
  232. package/server/routes/api-tokens.js +11 -0
  233. package/server/routes/content-api.js +20 -0
  234. package/server/routes/index.js +2 -0
  235. package/server/services/api-token.js +309 -29
  236. package/server/services/constants.js +10 -0
  237. package/server/services/permission/engine.js +36 -226
  238. package/server/services/permission.js +4 -1
  239. package/server/strategies/admin.js +7 -1
  240. package/server/strategies/api-token.js +72 -11
  241. package/server/validation/api-tokens.js +12 -2
  242. package/utils/create-plugins-exclude-path.js +40 -0
  243. package/utils/get-custom-app-config-file.js +5 -0
  244. package/webpack.alias.js +0 -13
  245. package/webpack.config.js +4 -1
  246. package/admin/src/assets/images/banner_strapi-rocket.png +0 -0
  247. package/admin/src/assets/images/big-logo-home.png +0 -0
  248. package/admin/src/assets/images/homepage-logo.png +0 -0
  249. package/admin/src/assets/images/icon_made-by-strapi.svg +0 -5
  250. package/admin/src/assets/images/logo_strapi_auth.png +0 -0
  251. package/admin/src/assets/images/logo_strapi_auth_v4.png +0 -0
  252. package/admin/src/assets/images/logo_strapi_menu.png +0 -0
  253. package/admin/src/assets/images/oops.png +0 -0
  254. package/admin/src/content-manager/components/State/index.js +0 -37
  255. package/admin/src/favicon.ico +0 -0
  256. package/build/15026a3d58aeb2828134.png +0 -0
  257. package/build/1856.47226450.chunk.js +0 -173
  258. package/build/2077.c935ee42.chunk.js +0 -205
  259. package/build/2912.a015078a.chunk.js +0 -258
  260. package/build/4715.58cd558f.chunk.js +0 -387
  261. package/build/4982.05eda880.chunk.js +0 -324
  262. package/build/7098.40dcd7bf.chunk.js +0 -1
  263. package/build/7841.91f793dc.chunk.js +0 -258
  264. package/build/7866.1201afbd.chunk.js +0 -504
  265. package/build/8380.8789ff76.chunk.js +0 -284
  266. package/build/8549.133c4473.chunk.js +0 -158
  267. package/build/8851.e4ac62f2.chunk.js +0 -158
  268. package/build/90f49a385afb000fb1d4.svg +0 -5
  269. package/build/9311.7cc03f29.chunk.js +0 -508
  270. package/build/Admin_marketplace.82c0570b.chunk.js +0 -11
  271. package/build/Admin_settingsPage.98a711e5.chunk.js +0 -178
  272. package/build/a6b842e0b6d2b61135d1.svg +0 -5
  273. package/build/admin-app.4f7618a9.chunk.js +0 -112
  274. package/build/admin-edit-roles-page.554ba3fa.chunk.js +0 -1
  275. package/build/api-tokens-create-page.4c262d6e.chunk.js +0 -1
  276. package/build/api-tokens-edit-page.10a9d368.chunk.js +0 -1
  277. package/build/api-tokens-list-page.442c9f3c.chunk.js +0 -15
  278. package/build/b997a22a2e0b87ef1fa2.ico +0 -0
  279. package/build/bd81ba6c07827282255d.png +0 -0
  280. package/build/c3de6118ef47086ad05c.png +0 -0
  281. package/build/ca-json.a16899ae.chunk.js +0 -1
  282. package/build/content-manager.7d57c9d1.chunk.js +0 -1200
  283. package/build/content-type-builder-list-view.8cc534e0.chunk.js +0 -194
  284. package/build/content-type-builder-translation-en-json.201bfb78.chunk.js +0 -1
  285. package/build/content-type-builder.684df7a4.chunk.js +0 -142
  286. package/build/de-json.aa6026b3.chunk.js +0 -1
  287. package/build/dk-json.fac2bcfb.chunk.js +0 -1
  288. package/build/en-json.0c69c7d7.chunk.js +0 -1
  289. package/build/es-json.d672e181.chunk.js +0 -1
  290. package/build/fb376b132d18bf4522ca.png +0 -0
  291. package/build/fde9b1ad0670d29a2516.png +0 -0
  292. package/build/fr-json.71a16175.chunk.js +0 -1
  293. package/build/gu-json.ca345cd1.chunk.js +0 -1
  294. package/build/he-json.3b825d80.chunk.js +0 -1
  295. package/build/hi-json.50c7e6d4.chunk.js +0 -1
  296. package/build/hu-json.e0521dcc.chunk.js +0 -1
  297. package/build/id-json.4b1ff8d6.chunk.js +0 -1
  298. package/build/it-json.86bac220.chunk.js +0 -1
  299. package/build/ja-json.4e44e36b.chunk.js +0 -1
  300. package/build/ko-json.1003756e.chunk.js +0 -1
  301. package/build/main.b47db1a3.js +0 -9337
  302. package/build/ml-json.c7774425.chunk.js +0 -1
  303. package/build/nl-json.f58ea235.chunk.js +0 -1
  304. package/build/no-json.40386397.chunk.js +0 -1
  305. package/build/pl-json.fed96aba.chunk.js +0 -1
  306. package/build/pt-BR-json.073799ab.chunk.js +0 -1
  307. package/build/ru-json.7ad2cbbf.chunk.js +0 -1
  308. package/build/runtime~main.feeac6d3.js +0 -2
  309. package/build/sa-json.f0f704f0.chunk.js +0 -1
  310. package/build/sk-json.a848961b.chunk.js +0 -1
  311. package/build/sso-settings-page.445184e0.chunk.js +0 -1
  312. package/build/sv-json.b038acbe.chunk.js +0 -1
  313. package/build/th-json.72e8de3d.chunk.js +0 -1
  314. package/build/webhook-list-page.2775a683.chunk.js +0 -134
  315. package/build/zh-Hans-json.03d2bda1.chunk.js +0 -1
  316. package/build/zh-json.3d0cc664.chunk.js +0 -1
  317. package/server/services/permission/engine-hooks.js +0 -82
@@ -3,8 +3,15 @@ import unset from 'lodash/unset';
3
3
  import get from 'lodash/get';
4
4
  import set from 'lodash/set';
5
5
  import take from 'lodash/take';
6
- import pull from 'lodash/pull';
7
- import { moveFields } from './utils';
6
+ import cloneDeep from 'lodash/cloneDeep';
7
+ import uniqBy from 'lodash/uniqBy';
8
+ import merge from 'lodash/merge';
9
+
10
+ import {
11
+ findLeafByPathAndReplace,
12
+ moveFields,
13
+ recursivelyFindPathsBasedOnCondition,
14
+ } from './utils';
8
15
  import { getMaxTempKey } from '../../utils';
9
16
 
10
17
  const initialState = {
@@ -15,6 +22,10 @@ const initialState = {
15
22
  modifiedData: null,
16
23
  shouldCheckErrors: false,
17
24
  modifiedDZName: null,
25
+ publishConfirmation: {
26
+ show: false,
27
+ draftCount: 0,
28
+ },
18
29
  };
19
30
 
20
31
  const reducer = (state, action) =>
@@ -22,63 +33,111 @@ const reducer = (state, action) =>
22
33
  produce(state, (draftState) => {
23
34
  switch (action.type) {
24
35
  case 'ADD_NON_REPEATABLE_COMPONENT_TO_FIELD': {
25
- set(
26
- draftState,
27
- ['modifiedData', ...action.keys],
28
- state.componentsDataStructure[action.componentUid]
29
- );
36
+ const { componentLayoutData, allComponents } = action;
30
37
 
31
- break;
32
- }
33
- case 'ADD_REPEATABLE_COMPONENT_TO_FIELD': {
34
- let currentValue = get(state, ['modifiedData', ...action.keys], []).slice();
38
+ const relationPaths = recursivelyFindPathsBasedOnCondition(
39
+ allComponents,
40
+ (value) => value.type === 'relation'
41
+ )(componentLayoutData.attributes);
35
42
 
36
43
  const defaultDataStructure = {
37
- ...state.componentsDataStructure[action.componentUid],
38
- __temp_key__: getMaxTempKey(currentValue) + 1,
44
+ ...state.componentsDataStructure[componentLayoutData.uid],
39
45
  };
40
46
 
41
- if (Array.isArray(currentValue)) {
42
- currentValue.push(defaultDataStructure);
43
- } else {
44
- currentValue = [defaultDataStructure];
45
- }
47
+ const repeatableFields = recursivelyFindPathsBasedOnCondition(
48
+ allComponents,
49
+ (value) => value.type === 'component' && value.repeatable
50
+ )(componentLayoutData.attributes);
46
51
 
47
- set(draftState, ['modifiedData', ...action.keys], currentValue);
52
+ const componentDataStructure = relationPaths.reduce((acc, current) => {
53
+ const [componentName] = current.split('.');
48
54
 
49
- if (action.shouldCheckErrors) {
50
- draftState.shouldCheckErrors = !state.shouldCheckErrors;
51
- }
55
+ /**
56
+ * Why do we do this? Because if a repeatable component
57
+ * has another repeatable component inside of it we
58
+ * don't need to attach the array at this point because that will be
59
+ * done again deeper in the nest.
60
+ */
61
+ if (!repeatableFields.includes(componentName)) {
62
+ set(acc, current, []);
63
+ }
64
+
65
+ return acc;
66
+ }, defaultDataStructure);
67
+
68
+ set(draftState, ['modifiedData', ...action.keys], componentDataStructure);
52
69
 
53
70
  break;
54
71
  }
55
- case 'ADD_COMPONENT_TO_DYNAMIC_ZONE': {
56
- draftState.modifiedDZName = action.keys[0];
72
+ case 'ADD_COMPONENT_TO_DYNAMIC_ZONE':
73
+ case 'ADD_REPEATABLE_COMPONENT_TO_FIELD': {
74
+ const { keys, allComponents, componentLayoutData, shouldCheckErrors } = action;
57
75
 
58
- if (action.shouldCheckErrors) {
76
+ if (shouldCheckErrors) {
59
77
  draftState.shouldCheckErrors = !state.shouldCheckErrors;
60
78
  }
61
79
 
62
- const defaultDataStructure = {
63
- ...state.componentsDataStructure[action.componentUid],
64
- __component: action.componentUid,
65
- };
80
+ if (action.type === 'ADD_COMPONENT_TO_DYNAMIC_ZONE') {
81
+ draftState.modifiedDZName = keys[0];
82
+ }
66
83
 
67
- const currentValue = get(state, ['modifiedData', ...action.keys], null);
68
- const updatedValue = currentValue
69
- ? [...currentValue, defaultDataStructure]
70
- : [defaultDataStructure];
84
+ const currentValue = get(state, ['modifiedData', ...keys], []);
71
85
 
72
- set(draftState, ['modifiedData', ...action.keys], updatedValue);
86
+ const defaultDataStructure =
87
+ action.type === 'ADD_COMPONENT_TO_DYNAMIC_ZONE'
88
+ ? {
89
+ ...state.componentsDataStructure[componentLayoutData.uid],
90
+ __component: componentLayoutData.uid,
91
+ }
92
+ : {
93
+ ...state.componentsDataStructure[componentLayoutData.uid],
94
+ __temp_key__: getMaxTempKey(currentValue) + 1,
95
+ };
96
+
97
+ const relationPaths = recursivelyFindPathsBasedOnCondition(
98
+ allComponents,
99
+ (value) => value.type === 'relation'
100
+ )(componentLayoutData.attributes);
101
+
102
+ const repeatableFields = recursivelyFindPathsBasedOnCondition(
103
+ allComponents,
104
+ (value) => value.type === 'component' && value.repeatable
105
+ )(componentLayoutData.attributes);
106
+
107
+ const componentDataStructure = relationPaths.reduce((acc, current) => {
108
+ const [componentName] = current.split('.');
109
+
110
+ /**
111
+ * Why do we do this? Because if a repeatable component
112
+ * has another repeatable component inside of it we
113
+ * don't need to attach the array at this point because that will be
114
+ * done again deeper in the nest.
115
+ */
116
+ if (!repeatableFields.includes(componentName)) {
117
+ set(acc, current, []);
118
+ }
119
+
120
+ return acc;
121
+ }, defaultDataStructure);
122
+
123
+ const newValue = Array.isArray(currentValue)
124
+ ? [...currentValue, componentDataStructure]
125
+ : [componentDataStructure];
126
+
127
+ set(draftState, ['modifiedData', ...keys], newValue);
73
128
 
74
129
  break;
75
130
  }
131
+
76
132
  case 'LOAD_RELATION': {
77
- const initialDataPath = ['initialData', ...action.keys, 'results'];
78
- const modifiedDataPath = ['modifiedData', ...action.keys, 'results'];
133
+ const initialDataPath = ['initialData', ...action.keys];
134
+ const modifiedDataPath = ['modifiedData', ...action.keys];
79
135
  const { value } = action;
80
136
 
81
- set(draftState, initialDataPath, value);
137
+ const initialDataRelations = get(state, initialDataPath);
138
+ const modifiedDataRelations = get(state, modifiedDataPath);
139
+
140
+ set(draftState, initialDataPath, uniqBy([...value, ...initialDataRelations], 'id'));
82
141
 
83
142
  /**
84
143
  * We need to set the value also on modifiedData, because initialData
@@ -86,126 +145,108 @@ const reducer = (state, action) =>
86
145
  * both states, to render the dirty UI state
87
146
  */
88
147
 
89
- set(draftState, modifiedDataPath, value);
148
+ set(draftState, modifiedDataPath, uniqBy([...value, ...modifiedDataRelations], 'id'));
90
149
 
91
150
  break;
92
151
  }
93
152
  case 'CONNECT_RELATION': {
94
153
  const path = ['modifiedData', ...action.keys];
95
- const { value, replace = false } = action;
96
- const connectedRelations = get(state, [...path, 'connect']);
97
- const disconnectedRelations = get(state, [...path, 'disconnect']);
98
-
99
- if (!connectedRelations) {
100
- set(draftState, [...path, 'connect'], []);
101
- }
154
+ const { value, toOneRelation } = action;
102
155
 
103
- if (replace) {
104
- set(draftState, [...path, 'connect'], [value]);
156
+ /**
157
+ * If the field is a single relation field we don't want to append
158
+ * we just want to replace the value.
159
+ */
160
+ if (toOneRelation) {
161
+ set(draftState, path, [value]);
105
162
  } else {
106
- const nextValue = get(draftState, [...path, 'connect']);
107
- nextValue.push(value);
108
- }
109
-
110
- if (disconnectedRelations?.length) {
111
- const existsInDisconnect = disconnectedRelations.find(
112
- (disconnectValue) => disconnectValue.id === value.id
113
- );
114
-
115
- if (existsInDisconnect) {
116
- const newDisconnectArray = pull([...disconnectedRelations], existsInDisconnect);
117
- set(draftState, [...path, 'disconnect'], newDisconnectArray);
118
- }
163
+ const modifiedDataRelations = get(state, path);
164
+ const newRelations = [...modifiedDataRelations, value];
165
+ set(draftState, path, newRelations);
119
166
  }
120
167
 
121
168
  break;
122
169
  }
123
170
  case 'DISCONNECT_RELATION': {
124
171
  const path = ['modifiedData', ...action.keys];
125
- const { value } = action;
126
- const disconnectedRelations = get(state, [...path, 'disconnect']);
127
- const connectedRelations = get(state, [...path, 'connect']);
128
-
129
- if (!disconnectedRelations) {
130
- set(draftState, [...path, 'disconnect'], []);
131
- }
132
-
133
- const nextValue = get(draftState, [...path, 'disconnect']);
134
- nextValue.push(value);
172
+ const { id } = action;
173
+ const modifiedDataRelation = get(state, [...path]);
135
174
 
136
- if (connectedRelations?.length) {
137
- const existsInConnect = connectedRelations.find(
138
- (connectValue) => connectValue.id === value.id
139
- );
175
+ /**
176
+ * TODO: before merge make this performant (e.g. 1000 relations === long time)
177
+ */
178
+ const newRelations = modifiedDataRelation.filter((rel) => rel.id !== id);
140
179
 
141
- if (existsInConnect) {
142
- const newConnectArray = pull([...connectedRelations], existsInConnect);
143
- set(draftState, [...path, 'connect'], newConnectArray);
144
- }
145
- }
180
+ set(draftState, path, newRelations);
146
181
 
147
182
  break;
148
183
  }
184
+ /**
185
+ * This action will be called when you open your entry (first load)
186
+ * but also every time you press publish.
187
+ */
149
188
  case 'INIT_FORM': {
150
- const { initialValues, relationalFields = [] } = action;
189
+ const {
190
+ initialValues,
191
+ relationalFieldPaths = [],
192
+ componentPaths = [],
193
+ repeatableComponentPaths = [],
194
+ dynamicZonePaths = [],
195
+ } = action;
151
196
 
152
- draftState.formErrors = {};
153
-
154
- draftState.initialData = {
155
- ...initialValues,
197
+ /**
198
+ * You can't mutate an actions value.
199
+ * and spreading an object only clones
200
+ * the first level, the deeply nested values
201
+ * are a reference.
202
+ */
203
+ const data = cloneDeep(initialValues);
156
204
 
157
- /**
158
- * The state we keep in the client for relations looks like:
159
- *
160
- * {
161
- * count: <int>
162
- * results: [<Relation>]
163
- * }
164
- *
165
- * The content API only returns { count: <int> }, which is why
166
- * we need to extend the existing state rather than overwriting it.
167
- */
205
+ /**
206
+ * relationalFieldPaths won't be an array which is what we're expecting
207
+ * Therefore we reset these bits of state to the correct data type
208
+ * which is an array. Hence why we replace those fields.
209
+ *
210
+ */
168
211
 
169
- ...relationalFields.reduce((acc, name) => {
170
- acc[name] = {
171
- ...(state.initialData?.[name] ?? {}),
172
- ...(initialValues?.[name] ?? {}),
173
- };
212
+ const mergeDataWithPreparedRelations = relationalFieldPaths
213
+ .map((path) => path.split('.'))
214
+ .reduce((acc, currentPaths) => {
215
+ const [componentName] = currentPaths;
216
+
217
+ if (state.modifiedData && get(state.modifiedData, componentName)) {
218
+ /**
219
+ * this will be null on initial load, however subsequent calls
220
+ * will have data in them correlating to the names of the relational fields.
221
+ *
222
+ * We also merge the fetched data so that things like `id` for components can be copied over
223
+ * which would be `undefined` in the `browserState`.
224
+ */
225
+ const currentState = cloneDeep(get(state.modifiedData, componentName));
226
+ set(acc, componentName, merge(currentState, get(initialValues, componentName)));
227
+ } else if (
228
+ repeatableComponentPaths.includes(componentName) ||
229
+ dynamicZonePaths.includes(componentName) ||
230
+ componentPaths.includes(componentName)
231
+ ) {
232
+ /**
233
+ * if the componentName is a repeatable field or dynamic zone we collect the list of paths e.g.
234
+ * ["repeatable_single_component_relation","categories"] and then reduce this
235
+ * recursively
236
+ */
237
+ const findleaf = findLeafByPathAndReplace(currentPaths.slice(-1)[0], []);
238
+ currentPaths.reduce(findleaf, acc);
239
+ } else {
240
+ set(acc, currentPaths, []);
241
+ }
174
242
 
175
243
  return acc;
176
- }, {}),
177
- };
178
-
179
- draftState.modifiedData = {
180
- ...initialValues,
181
-
182
- /**
183
- * The client sends the following to the content API:
184
- *
185
- * {
186
- * connect: [<Relation>],
187
- * disconnect: [<Relation>]
188
- * }
189
- *
190
- * but receives only { count: <int> } in return. After save/ publish
191
- * we have to:
192
- *
193
- * 1) reset the connect/ disconnect arrays
194
- * 2) extend the existing state with the API response, so that `count`
195
- * stays in sync
196
- */
197
-
198
- ...relationalFields.reduce((acc, name) => {
199
- const { connect, disconnect, ...currentState } = state.modifiedData?.[name] ?? {};
244
+ }, data);
200
245
 
201
- acc[name] = {
202
- ...(currentState ?? {}),
203
- ...(initialValues?.[name] ?? {}),
204
- };
246
+ draftState.initialData = mergeDataWithPreparedRelations;
247
+ draftState.modifiedData = mergeDataWithPreparedRelations;
205
248
 
206
- return acc;
207
- }, {}),
208
- };
249
+ draftState.formErrors = {};
209
250
 
210
251
  draftState.modifiedDZName = null;
211
252
  draftState.shouldCheckErrors = false;
@@ -345,7 +386,14 @@ const reducer = (state, action) =>
345
386
 
346
387
  break;
347
388
  }
348
-
389
+ case 'SET_PUBLISH_CONFIRMATION': {
390
+ draftState.publishConfirmation = { ...action.publishConfirmation };
391
+ break;
392
+ }
393
+ case 'RESET_PUBLISH_CONFIRMATION': {
394
+ draftState.publishConfirmation = { ...state.publishConfirmation, show: false };
395
+ break;
396
+ }
349
397
  default:
350
398
  return draftState;
351
399
  }
@@ -4,14 +4,31 @@ import isObject from 'lodash/isObject';
4
4
 
5
5
  /* eslint-disable indent */
6
6
 
7
- const cleanData = (retrievedData, currentSchema, componentsSchema) => {
7
+ /**
8
+ *
9
+ * @param {{ browserState: object, serverState: object }} browserState – the modifiedData from REDUX, serverState - the initialData from REDUX
10
+ * @param {object} currentSchema
11
+ * @param {object} componentsSchema
12
+ * @returns
13
+ */
14
+ const cleanData = ({ browserState, serverState }, currentSchema, componentsSchema) => {
8
15
  const getType = (schema, attrName) => get(schema, ['attributes', attrName, 'type'], '');
9
16
  const getOtherInfos = (schema, arr) => get(schema, ['attributes', ...arr], '');
10
17
 
11
- const recursiveCleanData = (data, schema) => {
12
- return Object.keys(data).reduce((acc, current) => {
18
+ /**
19
+ *
20
+ * @param {object} browserState – the modifiedData from REDUX
21
+ * @param {object} serverState – the initialData from REDUX
22
+ * @param {*} schema
23
+ * @returns
24
+ */
25
+ const recursiveCleanData = (browserState, serverState, schema) => {
26
+ return Object.keys(browserState).reduce((acc, current) => {
13
27
  const attrType = getType(schema, current);
14
- const value = get(data, current);
28
+
29
+ // This is the field value
30
+ const value = get(browserState, current);
31
+ const oldValue = get(serverState, current);
15
32
  const component = getOtherInfos(schema, [current, 'component']);
16
33
  const isRepeatable = getOtherInfos(schema, [current, 'repeatable']);
17
34
  let cleanedData;
@@ -40,34 +57,71 @@ const cleanData = (retrievedData, currentSchema, componentsSchema) => {
40
57
  case 'component':
41
58
  if (isRepeatable) {
42
59
  cleanedData = value
43
- ? value.map((data) => {
44
- const subCleanedData = recursiveCleanData(data, componentsSchema[component]);
60
+ ? value.map((data, index) => {
61
+ const subCleanedData = recursiveCleanData(
62
+ data,
63
+ (oldValue ?? [])[index],
64
+ componentsSchema[component]
65
+ );
45
66
 
46
67
  return subCleanedData;
47
68
  })
48
69
  : value;
49
70
  } else {
50
- cleanedData = value ? recursiveCleanData(value, componentsSchema[component]) : value;
71
+ cleanedData = value
72
+ ? recursiveCleanData(value, oldValue, componentsSchema[component])
73
+ : value;
51
74
  }
52
75
 
53
76
  break;
54
77
 
55
- case 'relation':
56
- // Instead of the full relation object, we only want to send its ID
57
- // and need to clean-up the connect|disconnect arrays
58
- cleanedData = Object.entries(value).reduce((acc, [key, value]) => {
59
- if (['connect', 'disconnect'].includes(key)) {
60
- acc[key] = value.map((currentValue) => ({ id: currentValue.id }));
78
+ case 'relation': {
79
+ /**
80
+ * Because of how repeatable components work when you dig into them the server
81
+ * will have no object to compare too therefore no relation array will be setup
82
+ * because the component has not been initialised, therefore we can safely assume
83
+ * it needs to be added and provide a default empty array.
84
+ */
85
+ let actualOldValue = oldValue ?? [];
86
+
87
+ /**
88
+ * Instead of the full relation object, we only want to send its ID
89
+ * connectedRelations are the items that are in the browserState
90
+ * array but not in the serverState
91
+ */
92
+ const connectedRelations = value.reduce((acc, relation) => {
93
+ if (!actualOldValue.find((oldRelation) => oldRelation.id === relation.id)) {
94
+ return [...acc, { id: relation.id }];
61
95
  }
62
96
 
63
97
  return acc;
64
- }, {});
98
+ }, []);
99
+
100
+ /**
101
+ * disconnectedRelations are the items that are in the serverState but
102
+ * are no longer in the browserState
103
+ */
104
+ const disconnectedRelations = actualOldValue.reduce((acc, relation) => {
105
+ if (!value.find((newRelation) => newRelation.id === relation.id)) {
106
+ return [...acc, { id: relation.id }];
107
+ }
108
+
109
+ return acc;
110
+ }, []);
111
+
112
+ cleanedData = {
113
+ disconnect: disconnectedRelations,
114
+ connect: connectedRelations,
115
+ };
116
+
65
117
  break;
118
+ }
66
119
 
67
120
  case 'dynamiczone':
68
- cleanedData = value.map((componentData) => {
121
+ cleanedData = value.map((componentData, index) => {
69
122
  const subCleanedData = recursiveCleanData(
70
123
  componentData,
124
+ (oldValue ?? [])[index],
71
125
  componentsSchema[componentData.__component]
72
126
  );
73
127
 
@@ -84,7 +138,7 @@ const cleanData = (retrievedData, currentSchema, componentsSchema) => {
84
138
  }, {});
85
139
  };
86
140
 
87
- return recursiveCleanData(retrievedData, currentSchema);
141
+ return recursiveCleanData(browserState, serverState, currentSchema);
88
142
  };
89
143
 
90
144
  // TODO: check which parts are still needed: I suspect the
@@ -0,0 +1,52 @@
1
+ import set from 'lodash/set';
2
+
3
+ /**
4
+ * @param {string} endpath – the final path that you're looking to replace
5
+ * @returns {function} findLeafReducer – a function that will be used in the reduce
6
+ */
7
+ export const findLeafByPathAndReplace = (endpath, replaceWith) => {
8
+ /**
9
+ * @param {object} acc – the data tree
10
+ * @param {*} curr – string, this _could_ be used to index the accumulator
11
+ * @param {*} ind - your current index of the array you're reducing
12
+ * @returns {object} – the new object with the replaced values
13
+ */
14
+ const findLeafAndReplace = (acc, curr, ind, currentArr) => {
15
+ /**
16
+ * Because we're returning the `accumulator[current]` at the bottom
17
+ * and some components may not exist at this point, we check if `accumulator`
18
+ * exists before trying to access & replace properties.
19
+ */
20
+ if (!acc) return acc;
21
+
22
+ /**
23
+ * If this is the last item in the array of paths
24
+ * and the current path is not undefined in the accumulator
25
+ * then we assume it's a leaf and we can replace it.
26
+ */
27
+ if (endpath === curr && acc[curr] !== undefined) {
28
+ set(acc, curr, replaceWith);
29
+
30
+ return acc;
31
+ }
32
+
33
+ /**
34
+ * If the value of the accumulator[current] is an array
35
+ * then we need to loop over it and call the reducer again
36
+ * this time with each array item being the accumulator.
37
+ */
38
+ if (Array.isArray(acc[curr])) {
39
+ acc[curr].forEach((item) => {
40
+ currentArr.slice(ind + 1).reduce(findLeafAndReplace, item);
41
+ });
42
+ }
43
+
44
+ /**
45
+ * accumulator[current]return accumulator[current] instead of the main accumulator,
46
+ * this will stop the same keys overwrite the wrong objects
47
+ */
48
+ return acc[curr];
49
+ };
50
+
51
+ return findLeafAndReplace;
52
+ };
@@ -1,3 +1,5 @@
1
1
  export { default as moveFields } from './moveFields';
2
2
  export { default as cleanData } from './cleanData';
3
3
  export { default as createYupSchema } from './schema';
4
+ export { recursivelyFindPathsBasedOnCondition } from './recursivelyFindPathsBasedOnCondition';
5
+ export { findLeafByPathAndReplace } from './findLeafByPathAndReplace';
@@ -0,0 +1,72 @@
1
+ /**
2
+ * @typedef Attribute
3
+ * @type { { type: string }}
4
+ *
5
+ * @typedef Attributes
6
+ * @type {{ [key: string]: Attribute }}
7
+ */
8
+
9
+ /**
10
+ * This function will recursively find all the paths in the `currentContentTypeLayout.attributes`
11
+ * based on the boolean return of the condition e.g. `type === 'relation'`.
12
+ *
13
+ * It's original use was for the preperation of action items for the INIT_FORM action. It requires
14
+ * knowledge of the `components` in the entity, however `components` doesn't change nor does the predicate
15
+ * function so we don't need to pass it everytime hence why it's curried.
16
+ *
17
+ *
18
+ * @param {{[key: string]: { attributes: Attributes }}} components
19
+ * @param {(value: Attribute) => boolean} predicate
20
+ * @returns {(attributes: Attributes) => string[]}
21
+ */
22
+ const recursivelyFindPathsBasedOnConditionSetup = (components, predicate = () => false) => {
23
+ /**
24
+ *
25
+ * @param {Attributes} attributes
26
+ * @returns {string[]}
27
+ */
28
+ const recursivelyFindPathsBasedOnCondition = (attributes) => {
29
+ return Object.entries(attributes).reduce((acc, [key, value]) => {
30
+ if (predicate(value)) {
31
+ acc = [...acc, key];
32
+ }
33
+
34
+ if (value.type === 'component') {
35
+ const componentAttributes = components[value.component].attributes;
36
+
37
+ const attributesInComponent = recursivelyFindPathsBasedOnCondition(componentAttributes);
38
+
39
+ const attributesInComponentPaths = attributesInComponent.map((path) => `${key}.${path}`);
40
+
41
+ acc = [...acc, attributesInComponentPaths];
42
+ } else if (value.type === 'dynamiczone') {
43
+ const dynamicComponents = value.components;
44
+
45
+ const attributesInDynamicComponents = dynamicComponents
46
+ .flatMap((componentName) => {
47
+ return recursivelyFindPathsBasedOnCondition({
48
+ [componentName]: { type: 'component', component: componentName },
49
+ /**
50
+ * DynamicZones are an array of components, therefore the componentName shouldn't
51
+ * be part of the path because it's not a property of the component.
52
+ *
53
+ * e.g. { dynamic_zone: [{ __component: 'basic.simple', id: 36, my_name: null, categories: { count: 1, } }] }
54
+ * where the path to `id` is `dynamic_zone.id` and not `dynamic_zone.basic.simple.id`
55
+ *
56
+ * NOTE: we don't need to know the path to the `array` because it's about data shape not about the actual data
57
+ */
58
+ }).map((path) => path.split(`${componentName}.`)[1]);
59
+ })
60
+ .map((path) => `${key}.${path}`);
61
+
62
+ acc = [...acc, attributesInDynamicComponents];
63
+ }
64
+
65
+ return acc.flat();
66
+ }, []);
67
+ };
68
+
69
+ return recursivelyFindPathsBasedOnCondition;
70
+ };
71
+
72
+ export { recursivelyFindPathsBasedOnConditionSetup as recursivelyFindPathsBasedOnCondition };