@strapi/admin 4.13.0-beta.0 → 4.13.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 (156) 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/DynamicZone/components/DynamicZoneLabel.js +1 -1
  4. package/admin/src/content-manager/components/EditViewDataManagerProvider/reducer.js +7 -9
  5. package/admin/src/content-manager/components/EditViewDataManagerProvider/utils/cleanData.js +6 -0
  6. package/admin/src/content-manager/components/Filter/Filter.js +21 -23
  7. package/admin/src/content-manager/components/InputUID/index.js +222 -216
  8. package/admin/src/content-manager/components/RelationInput/RelationInput.js +4 -0
  9. package/admin/src/content-manager/components/RepeatableComponent/index.js +32 -2
  10. package/admin/src/content-manager/components/Wysiwyg/Editor.js +432 -68
  11. package/admin/src/content-manager/components/Wysiwyg/WysiwygNav.js +7 -30
  12. package/admin/src/content-manager/components/Wysiwyg/WysiwygStyles.js +0 -7
  13. package/admin/src/content-manager/components/Wysiwyg/index.js +147 -152
  14. package/admin/src/content-manager/constants/attributes.js +3 -0
  15. package/admin/src/content-manager/hooks/useAllowedAttributes.js +3 -7
  16. package/admin/src/content-manager/pages/CollectionTypeRecursivePath/index.js +1 -1
  17. package/admin/src/content-manager/pages/ListSettingsView/index.js +16 -41
  18. package/admin/src/content-manager/pages/ListView/components/ViewSettingsMenu/index.js +7 -1
  19. package/admin/src/content-manager/pages/ListView/index.js +14 -5
  20. package/admin/src/pages/Admin/index.js +3 -1
  21. package/admin/src/pages/AuthPage/components/Register/index.js +5 -0
  22. package/admin/src/pages/MarketplacePage/index.js +0 -1
  23. package/admin/src/pages/SettingsPage/components/SettingsNav/index.js +3 -3
  24. package/admin/src/pages/SettingsPage/index.js +16 -26
  25. package/admin/src/pages/SettingsPage/pages/ApiTokens/ListView/index.js +24 -31
  26. package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/index.js +69 -35
  27. package/admin/src/pages/SettingsPage/pages/TransferTokens/ListView/index.js +11 -6
  28. package/admin/src/pages/SettingsPage/pages/Users/EditPage/index.js +2 -0
  29. package/admin/src/pages/SettingsPage/pages/Users/ListPage/index.js +1 -0
  30. package/admin/src/plugins.js +7 -8
  31. package/admin/src/translations/en.json +7 -0
  32. package/build/{1049.f76cb14b.chunk.js → 1049.ec69f5e0.chunk.js} +1 -1
  33. package/build/1227.9f37e1dc.chunk.js +1 -0
  34. package/build/{1386.879bcd90.chunk.js → 1386.ea73b677.chunk.js} +1 -1
  35. package/build/1504.eff012f7.chunk.js +95 -0
  36. package/build/{2225.c6244756.chunk.js → 2225.649fb7bc.chunk.js} +11 -11
  37. package/build/2237.b832ae6e.chunk.js +114 -0
  38. package/build/2379.1f98a31a.chunk.js +1 -0
  39. package/build/2395.0e5e8ded.chunk.js +26 -0
  40. package/build/2801.8e1aa82a.chunk.js +1 -0
  41. package/build/{3483.03c24f96.chunk.js → 3483.19381b40.chunk.js} +1 -1
  42. package/build/{4174.fa8f9954.chunk.js → 4174.f1f39e40.chunk.js} +1 -1
  43. package/build/{4546.ff09eeda.chunk.js → 4546.a5946d22.chunk.js} +1 -1
  44. package/build/4724.aea5c8c1.chunk.js +6 -0
  45. package/build/502.7bba43b1.chunk.js +1 -0
  46. package/build/7464.eb057bec.chunk.js +1 -0
  47. package/build/8276.be3ed581.chunk.js +26 -0
  48. package/build/{Admin-authenticatedApp.53a24d28.chunk.js → Admin-authenticatedApp.baece4ac.chunk.js} +2 -2
  49. package/build/{Admin_InternalErrorPage.f45f2462.chunk.js → Admin_InternalErrorPage.38155af3.chunk.js} +1 -1
  50. package/build/{Admin_homePage.ac9dfb86.chunk.js → Admin_homePage.6f128523.chunk.js} +1 -1
  51. package/build/{Admin_marketplace.dde9c148.chunk.js → Admin_marketplace.061a6e5a.chunk.js} +2 -2
  52. package/build/{Admin_pluginsPage.bbe79434.chunk.js → Admin_pluginsPage.16f837b8.chunk.js} +1 -1
  53. package/build/{Admin_profilePage.192edc52.chunk.js → Admin_profilePage.678bce24.chunk.js} +2 -2
  54. package/build/Admin_settingsPage.af7309e4.chunk.js +111 -0
  55. package/build/{Upload_ConfigureTheView.345ac1e0.chunk.js → Upload_ConfigureTheView.3fc1c100.chunk.js} +1 -1
  56. package/build/admin-app.d63bd229.chunk.js +36 -0
  57. package/build/{admin-edit-roles-page.6d567273.chunk.js → admin-edit-roles-page.38a6c863.chunk.js} +3 -3
  58. package/build/admin-edit-users.545fc882.chunk.js +10 -0
  59. package/build/{admin-roles-list.23ddff26.chunk.js → admin-roles-list.1e2e814d.chunk.js} +1 -1
  60. package/build/{admin-users.123aa08e.chunk.js → admin-users.b8ea5677.chunk.js} +2 -2
  61. package/build/{api-tokens-create-page.46c2ea84.chunk.js → api-tokens-create-page.e0c15627.chunk.js} +1 -1
  62. package/build/{api-tokens-edit-page.58139df9.chunk.js → api-tokens-edit-page.9f2dce47.chunk.js} +1 -1
  63. package/build/api-tokens-list-page.d747051c.chunk.js +16 -0
  64. package/build/{audit-logs-settings-page.0f73ccf8.chunk.js → audit-logs-settings-page.96f9d608.chunk.js} +1 -1
  65. package/build/content-manager.2d676432.chunk.js +1097 -0
  66. package/build/{content-type-builder-list-view.bf9be456.chunk.js → content-type-builder-list-view.b71cf240.chunk.js} +1 -1
  67. package/build/{content-type-builder.cd999f6e.chunk.js → content-type-builder.e5669749.chunk.js} +2 -2
  68. package/build/email-settings-page.2809f0bf.chunk.js +11 -0
  69. package/build/en-json.e12fd5fc.chunk.js +1 -0
  70. package/build/{i18n-settings-page.47f78016.chunk.js → i18n-settings-page.5f716172.chunk.js} +1 -1
  71. package/build/index.html +1 -1
  72. package/build/main.c6c9e04c.js +2859 -0
  73. package/build/review-workflows-settings-create-view.4a156a19.chunk.js +1 -0
  74. package/build/review-workflows-settings-edit-view.ce984d1f.chunk.js +1 -0
  75. package/build/review-workflows-settings-list-view.419b8deb.chunk.js +56 -0
  76. package/build/{runtime~main.b16af570.js → runtime~main.a883e1c1.js} +2 -2
  77. package/build/{sso-settings-page.12b6d8ae.chunk.js → sso-settings-page.45153df5.chunk.js} +1 -1
  78. package/build/{transfer-tokens-create-page.1597e6ab.chunk.js → transfer-tokens-create-page.ebba16d8.chunk.js} +1 -1
  79. package/build/{transfer-tokens-edit-page.8741529f.chunk.js → transfer-tokens-edit-page.d7bb2b3e.chunk.js} +1 -1
  80. package/build/transfer-tokens-list-page.cfe1736c.chunk.js +16 -0
  81. package/build/{upload-settings.7f93d4c0.chunk.js → upload-settings.cc5ad813.chunk.js} +1 -1
  82. package/build/{upload.37488080.chunk.js → upload.756efc28.chunk.js} +1 -1
  83. package/build/users-advanced-settings-page.818d84eb.chunk.js +9 -0
  84. package/build/users-email-settings-page.c1967c09.chunk.js +9 -0
  85. package/build/users-providers-settings-page.11893e08.chunk.js +14 -0
  86. package/build/users-roles-settings-page.2b051e6a.chunk.js +55 -0
  87. package/build/{webhook-edit-page.6cb479ff.chunk.js → webhook-edit-page.de45c635.chunk.js} +2 -2
  88. package/build/{webhook-list-page.65e1b5bb.chunk.js → webhook-list-page.ca91df8b.chunk.js} +1 -1
  89. package/ee/admin/content-manager/pages/EditView/InformationBox/components/AssigneeSelect/AssigneeSelect.js +69 -71
  90. package/ee/admin/content-manager/pages/EditView/InformationBox/components/StageSelect/StageSelect.js +3 -1
  91. package/ee/admin/content-manager/pages/ListView/ReviewWorkflowsColumn/ReviewWorkflowsAssigneeEE.js +8 -38
  92. package/ee/admin/hooks/useAuthProviders.js +25 -0
  93. package/ee/admin/hooks/{useLicenseLimitNotification/index.js → useLicenseLimitNotification.js} +2 -4
  94. package/ee/admin/hooks/{useLicenseLimits/useLicenseLimits.js → useLicenseLimits.js} +4 -1
  95. package/ee/admin/pages/AuthPage/components/Login/index.js +8 -4
  96. package/ee/admin/pages/AuthPage/components/Providers/index.js +8 -5
  97. package/ee/admin/pages/HomePage/index.js +1 -1
  98. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/pages/CreateView/CreateView.js +1 -1
  99. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/pages/EditView/EditView.js +1 -1
  100. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/pages/ListView/ListView.js +1 -1
  101. package/ee/admin/pages/SettingsPage/pages/Users/ListPage/CreateAction/index.js +1 -1
  102. package/ee/admin/pages/SettingsPage/pages/Users/ListPage/index.js +1 -1
  103. package/index.js +2 -6
  104. package/package.json +9 -9
  105. package/scripts/build.js +15 -15
  106. package/scripts/create-dev-plugins-file.js +5 -38
  107. package/server/controllers/role.js +2 -0
  108. package/server/controllers/user.js +2 -0
  109. package/server/services/permission/permissions-manager/index.js +3 -1
  110. package/server/services/permission/permissions-manager/sanitize.js +7 -7
  111. package/server/services/permission/permissions-manager/validate.js +218 -0
  112. package/utils/create-cache-dir.js +62 -16
  113. package/utils/create-plugins-exclude-path.js +3 -23
  114. package/utils/get-plugins.js +110 -0
  115. package/utils/index.js +1 -1
  116. package/webpack.config.js +10 -13
  117. package/admin/src/content-manager/components/Wysiwyg/EditorStylesContainer.js +0 -344
  118. package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/utils/api.js +0 -23
  119. package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/utils/prefixAllUrls.js +0 -17
  120. package/admin/src/pages/SettingsPage/utils/createSectionsRoutes.js +0 -11
  121. package/admin/src/pages/SettingsPage/utils/getSectionsToDisplay.js +0 -5
  122. package/admin/src/pages/SettingsPage/utils/index.js +0 -2
  123. package/build/1227.32fe57ce.chunk.js +0 -1
  124. package/build/2379.f1641312.chunk.js +0 -1
  125. package/build/2395.46f8d0c1.chunk.js +0 -26
  126. package/build/2801.5cef5ec8.chunk.js +0 -1
  127. package/build/3929.5632f24d.chunk.js +0 -114
  128. package/build/4724.baf7c5b1.chunk.js +0 -6
  129. package/build/502.8ae8ef60.chunk.js +0 -1
  130. package/build/5542.2415a393.chunk.js +0 -63
  131. package/build/7464.3e64a1d5.chunk.js +0 -1
  132. package/build/8276.10a3f883.chunk.js +0 -26
  133. package/build/Admin_settingsPage.97cb9d41.chunk.js +0 -111
  134. package/build/admin-app.91898385.chunk.js +0 -36
  135. package/build/admin-edit-users.79eeb125.chunk.js +0 -10
  136. package/build/api-tokens-list-page.505bf7e0.chunk.js +0 -16
  137. package/build/content-manager.7f96a2f1.chunk.js +0 -1097
  138. package/build/email-settings-page.d494d1eb.chunk.js +0 -11
  139. package/build/en-json.4f06fe03.chunk.js +0 -1
  140. package/build/main.40b94779.js +0 -2859
  141. package/build/review-workflows-settings-create-view.cb08cfa2.chunk.js +0 -1
  142. package/build/review-workflows-settings-edit-view.3c7cbe63.chunk.js +0 -1
  143. package/build/review-workflows-settings-list-view.1611dc1f.chunk.js +0 -56
  144. package/build/transfer-tokens-list-page.22147d2c.chunk.js +0 -16
  145. package/build/users-advanced-settings-page.f0760eb8.chunk.js +0 -9
  146. package/build/users-email-settings-page.ff4b32f3.chunk.js +0 -9
  147. package/build/users-providers-settings-page.48de0306.chunk.js +0 -14
  148. package/build/users-roles-settings-page.9d9a1eff.chunk.js +0 -30
  149. package/ee/admin/hooks/index.js +0 -4
  150. package/ee/admin/hooks/useAuthProviders/index.js +0 -50
  151. package/ee/admin/hooks/useAuthProviders/reducer.js +0 -26
  152. package/ee/admin/hooks/useLicenseLimits/index.js +0 -1
  153. package/scripts/create-plugins-file.js +0 -92
  154. package/utils/get-plugins-path.js +0 -41
  155. /package/ee/admin/hooks/{useLicenseLimits/__mocks__/index.js → __mocks__/useLicenseLimits.js} +0 -0
  156. /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);