@strapi/admin 4.12.7 → 4.13.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (180) hide show
  1. package/admin/src/components/NpsSurvey/hooks/useNpsSurveySettings.js +17 -0
  2. package/admin/src/components/NpsSurvey/index.js +365 -0
  3. package/admin/src/content-manager/components/DynamicTable/CellContent/ReviewWorkflowsStage/getTableColumns.js +2 -0
  4. package/admin/src/content-manager/components/DynamicZone/components/DynamicZoneLabel.js +1 -1
  5. package/admin/src/content-manager/components/EditViewDataManagerProvider/reducer.js +7 -2
  6. package/admin/src/content-manager/components/EditViewDataManagerProvider/utils/cleanData.js +6 -0
  7. package/admin/src/content-manager/components/Filter/CustomInputs/AdminUsersFilter.js +42 -0
  8. package/admin/src/content-manager/components/Filter/Filter.js +54 -0
  9. package/admin/src/content-manager/components/Filter/index.js +1 -0
  10. package/admin/src/content-manager/components/InputUID/index.js +222 -216
  11. package/admin/src/content-manager/components/RelationInput/RelationInput.js +4 -0
  12. package/admin/src/content-manager/components/RepeatableComponent/index.js +32 -2
  13. package/admin/src/content-manager/components/Wysiwyg/Editor.js +432 -68
  14. package/admin/src/content-manager/components/Wysiwyg/WysiwygStyles.js +0 -7
  15. package/admin/src/content-manager/components/Wysiwyg/index.js +147 -152
  16. package/admin/src/content-manager/constants/attributes.js +3 -0
  17. package/admin/src/content-manager/hooks/useAllowedAttributes.js +43 -0
  18. package/admin/src/content-manager/pages/EditView/Information/index.js +9 -8
  19. package/admin/src/content-manager/pages/ListSettingsView/components/Settings.js +40 -7
  20. package/admin/src/content-manager/pages/ListSettingsView/index.js +6 -2
  21. package/admin/src/content-manager/pages/ListView/components/FieldPicker/index.js +67 -69
  22. package/admin/src/content-manager/pages/ListView/components/ViewSettingsMenu/index.js +80 -0
  23. package/admin/src/content-manager/pages/ListView/index.js +236 -67
  24. package/admin/src/content-manager/utils/getDisplayName.js +33 -0
  25. package/admin/src/content-manager/utils/index.js +1 -0
  26. package/admin/src/pages/Admin/index.js +3 -1
  27. package/admin/src/pages/AuthPage/components/Register/index.js +5 -0
  28. package/admin/src/pages/SettingsPage/components/SettingsNav/index.js +3 -3
  29. package/admin/src/pages/SettingsPage/index.js +16 -26
  30. package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/index.js +69 -35
  31. package/admin/src/plugins.js +7 -8
  32. package/admin/src/translations/en.json +10 -1
  33. package/build/{1049.f76cb14b.chunk.js → 1049.ec69f5e0.chunk.js} +1 -1
  34. package/build/1227.9f37e1dc.chunk.js +1 -0
  35. package/build/{1386.879bcd90.chunk.js → 1386.ea73b677.chunk.js} +1 -1
  36. package/build/1504.eff012f7.chunk.js +95 -0
  37. package/build/{2225.c6244756.chunk.js → 2225.649fb7bc.chunk.js} +11 -11
  38. package/build/2237.b832ae6e.chunk.js +114 -0
  39. package/build/2379.1f98a31a.chunk.js +1 -0
  40. package/build/2395.0e5e8ded.chunk.js +26 -0
  41. package/build/2801.8e1aa82a.chunk.js +1 -0
  42. package/build/{3483.03c24f96.chunk.js → 3483.19381b40.chunk.js} +1 -1
  43. package/build/4174.f1f39e40.chunk.js +1 -0
  44. package/build/4546.a5946d22.chunk.js +1 -0
  45. package/build/4724.aea5c8c1.chunk.js +6 -0
  46. package/build/502.7bba43b1.chunk.js +1 -0
  47. package/build/6158.c3c13c20.chunk.js +1 -0
  48. package/build/7464.eb057bec.chunk.js +1 -0
  49. package/build/78.dcc6df5c.chunk.js +1 -0
  50. package/build/8276.be3ed581.chunk.js +26 -0
  51. package/build/{Admin-authenticatedApp.31497f74.chunk.js → Admin-authenticatedApp.36b0fe22.chunk.js} +2 -2
  52. package/build/{Admin_InternalErrorPage.f45f2462.chunk.js → Admin_InternalErrorPage.38155af3.chunk.js} +1 -1
  53. package/build/{Admin_homePage.ac9dfb86.chunk.js → Admin_homePage.6f128523.chunk.js} +1 -1
  54. package/build/{Admin_marketplace.c94239f6.chunk.js → Admin_marketplace.061a6e5a.chunk.js} +1 -1
  55. package/build/{Admin_pluginsPage.bbe79434.chunk.js → Admin_pluginsPage.16f837b8.chunk.js} +1 -1
  56. package/build/{Admin_profilePage.192edc52.chunk.js → Admin_profilePage.678bce24.chunk.js} +2 -2
  57. package/build/Admin_settingsPage.af7309e4.chunk.js +111 -0
  58. package/build/{Upload_ConfigureTheView.345ac1e0.chunk.js → Upload_ConfigureTheView.3fc1c100.chunk.js} +1 -1
  59. package/build/admin-app.d63bd229.chunk.js +36 -0
  60. package/build/{admin-edit-roles-page.6d567273.chunk.js → admin-edit-roles-page.38a6c863.chunk.js} +3 -3
  61. package/build/{admin-edit-users.acfd4128.chunk.js → admin-edit-users.545fc882.chunk.js} +2 -2
  62. package/build/{admin-roles-list.23ddff26.chunk.js → admin-roles-list.1e2e814d.chunk.js} +1 -1
  63. package/build/{admin-users.00e20017.chunk.js → admin-users.b8ea5677.chunk.js} +2 -2
  64. package/build/{api-tokens-create-page.46c2ea84.chunk.js → api-tokens-create-page.e0c15627.chunk.js} +1 -1
  65. package/build/{api-tokens-edit-page.58139df9.chunk.js → api-tokens-edit-page.9f2dce47.chunk.js} +1 -1
  66. package/build/{api-tokens-list-page.0af7d431.chunk.js → api-tokens-list-page.d747051c.chunk.js} +2 -2
  67. package/build/{audit-logs-settings-page.0f73ccf8.chunk.js → audit-logs-settings-page.96f9d608.chunk.js} +1 -1
  68. package/build/content-manager.2d676432.chunk.js +1097 -0
  69. package/build/{content-type-builder-list-view.bf9be456.chunk.js → content-type-builder-list-view.b71cf240.chunk.js} +1 -1
  70. package/build/{content-type-builder.cd999f6e.chunk.js → content-type-builder.e5669749.chunk.js} +2 -2
  71. package/build/email-settings-page.2809f0bf.chunk.js +11 -0
  72. package/build/en-json.e12fd5fc.chunk.js +1 -0
  73. package/build/{i18n-settings-page.47f78016.chunk.js → i18n-settings-page.5f716172.chunk.js} +1 -1
  74. package/build/index.html +1 -1
  75. package/build/main.c6c9e04c.js +2859 -0
  76. package/build/review-workflows-settings-create-view.4a156a19.chunk.js +1 -0
  77. package/build/review-workflows-settings-edit-view.ce984d1f.chunk.js +1 -0
  78. package/build/review-workflows-settings-list-view.419b8deb.chunk.js +56 -0
  79. package/build/{runtime~main.d515c521.js → runtime~main.5a10b789.js} +2 -2
  80. package/build/{sso-settings-page.12b6d8ae.chunk.js → sso-settings-page.45153df5.chunk.js} +1 -1
  81. package/build/{transfer-tokens-create-page.1597e6ab.chunk.js → transfer-tokens-create-page.ebba16d8.chunk.js} +1 -1
  82. package/build/{transfer-tokens-edit-page.8741529f.chunk.js → transfer-tokens-edit-page.d7bb2b3e.chunk.js} +1 -1
  83. package/build/{transfer-tokens-list-page.d6986b03.chunk.js → transfer-tokens-list-page.cfe1736c.chunk.js} +2 -2
  84. package/build/{upload-settings.7f93d4c0.chunk.js → upload-settings.cc5ad813.chunk.js} +1 -1
  85. package/build/{upload.37488080.chunk.js → upload.756efc28.chunk.js} +1 -1
  86. package/build/users-advanced-settings-page.818d84eb.chunk.js +9 -0
  87. package/build/users-email-settings-page.c1967c09.chunk.js +9 -0
  88. package/build/users-providers-settings-page.11893e08.chunk.js +14 -0
  89. package/build/users-roles-settings-page.2b051e6a.chunk.js +55 -0
  90. package/build/{webhook-edit-page.6cb479ff.chunk.js → webhook-edit-page.de45c635.chunk.js} +2 -2
  91. package/build/{webhook-list-page.65e1b5bb.chunk.js → webhook-list-page.ca91df8b.chunk.js} +1 -1
  92. package/ee/admin/content-manager/components/Filter/CustomInputs/ReviewWorkflows/AssigneeFilter.js +42 -0
  93. package/ee/admin/content-manager/components/Filter/CustomInputs/ReviewWorkflows/StageFilter.js +70 -0
  94. package/ee/admin/content-manager/components/Filter/CustomInputs/ReviewWorkflows/constants.js +71 -0
  95. package/ee/admin/content-manager/pages/EditView/InformationBox/InformationBoxEE.js +9 -217
  96. package/ee/admin/content-manager/pages/EditView/InformationBox/components/AssigneeSelect/AssigneeSelect.js +147 -0
  97. package/ee/admin/content-manager/pages/EditView/InformationBox/components/AssigneeSelect/index.js +1 -0
  98. package/ee/admin/content-manager/pages/EditView/InformationBox/components/StageSelect/StageSelect.js +243 -0
  99. package/ee/admin/content-manager/pages/EditView/InformationBox/components/StageSelect/index.js +1 -0
  100. package/ee/admin/content-manager/pages/EditView/InformationBox/constants.js +2 -0
  101. package/ee/admin/content-manager/pages/ListSettingsView/constants.js +7 -0
  102. package/ee/admin/content-manager/pages/ListView/ReviewWorkflowsColumn/ReviewWorkflowsAssigneeEE.js +21 -0
  103. package/ee/admin/content-manager/pages/ListView/ReviewWorkflowsColumn/constants.js +44 -17
  104. package/ee/admin/content-manager/pages/ListView/ReviewWorkflowsColumn/index.js +1 -0
  105. package/ee/admin/hooks/useAuthProviders.js +25 -0
  106. package/ee/admin/hooks/{useLicenseLimitNotification/index.js → useLicenseLimitNotification.js} +2 -4
  107. package/ee/admin/hooks/{useLicenseLimits/useLicenseLimits.js → useLicenseLimits.js} +4 -1
  108. package/ee/admin/pages/AuthPage/components/Login/index.js +8 -4
  109. package/ee/admin/pages/AuthPage/components/Providers/index.js +8 -5
  110. package/ee/admin/pages/HomePage/index.js +1 -1
  111. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/pages/CreateView/CreateView.js +1 -1
  112. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/pages/EditView/EditView.js +1 -1
  113. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/pages/ListView/ListView.js +1 -1
  114. package/ee/admin/pages/SettingsPage/pages/Users/ListPage/CreateAction/index.js +1 -1
  115. package/ee/admin/pages/SettingsPage/pages/Users/ListPage/index.js +1 -1
  116. package/ee/server/constants/workflows.js +1 -0
  117. package/ee/server/controllers/index.js +1 -0
  118. package/ee/server/controllers/workflows/assignees/index.js +44 -0
  119. package/ee/server/routes/review-workflows.js +17 -0
  120. package/ee/server/services/index.js +1 -0
  121. package/ee/server/services/review-workflows/assignees.js +54 -0
  122. package/ee/server/services/review-workflows/metrics/index.js +5 -0
  123. package/ee/server/services/review-workflows/review-workflows.js +20 -11
  124. package/ee/server/validation/review-workflows.js +8 -0
  125. package/index.js +2 -6
  126. package/package.json +9 -9
  127. package/scripts/build.js +15 -15
  128. package/scripts/create-dev-plugins-file.js +5 -38
  129. package/server/controllers/role.js +2 -0
  130. package/server/controllers/user.js +2 -0
  131. package/server/services/permission/permissions-manager/index.js +3 -1
  132. package/server/services/permission/permissions-manager/sanitize.js +19 -7
  133. package/server/services/permission/permissions-manager/validate.js +218 -0
  134. package/utils/create-cache-dir.js +62 -16
  135. package/utils/create-plugins-exclude-path.js +3 -23
  136. package/utils/get-plugins.js +110 -0
  137. package/utils/index.js +1 -1
  138. package/webpack.config.js +10 -13
  139. package/admin/src/content-manager/components/AttributeFilter/Filters.js +0 -58
  140. package/admin/src/content-manager/components/AttributeFilter/hooks/useAllowedAttributes.js +0 -42
  141. package/admin/src/content-manager/components/AttributeFilter/index.js +0 -40
  142. package/admin/src/content-manager/components/Wysiwyg/EditorStylesContainer.js +0 -344
  143. package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/utils/api.js +0 -23
  144. package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/utils/prefixAllUrls.js +0 -17
  145. package/admin/src/pages/SettingsPage/utils/createSectionsRoutes.js +0 -11
  146. package/admin/src/pages/SettingsPage/utils/getSectionsToDisplay.js +0 -5
  147. package/admin/src/pages/SettingsPage/utils/index.js +0 -2
  148. package/build/2379.f1641312.chunk.js +0 -1
  149. package/build/2395.46f8d0c1.chunk.js +0 -26
  150. package/build/2801.5cef5ec8.chunk.js +0 -1
  151. package/build/3929.5632f24d.chunk.js +0 -114
  152. package/build/3984.dda474f7.chunk.js +0 -1
  153. package/build/4546.7a3c0d03.chunk.js +0 -1
  154. package/build/502.8ae8ef60.chunk.js +0 -1
  155. package/build/5483.6dd2e776.chunk.js +0 -6
  156. package/build/5542.2415a393.chunk.js +0 -63
  157. package/build/6158.c974fd83.chunk.js +0 -1
  158. package/build/7464.3e64a1d5.chunk.js +0 -1
  159. package/build/8276.10a3f883.chunk.js +0 -26
  160. package/build/Admin_settingsPage.97cb9d41.chunk.js +0 -111
  161. package/build/admin-app.91898385.chunk.js +0 -36
  162. package/build/content-manager.b40f79c0.chunk.js +0 -1099
  163. package/build/email-settings-page.d494d1eb.chunk.js +0 -11
  164. package/build/en-json.08c05fcf.chunk.js +0 -1
  165. package/build/main.9dbe4579.js +0 -2859
  166. package/build/review-workflows-settings-create-view.cb08cfa2.chunk.js +0 -1
  167. package/build/review-workflows-settings-edit-view.3c7cbe63.chunk.js +0 -1
  168. package/build/review-workflows-settings-list-view.1611dc1f.chunk.js +0 -56
  169. package/build/users-advanced-settings-page.f0760eb8.chunk.js +0 -9
  170. package/build/users-email-settings-page.ff4b32f3.chunk.js +0 -9
  171. package/build/users-providers-settings-page.48de0306.chunk.js +0 -14
  172. package/build/users-roles-settings-page.9d9a1eff.chunk.js +0 -30
  173. package/ee/admin/hooks/index.js +0 -4
  174. package/ee/admin/hooks/useAuthProviders/index.js +0 -50
  175. package/ee/admin/hooks/useAuthProviders/reducer.js +0 -26
  176. package/ee/admin/hooks/useLicenseLimits/index.js +0 -1
  177. package/scripts/create-plugins-file.js +0 -92
  178. package/utils/get-plugins-path.js +0 -41
  179. /package/ee/admin/hooks/{useLicenseLimits/__mocks__/index.js → __mocks__/useLicenseLimits.js} +0 -0
  180. /package/server/services/permission/permissions-manager/{query-builers.js → query-builders.js} +0 -0
@@ -1,4 +1,4 @@
1
- import React, { useEffect, useRef, useState } from 'react';
1
+ import React, { forwardRef, useEffect, useRef, useState } from 'react';
2
2
 
3
3
  import { Flex, TextInput, Typography } from '@strapi/design-system';
4
4
  import {
@@ -16,247 +16,253 @@ import useDebounce from '../../../hooks/useDebounce';
16
16
  import { FieldActionWrapper, LoadingWrapper, TextValidation } from './endActionStyle';
17
17
  import UID_REGEX from './regex';
18
18
 
19
- const InputUID = ({
20
- attribute,
21
- contentTypeUID,
22
- hint,
23
- disabled,
24
- error,
25
- intlLabel,
26
- labelAction,
27
- name,
28
- onChange,
29
- value,
30
- placeholder,
31
- required,
32
- }) => {
33
- const { modifiedData, initialData, layout } = useCMEditViewDataManager();
34
- const [isLoading, setIsLoading] = useState(false);
35
- const [availability, setAvailability] = useState(null);
36
- const debouncedValue = useDebounce(value, 300);
37
- const generateUid = useRef();
38
- const toggleNotification = useNotification();
39
- const { formatAPIError } = useAPIErrorHandler();
40
- const initialValue = initialData[name];
41
- const { formatMessage } = useIntl();
42
- const createdAtName = layout?.options?.timestamps ?? 0;
43
- const isCreation = !initialData[createdAtName];
44
- const debouncedTargetFieldValue = useDebounce(modifiedData[attribute.targetField], 300);
45
- const [isCustomized, setIsCustomized] = useState(false);
46
- const [regenerateLabel, setRegenerateLabel] = useState(null);
47
- const { post } = useFetchClient();
19
+ const InputUID = forwardRef(
20
+ (
21
+ {
22
+ attribute,
23
+ contentTypeUID,
24
+ hint,
25
+ disabled,
26
+ error,
27
+ intlLabel,
28
+ labelAction,
29
+ name,
30
+ onChange,
31
+ value,
32
+ placeholder,
33
+ required,
34
+ },
35
+ forwardedRef
36
+ ) => {
37
+ const { modifiedData, initialData, layout } = useCMEditViewDataManager();
38
+ const [isLoading, setIsLoading] = useState(false);
39
+ const [availability, setAvailability] = useState(null);
40
+ const debouncedValue = useDebounce(value, 300);
41
+ const generateUid = useRef();
42
+ const toggleNotification = useNotification();
43
+ const { formatAPIError } = useAPIErrorHandler();
44
+ const initialValue = initialData[name];
45
+ const { formatMessage } = useIntl();
46
+ const createdAtName = layout?.options?.timestamps ?? 0;
47
+ const isCreation = !initialData[createdAtName];
48
+ const debouncedTargetFieldValue = useDebounce(modifiedData[attribute.targetField], 300);
49
+ const [isCustomized, setIsCustomized] = useState(false);
50
+ const [regenerateLabel, setRegenerateLabel] = useState(null);
51
+ const { post } = useFetchClient();
48
52
 
49
- const label = intlLabel.id
50
- ? formatMessage(
51
- { id: intlLabel.id, defaultMessage: intlLabel.defaultMessage },
52
- { ...intlLabel.values }
53
- )
54
- : name;
53
+ const label = intlLabel.id
54
+ ? formatMessage(
55
+ { id: intlLabel.id, defaultMessage: intlLabel.defaultMessage },
56
+ { ...intlLabel.values }
57
+ )
58
+ : name;
55
59
 
56
- const formattedPlaceholder = placeholder
57
- ? formatMessage(
58
- { id: placeholder.id, defaultMessage: placeholder.defaultMessage },
59
- { ...placeholder.values }
60
- )
61
- : '';
60
+ const formattedPlaceholder = placeholder
61
+ ? formatMessage(
62
+ { id: placeholder.id, defaultMessage: placeholder.defaultMessage },
63
+ { ...placeholder.values }
64
+ )
65
+ : '';
62
66
 
63
- generateUid.current = async (shouldSetInitialValue = false) => {
64
- setIsLoading(true);
67
+ generateUid.current = async (shouldSetInitialValue = false) => {
68
+ setIsLoading(true);
65
69
 
66
- try {
67
- const {
68
- data: { data },
69
- } = await post('/content-manager/uid/generate', {
70
- contentTypeUID,
71
- field: name,
72
- data: modifiedData,
73
- });
70
+ try {
71
+ const {
72
+ data: { data },
73
+ } = await post('/content-manager/uid/generate', {
74
+ contentTypeUID,
75
+ field: name,
76
+ data: modifiedData,
77
+ });
74
78
 
75
- onChange({ target: { name, value: data, type: 'text' } }, shouldSetInitialValue);
76
- setIsLoading(false);
77
- } catch (error) {
78
- setIsLoading(false);
79
- toggleNotification({
80
- type: 'warning',
81
- message: formatAPIError(error),
82
- });
83
- }
84
- };
85
-
86
- const checkAvailability = async () => {
87
- if (!value) {
88
- return;
89
- }
90
-
91
- setIsLoading(true);
79
+ onChange({ target: { name, value: data, type: 'text' } }, shouldSetInitialValue);
80
+ setIsLoading(false);
81
+ } catch (error) {
82
+ setIsLoading(false);
83
+ toggleNotification({
84
+ type: 'warning',
85
+ message: formatAPIError(error),
86
+ });
87
+ }
88
+ };
92
89
 
93
- try {
94
- const { data } = await post('/content-manager/uid/check-availability', {
95
- contentTypeUID,
96
- field: name,
97
- value: value ? value.trim() : '',
98
- });
90
+ const checkAvailability = async () => {
91
+ if (!value) {
92
+ return;
93
+ }
99
94
 
100
- setIsLoading(false);
101
- setAvailability(data);
102
- } catch (error) {
103
- setIsLoading(false);
104
- toggleNotification({
105
- type: 'warning',
106
- message: formatAPIError(error),
107
- });
108
- }
109
- };
95
+ setIsLoading(true);
110
96
 
111
- // FIXME: we need to find a better way to autofill the input when it is required.
112
- useEffect(() => {
113
- if (!value && attribute.required) {
114
- generateUid.current(true);
115
- }
116
- }, [attribute.required, generateUid, value]);
97
+ try {
98
+ const { data } = await post('/content-manager/uid/check-availability', {
99
+ contentTypeUID,
100
+ field: name,
101
+ value: value ? value.trim() : '',
102
+ });
117
103
 
118
- useEffect(() => {
119
- if (debouncedValue?.trim().match(UID_REGEX) && debouncedValue !== initialValue) {
120
- checkAvailability();
121
- }
104
+ setIsLoading(false);
105
+ setAvailability(data);
106
+ } catch (error) {
107
+ setIsLoading(false);
108
+ toggleNotification({
109
+ type: 'warning',
110
+ message: formatAPIError(error),
111
+ });
112
+ }
113
+ };
122
114
 
123
- if (!debouncedValue) {
124
- setAvailability(null);
125
- }
126
- // eslint-disable-next-line react-hooks/exhaustive-deps
127
- }, [initialValue, debouncedValue]);
115
+ // FIXME: we need to find a better way to autofill the input when it is required.
116
+ useEffect(() => {
117
+ if (!value && attribute.required) {
118
+ generateUid.current(true);
119
+ }
120
+ }, [attribute.required, generateUid, value]);
128
121
 
129
- useEffect(() => {
130
- let timer;
122
+ useEffect(() => {
123
+ if (debouncedValue?.trim().match(UID_REGEX) && debouncedValue !== initialValue) {
124
+ checkAvailability();
125
+ }
131
126
 
132
- if (availability?.isAvailable) {
133
- timer = setTimeout(() => {
127
+ if (!debouncedValue) {
134
128
  setAvailability(null);
135
- }, 4000);
136
- }
129
+ }
130
+ // eslint-disable-next-line react-hooks/exhaustive-deps
131
+ }, [initialValue, debouncedValue]);
132
+
133
+ useEffect(() => {
134
+ let timer;
137
135
 
138
- return () => {
139
- if (timer) {
140
- clearTimeout(timer);
136
+ if (availability?.isAvailable) {
137
+ timer = setTimeout(() => {
138
+ setAvailability(null);
139
+ }, 4000);
141
140
  }
142
- };
143
- }, [availability]);
144
141
 
145
- useEffect(() => {
146
- if (
147
- !isCustomized &&
148
- isCreation &&
149
- debouncedTargetFieldValue &&
150
- modifiedData[attribute.targetField] &&
151
- !value
152
- ) {
153
- generateUid.current(true);
154
- }
155
- // eslint-disable-next-line react-hooks/exhaustive-deps
156
- }, [debouncedTargetFieldValue, isCustomized, isCreation]);
142
+ return () => {
143
+ if (timer) {
144
+ clearTimeout(timer);
145
+ }
146
+ };
147
+ }, [availability]);
157
148
 
158
- const handleGenerateMouseEnter = () => {
159
- setRegenerateLabel(
160
- formatMessage({
161
- id: 'content-manager.components.uid.regenerate',
162
- defaultMessage: 'Regenerate',
163
- })
164
- );
165
- };
149
+ useEffect(() => {
150
+ if (
151
+ !isCustomized &&
152
+ isCreation &&
153
+ debouncedTargetFieldValue &&
154
+ modifiedData[attribute.targetField] &&
155
+ !value
156
+ ) {
157
+ generateUid.current(true);
158
+ }
159
+ // eslint-disable-next-line react-hooks/exhaustive-deps
160
+ }, [debouncedTargetFieldValue, isCustomized, isCreation]);
166
161
 
167
- const handleGenerateMouseLeave = () => {
168
- setRegenerateLabel(null);
169
- };
162
+ const handleGenerateMouseEnter = () => {
163
+ setRegenerateLabel(
164
+ formatMessage({
165
+ id: 'content-manager.components.uid.regenerate',
166
+ defaultMessage: 'Regenerate',
167
+ })
168
+ );
169
+ };
170
170
 
171
- const handleChange = (e) => {
172
- if (e.target.value && isCreation) {
173
- setIsCustomized(true);
174
- }
171
+ const handleGenerateMouseLeave = () => {
172
+ setRegenerateLabel(null);
173
+ };
175
174
 
176
- onChange(e);
177
- };
175
+ const handleChange = (e) => {
176
+ if (e.target.value && isCreation) {
177
+ setIsCustomized(true);
178
+ }
178
179
 
179
- return (
180
- <TextInput
181
- disabled={disabled}
182
- error={error}
183
- endAction={
184
- <Flex position="relative" gap={1}>
185
- {availability && !regenerateLabel && (
186
- <TextValidation
187
- alignItems="center"
188
- gap={1}
189
- justifyContent="flex-end"
190
- available={!!availability?.isAvailable}
191
- data-not-here-outer
192
- position="absolute"
193
- pointerEvents="none"
194
- right={6}
195
- width="100px"
196
- >
197
- {availability?.isAvailable ? <CheckCircle /> : <ExclamationMarkCircle />}
180
+ onChange(e);
181
+ };
198
182
 
199
- <Typography
200
- textColor={availability.isAvailable ? 'success600' : 'danger600'}
201
- variant="pi"
183
+ return (
184
+ <TextInput
185
+ ref={forwardedRef}
186
+ disabled={disabled}
187
+ error={error}
188
+ endAction={
189
+ <Flex position="relative" gap={1}>
190
+ {availability && !regenerateLabel && (
191
+ <TextValidation
192
+ alignItems="center"
193
+ gap={1}
194
+ justifyContent="flex-end"
195
+ available={!!availability?.isAvailable}
196
+ data-not-here-outer
197
+ position="absolute"
198
+ pointerEvents="none"
199
+ right={6}
200
+ width="100px"
202
201
  >
203
- {formatMessage(
204
- availability.isAvailable
205
- ? {
206
- id: 'content-manager.components.uid.available',
207
- defaultMessage: 'Available',
208
- }
209
- : {
210
- id: 'content-manager.components.uid.unavailable',
211
- defaultMessage: 'Unavailable',
212
- }
213
- )}
214
- </Typography>
215
- </TextValidation>
216
- )}
202
+ {availability?.isAvailable ? <CheckCircle /> : <ExclamationMarkCircle />}
217
203
 
218
- {!disabled && (
219
- <>
220
- {regenerateLabel && (
221
- <TextValidation alignItems="center" justifyContent="flex-end" gap={1}>
222
- <Typography textColor="primary600" variant="pi">
223
- {regenerateLabel}
224
- </Typography>
225
- </TextValidation>
226
- )}
204
+ <Typography
205
+ textColor={availability.isAvailable ? 'success600' : 'danger600'}
206
+ variant="pi"
207
+ >
208
+ {formatMessage(
209
+ availability.isAvailable
210
+ ? {
211
+ id: 'content-manager.components.uid.available',
212
+ defaultMessage: 'Available',
213
+ }
214
+ : {
215
+ id: 'content-manager.components.uid.unavailable',
216
+ defaultMessage: 'Unavailable',
217
+ }
218
+ )}
219
+ </Typography>
220
+ </TextValidation>
221
+ )}
227
222
 
228
- <FieldActionWrapper
229
- onClick={() => generateUid.current()}
230
- label={formatMessage({
231
- id: 'content-manager.components.uid.regenerate',
232
- defaultMessage: 'Regenerate',
233
- })}
234
- onMouseEnter={handleGenerateMouseEnter}
235
- onMouseLeave={handleGenerateMouseLeave}
236
- >
237
- {isLoading ? (
238
- <LoadingWrapper data-testid="loading-wrapper">
239
- <Loader />
240
- </LoadingWrapper>
241
- ) : (
242
- <Refresh />
223
+ {!disabled && (
224
+ <>
225
+ {regenerateLabel && (
226
+ <TextValidation alignItems="center" justifyContent="flex-end" gap={1}>
227
+ <Typography textColor="primary600" variant="pi">
228
+ {regenerateLabel}
229
+ </Typography>
230
+ </TextValidation>
243
231
  )}
244
- </FieldActionWrapper>
245
- </>
246
- )}
247
- </Flex>
248
- }
249
- hint={hint}
250
- label={label}
251
- labelAction={labelAction}
252
- name={name}
253
- onChange={handleChange}
254
- placeholder={formattedPlaceholder}
255
- value={value || ''}
256
- required={required}
257
- />
258
- );
259
- };
232
+
233
+ <FieldActionWrapper
234
+ onClick={() => generateUid.current()}
235
+ label={formatMessage({
236
+ id: 'content-manager.components.uid.regenerate',
237
+ defaultMessage: 'Regenerate',
238
+ })}
239
+ onMouseEnter={handleGenerateMouseEnter}
240
+ onMouseLeave={handleGenerateMouseLeave}
241
+ >
242
+ {isLoading ? (
243
+ <LoadingWrapper data-testid="loading-wrapper">
244
+ <Loader />
245
+ </LoadingWrapper>
246
+ ) : (
247
+ <Refresh />
248
+ )}
249
+ </FieldActionWrapper>
250
+ </>
251
+ )}
252
+ </Flex>
253
+ }
254
+ hint={hint}
255
+ label={label}
256
+ labelAction={labelAction}
257
+ name={name}
258
+ onChange={handleChange}
259
+ placeholder={formattedPlaceholder}
260
+ value={value || ''}
261
+ required={required}
262
+ />
263
+ );
264
+ }
265
+ );
260
266
 
261
267
  InputUID.propTypes = {
262
268
  attribute: PropTypes.shape({
@@ -12,6 +12,7 @@ import {
12
12
  VisuallyHidden,
13
13
  Combobox,
14
14
  } from '@strapi/design-system';
15
+ import { useFocusInputField } from '@strapi/helper-plugin';
15
16
  import { Cross, Refresh } from '@strapi/icons';
16
17
  import PropTypes from 'prop-types';
17
18
  import { FixedSizeList as List } from 'react-window';
@@ -86,6 +87,8 @@ const RelationInput = ({
86
87
  const listRef = useRef();
87
88
  const outerListRef = useRef();
88
89
 
90
+ const fieldRef = useFocusInputField(name);
91
+
89
92
  const { data } = searchResults;
90
93
 
91
94
  const relations = paginatedRelations.data;
@@ -206,6 +209,7 @@ const RelationInput = ({
206
209
  <Flex gap={3} justifyContent="space-between" alignItems="end" wrap="wrap">
207
210
  <Flex direction="column" alignItems="stretch" basis={size <= 6 ? '100%' : '70%'} gap={2}>
208
211
  <Combobox
212
+ ref={fieldRef}
209
213
  autocomplete="list"
210
214
  error={error}
211
215
  name={name}
@@ -1,8 +1,8 @@
1
1
  /* eslint-disable import/no-cycle */
2
- import React, { memo, useMemo, useState } from 'react';
2
+ import React, { memo, useEffect, useMemo, useState } from 'react';
3
3
 
4
4
  import { Box, Flex, TextButton, VisuallyHidden } from '@strapi/design-system';
5
- import { useCMEditViewDataManager, useNotification } from '@strapi/helper-plugin';
5
+ import { useCMEditViewDataManager, useNotification, useQuery } from '@strapi/helper-plugin';
6
6
  import { Plus } from '@strapi/icons';
7
7
  import get from 'lodash/get';
8
8
  import PropTypes from 'prop-types';
@@ -50,6 +50,36 @@ const RepeatableComponent = ({
50
50
  [componentUid, getComponentLayout]
51
51
  );
52
52
 
53
+ const search = useQuery();
54
+
55
+ /**
56
+ * Get the temp key of the component that has the field that is currently focussed
57
+ * as defined by the `field` query param. We can then force this specific component
58
+ * to be in it's "open" state.
59
+ */
60
+ const componentTmpKeyWithFocussedField = useMemo(() => {
61
+ if (search.has('field')) {
62
+ const field = search.get('field');
63
+
64
+ const [, path] = field.split(`${name}.`);
65
+
66
+ if (get(componentValue, path, undefined) !== undefined) {
67
+ const subpaths = path.split('.');
68
+
69
+ return get(componentValue, subpaths[0], undefined)?.__temp_key__;
70
+ }
71
+ }
72
+
73
+ // eslint-disable-next-line consistent-return
74
+ return undefined;
75
+ }, [componentValue, search, name]);
76
+
77
+ useEffect(() => {
78
+ if (typeof componentTmpKeyWithFocussedField === 'number') {
79
+ setCollapseToOpen(componentTmpKeyWithFocussedField);
80
+ }
81
+ }, [componentTmpKeyWithFocussedField]);
82
+
53
83
  const nextTempKey = useMemo(() => getMaxTempKey(componentValue || []) + 1, [componentValue]);
54
84
 
55
85
  const componentErrorKeys = getComponentErrorKeys(name, formErrors);