@strapi/admin 4.5.0-beta.0 → 4.5.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 (264) hide show
  1. package/admin/src/StrapiApp.js +17 -6
  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/content-manager/components/DynamicTable/CellContent/CellValue.js +1 -1
  7. package/admin/src/content-manager/components/DynamicTable/CellContent/RelationMultiple/index.js +5 -4
  8. package/admin/src/content-manager/components/DynamicTable/CellContent/index.js +10 -0
  9. package/admin/src/content-manager/components/DynamicTable/index.js +21 -4
  10. package/admin/src/content-manager/components/DynamicZone/components/{AddComponentButton/index.js → AddComponentButton.js} +12 -6
  11. package/admin/src/content-manager/components/DynamicZone/components/{ComponentPicker/Category/ComponentCard/index.js → ComponentCard.js} +8 -19
  12. package/admin/src/content-manager/components/DynamicZone/components/{ComponentPicker/Category/index.js → ComponentCategory.js} +19 -18
  13. package/admin/src/content-manager/components/DynamicZone/components/{ComponentPicker/index.js → ComponentPicker.js} +36 -38
  14. package/admin/src/content-manager/components/DynamicZone/components/DynamicComponent.js +195 -0
  15. package/admin/src/content-manager/components/DynamicZone/components/{DzLabel/index.js → DynamicZoneLabel.js} +13 -5
  16. package/admin/src/content-manager/components/DynamicZone/index.js +35 -116
  17. package/admin/src/content-manager/components/EditViewDataManagerProvider/index.js +103 -60
  18. package/admin/src/content-manager/components/EditViewDataManagerProvider/reducer.js +169 -162
  19. package/admin/src/content-manager/components/EditViewDataManagerProvider/utils/cleanData.js +70 -16
  20. package/admin/src/content-manager/components/EditViewDataManagerProvider/utils/findLeafByPathAndReplace.js +52 -0
  21. package/admin/src/content-manager/components/EditViewDataManagerProvider/utils/index.js +2 -0
  22. package/admin/src/content-manager/components/EditViewDataManagerProvider/utils/recursivelyFindPathsBasedOnCondition.js +72 -0
  23. package/admin/src/content-manager/components/FieldComponent/index.js +9 -2
  24. package/admin/src/content-manager/components/PreviewWysiwyg/index.js +1 -1
  25. package/admin/src/content-manager/components/RelationInput/RelationInput.js +80 -76
  26. package/admin/src/content-manager/components/RelationInputDataManager/RelationInputDataManager.js +95 -63
  27. package/admin/src/content-manager/components/RelationInputDataManager/utils/diffRelations.js +24 -0
  28. package/admin/src/content-manager/components/RelationInputDataManager/utils/index.js +2 -1
  29. package/admin/src/content-manager/components/RelationInputDataManager/utils/normalizeRelations.js +8 -29
  30. package/admin/src/content-manager/components/RelationInputDataManager/utils/normalizeSearchResults.js +8 -4
  31. package/admin/src/content-manager/components/RelationInputDataManager/utils/select.js +1 -0
  32. package/admin/src/content-manager/components/RepeatableComponent/index.js +4 -3
  33. package/admin/src/content-manager/hooks/__test__/usePrev.test.js +26 -0
  34. package/admin/src/content-manager/hooks/index.js +1 -0
  35. package/admin/src/content-manager/hooks/useFetchContentTypeLayout/utils/formatLayouts.js +19 -48
  36. package/admin/src/content-manager/hooks/usePrev.js +14 -0
  37. package/admin/src/content-manager/hooks/useRelation/useRelation.js +100 -7
  38. package/admin/src/content-manager/pages/App/reducer.js +3 -0
  39. package/admin/src/content-manager/pages/ListSettingsView/components/DraggableCard.js +3 -3
  40. package/admin/src/content-manager/pages/ListSettingsView/components/Settings.js +2 -2
  41. package/admin/src/content-manager/pages/ListSettingsView/components/SortDisplayedFields.js +1 -1
  42. package/admin/src/core/apis/CustomFields.js +0 -1
  43. package/admin/src/core/store/configureStore.js +17 -2
  44. package/admin/src/favicon.png +0 -0
  45. package/admin/src/hooks/useFetchMarketplacePlugins/index.js +2 -2
  46. package/admin/src/hooks/useFetchMarketplacePlugins/utils/api.js +4 -2
  47. package/admin/src/hooks/useFetchMarketplaceProviders/index.js +3 -3
  48. package/admin/src/hooks/useFetchMarketplaceProviders/utils/api.js +5 -3
  49. package/admin/src/index.js +1 -0
  50. package/admin/src/pages/App/index.js +1 -1
  51. package/admin/src/pages/HomePage/assets/corner-ornament.svg +48 -0
  52. package/admin/src/pages/HomePage/index.js +4 -3
  53. package/admin/src/pages/MarketplacePage/components/NpmPackageCard/CardButton.js +110 -0
  54. package/admin/src/pages/MarketplacePage/components/NpmPackageCard/InstallPluginButton.js +32 -21
  55. package/admin/src/pages/MarketplacePage/components/NpmPackageCard/PackageStats.js +79 -0
  56. package/admin/src/pages/MarketplacePage/components/NpmPackageCard/index.js +28 -11
  57. package/admin/src/pages/MarketplacePage/components/NpmPackagesFilters/FilterSelect.js +42 -0
  58. package/admin/src/pages/MarketplacePage/components/NpmPackagesFilters/FiltersPopover.js +96 -0
  59. package/admin/src/pages/MarketplacePage/components/NpmPackagesFilters/index.js +107 -0
  60. package/admin/src/pages/MarketplacePage/components/NpmPackagesGrid/index.js +4 -0
  61. package/admin/src/pages/MarketplacePage/components/SortSelect/index.js +70 -0
  62. package/admin/src/pages/MarketplacePage/index.js +68 -8
  63. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/FormApiTokenContainer/index.js +5 -4
  64. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/FormBody/index.js +4 -3
  65. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/FormHead/index.js +6 -2
  66. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/Regenerate/index.js +1 -1
  67. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/index.js +5 -4
  68. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/utils/schema.js +1 -1
  69. package/admin/src/pages/SettingsPage/pages/Roles/EditPage/components/ConditionsModal/ActionRow/index.js +7 -38
  70. package/admin/src/pages/SettingsPage/pages/Roles/EditPage/components/ConditionsModal/ActionRow/utils/options.js +31 -0
  71. package/admin/src/pages/SettingsPage/pages/Roles/EditPage/components/ConditionsModal/index.js +32 -43
  72. package/admin/src/pages/SettingsPage/pages/Roles/EditPage/components/ContentTypeCollapse/Collapse/index.js +1 -1
  73. package/admin/src/pages/SettingsPage/pages/Roles/ListPage/components/RoleRow/index.js +3 -1
  74. package/admin/src/pages/SettingsPage/pages/Roles/ListPage/index.js +2 -1
  75. package/admin/src/pages/SettingsPage/pages/Webhooks/EditView/components/EventInput/index.js +2 -2
  76. package/admin/src/translations/ca.json +1 -1
  77. package/admin/src/translations/de.json +1 -1
  78. package/admin/src/translations/dk.json +1 -1
  79. package/admin/src/translations/en.json +21 -7
  80. package/admin/src/translations/es.json +1 -1
  81. package/admin/src/translations/fr.json +1 -1
  82. package/admin/src/translations/gu.json +1 -1
  83. package/admin/src/translations/he.json +1 -1
  84. package/admin/src/translations/hi.json +1 -1
  85. package/admin/src/translations/hu.json +1 -1
  86. package/admin/src/translations/id.json +1 -1
  87. package/admin/src/translations/it.json +1 -1
  88. package/admin/src/translations/ja.json +1 -1
  89. package/admin/src/translations/ko.json +1 -1
  90. package/admin/src/translations/ml.json +1 -1
  91. package/admin/src/translations/nl.json +1 -1
  92. package/admin/src/translations/no.json +1 -1
  93. package/admin/src/translations/pl.json +1 -1
  94. package/admin/src/translations/pt-BR.json +15 -15
  95. package/admin/src/translations/ru.json +1 -1
  96. package/admin/src/translations/sa.json +1 -1
  97. package/admin/src/translations/sk.json +1 -1
  98. package/admin/src/translations/sv.json +118 -86
  99. package/admin/src/translations/th.json +1 -1
  100. package/admin/src/translations/zh-Hans.json +1 -1
  101. package/admin/src/translations/zh.json +1 -1
  102. package/build/1856.db9f5782.chunk.js +174 -0
  103. package/build/2077.fed8c9c3.chunk.js +206 -0
  104. package/build/2912.fccb2c43.chunk.js +259 -0
  105. package/build/4318.5e670740.chunk.js +30 -0
  106. package/build/{9166.8fcb3019.chunk.js → 4610.7614b003.chunk.js} +22 -21
  107. package/build/4715.8e33d630.chunk.js +387 -0
  108. package/build/{4800.d09f1225.chunk.js → 4800.a6935af6.chunk.js} +1 -1
  109. package/build/4982.9e58ea3f.chunk.js +325 -0
  110. package/build/617f9c948fa79e6d73bd.png +0 -0
  111. package/build/6925.bb6dd64d.chunk.js +762 -0
  112. package/build/6d21938306785f176538.png +0 -0
  113. package/build/70674f63fc3904c20de0.svg +7 -0
  114. package/build/{7379.d246dd38.chunk.js → 7379.e972985f.chunk.js} +1 -1
  115. package/build/7692.31e83caa.chunk.js +470 -0
  116. package/build/7841.4804bd98.chunk.js +259 -0
  117. package/build/7866.6db2248d.chunk.js +505 -0
  118. package/build/7e9af4fb7e723fcebf1f.svg +48 -0
  119. package/build/8380.37126e0d.chunk.js +299 -0
  120. package/build/8549.5e5fb6b6.chunk.js +159 -0
  121. package/build/8738.5a02bffb.chunk.js +463 -0
  122. package/build/{9066.26faf397.chunk.js → 9066.5d980488.chunk.js} +5 -5
  123. package/build/9420.7addc099.chunk.js +505 -0
  124. package/build/9649.b6afc945.chunk.js +199 -0
  125. package/build/9d5d788027e86620c234.svg +5 -0
  126. package/build/Admin-authenticatedApp.c07d2a86.chunk.js +80 -0
  127. package/build/{Admin_homePage.4b2be829.chunk.js → Admin_homePage.26d32e30.chunk.js} +5 -4
  128. package/build/Admin_marketplace.444ff7b8.chunk.js +22 -0
  129. package/build/Admin_settingsPage.bf2234e1.chunk.js +178 -0
  130. package/build/admin-app.b157c10a.chunk.js +112 -0
  131. package/build/{admin-edit-roles-page.4dd6bcb9.chunk.js → admin-edit-roles-page.69d9fcb2.chunk.js} +1 -1
  132. package/build/ca-json.07ae0f2c.chunk.js +1 -0
  133. package/build/content-manager.f38edbb6.chunk.js +1202 -0
  134. package/build/content-type-builder-translation-pt-BR-json.6fe3b8d1.chunk.js +1 -0
  135. package/build/content-type-builder-translation-sv-json.6deff030.chunk.js +1 -0
  136. package/build/{content-type-builder.a6e29716.chunk.js → content-type-builder.16af63a6.chunk.js} +13 -13
  137. package/build/de-json.6b3e1894.chunk.js +1 -0
  138. package/build/dk-json.144c6a8e.chunk.js +1 -0
  139. package/build/{email-settings-page.bfe6227f.chunk.js → email-settings-page.91c925a5.chunk.js} +6 -6
  140. package/build/email-translation-en-json.ebad8943.chunk.js +1 -0
  141. package/build/en-json.4a269f6b.chunk.js +1 -0
  142. package/build/es-json.6d123a82.chunk.js +1 -0
  143. package/build/fr-json.28ab54cb.chunk.js +1 -0
  144. package/build/gu-json.9a50ea64.chunk.js +1 -0
  145. package/build/he-json.72f18790.chunk.js +1 -0
  146. package/build/hi-json.0301b7ba.chunk.js +1 -0
  147. package/build/hu-json.c4b641bb.chunk.js +1 -0
  148. package/build/{i18n-settings-page.18166125.chunk.js → i18n-settings-page.4ef64441.chunk.js} +5 -5
  149. package/build/id-json.86035797.chunk.js +1 -0
  150. package/build/index.html +1 -1
  151. package/build/it-json.bbdc8993.chunk.js +1 -0
  152. package/build/ja-json.1c9eeeec.chunk.js +1 -0
  153. package/build/ko-json.e1f66398.chunk.js +1 -0
  154. package/build/main.ca8b0ee3.js +9465 -0
  155. package/build/ml-json.963c889f.chunk.js +1 -0
  156. package/build/nl-json.2b8cc3a0.chunk.js +1 -0
  157. package/build/no-json.a58c28bd.chunk.js +1 -0
  158. package/build/pl-json.249626b3.chunk.js +1 -0
  159. package/build/pt-BR-json.2b72b1d6.chunk.js +1 -0
  160. package/build/ru-json.d7cfc2ff.chunk.js +1 -0
  161. package/build/runtime~main.ede9da1e.js +2 -0
  162. package/build/sa-json.44e95991.chunk.js +1 -0
  163. package/build/sk-json.7ba4b330.chunk.js +1 -0
  164. package/build/sv-json.fb1081ff.chunk.js +1 -0
  165. package/build/th-json.a67309b1.chunk.js +1 -0
  166. package/build/{upload-settings.3d613216.chunk.js → upload-settings.3f7ad973.chunk.js} +5 -5
  167. package/build/{users-advanced-settings-page.f4051d92.chunk.js → users-advanced-settings-page.6a838320.chunk.js} +5 -5
  168. package/build/users-permissions-translation-sv-json.d5d11648.chunk.js +1 -0
  169. package/build/{webhook-edit-page.9e46fc3f.chunk.js → webhook-edit-page.dc9442ce.chunk.js} +1 -1
  170. package/build/webhook-list-page.a110c462.chunk.js +134 -0
  171. package/build/zh-Hans-json.21617c24.chunk.js +1 -0
  172. package/build/zh-json.608aaf24.chunk.js +1 -0
  173. package/ee/admin/pages/SettingsPage/pages/Roles/ListPage/index.js +3 -2
  174. package/env.js +1 -0
  175. package/package.json +18 -17
  176. package/scripts/build.js +11 -0
  177. package/server/content-types/api-token.js +1 -1
  178. package/utils/create-plugins-exclude-path.js +40 -0
  179. package/webpack.alias.js +0 -13
  180. package/webpack.config.js +4 -1
  181. package/admin/src/assets/images/banner_strapi-rocket.png +0 -0
  182. package/admin/src/assets/images/big-logo-home.png +0 -0
  183. package/admin/src/assets/images/homepage-logo.png +0 -0
  184. package/admin/src/assets/images/icon_made-by-strapi.svg +0 -5
  185. package/admin/src/assets/images/logo_strapi_auth.png +0 -0
  186. package/admin/src/assets/images/logo_strapi_auth_v4.png +0 -0
  187. package/admin/src/assets/images/logo_strapi_menu.png +0 -0
  188. package/admin/src/assets/images/oops.png +0 -0
  189. package/admin/src/content-manager/components/DynamicZone/components/Component/Rectangle.js +0 -19
  190. package/admin/src/content-manager/components/DynamicZone/components/Component/index.js +0 -191
  191. package/admin/src/content-manager/components/State/index.js +0 -37
  192. package/admin/src/content-manager/icons/Bold/index.js +0 -22
  193. package/admin/src/content-manager/icons/Code/index.js +0 -13
  194. package/admin/src/content-manager/icons/Cross/index.js +0 -28
  195. package/admin/src/content-manager/icons/Italic/index.js +0 -23
  196. package/admin/src/content-manager/icons/Link/index.js +0 -21
  197. package/admin/src/content-manager/icons/Media/index.js +0 -14
  198. package/admin/src/content-manager/icons/Na/index.js +0 -39
  199. package/admin/src/content-manager/icons/Ol/index.js +0 -13
  200. package/admin/src/content-manager/icons/Quote/index.js +0 -13
  201. package/admin/src/content-manager/icons/Striked/index.js +0 -24
  202. package/admin/src/content-manager/icons/Ul/index.js +0 -15
  203. package/admin/src/content-manager/icons/Underline/index.js +0 -22
  204. package/admin/src/favicon.ico +0 -0
  205. package/build/15026a3d58aeb2828134.png +0 -0
  206. package/build/1856.d8f13391.chunk.js +0 -173
  207. package/build/1939.e3c87653.chunk.js +0 -325
  208. package/build/2077.31a2d91e.chunk.js +0 -205
  209. package/build/2912.ab68a736.chunk.js +0 -258
  210. package/build/4318.7d167b58.chunk.js +0 -30
  211. package/build/4715.44b1ef9b.chunk.js +0 -386
  212. package/build/4982.c2a311b7.chunk.js +0 -324
  213. package/build/6925.f5c8b6fc.chunk.js +0 -761
  214. package/build/7841.4b67af3f.chunk.js +0 -258
  215. package/build/7866.5fbeb7e5.chunk.js +0 -504
  216. package/build/8380.9b53a31d.chunk.js +0 -284
  217. package/build/8549.cf10b5d1.chunk.js +0 -158
  218. package/build/8738.a30a2160.chunk.js +0 -461
  219. package/build/90f49a385afb000fb1d4.svg +0 -5
  220. package/build/9420.0fe11290.chunk.js +0 -504
  221. package/build/962.8651ba3f.chunk.js +0 -184
  222. package/build/Admin-authenticatedApp.883449a5.chunk.js +0 -80
  223. package/build/Admin_marketplace.82c0570b.chunk.js +0 -11
  224. package/build/Admin_settingsPage.98e2a62b.chunk.js +0 -178
  225. package/build/a6b842e0b6d2b61135d1.svg +0 -5
  226. package/build/admin-app.a61d5c2e.chunk.js +0 -112
  227. package/build/b997a22a2e0b87ef1fa2.ico +0 -0
  228. package/build/bd81ba6c07827282255d.png +0 -0
  229. package/build/c3de6118ef47086ad05c.png +0 -0
  230. package/build/ca-json.82df6eab.chunk.js +0 -1
  231. package/build/content-manager.933dc286.chunk.js +0 -1201
  232. package/build/content-type-builder-translation-pt-BR-json.d6c7fcc1.chunk.js +0 -1
  233. package/build/de-json.0ad554eb.chunk.js +0 -1
  234. package/build/dk-json.e195ea1a.chunk.js +0 -1
  235. package/build/email-translation-en-json.3d74ff95.chunk.js +0 -1
  236. package/build/en-json.1889403c.chunk.js +0 -1
  237. package/build/es-json.09f80f6e.chunk.js +0 -1
  238. package/build/fb376b132d18bf4522ca.png +0 -0
  239. package/build/fde9b1ad0670d29a2516.png +0 -0
  240. package/build/fr-json.606d056b.chunk.js +0 -1
  241. package/build/gu-json.9881264f.chunk.js +0 -1
  242. package/build/he-json.3b825d80.chunk.js +0 -1
  243. package/build/hi-json.83dcf48f.chunk.js +0 -1
  244. package/build/hu-json.6f328bce.chunk.js +0 -1
  245. package/build/id-json.1f3c4303.chunk.js +0 -1
  246. package/build/it-json.494ac432.chunk.js +0 -1
  247. package/build/ja-json.6f262117.chunk.js +0 -1
  248. package/build/ko-json.36dc3b9a.chunk.js +0 -1
  249. package/build/main.63e7ea0a.js +0 -9338
  250. package/build/ml-json.9566bf9a.chunk.js +0 -1
  251. package/build/nl-json.94c3a289.chunk.js +0 -1
  252. package/build/no-json.40386397.chunk.js +0 -1
  253. package/build/pl-json.ccc6ef23.chunk.js +0 -1
  254. package/build/pt-BR-json.744f024d.chunk.js +0 -1
  255. package/build/ru-json.d22ea13c.chunk.js +0 -1
  256. package/build/runtime~main.3a5e1b07.js +0 -2
  257. package/build/sa-json.8fb1c04d.chunk.js +0 -1
  258. package/build/sk-json.6c7335d4.chunk.js +0 -1
  259. package/build/sv-json.2e589a7d.chunk.js +0 -1
  260. package/build/th-json.72e8de3d.chunk.js +0 -1
  261. package/build/users-permissions-translation-sv-json.83c60841.chunk.js +0 -1
  262. package/build/webhook-list-page.a712ae40.chunk.js +0 -134
  263. package/build/zh-Hans-json.a4d7dc69.chunk.js +0 -1
  264. package/build/zh-json.66aa2ae1.chunk.js +0 -1
@@ -32,34 +32,13 @@ export const normalizeRelation = (relation, { shouldAddLink, mainFieldName, targ
32
32
 
33
33
  export const normalizeRelations = (
34
34
  relations,
35
- { modifiedData = {}, shouldAddLink = false, mainFieldName, targetModel }
35
+ { shouldAddLink = false, mainFieldName, targetModel } = {}
36
36
  ) => {
37
- return {
38
- ...relations,
39
- data: {
40
- pages:
41
- [
42
- ...(relations?.data?.pages.reverse() ?? []),
43
- ...(modifiedData?.connect ? [{ results: modifiedData.connect }] : []),
44
- ]
45
- ?.map((page) =>
46
- page?.results
47
- .filter(
48
- (relation) =>
49
- !modifiedData?.disconnect?.find(
50
- (disconnectRelation) => disconnectRelation.id === relation.id
51
- )
52
- )
53
- .map((relation) =>
54
- normalizeRelation(relation, {
55
- shouldAddLink,
56
- mainFieldName,
57
- targetModel,
58
- })
59
- )
60
- .filter(Boolean)
61
- )
62
- ?.filter((page) => page.length > 0) ?? [],
63
- },
64
- };
37
+ return [...relations].map((relation) =>
38
+ normalizeRelation(relation, {
39
+ shouldAddLink,
40
+ mainFieldName,
41
+ targetModel,
42
+ })
43
+ );
65
44
  };
@@ -1,12 +1,16 @@
1
1
  import { normalizeRelation } from './normalizeRelations';
2
2
 
3
3
  export const normalizeSearchResults = (relations, { mainFieldName }) => {
4
+ const { data } = relations;
5
+ const { pages = [] } = data ?? {};
6
+
4
7
  return {
5
8
  ...relations,
6
- data: {
7
- pages: [...(relations?.data?.pages ?? [])]?.map((page) =>
9
+ data: pages
10
+ .map((page) =>
8
11
  page?.results.map((relation) => normalizeRelation(relation, { mainFieldName }))
9
- ),
10
- },
12
+ )
13
+ .filter(Boolean)
14
+ .flat(),
11
15
  };
12
16
  };
@@ -82,6 +82,7 @@ function useSelect({
82
82
 
83
83
  return {
84
84
  componentId,
85
+ isComponentRelation: Boolean(componentUid),
85
86
  queryInfos: {
86
87
  ...queryInfos,
87
88
  endpoints: {
@@ -48,7 +48,7 @@ const RepeatableComponent = ({
48
48
  const [collapseToOpen, setCollapseToOpen] = useState('');
49
49
  const [isDraggingSibling, setIsDraggingSibling] = useState(false);
50
50
  const [, drop] = useDrop({ accept: ItemTypes.COMPONENT });
51
- const { getComponentLayout } = useContentTypeLayout();
51
+ const { getComponentLayout, components } = useContentTypeLayout();
52
52
  const componentLayoutData = useMemo(
53
53
  () => getComponentLayout(componentUid),
54
54
  [componentUid, getComponentLayout]
@@ -73,7 +73,7 @@ const RepeatableComponent = ({
73
73
  if (componentValueLength < max) {
74
74
  const shouldCheckErrors = hasMinError;
75
75
 
76
- addRepeatableComponentToField(name, componentUid, shouldCheckErrors);
76
+ addRepeatableComponentToField(name, componentLayoutData, components, shouldCheckErrors);
77
77
 
78
78
  setCollapseToOpen(nextTempKey);
79
79
  } else if (componentValueLength >= max) {
@@ -84,8 +84,9 @@ const RepeatableComponent = ({
84
84
  }
85
85
  }
86
86
  }, [
87
+ components,
87
88
  addRepeatableComponentToField,
88
- componentUid,
89
+ componentLayoutData,
89
90
  componentValueLength,
90
91
  hasMinError,
91
92
  isReadOnly,
@@ -0,0 +1,26 @@
1
+ import { renderHook } from '@testing-library/react-hooks';
2
+
3
+ import { usePrev } from '../usePrev';
4
+
5
+ describe('usePrev', () => {
6
+ const setup = () => renderHook(({ state }) => usePrev(state), { initialProps: { state: 0 } });
7
+
8
+ it('should return undefined on initial render', () => {
9
+ const { result } = setup();
10
+
11
+ expect(result.current).toBeUndefined();
12
+ });
13
+
14
+ it('should always return previous state after each update', () => {
15
+ const { result, rerender } = setup();
16
+
17
+ rerender({ state: 2 });
18
+ expect(result.current).toBe(0);
19
+
20
+ rerender({ state: 4 });
21
+ expect(result.current).toBe(2);
22
+
23
+ rerender({ state: 6 });
24
+ expect(result.current).toBe(4);
25
+ });
26
+ });
@@ -5,3 +5,4 @@ export { default as useLayoutDnd } from './useLayoutDnd';
5
5
  export { default as usePluginsQueryParams } from './usePluginsQueryParams';
6
6
  export { default as useSyncRbac } from './useSyncRbac';
7
7
  export { default as useWysiwyg } from './useWysiwyg';
8
+ export { usePrev } from './usePrev';
@@ -6,21 +6,19 @@ const getRelationModel = (targetModel, models) => models.find((model) => model.u
6
6
  const formatLayouts = (initialData, models) => {
7
7
  const data = createMetasSchema(initialData, models);
8
8
 
9
- const formattedCTEditLayout = formatLayoutWithMetas(data.contentType, null, models);
10
- const ctUid = data.contentType.uid;
9
+ const formattedCTEditLayout = formatLayoutWithMetas(data.contentType, models);
11
10
  const formattedListLayout = formatListLayoutWithMetas(data.contentType, data.components);
12
11
 
13
12
  set(data, ['contentType', 'layouts', 'edit'], formattedCTEditLayout);
14
13
  set(data, ['contentType', 'layouts', 'list'], formattedListLayout);
15
14
 
16
- Object.keys(data.components).forEach((compoUID) => {
17
- const formattedCompoEditLayout = formatLayoutWithMetas(
18
- data.components[compoUID],
19
- ctUid,
15
+ Object.keys(data.components).forEach((componentUid) => {
16
+ const formattedComponentEditLayout = formatLayoutWithMetas(
17
+ data.components[componentUid],
20
18
  models
21
19
  );
22
20
 
23
- set(data, ['components', compoUID, 'layouts', 'edit'], formattedCompoEditLayout);
21
+ set(data, ['components', componentUid, 'layouts', 'edit'], formattedComponentEditLayout);
24
22
  });
25
23
 
26
24
  return data;
@@ -73,8 +71,8 @@ const createMetasSchema = (initialData, models) => {
73
71
  return data;
74
72
  };
75
73
 
76
- const formatLayoutWithMetas = (contentTypeConfiguration, ctUid, models) => {
77
- const formatted = contentTypeConfiguration.layouts.edit.reduce((acc, current) => {
74
+ const formatLayoutWithMetas = (contentTypeConfiguration, models) =>
75
+ contentTypeConfiguration.layouts.edit.reduce((acc, current) => {
78
76
  const row = current.map((attribute) => {
79
77
  const fieldSchema = get(contentTypeConfiguration, ['attributes', attribute.name], {});
80
78
 
@@ -85,20 +83,17 @@ const formatLayoutWithMetas = (contentTypeConfiguration, ctUid, models) => {
85
83
  };
86
84
 
87
85
  if (fieldSchema.type === 'relation') {
88
- const targetModelUID = fieldSchema.targetModel;
89
- const targetModelSchema = getRelationModel(targetModelUID, models);
86
+ const targetModelSchema = getRelationModel(fieldSchema.targetModel, models);
90
87
  const targetModelPluginOptions = targetModelSchema.pluginOptions || {};
91
88
 
92
- const queryInfos = ctUid
93
- ? generateRelationQueryInfosForComponents(
94
- contentTypeConfiguration,
95
- attribute.name,
96
- models
97
- )
98
- : generateRelationQueryInfos(contentTypeConfiguration, attribute.name, models);
99
-
100
89
  set(data, 'targetModelPluginOptions', targetModelPluginOptions);
101
- set(data, 'queryInfos', queryInfos);
90
+ set(data, 'queryInfos', {
91
+ shouldDisplayRelationLink: shouldDisplayRelationLink(
92
+ contentTypeConfiguration,
93
+ attribute.name,
94
+ models
95
+ ),
96
+ });
102
97
  }
103
98
 
104
99
  return data;
@@ -109,9 +104,6 @@ const formatLayoutWithMetas = (contentTypeConfiguration, ctUid, models) => {
109
104
  return acc;
110
105
  }, []);
111
106
 
112
- return formatted;
113
- };
114
-
115
107
  const formatListLayoutWithMetas = (contentTypeConfiguration, components) => {
116
108
  const formatted = contentTypeConfiguration.layouts.list.reduce((acc, current) => {
117
109
  const fieldSchema = get(contentTypeConfiguration, ['attributes', current], {});
@@ -120,11 +112,7 @@ const formatListLayoutWithMetas = (contentTypeConfiguration, components) => {
120
112
  const type = fieldSchema.type;
121
113
 
122
114
  if (type === 'relation') {
123
- const queryInfos = {
124
- defaultParams: {},
125
- };
126
-
127
- acc.push({ key: `__${current}_key__`, name: current, fieldSchema, metadatas, queryInfos });
115
+ acc.push({ key: `__${current}_key__`, name: current, fieldSchema, metadatas });
128
116
 
129
117
  return acc;
130
118
  }
@@ -158,26 +146,10 @@ const formatListLayoutWithMetas = (contentTypeConfiguration, components) => {
158
146
  return formatted;
159
147
  };
160
148
 
161
- const generateRelationQueryInfos = (contentTypeConfiguration, fieldName, models) => {
149
+ const shouldDisplayRelationLink = (contentTypeConfiguration, fieldName, models) => {
162
150
  const targetModel = get(contentTypeConfiguration, ['attributes', fieldName, 'targetModel'], '');
163
- const shouldDisplayRelationLink = getDisplayedModels(models).includes(targetModel);
164
151
 
165
- return {
166
- defaultParams: {},
167
- shouldDisplayRelationLink,
168
- };
169
- };
170
-
171
- const generateRelationQueryInfosForComponents = (contentTypeConfiguration, fieldName, models) => {
172
- const targetModel = get(contentTypeConfiguration, ['attributes', fieldName, 'targetModel'], '');
173
- const shouldDisplayRelationLink = getDisplayedModels(models).includes(targetModel);
174
-
175
- return {
176
- defaultParams: {
177
- component: contentTypeConfiguration.uid,
178
- },
179
- shouldDisplayRelationLink,
180
- };
152
+ return getDisplayedModels(models).includes(targetModel);
181
153
  };
182
154
 
183
155
  const getDisplayedModels = (models) =>
@@ -187,7 +159,6 @@ export default formatLayouts;
187
159
  export {
188
160
  formatLayoutWithMetas,
189
161
  formatListLayoutWithMetas,
190
- generateRelationQueryInfos,
191
- generateRelationQueryInfosForComponents,
162
+ shouldDisplayRelationLink,
192
163
  getDisplayedModels,
193
164
  };
@@ -0,0 +1,14 @@
1
+ import { useEffect, useRef } from 'react';
2
+
3
+ /**
4
+ * @type {<T>(value: T) => T | undefined}
5
+ */
6
+ export const usePrev = (value) => {
7
+ const ref = useRef();
8
+
9
+ useEffect(() => {
10
+ ref.current = value;
11
+ }, [value]);
12
+
13
+ return ref.current;
14
+ };
@@ -1,11 +1,16 @@
1
- import { useState } from 'react';
1
+ import { useState, useEffect } from 'react';
2
2
  import { useInfiniteQuery } from 'react-query';
3
3
 
4
4
  import { axiosInstance } from '../../../core/utils';
5
5
 
6
- export const useRelation = (cacheKey, { relation, search }) => {
7
- const [searchParams, setSearchParams] = useState({});
6
+ import { normalizeRelations } from '../../components/RelationInputDataManager/utils';
8
7
 
8
+ export const useRelation = (cacheKey, { name, relation, search }) => {
9
+ const [searchParams, setSearchParams] = useState({});
10
+ const [currentPage, setCurrentPage] = useState(0);
11
+ /**
12
+ * This runs in `useInfiniteQuery` to actually fetch the data
13
+ */
9
14
  const fetchRelations = async ({ pageParam = 1 }) => {
10
15
  try {
11
16
  const { data } = await axiosInstance.get(relation?.endpoint, {
@@ -15,6 +20,8 @@ export const useRelation = (cacheKey, { relation, search }) => {
15
20
  },
16
21
  });
17
22
 
23
+ setCurrentPage(pageParam);
24
+
18
25
  return data;
19
26
  } catch (err) {
20
27
  return null;
@@ -37,12 +44,32 @@ export const useRelation = (cacheKey, { relation, search }) => {
37
44
  }
38
45
  };
39
46
 
47
+ const { onLoad: onLoadRelationsCallback, normalizeArguments = {} } = relation;
48
+
40
49
  const relationsRes = useInfiniteQuery(['relation', cacheKey], fetchRelations, {
41
50
  cacheTime: 0,
42
51
  enabled: relation.enabled,
52
+ /**
53
+ * @type {(lastPage:
54
+ * | { data: null }
55
+ * | { results: any[],
56
+ * pagination: {
57
+ * page: number,
58
+ * pageCount: number,
59
+ * pageSize: number,
60
+ * total: number
61
+ * }
62
+ * }
63
+ * ) => number}
64
+ */
43
65
  getNextPageParam(lastPage) {
44
- // the API may send an empty 204 response
45
- if (!lastPage || lastPage.pagination.page >= lastPage.pagination.pageCount) {
66
+ const isXToOneRelation = !lastPage?.pagination;
67
+
68
+ if (
69
+ !lastPage || // the API may send an empty 204 response
70
+ isXToOneRelation || // xToOne relations do not have a pagination
71
+ lastPage?.pagination.page >= lastPage?.pagination.pageCount
72
+ ) {
46
73
  return undefined;
47
74
  }
48
75
 
@@ -50,17 +77,83 @@ export const useRelation = (cacheKey, { relation, search }) => {
50
77
  return lastPage.pagination.page + 1;
51
78
  },
52
79
  select: (data) => ({
53
- pages: data.pages.map((page) => ({ ...page, results: [...(page.results ?? [])].reverse() })),
80
+ ...data,
81
+ pages: data.pages.map((page) => {
82
+ if (!page) {
83
+ return page;
84
+ }
85
+
86
+ const { data, results, pagination } = page;
87
+ const isXToOneRelation = !!data;
88
+ let normalizedResults = [];
89
+
90
+ // xToOne relations return an object, which we normalize so that relations
91
+ // always have the same shape
92
+ if (isXToOneRelation) {
93
+ normalizedResults = [data];
94
+ } else if (results) {
95
+ normalizedResults = [...results].reverse();
96
+ }
97
+
98
+ return {
99
+ pagination,
100
+ results: normalizedResults,
101
+ };
102
+ }),
54
103
  }),
55
104
  });
56
105
 
106
+ const { pageGoal } = relation;
107
+
108
+ const { status, data, fetchNextPage, hasNextPage } = relationsRes;
109
+
110
+ useEffect(() => {
111
+ /**
112
+ * This ensures the infiniteQuery hook fetching has caught-up with the modifiedData
113
+ * state i.e. in circumstances where you add 10 relations, the browserState knows this,
114
+ * but the hook would think it could fetch more, when in reality, it can't.
115
+ */
116
+ if (pageGoal > currentPage && hasNextPage && status === 'success') {
117
+ fetchNextPage({
118
+ pageParam: currentPage + 1,
119
+ });
120
+ }
121
+ }, [pageGoal, currentPage, fetchNextPage, hasNextPage, status]);
122
+
123
+ useEffect(() => {
124
+ if (status === 'success' && data && data.pages?.at(-1)?.results && onLoadRelationsCallback) {
125
+ // everytime we fetch, we normalize prior to adding to redux
126
+ const normalizedResults = normalizeRelations(data.pages.at(-1).results, normalizeArguments);
127
+
128
+ // this is loadRelation from EditViewDataManagerProvider
129
+ onLoadRelationsCallback({
130
+ target: { name, value: normalizedResults },
131
+ });
132
+ }
133
+
134
+ // eslint-disable-next-line react-hooks/exhaustive-deps
135
+ }, [status, onLoadRelationsCallback, name, data]);
136
+
57
137
  const searchRes = useInfiniteQuery(
58
138
  ['relation', cacheKey, 'search', JSON.stringify(searchParams)],
59
139
  fetchSearch,
60
140
  {
61
141
  enabled: Object.keys(searchParams).length > 0,
142
+ /**
143
+ * @type {(lastPage:
144
+ * | { data: null }
145
+ * | { results: any[],
146
+ * pagination: {
147
+ * page: number,
148
+ * pageCount: number,
149
+ * pageSize: number,
150
+ * total: number
151
+ * }
152
+ * }
153
+ * ) => number}
154
+ */
62
155
  getNextPageParam(lastPage) {
63
- if (lastPage.pagination.page >= lastPage.pagination.pageCount) {
156
+ if (!lastPage?.pagination || lastPage.pagination.page >= lastPage.pagination.pageCount) {
64
157
  return undefined;
65
158
  }
66
159
 
@@ -14,6 +14,9 @@ const initialState = {
14
14
  singleTypeLinks: [],
15
15
  };
16
16
 
17
+ /**
18
+ * Known as content-manager_app in the redux store
19
+ */
17
20
  const mainReducer = (state = initialState, action) =>
18
21
  produce(state, (draftState) => {
19
22
  switch (action.type) {
@@ -201,7 +201,7 @@ const DraggableCard = ({
201
201
  id: getTrad('components.DraggableCard.move.field'),
202
202
  defaultMessage: 'Move {item}',
203
203
  },
204
- { item: name }
204
+ { item: labelField }
205
205
  )}
206
206
  onClick={(e) => e.stopPropagation()}
207
207
  ref={refs.dragRef}
@@ -223,7 +223,7 @@ const DraggableCard = ({
223
223
  id: getTrad('components.DraggableCard.edit.field'),
224
224
  defaultMessage: 'Edit {item}',
225
225
  },
226
- { item: name }
226
+ { item: labelField }
227
227
  )}
228
228
  type="button"
229
229
  >
@@ -237,7 +237,7 @@ const DraggableCard = ({
237
237
  id: getTrad('components.DraggableCard.delete.field'),
238
238
  defaultMessage: 'Delete {item}',
239
239
  },
240
- { item: name }
240
+ { item: labelField }
241
241
  )}
242
242
  type="button"
243
243
  >
@@ -16,7 +16,7 @@ const FlexGap = styled(Flex)`
16
16
 
17
17
  const Settings = ({ modifiedData, onChange, sortOptions }) => {
18
18
  const { formatMessage } = useIntl();
19
- const { settings } = modifiedData;
19
+ const { settings, metadatas } = modifiedData;
20
20
 
21
21
  return (
22
22
  <>
@@ -122,7 +122,7 @@ const Settings = ({ modifiedData, onChange, sortOptions }) => {
122
122
  >
123
123
  {sortOptions.map((sortBy) => (
124
124
  <Option key={sortBy} value={sortBy}>
125
- {sortBy}
125
+ {metadatas[sortBy].list.label || sortBy}
126
126
  </Option>
127
127
  ))}
128
128
  </Select>
@@ -104,7 +104,7 @@ const SortDisplayedFields = ({
104
104
  >
105
105
  {listRemainingFields.map((field) => (
106
106
  <MenuItem key={field} onClick={() => handleAddField(field)}>
107
- {field}
107
+ {metadatas[field].list.label || field}
108
108
  </MenuItem>
109
109
  ))}
110
110
  </SimpleMenu>
@@ -16,7 +16,6 @@ const ALLOWED_TYPES = [
16
16
  'string',
17
17
  'text',
18
18
  'time',
19
- 'timestamp',
20
19
  'uid',
21
20
  ];
22
21
 
@@ -1,14 +1,29 @@
1
- import { createStore, applyMiddleware } from 'redux';
1
+ import { createStore, applyMiddleware, compose } from 'redux';
2
2
  import createReducer from './createReducer';
3
3
 
4
4
  const configureStore = (appMiddlewares, appReducers) => {
5
+ let composeEnhancers = compose;
6
+
5
7
  const middlewares = [];
6
8
 
7
9
  appMiddlewares.forEach((middleware) => {
8
10
  middlewares.push(middleware());
9
11
  });
10
12
 
11
- return createStore(createReducer(appReducers), {}, applyMiddleware(...middlewares));
13
+ // If Redux Dev Tools are installed, enable them
14
+ if (
15
+ process.env.NODE_ENV !== 'production' &&
16
+ typeof window === 'object' &&
17
+ window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
18
+ ) {
19
+ composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({});
20
+ }
21
+
22
+ return createStore(
23
+ createReducer(appReducers),
24
+ {},
25
+ composeEnhancers(applyMiddleware(...middlewares))
26
+ );
12
27
  };
13
28
 
14
29
  export default configureStore;
Binary file
@@ -2,10 +2,10 @@ import { useQuery } from 'react-query';
2
2
  import { useNotification } from '@strapi/helper-plugin';
3
3
  import { fetchMarketplacePlugins } from './utils/api';
4
4
 
5
- const useFetchMarketplacePlugins = (notifyLoad) => {
5
+ const useFetchMarketplacePlugins = (notifyLoad, params) => {
6
6
  const toggleNotification = useNotification();
7
7
 
8
- return useQuery('list-marketplace-plugins', () => fetchMarketplacePlugins(), {
8
+ return useQuery(['list-marketplace-plugins', params], () => fetchMarketplacePlugins(params), {
9
9
  onSuccess() {
10
10
  if (notifyLoad) {
11
11
  notifyLoad();
@@ -2,8 +2,10 @@ import axios from 'axios';
2
2
 
3
3
  const MARKETPLACE_API_URL = 'https://market-api.strapi.io';
4
4
 
5
- const fetchMarketplacePlugins = async () => {
6
- const { data: response } = await axios.get(`${MARKETPLACE_API_URL}/plugins`);
5
+ const fetchMarketplacePlugins = async (params = {}) => {
6
+ const { data: response } = await axios.get(`${MARKETPLACE_API_URL}/plugins`, {
7
+ params,
8
+ });
7
9
 
8
10
  // Only keep v4 plugins
9
11
  const filteredResponse = {
@@ -1,11 +1,11 @@
1
1
  import { useQuery } from 'react-query';
2
2
  import { useNotification } from '@strapi/helper-plugin';
3
- import { fetchMarketplacePlugins } from './utils/api';
3
+ import { fetchMarketplaceProviders } from './utils/api';
4
4
 
5
- const useFetchMarketplaceProviders = (notifyLoad) => {
5
+ const useFetchMarketplaceProviders = (notifyLoad, params) => {
6
6
  const toggleNotification = useNotification();
7
7
 
8
- return useQuery('list-marketplace-providers', () => fetchMarketplacePlugins(), {
8
+ return useQuery(['list-marketplace-providers', params], () => fetchMarketplaceProviders(params), {
9
9
  onSuccess() {
10
10
  if (notifyLoad) {
11
11
  notifyLoad();
@@ -2,10 +2,12 @@ import axios from 'axios';
2
2
 
3
3
  const MARKETPLACE_API_URL = 'https://market-api.strapi.io';
4
4
 
5
- const fetchMarketplacePlugins = async () => {
6
- const { data } = await axios.get(`${MARKETPLACE_API_URL}/providers`);
5
+ const fetchMarketplaceProviders = async (params = {}) => {
6
+ const { data } = await axios.get(`${MARKETPLACE_API_URL}/providers`, {
7
+ params,
8
+ });
7
9
 
8
10
  return data;
9
11
  };
10
12
 
11
- export { fetchMarketplacePlugins };
13
+ export { fetchMarketplaceProviders };
@@ -9,6 +9,7 @@ import appReducers from './reducers';
9
9
  window.strapi = {
10
10
  backendURL: process.env.STRAPI_ADMIN_BACKEND_URL,
11
11
  isEE: false,
12
+ telemetryDisabled: process.env.STRAPI_TELEMETRY_DISABLED ?? false,
12
13
  features: {
13
14
  SSO: 'sso',
14
15
  },
@@ -91,7 +91,7 @@ function App() {
91
91
  try {
92
92
  const deviceId = await getUID();
93
93
 
94
- fetch('https://analytics.strapi.io/track', {
94
+ await fetch('https://analytics.strapi.io/track', {
95
95
  method: 'POST',
96
96
  body: JSON.stringify({
97
97
  event: 'didInitializeAdministration',
@@ -0,0 +1,48 @@
1
+ <svg width="148" height="148" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <g opacity=".8" fill-rule="evenodd" clip-rule="evenodd">
3
+ <path opacity=".15" d="M110.81 37H73.97V74.1h36.84V37Z" fill="url(#a)"/>
4
+ <path opacity=".07" d="M36.84 0H0v37.08h36.84V0Z" fill="url(#b)"/>
5
+ <path opacity=".07" d="M73.92 73.95H37.08v37.08h36.84V73.95Z" fill="url(#c)"/>
6
+ <path opacity=".07" d="M147.99 110.92h-37.3V148H148v-37.08Z" fill="url(#d)"/>
7
+ <path opacity=".15" d="M73.83 37H36.84L73.83 0v37Z" fill="url(#e)"/>
8
+ <path opacity=".15" d="M110.6 111.02v-37h36.98l-36.99 37Z" fill="url(#f)"/>
9
+ <path opacity=".4" d="M73.83 0v37h36.98v37.01h37V3a3 3 0 0 0-3-3H73.82Z" fill="url(#g)"/>
10
+ </g>
11
+
12
+ <defs>
13
+ <linearGradient id="a" x1="91.31" y1="83.31" x2="118.24" y2="56.59" gradientUnits="userSpaceOnUse">
14
+ <stop stop-color="#7A92FF"/>
15
+ <stop offset="1" stop-color="#3253EA"/>
16
+ </linearGradient>
17
+
18
+ <linearGradient id="b" x1="40.99" y1="13.88" x2=".01" y2="11.64" gradientUnits="userSpaceOnUse">
19
+ <stop stop-color="#A8B8FF"/>
20
+ <stop offset="1" stop-color="#3253EA"/>
21
+ </linearGradient>
22
+
23
+ <linearGradient id="c" x1="54.41" y1="120.25" x2="81.35" y2="93.52" gradientUnits="userSpaceOnUse">
24
+ <stop stop-color="#A8B8FF"/>
25
+ <stop offset="1" stop-color="#3253EA"/>
26
+ </linearGradient>
27
+
28
+ <linearGradient id="d" x1="128.24" y1="157.22" x2="155.17" y2="130.17" gradientUnits="userSpaceOnUse">
29
+ <stop stop-color="#A8B8FF"/>
30
+ <stop offset="1" stop-color="#3253EA"/>
31
+ </linearGradient>
32
+
33
+ <linearGradient id="e" x1="54.24" y1="46.21" x2="81.12" y2="19.38" gradientUnits="userSpaceOnUse">
34
+ <stop stop-color="#7A92FF"/>
35
+ <stop offset="1" stop-color="#3253EA"/>
36
+ </linearGradient>
37
+
38
+ <linearGradient id="f" x1="126.28" y1="74.05" x2="124.94" y2="111.07" gradientUnits="userSpaceOnUse">
39
+ <stop stop-color="#7A92FF"/>
40
+ <stop offset="1" stop-color="#3253EA"/>
41
+ </linearGradient>
42
+
43
+ <linearGradient id="g" x1="73.37" y1="36.87" x2="132.87" y2="66.74" gradientUnits="userSpaceOnUse">
44
+ <stop stop-color="#7A92FF"/>
45
+ <stop offset="1" stop-color="#3858EA"/>
46
+ </linearGradient>
47
+ </defs>
48
+ </svg>