@strapi/admin 4.11.2 → 4.11.4

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 (205) hide show
  1. package/admin/src/components/AuthenticatedApp/index.js +2 -2
  2. package/admin/src/constants.js +90 -0
  3. package/admin/src/content-manager/components/CollectionTypeFormWrapper/index.js +10 -1
  4. package/admin/src/content-manager/components/EditViewDataManagerProvider/index.js +12 -8
  5. package/admin/src/content-manager/components/EditViewDataManagerProvider/reducer.js +5 -6
  6. package/admin/src/content-manager/components/RelationInput/RelationInput.js +99 -178
  7. package/admin/src/content-manager/components/RelationInput/components/Option.js +17 -15
  8. package/admin/src/content-manager/components/RelationInput/components/RelationList.js +2 -2
  9. package/admin/src/content-manager/components/RelationInputDataManager/RelationInputDataManager.js +12 -6
  10. package/admin/src/content-manager/components/RelationInputDataManager/utils/select.js +18 -3
  11. package/admin/src/content-manager/pages/App/index.js +4 -4
  12. package/admin/src/content-manager/pages/CollectionTypeRecursivePath/index.js +9 -5
  13. package/admin/src/content-manager/pages/ComponentSetttingsView/index.js +3 -4
  14. package/admin/src/content-manager/pages/EditView/hooks/useOnce.js +14 -0
  15. package/admin/src/content-manager/pages/EditView/index.js +31 -10
  16. package/admin/src/content-manager/{components/DynamicTable → pages/ListView/components}/CellContent/RelationMultiple/index.js +1 -1
  17. package/admin/src/content-manager/{components/DynamicTable → pages/ListView/components}/CellContent/utils/hasContent.js +1 -1
  18. package/admin/src/content-manager/{components/DynamicTable → pages/ListView/components}/ConfirmDialogDelete/index.js +7 -4
  19. package/admin/src/content-manager/pages/ListView/components/ConfirmDialogDeleteAll/index.js +78 -0
  20. package/admin/src/content-manager/pages/ListView/{FieldPicker → components/FieldPicker}/index.js +20 -9
  21. package/admin/src/content-manager/{components/DynamicTable → pages/ListView/components}/TableRows/index.js +90 -61
  22. package/admin/src/content-manager/pages/ListView/index.js +173 -34
  23. package/admin/src/content-manager/pages/ListView/utils/index.js +0 -2
  24. package/admin/src/content-manager/pages/ListViewLayoutManager/Permissions.js +1 -1
  25. package/admin/src/content-manager/pages/SingleTypeRecursivePath/index.js +4 -4
  26. package/admin/src/hooks/useMenu/index.js +70 -37
  27. package/admin/src/hooks/useMenu/utils/getGeneralLinks.js +5 -2
  28. package/admin/src/hooks/useSettingsMenu/constants.js +0 -7
  29. package/admin/src/hooks/useSettingsMenu/index.js +19 -5
  30. package/admin/src/pages/App/constants.js +1 -0
  31. package/admin/src/pages/App/index.js +23 -2
  32. package/admin/src/pages/App/reducer.js +8 -1
  33. package/admin/src/pages/App/selectors.js +12 -0
  34. package/admin/src/pages/AuthPage/{utils/forms.js → constants.js} +6 -8
  35. package/admin/src/pages/AuthPage/index.js +17 -5
  36. package/admin/src/pages/InstalledPluginsPage/index.js +10 -7
  37. package/admin/src/pages/MarketplacePage/index.js +11 -6
  38. package/admin/src/pages/ProfilePage/index.js +2 -2
  39. package/admin/src/pages/SettingsPage/components/Tokens/Table/index.js +15 -1
  40. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/index.js +4 -2
  41. package/admin/src/pages/SettingsPage/pages/ApiTokens/ListView/index.js +4 -2
  42. package/admin/src/pages/SettingsPage/pages/ApiTokens/ProtectedCreateView/index.js +5 -2
  43. package/admin/src/pages/SettingsPage/pages/ApiTokens/ProtectedEditView/index.js +5 -2
  44. package/admin/src/pages/SettingsPage/pages/ApiTokens/ProtectedListView/index.js +11 -6
  45. package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/index.js +130 -107
  46. package/admin/src/pages/SettingsPage/pages/Roles/CreatePage/index.js +5 -3
  47. package/admin/src/pages/SettingsPage/pages/Roles/ListPage/index.js +4 -2
  48. package/admin/src/pages/SettingsPage/pages/Roles/ProtectedEditPage/index.js +8 -9
  49. package/admin/src/pages/SettingsPage/pages/Roles/ProtectedListPage/index.js +11 -6
  50. package/admin/src/pages/SettingsPage/pages/TransferTokens/EditView/index.js +4 -2
  51. package/admin/src/pages/SettingsPage/pages/TransferTokens/ListView/index.js +4 -2
  52. package/admin/src/pages/SettingsPage/pages/TransferTokens/ProtectedCreateView/index.js +5 -2
  53. package/admin/src/pages/SettingsPage/pages/TransferTokens/ProtectedEditView/index.js +5 -2
  54. package/admin/src/pages/SettingsPage/pages/TransferTokens/ProtectedListView/index.js +11 -6
  55. package/admin/src/pages/SettingsPage/pages/Users/EditPage/index.js +2 -2
  56. package/admin/src/pages/SettingsPage/pages/Users/ListPage/ModalForm/{utils/layout.js → constants.js} +35 -2
  57. package/admin/src/pages/SettingsPage/pages/Users/ListPage/ModalForm/index.js +43 -10
  58. package/admin/src/pages/SettingsPage/pages/Users/ListPage/index.js +4 -2
  59. package/admin/src/pages/SettingsPage/pages/Users/ProtectedEditPage/index.js +13 -9
  60. package/admin/src/pages/SettingsPage/pages/Users/ProtectedListPage/index.js +11 -6
  61. package/admin/src/pages/SettingsPage/pages/Webhooks/EditView/components/Events/index.js +4 -2
  62. package/admin/src/pages/SettingsPage/pages/Webhooks/EditView/components/WebhookForm/utils/makeWebhookValidationSchema.js +11 -5
  63. package/admin/src/pages/SettingsPage/pages/Webhooks/ListView/index.js +4 -3
  64. package/admin/src/pages/SettingsPage/pages/Webhooks/ProtectedCreateView/index.js +11 -6
  65. package/admin/src/pages/SettingsPage/pages/Webhooks/ProtectedEditView/index.js +11 -6
  66. package/admin/src/pages/SettingsPage/pages/Webhooks/ProtectedListView/index.js +11 -6
  67. package/admin/src/translations/ca.json +1 -0
  68. package/admin/src/translations/en.json +4 -1
  69. package/admin/src/translations/es.json +5 -0
  70. package/admin/src/translations/fr.json +1 -0
  71. package/build/1386.3b2aa6a7.chunk.js +3 -0
  72. package/build/1799.44d2e264.chunk.js +33 -0
  73. package/build/1970.39a2d75e.chunk.js +1 -0
  74. package/build/3269.1ea0f5a6.chunk.js +1 -0
  75. package/build/{3528.969338e2.chunk.js → 3528.4845cf92.chunk.js} +1 -1
  76. package/build/448.829e1344.chunk.js +1 -0
  77. package/build/{5542.64b623c9.chunk.js → 5542.c62d0daf.chunk.js} +1 -1
  78. package/build/5563.86f9aa9c.chunk.js +79 -0
  79. package/build/{5932.9e1f8f92.chunk.js → 5932.6a23b88c.chunk.js} +1 -1
  80. package/build/{7018.0e8a6297.chunk.js → 7018.98feed67.chunk.js} +1 -1
  81. package/build/7259.fb69d4bf.chunk.js +1 -0
  82. package/build/7394.423886bd.chunk.js +1 -0
  83. package/build/{371.6e4e2c1f.chunk.js → 970.89601f27.chunk.js} +24 -24
  84. package/build/Admin-authenticatedApp.cb649fc1.chunk.js +79 -0
  85. package/build/{Admin_InternalErrorPage.4a6f7b20.chunk.js → Admin_InternalErrorPage.8911cb49.chunk.js} +1 -1
  86. package/build/{Admin_homePage.6cd6c25c.chunk.js → Admin_homePage.be30ef4e.chunk.js} +1 -1
  87. package/build/{Admin_marketplace.c82c1d3c.chunk.js → Admin_marketplace.74a58e20.chunk.js} +8 -8
  88. package/build/Admin_pluginsPage.ce464189.chunk.js +6 -0
  89. package/build/{Admin_profilePage.9d70d609.chunk.js → Admin_profilePage.2131eb68.chunk.js} +2 -2
  90. package/build/Admin_settingsPage.4069bb8a.chunk.js +79 -0
  91. package/build/{Upload_ConfigureTheView.34f449d7.chunk.js → Upload_ConfigureTheView.7a1cb9c9.chunk.js} +1 -1
  92. package/build/admin-app.fea867af.chunk.js +61 -0
  93. package/build/admin-edit-roles-page.3fdd6b9d.chunk.js +267 -0
  94. package/build/admin-edit-users.200551e3.chunk.js +10 -0
  95. package/build/admin-roles-list.e17b00d7.chunk.js +23 -0
  96. package/build/admin-users.3b12dca2.chunk.js +11 -0
  97. package/build/api-tokens-create-page.3dd4e921.chunk.js +1 -0
  98. package/build/api-tokens-edit-page.9a1dd2fa.chunk.js +1 -0
  99. package/build/api-tokens-list-page.a103f526.chunk.js +16 -0
  100. package/build/audit-logs-settings-page.f538490f.chunk.js +1 -0
  101. package/build/ca-json.1fed5d8b.chunk.js +1 -0
  102. package/build/content-manager.c40f5ff9.chunk.js +1088 -0
  103. package/build/{content-type-builder-list-view.c28d33a6.chunk.js → content-type-builder-list-view.a200a358.chunk.js} +3 -3
  104. package/build/content-type-builder.bd1bbff1.chunk.js +166 -0
  105. package/build/{email-settings-page.aee46eaa.chunk.js → email-settings-page.45695daa.chunk.js} +2 -2
  106. package/build/en-json.fb9f6ddd.chunk.js +1 -0
  107. package/build/es-json.42096084.chunk.js +1 -0
  108. package/build/fr-json.69789980.chunk.js +1 -0
  109. package/build/{i18n-settings-page.4bc37a3f.chunk.js → i18n-settings-page.29308d0b.chunk.js} +1 -1
  110. package/build/index.html +1 -1
  111. package/build/main.ee36abd9.js +2927 -0
  112. package/build/review-workflows-settings.93808ae0.chunk.js +110 -0
  113. package/build/{runtime~main.2d0ed226.js → runtime~main.efd966f6.js} +2 -2
  114. package/build/sso-settings-page.0cdb96a6.chunk.js +1 -0
  115. package/build/transfer-tokens-create-page.de14cad4.chunk.js +1 -0
  116. package/build/transfer-tokens-edit-page.4f5e39af.chunk.js +1 -0
  117. package/build/transfer-tokens-list-page.7237443d.chunk.js +16 -0
  118. package/build/{upload-settings.a05aa26c.chunk.js → upload-settings.cb6c14c3.chunk.js} +2 -2
  119. package/build/upload.7e629643.chunk.js +26 -0
  120. package/build/users-advanced-settings-page.750b1f76.chunk.js +9 -0
  121. package/build/{users-email-settings-page.0bc87315.chunk.js → users-email-settings-page.e9bcd865.chunk.js} +1 -1
  122. package/build/{users-providers-settings-page.e88f1ac5.chunk.js → users-providers-settings-page.a94253e9.chunk.js} +1 -1
  123. package/build/{users-roles-settings-page.573a5c3e.chunk.js → users-roles-settings-page.1f505119.chunk.js} +5 -5
  124. package/build/webhook-edit-page.77ef4f1a.chunk.js +33 -0
  125. package/build/webhook-list-page.940a40f1.chunk.js +63 -0
  126. package/ee/admin/constants.js +16 -0
  127. package/ee/admin/content-manager/pages/EditView/InformationBox/InformationBoxEE.js +1 -1
  128. package/ee/admin/hooks/useLicenseLimits/index.js +4 -2
  129. package/ee/admin/hooks/useSettingsMenu/constants.js +0 -5
  130. package/ee/admin/pages/AuthPage/constants.js +12 -0
  131. package/ee/admin/pages/SettingsPage/pages/AuditLogs/ListView/index.js +7 -7
  132. package/ee/admin/pages/SettingsPage/pages/AuditLogs/ProtectedListPage/index.js +11 -6
  133. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/ProtectedPage.js +20 -0
  134. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/ReviewWorkflows.js +68 -73
  135. package/ee/admin/pages/SettingsPage/pages/SingleSignOn/index.js +16 -12
  136. package/ee/admin/pages/SettingsPage/pages/Users/ListPage/ModalForm/{utils/roleSettingsForm.js → constants.js} +14 -8
  137. package/ee/admin/pages/SettingsPage/pages/Webhooks/EditView/components/EventTable/EventTableEE.js +8 -9
  138. package/ee/server/constants/webhookEvents.js +5 -0
  139. package/ee/server/controllers/workflows/stages/index.js +1 -1
  140. package/ee/server/services/passport.js +1 -1
  141. package/ee/server/services/review-workflows/entity-service-decorator.js +52 -1
  142. package/ee/server/services/review-workflows/review-workflows.js +4 -1
  143. package/package.json +12 -12
  144. package/server/content-types/User.js +10 -0
  145. package/server/services/permission/permissions-manager/sanitize.js +1 -1
  146. package/server/strategies/api-token.js +9 -5
  147. package/server/strategies/data-transfer.js +9 -5
  148. package/admin/src/content-manager/components/DynamicTable/index.js +0 -163
  149. package/admin/src/content-manager/components/RelationInput/components/Relation.js +0 -53
  150. package/admin/src/content-manager/pages/ListView/FieldPicker/utils/getAllAllowedHeader.js +0 -17
  151. package/admin/src/content-manager/pages/ListView/PaginationFooter/index.js +0 -35
  152. package/admin/src/hooks/useMenu/reducer.js +0 -63
  153. package/admin/src/pages/AuthPage/utils/index.js +0 -2
  154. package/admin/src/pages/SettingsPage/pages/Users/ListPage/ModalForm/utils/formDataModel.js +0 -8
  155. package/admin/src/pages/SettingsPage/pages/Users/ListPage/ModalForm/utils/roleSettingsForm.js +0 -3
  156. package/admin/src/pages/SettingsPage/pages/Users/ListPage/ModalForm/utils/schema.js +0 -11
  157. package/admin/src/pages/SettingsPage/pages/Users/ListPage/ModalForm/utils/stepper.js +0 -17
  158. package/admin/src/permissions/customPermissions.js +0 -1
  159. package/admin/src/permissions/defaultPermissions.js +0 -92
  160. package/admin/src/permissions/index.js +0 -8
  161. package/build/1970.d246745e.chunk.js +0 -1
  162. package/build/3562.e0b1a0b3.chunk.js +0 -50
  163. package/build/5563.8a76bb1d.chunk.js +0 -79
  164. package/build/7259.eac09d4b.chunk.js +0 -1
  165. package/build/7447.3dabc92f.chunk.js +0 -35
  166. package/build/9363.6a7a78fc.chunk.js +0 -33
  167. package/build/Admin-authenticatedApp.4e158a8c.chunk.js +0 -79
  168. package/build/Admin_pluginsPage.5d9d4060.chunk.js +0 -6
  169. package/build/Admin_settingsPage.fefeafa0.chunk.js +0 -79
  170. package/build/admin-app.42c7a752.chunk.js +0 -63
  171. package/build/admin-edit-roles-page.6d62ca0b.chunk.js +0 -267
  172. package/build/admin-edit-users.bce64103.chunk.js +0 -10
  173. package/build/admin-roles-list.81ae57e3.chunk.js +0 -23
  174. package/build/admin-users.1ec50325.chunk.js +0 -11
  175. package/build/api-tokens-create-page.65411a36.chunk.js +0 -1
  176. package/build/api-tokens-edit-page.60312cb6.chunk.js +0 -1
  177. package/build/api-tokens-list-page.36a241c1.chunk.js +0 -16
  178. package/build/audit-logs-settings-page.fca8e2a0.chunk.js +0 -1
  179. package/build/ca-json.43e14418.chunk.js +0 -1
  180. package/build/content-manager.d6e60c78.chunk.js +0 -1094
  181. package/build/content-type-builder.dc0c8745.chunk.js +0 -132
  182. package/build/en-json.f5fa476a.chunk.js +0 -1
  183. package/build/es-json.715b6fd8.chunk.js +0 -1
  184. package/build/fr-json.73494bf5.chunk.js +0 -1
  185. package/build/main.9b423e8b.js +0 -2926
  186. package/build/review-workflows-settings.fc0b59ca.chunk.js +0 -61
  187. package/build/sso-settings-page.52f8d7de.chunk.js +0 -1
  188. package/build/transfer-tokens-create-page.9ec277d7.chunk.js +0 -1
  189. package/build/transfer-tokens-edit-page.fa5ade14.chunk.js +0 -1
  190. package/build/transfer-tokens-list-page.ae9900e4.chunk.js +0 -16
  191. package/build/upload.b0efd607.chunk.js +0 -26
  192. package/build/users-advanced-settings-page.d9e11bab.chunk.js +0 -9
  193. package/build/webhook-edit-page.1e8c9382.chunk.js +0 -31
  194. package/build/webhook-list-page.b2bcb3b6.chunk.js +0 -63
  195. package/ee/admin/pages/AuthPage/utils/forms.js +0 -16
  196. package/ee/admin/pages/SettingsPage/pages/Users/ListPage/ModalForm/utils/formDataModel.js +0 -14
  197. /package/admin/src/content-manager/{components/DynamicTable → pages/ListView/components}/CellContent/CellValue.js +0 -0
  198. /package/admin/src/content-manager/{components/DynamicTable → pages/ListView/components}/CellContent/Media/FileWrapper.js +0 -0
  199. /package/admin/src/content-manager/{components/DynamicTable → pages/ListView/components}/CellContent/Media/index.js +0 -0
  200. /package/admin/src/content-manager/{components/DynamicTable → pages/ListView/components}/CellContent/MultipleMedias.js +0 -0
  201. /package/admin/src/content-manager/{components/DynamicTable → pages/ListView/components}/CellContent/RelationSingle/index.js +0 -0
  202. /package/admin/src/content-manager/{components/DynamicTable → pages/ListView/components}/CellContent/RepeatableComponent/index.js +0 -0
  203. /package/admin/src/content-manager/{components/DynamicTable → pages/ListView/components}/CellContent/SingleComponent/index.js +0 -0
  204. /package/admin/src/content-manager/{components/DynamicTable → pages/ListView/components}/CellContent/index.js +0 -0
  205. /package/admin/src/content-manager/{components/DynamicTable → pages/ListView/components}/CellContent/utils/isSingleRelation.js +0 -0
@@ -38,7 +38,7 @@ const AuthenticatedApp = () => {
38
38
  const [
39
39
  { data: appInfos, status },
40
40
  { data: tagName, isLoading },
41
- { data: permissions, status: fetchPermissionsStatus, refetch, isFetched, isFetching },
41
+ { data: permissions, status: fetchPermissionsStatus, refetch, isFetching },
42
42
  { data: userRoles },
43
43
  ] = useQueries([
44
44
  { queryKey: 'app-infos', queryFn: fetchAppInfo },
@@ -86,7 +86,7 @@ const AuthenticatedApp = () => {
86
86
  // We don't need to wait for the release query to be fetched before rendering the plugins
87
87
  // however, we need the appInfos and the permissions
88
88
  const shouldShowNotDependentQueriesLoader =
89
- (isFetching && isFetched) || status === 'loading' || fetchPermissionsStatus === 'loading';
89
+ isFetching || status === 'loading' || fetchPermissionsStatus === 'loading';
90
90
 
91
91
  const shouldShowLoader = isLoading || shouldShowNotDependentQueriesLoader;
92
92
 
@@ -0,0 +1,90 @@
1
+ export const ADMIN_PERMISSIONS_CE = {
2
+ contentManager: {
3
+ main: [],
4
+ collectionTypesConfigurations: [
5
+ {
6
+ action: 'plugin::content-manager.collection-types.configure-view',
7
+ subject: null,
8
+ },
9
+ ],
10
+ componentsConfigurations: [
11
+ {
12
+ action: 'plugin::content-manager.components.configure-layout',
13
+ subject: null,
14
+ },
15
+ ],
16
+ singleTypesConfigurations: [
17
+ {
18
+ action: 'plugin::content-manager.single-types.configure-view',
19
+ subject: null,
20
+ },
21
+ ],
22
+ },
23
+ marketplace: {
24
+ main: [{ action: 'admin::marketplace.read', subject: null }],
25
+ read: [{ action: 'admin::marketplace.read', subject: null }],
26
+ },
27
+ settings: {
28
+ roles: {
29
+ main: [
30
+ { action: 'admin::roles.create', subject: null },
31
+ { action: 'admin::roles.update', subject: null },
32
+ { action: 'admin::roles.read', subject: null },
33
+ { action: 'admin::roles.delete', subject: null },
34
+ ],
35
+ create: [{ action: 'admin::roles.create', subject: null }],
36
+ delete: [{ action: 'admin::roles.delete', subject: null }],
37
+ read: [{ action: 'admin::roles.read', subject: null }],
38
+ update: [{ action: 'admin::roles.update', subject: null }],
39
+ },
40
+ users: {
41
+ main: [
42
+ { action: 'admin::users.create', subject: null },
43
+ { action: 'admin::users.read', subject: null },
44
+ { action: 'admin::users.update', subject: null },
45
+ { action: 'admin::users.delete', subject: null },
46
+ ],
47
+ create: [{ action: 'admin::users.create', subject: null }],
48
+ delete: [{ action: 'admin::users.delete', subject: null }],
49
+ read: [{ action: 'admin::users.read', subject: null }],
50
+ update: [{ action: 'admin::users.update', subject: null }],
51
+ },
52
+ webhooks: {
53
+ main: [
54
+ { action: 'admin::webhooks.create', subject: null },
55
+ { action: 'admin::webhooks.read', subject: null },
56
+ { action: 'admin::webhooks.update', subject: null },
57
+ { action: 'admin::webhooks.delete', subject: null },
58
+ ],
59
+ create: [{ action: 'admin::webhooks.create', subject: null }],
60
+ delete: [{ action: 'admin::webhooks.delete', subject: null }],
61
+ read: [
62
+ { action: 'admin::webhooks.read', subject: null },
63
+ // NOTE: We need to check with the API
64
+ { action: 'admin::webhooks.update', subject: null },
65
+ { action: 'admin::webhooks.delete', subject: null },
66
+ ],
67
+ update: [{ action: 'admin::webhooks.update', subject: null }],
68
+ },
69
+ 'api-tokens': {
70
+ main: [{ action: 'admin::api-tokens.access', subject: null }],
71
+ create: [{ action: 'admin::api-tokens.create', subject: null }],
72
+ delete: [{ action: 'admin::api-tokens.delete', subject: null }],
73
+ read: [{ action: 'admin::api-tokens.read', subject: null }],
74
+ update: [{ action: 'admin::api-tokens.update', subject: null }],
75
+ regenerate: [{ action: 'admin::api-tokens.regenerate', subject: null }],
76
+ },
77
+ 'transfer-tokens': {
78
+ main: [{ action: 'admin::transfer.tokens.access', subject: null }],
79
+ create: [{ action: 'admin::transfer.tokens.create', subject: null }],
80
+ delete: [{ action: 'admin::transfer.tokens.delete', subject: null }],
81
+ read: [{ action: 'admin::transfer.tokens.read', subject: null }],
82
+ update: [{ action: 'admin::transfer.tokens.update', subject: null }],
83
+ regenerate: [{ action: 'admin::transfer.tokens.regenerate', subject: null }],
84
+ },
85
+ 'project-settings': {
86
+ read: [{ action: 'admin::project-settings.read', subject: null }],
87
+ update: [{ action: 'admin::project-settings.update', subject: null }],
88
+ },
89
+ },
90
+ };
@@ -237,7 +237,15 @@ const CollectionTypeFormWrapper = ({ allLayoutData, children, slug, id, origin }
237
237
 
238
238
  const onPost = useCallback(
239
239
  async (body, trackerProperty) => {
240
- const endPoint = `${getRequestUrl(`collection-types/${slug}`)}${rawQuery}`;
240
+ /**
241
+ * If we're cloning we want to post directly to this endpoint
242
+ * so that the relations even if they're not listed in the EditView
243
+ * are correctly attached to the entry.
244
+ */
245
+ const endPoint =
246
+ typeof origin === 'string'
247
+ ? `${getRequestUrl(`collection-types/${slug}/clone/${origin}`)}${rawQuery}`
248
+ : `${getRequestUrl(`collection-types/${slug}`)}${rawQuery}`;
241
249
  try {
242
250
  // Show a loading button in the EditView/Header.js && lock the app => no navigation
243
251
  dispatch(setStatus('submit-pending'));
@@ -272,6 +280,7 @@ const CollectionTypeFormWrapper = ({ allLayoutData, children, slug, id, origin }
272
280
  }
273
281
  },
274
282
  [
283
+ origin,
275
284
  cleanReceivedData,
276
285
  displayErrors,
277
286
  replace,
@@ -241,14 +241,18 @@ const EditViewDataManagerProvider = ({
241
241
  });
242
242
  }, []);
243
243
 
244
- const relationLoad = useCallback(({ target: { initialDataPath, modifiedDataPath, value } }) => {
245
- dispatch({
246
- type: 'LOAD_RELATION',
247
- modifiedDataPath,
248
- initialDataPath,
249
- value,
250
- });
251
- }, []);
244
+ const relationLoad = useCallback(
245
+ ({ target: { initialDataPath, modifiedDataPath, value, modifiedDataOnly } }) => {
246
+ dispatch({
247
+ type: 'LOAD_RELATION',
248
+ modifiedDataPath,
249
+ initialDataPath,
250
+ value,
251
+ modifiedDataOnly,
252
+ });
253
+ },
254
+ []
255
+ );
252
256
 
253
257
  const addRepeatableComponentToField = dispatchAddComponent('ADD_REPEATABLE_COMPONENT_TO_FIELD');
254
258
 
@@ -138,17 +138,16 @@ const reducer = (state, action) =>
138
138
  __temp_key__: keys[index],
139
139
  }));
140
140
 
141
- set(
142
- draftState,
143
- initialDataPath,
144
- uniqBy([...valuesWithKeys, ...initialDataRelations], 'id')
145
- );
146
-
147
141
  /**
148
142
  * We need to set the value also on modifiedData, because initialData
149
143
  * and modifiedData need to stay in sync, so that the CM can compare
150
144
  * both states, to render the dirty UI state
151
145
  */
146
+ set(
147
+ draftState,
148
+ initialDataPath,
149
+ uniqBy([...valuesWithKeys, ...initialDataRelations], 'id')
150
+ );
152
151
  set(
153
152
  draftState,
154
153
  modifiedDataPath,
@@ -1,24 +1,17 @@
1
- import React, { useEffect, useMemo, useRef, useState } from 'react';
1
+ import React, { useRef, useState, useMemo, useEffect } from 'react';
2
2
 
3
3
  import {
4
+ Status,
4
5
  Box,
5
- Field,
6
- FieldError,
7
- FieldHint,
8
- FieldLabel,
9
- Icon,
10
6
  Link,
11
- Status,
7
+ Icon,
8
+ Flex,
12
9
  TextButton,
13
- Tooltip,
14
10
  Typography,
11
+ Tooltip,
15
12
  VisuallyHidden,
13
+ Combobox,
16
14
  } from '@strapi/design-system';
17
- /**
18
- * TODO: this will come in another PR.
19
- */
20
- // eslint-disable-next-line no-restricted-imports
21
- import { ReactSelect } from '@strapi/helper-plugin';
22
15
  import { Cross, Refresh } from '@strapi/icons';
23
16
  import PropTypes from 'prop-types';
24
17
  import { FixedSizeList as List } from 'react-window';
@@ -27,7 +20,6 @@ import styled from 'styled-components';
27
20
  import { usePrev } from '../../hooks';
28
21
 
29
22
  import { Option } from './components/Option';
30
- import { Relation } from './components/Relation';
31
23
  import { RelationItem } from './components/RelationItem';
32
24
  import { RelationList } from './components/RelationList';
33
25
  import { RELATION_GUTTER, RELATION_ITEM_HEIGHT } from './constants';
@@ -88,7 +80,7 @@ const RelationInput = ({
88
80
  searchResults,
89
81
  size,
90
82
  }) => {
91
- const [value, setValue] = useState(null);
83
+ const [textValue, setTextValue] = useState('');
92
84
  const [overflow, setOverflow] = useState('');
93
85
 
94
86
  const listRef = useRef();
@@ -158,71 +150,10 @@ const RelationInput = ({
158
150
  };
159
151
  }, [paginatedRelations, relations, numberOfRelationsToDisplay, totalNumberOfRelations]);
160
152
 
161
- /**
162
- * --- ReactSelect Workaround START ---
163
- */
164
- /**
165
- * This code is being isolated because it's a hack to fix a placement bug in
166
- * `react-select` where when the options prop is updated the position of the
167
- * menu is not recalculated.
168
- */
169
- const [isMenuOpen, setIsMenuOpen] = useState(false);
170
-
171
- const timeoutRef = useRef();
172
- const previousOptions = useRef([]);
173
-
174
- useEffect(() => {
175
- /**
176
- * We only really want this effect to fire once when the options
177
- * change from an empty array to an array with values.
178
- * Otherwise, it'll fire when the infinite scrolling happens causing
179
- * the menu to jump to the top all the time when loading more.
180
- */
181
- if (options.length > 0 && previousOptions.current.length === 0) {
182
- setIsMenuOpen((isCurrentlyOpened) => {
183
- /**
184
- * If we're currently open and the options changed
185
- * we want to close and open to ensure the menu's
186
- * position is correctly calculated
187
- */
188
- if (isCurrentlyOpened) {
189
- timeoutRef.current = setTimeout(() => {
190
- setIsMenuOpen(true);
191
- }, 10);
192
-
193
- return false;
194
- }
195
-
196
- return false;
197
- });
153
+ const handleMenuOpen = (isOpen) => {
154
+ if (isOpen) {
155
+ onSearch();
198
156
  }
199
-
200
- return () => {
201
- previousOptions.current = options || [];
202
- };
203
- }, [options]);
204
-
205
- useEffect(() => {
206
- return () => {
207
- /**
208
- * If the component unmounts and a timer is set we should clear that timer
209
- */
210
- if (timeoutRef.current) {
211
- clearTimeout(timeoutRef.current);
212
- }
213
- };
214
- }, []);
215
-
216
- const handleMenuClose = () => {
217
- setIsMenuOpen(false);
218
- };
219
- /**
220
- * --- ReactSelect Workaround END ---
221
- */
222
-
223
- const handleMenuOpen = () => {
224
- setIsMenuOpen(true);
225
- onSearch();
226
157
  };
227
158
 
228
159
  /**
@@ -250,122 +181,112 @@ const RelationInput = ({
250
181
  };
251
182
 
252
183
  useEffect(() => {
184
+ if (updatedRelationsWith.current === 'onChange') {
185
+ setTextValue('');
186
+ }
187
+
253
188
  if (
254
189
  updatedRelationsWith.current === 'onChange' &&
255
190
  relations.length !== previewRelationsLength
256
191
  ) {
257
192
  listRef.current.scrollToItem(relations.length, 'end');
193
+ updatedRelationsWith.current = undefined;
258
194
  } else if (
259
195
  updatedRelationsWith.current === 'loadMore' &&
260
196
  relations.length !== previewRelationsLength
261
197
  ) {
262
198
  listRef.current.scrollToItem(0, 'start');
199
+ updatedRelationsWith.current = undefined;
263
200
  }
264
-
265
- updatedRelationsWith.current = undefined;
266
201
  }, [previewRelationsLength, relations]);
267
202
 
268
203
  const ariaDescriptionId = `${name}-item-instructions`;
269
204
 
270
205
  return (
271
- <Field error={error} name={name} hint={description} id={id} required={required}>
272
- <Relation
273
- totalNumberOfRelations={totalNumberOfRelations}
274
- size={size}
275
- search={
276
- <>
277
- <FieldLabel action={labelAction}>{label}</FieldLabel>
278
- <ReactSelect
279
- // position fixed doesn't update position on scroll
280
- // react select doesn't update menu position on options change
281
- menuPosition="absolute"
282
- menuPlacement="auto"
283
- components={{ Option }}
284
- options={options}
285
- isDisabled={disabled}
286
- isLoading={searchResults.isLoading}
287
- error={error}
288
- inputId={id}
289
- isSearchable
290
- isClear
291
- loadingMessage={() => loadingMessage}
292
- onChange={(relation) => {
293
- setValue(null);
294
- onRelationConnect(relation);
295
- updatedRelationsWith.current = 'onChange';
296
- }}
297
- onInputChange={(value) => {
298
- setValue(value);
299
- onSearch(value);
300
- }}
301
- onMenuClose={handleMenuClose}
302
- onMenuOpen={handleMenuOpen}
303
- menuIsOpen={isMenuOpen}
304
- noOptionsMessage={() => noRelationsMessage}
305
- onMenuScrollToBottom={() => {
306
- if (searchResults.hasNextPage) {
307
- onSearchNextPage();
308
- }
309
- }}
310
- placeholder={placeholder}
311
- name={name}
312
- value={value}
313
- />
314
- </>
315
- }
316
- loadMore={
317
- shouldDisplayLoadMoreButton && (
318
- <TextButton
319
- disabled={paginatedRelations.isLoading || paginatedRelations.isFetchingNextPage}
320
- onClick={handleLoadMore}
321
- loading={paginatedRelations.isLoading || paginatedRelations.isFetchingNextPage}
322
- startIcon={<Refresh />}
323
- >
324
- {labelLoadMore}
325
- </TextButton>
326
- )
327
- }
328
- >
329
- {relations.length > 0 && (
330
- <RelationList overflow={overflow}>
331
- <VisuallyHidden id={ariaDescriptionId}>{listAriaDescription}</VisuallyHidden>
332
- <VisuallyHidden aria-live="assertive">{liveText}</VisuallyHidden>
333
- <List
334
- height={dynamicListHeight}
335
- ref={listRef}
336
- outerRef={outerListRef}
337
- itemCount={totalNumberOfRelations}
338
- itemSize={RELATION_ITEM_HEIGHT + RELATION_GUTTER}
339
- itemData={{
340
- name,
341
- ariaDescribedBy: ariaDescriptionId,
342
- canDrag: canReorder,
343
- disabled,
344
- handleCancel: onCancel,
345
- handleDropItem: onDropItem,
346
- handleGrabItem: onGrabItem,
347
- iconButtonAriaLabel,
348
- labelDisconnectRelation,
349
- onRelationDisconnect,
350
- publicationStateTranslations,
351
- relations,
352
- updatePositionOfRelation: handleUpdatePositionOfRelation,
353
- }}
354
- itemKey={(index) => `${relations[index].mainField}_${relations[index].id}`}
355
- innerElementType="ol"
356
- >
357
- {ListItem}
358
- </List>
359
- </RelationList>
360
- )}
361
- {(description || error) && (
362
- <Box paddingTop={2}>
363
- <FieldHint />
364
- <FieldError />
365
- </Box>
206
+ <Flex gap={3} justifyContent="space-between" alignItems="end" wrap="wrap">
207
+ <Flex direction="column" alignItems="stretch" basis={size <= 6 ? '100%' : '70%'} gap={2}>
208
+ <Combobox
209
+ autocomplete="list"
210
+ error={error}
211
+ name={name}
212
+ hint={description}
213
+ id={id}
214
+ required={required}
215
+ label={label}
216
+ labelAction={labelAction}
217
+ disabled={disabled}
218
+ placeholder={placeholder}
219
+ hasMoreItems={searchResults.hasNextPage}
220
+ loading={searchResults.isLoading}
221
+ onOpenChange={handleMenuOpen}
222
+ noOptionsMessage={() => noRelationsMessage}
223
+ loadingMessage={loadingMessage}
224
+ onLoadMore={() => {
225
+ onSearchNextPage();
226
+ }}
227
+ textValue={textValue}
228
+ onChange={(relationId) => {
229
+ if (!relationId) {
230
+ return;
231
+ }
232
+ onRelationConnect(options.find((opt) => opt.id === relationId));
233
+ updatedRelationsWith.current = 'onChange';
234
+ }}
235
+ onTextValueChange={(text) => {
236
+ setTextValue(text);
237
+ }}
238
+ onInputChange={(event) => {
239
+ onSearch(event.currentTarget.value);
240
+ }}
241
+ >
242
+ {options.map((opt) => {
243
+ return <Option key={opt.id} {...opt} />;
244
+ })}
245
+ </Combobox>
246
+ {shouldDisplayLoadMoreButton && (
247
+ <TextButton
248
+ disabled={paginatedRelations.isLoading || paginatedRelations.isFetchingNextPage}
249
+ onClick={handleLoadMore}
250
+ loading={paginatedRelations.isLoading || paginatedRelations.isFetchingNextPage}
251
+ startIcon={<Refresh />}
252
+ >
253
+ {labelLoadMore}
254
+ </TextButton>
366
255
  )}
367
- </Relation>
368
- </Field>
256
+ </Flex>
257
+ {relations.length > 0 && (
258
+ <RelationList overflow={overflow}>
259
+ <VisuallyHidden id={ariaDescriptionId}>{listAriaDescription}</VisuallyHidden>
260
+ <VisuallyHidden aria-live="assertive">{liveText}</VisuallyHidden>
261
+ <List
262
+ height={dynamicListHeight}
263
+ ref={listRef}
264
+ outerRef={outerListRef}
265
+ itemCount={totalNumberOfRelations}
266
+ itemSize={RELATION_ITEM_HEIGHT + RELATION_GUTTER}
267
+ itemData={{
268
+ name,
269
+ ariaDescribedBy: ariaDescriptionId,
270
+ canDrag: canReorder,
271
+ disabled,
272
+ handleCancel: onCancel,
273
+ handleDropItem: onDropItem,
274
+ handleGrabItem: onGrabItem,
275
+ iconButtonAriaLabel,
276
+ labelDisconnectRelation,
277
+ onRelationDisconnect,
278
+ publicationStateTranslations,
279
+ relations,
280
+ updatePositionOfRelation: handleUpdatePositionOfRelation,
281
+ }}
282
+ itemKey={(index) => `${relations[index].mainField}_${relations[index].id}`}
283
+ innerElementType="ol"
284
+ >
285
+ {ListItem}
286
+ </List>
287
+ </RelationList>
288
+ )}
289
+ </Flex>
369
290
  );
370
291
  };
371
292
 
@@ -1,10 +1,9 @@
1
1
  import React from 'react';
2
2
 
3
- import { Flex, Typography } from '@strapi/design-system';
3
+ import { Flex, Typography, ComboboxOption } from '@strapi/design-system';
4
4
  import { pxToRem } from '@strapi/helper-plugin';
5
5
  import PropTypes from 'prop-types';
6
6
  import { useIntl } from 'react-intl';
7
- import { components } from 'react-select';
8
7
  import styled from 'styled-components';
9
8
 
10
9
  import { getTrad } from '../../../utils';
@@ -19,10 +18,8 @@ const StyledBullet = styled.div`
19
18
  border-radius: 50%;
20
19
  `;
21
20
 
22
- export const Option = (props) => {
21
+ export const Option = ({ publicationState, mainField, id }) => {
23
22
  const { formatMessage } = useIntl();
24
- const Component = components.Option;
25
- const { publicationState, mainField, id } = props.data;
26
23
 
27
24
  if (publicationState) {
28
25
  const isDraft = publicationState === 'draft';
@@ -37,24 +34,29 @@ export const Option = (props) => {
37
34
  const title = isDraft ? formatMessage(draftMessage) : formatMessage(publishedMessage);
38
35
 
39
36
  return (
40
- <Component {...props}>
37
+ <ComboboxOption value={id} textValue={mainField ?? id}>
41
38
  <Flex>
42
39
  <StyledBullet title={title} isDraft={isDraft} />
43
40
  <Typography ellipsis>{mainField ?? id}</Typography>
44
41
  </Flex>
45
- </Component>
42
+ </ComboboxOption>
46
43
  );
47
44
  }
48
45
 
49
- return <Component {...props}>{mainField ?? id}</Component>;
46
+ return (
47
+ <ComboboxOption value={id} textValue={mainField ?? id}>
48
+ {mainField ?? id}
49
+ </ComboboxOption>
50
+ );
51
+ };
52
+
53
+ Option.defaultProps = {
54
+ mainField: undefined,
55
+ publicationState: undefined,
50
56
  };
51
57
 
52
58
  Option.propTypes = {
53
- isFocused: PropTypes.bool.isRequired,
54
- data: PropTypes.shape({
55
- id: PropTypes.number.isRequired,
56
- isDraft: PropTypes.bool,
57
- mainField: PropTypes.string,
58
- publicationState: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
59
- }).isRequired,
59
+ id: PropTypes.number.isRequired,
60
+ mainField: PropTypes.string,
61
+ publicationState: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
60
62
  };
@@ -6,8 +6,8 @@ import styled from 'styled-components';
6
6
 
7
7
  const ShadowBox = styled(Box)`
8
8
  position: relative;
9
- overflow-x: hidden;
10
- overflow-y: auto;
9
+ overflow: hidden;
10
+ flex: 1;
11
11
 
12
12
  &:before,
13
13
  &:after {
@@ -17,12 +17,14 @@ import { connect, diffRelations, normalizeRelation, normalizeSearchResults, sele
17
17
 
18
18
  export const RelationInputDataManager = ({
19
19
  error,
20
+ entityId,
20
21
  componentId,
21
22
  isComponentRelation,
22
23
  editable,
23
24
  description,
24
25
  intlLabel,
25
26
  isCreatingEntry,
27
+ isCloningEntry,
26
28
  isFieldAllowed,
27
29
  isFieldReadable,
28
30
  labelAction,
@@ -86,11 +88,12 @@ export const RelationInputDataManager = ({
86
88
  pageParams: {
87
89
  ...defaultParams,
88
90
  // eslint-disable-next-line no-nested-ternary
89
- entityId: isCreatingEntry
90
- ? undefined
91
- : isComponentRelation
92
- ? componentId
93
- : initialData.id,
91
+ entityId:
92
+ isCreatingEntry || isCloningEntry
93
+ ? undefined
94
+ : isComponentRelation
95
+ ? componentId
96
+ : entityId,
94
97
  pageSize: SEARCH_RESULTS_TO_DISPLAY,
95
98
  },
96
99
  },
@@ -300,7 +303,7 @@ export const RelationInputDataManager = ({
300
303
  })} ${totalRelations > 0 ? `(${totalRelations})` : ''}`}
301
304
  labelAction={labelAction}
302
305
  labelLoadMore={
303
- !isCreatingEntry
306
+ !isCreatingEntry || isCloningEntry
304
307
  ? formatMessage({
305
308
  id: getTrad('relation.loadMore'),
306
309
  defaultMessage: 'Load More',
@@ -372,6 +375,7 @@ export const RelationInputDataManager = ({
372
375
 
373
376
  RelationInputDataManager.defaultProps = {
374
377
  componentId: undefined,
378
+ entityId: undefined,
375
379
  editable: true,
376
380
  error: undefined,
377
381
  description: '',
@@ -384,6 +388,7 @@ RelationInputDataManager.defaultProps = {
384
388
 
385
389
  RelationInputDataManager.propTypes = {
386
390
  componentId: PropTypes.number,
391
+ entityId: PropTypes.number,
387
392
  editable: PropTypes.bool,
388
393
  error: PropTypes.string,
389
394
  description: PropTypes.string,
@@ -393,6 +398,7 @@ RelationInputDataManager.propTypes = {
393
398
  values: PropTypes.object,
394
399
  }).isRequired,
395
400
  labelAction: PropTypes.element,
401
+ isCloningEntry: PropTypes.bool.isRequired,
396
402
  isCreatingEntry: PropTypes.bool.isRequired,
397
403
  isComponentRelation: PropTypes.bool,
398
404
  isFieldAllowed: PropTypes.bool,