@strapi/admin 4.5.0-alpha.0 → 4.5.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (191) hide show
  1. package/admin/src/StrapiApp.js +4 -12
  2. package/admin/src/components/Providers/index.js +14 -10
  3. package/admin/src/content-manager/components/CollectionTypeFormWrapper/index.js +24 -0
  4. package/admin/src/content-manager/components/DynamicTable/TableRows/index.js +20 -15
  5. package/admin/src/content-manager/components/DynamicZone/components/Component/index.js +19 -9
  6. package/admin/src/content-manager/components/EditViewDataManagerProvider/index.js +50 -3
  7. package/admin/src/content-manager/components/EditViewDataManagerProvider/reducer.js +50 -9
  8. package/admin/src/content-manager/components/FieldTypeIcon/index.js +31 -1
  9. package/admin/src/content-manager/components/Inputs/index.js +36 -14
  10. package/admin/src/content-manager/components/NonRepeatableComponent/index.js +2 -0
  11. package/admin/src/content-manager/components/RelationInput/RelationInput.js +95 -32
  12. package/admin/src/content-manager/components/RelationInput/components/RelationItem.js +2 -2
  13. package/admin/src/content-manager/components/RelationInput/constants.js +1 -1
  14. package/admin/src/content-manager/components/RelationInputDataManager/RelationInputDataManager.js +33 -22
  15. package/admin/src/content-manager/components/RelationInputDataManager/utils/index.js +1 -0
  16. package/admin/src/content-manager/components/RelationInputDataManager/utils/normalizeRelations.js +10 -3
  17. package/admin/src/content-manager/components/RelationInputDataManager/utils/normalizeSearchResults.js +12 -0
  18. package/admin/src/content-manager/components/RelationInputDataManager/utils/select.js +34 -11
  19. package/admin/src/content-manager/components/RepeatableComponent/DraggedItem/index.js +5 -0
  20. package/admin/src/content-manager/components/SingleTypeFormWrapper/index.js +23 -0
  21. package/admin/src/content-manager/hooks/useRelation/useRelation.js +17 -9
  22. package/admin/src/content-manager/pages/EditSettingsView/components/FormModal.js +7 -2
  23. package/admin/src/content-manager/pages/EditSettingsView/index.js +2 -1
  24. package/admin/src/content-manager/pages/EditView/Header/index.js +118 -50
  25. package/admin/src/content-manager/pages/EditView/Header/utils/select.js +4 -0
  26. package/admin/src/content-manager/pages/EditView/index.js +102 -93
  27. package/admin/src/content-manager/pages/ListView/index.js +24 -15
  28. package/admin/src/content-manager/pages/ListView/utils/buildQueryString.js +14 -2
  29. package/admin/src/contexts/ApiTokenPermissions/index.js +24 -0
  30. package/admin/src/core/apis/CustomFields.js +80 -0
  31. package/admin/src/core/apis/index.js +1 -0
  32. package/admin/src/hooks/index.js +1 -0
  33. package/admin/src/hooks/useRegenerate/index.js +34 -0
  34. package/admin/src/pages/HomePage/SocialLinks.js +1 -1
  35. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/ActionBoundRoutes/index.js +56 -0
  36. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/BoundRoute/getMethodColor.js +41 -0
  37. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/BoundRoute/index.js +72 -0
  38. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/CollapsableContentType/CheckBoxWrapper.js +30 -0
  39. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/CollapsableContentType/index.js +150 -0
  40. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/ContenTypesSection/index.js +37 -0
  41. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/FormApiTokenContainer/index.js +254 -0
  42. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/FormBody/index.js +77 -0
  43. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/FormHead/index.js +85 -0
  44. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/Permissions/index.js +40 -0
  45. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/Regenerate/index.js +68 -0
  46. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/index.js +215 -197
  47. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/init.js +13 -0
  48. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/reducer.js +72 -0
  49. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/utils/getDateOfExpiration.js +16 -0
  50. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/utils/index.js +5 -0
  51. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/utils/schema.js +2 -1
  52. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/utils/transformPermissionsData.js +36 -0
  53. package/admin/src/pages/SettingsPage/pages/ApiTokens/ListView/DynamicTable/DefaultButton/index.js +63 -0
  54. package/admin/src/pages/SettingsPage/pages/ApiTokens/ListView/DynamicTable/DeleteButton/index.js +1 -0
  55. package/admin/src/pages/SettingsPage/pages/ApiTokens/ListView/DynamicTable/ReadButton/index.js +19 -0
  56. package/admin/src/pages/SettingsPage/pages/ApiTokens/ListView/DynamicTable/UpdateButton/index.js +3 -36
  57. package/admin/src/pages/SettingsPage/pages/ApiTokens/ListView/DynamicTable/index.js +13 -11
  58. package/admin/src/pages/SettingsPage/pages/ApiTokens/ListView/index.js +3 -2
  59. package/admin/src/pages/SettingsPage/pages/ApiTokens/ListView/utils/tableHeaders.js +8 -8
  60. package/admin/src/pages/SettingsPage/pages/ApiTokens/ProtectedEditView/index.js +1 -1
  61. package/admin/src/pages/SettingsPage/pages/Users/ListPage/ModalForm/index.js +2 -2
  62. package/admin/src/permissions/defaultPermissions.js +2 -6
  63. package/admin/src/translations/ca.json +3 -1
  64. package/admin/src/translations/de.json +4 -1
  65. package/admin/src/translations/dk.json +3 -0
  66. package/admin/src/translations/en.json +22 -1
  67. package/admin/src/translations/es.json +156 -157
  68. package/admin/src/translations/fr.json +3 -0
  69. package/admin/src/translations/gu.json +608 -606
  70. package/admin/src/translations/hi.json +689 -687
  71. package/admin/src/translations/hu.json +2 -0
  72. package/admin/src/translations/id.json +2 -0
  73. package/admin/src/translations/it.json +2 -0
  74. package/admin/src/translations/ja.json +2 -0
  75. package/admin/src/translations/ko.json +2 -0
  76. package/admin/src/translations/ml.json +689 -687
  77. package/admin/src/translations/nl.json +3 -0
  78. package/admin/src/translations/pl.json +2 -0
  79. package/admin/src/translations/pt-BR.json +3 -0
  80. package/admin/src/translations/ru.json +489 -491
  81. package/admin/src/translations/sa.json +85 -82
  82. package/admin/src/translations/sk.json +3 -0
  83. package/admin/src/translations/sv.json +3 -0
  84. package/admin/src/translations/zh-Hans.json +4 -1
  85. package/admin/src/translations/zh.json +3 -0
  86. package/build/1856.d8f13391.chunk.js +173 -0
  87. package/build/{9311.7cc03f29.chunk.js → 1939.e3c87653.chunk.js} +108 -291
  88. package/build/{2077.c935ee42.chunk.js → 2077.31a2d91e.chunk.js} +4 -4
  89. package/build/{2912.a015078a.chunk.js → 2912.ab68a736.chunk.js} +8 -8
  90. package/build/4318.7d167b58.chunk.js +30 -0
  91. package/build/4715.44b1ef9b.chunk.js +386 -0
  92. package/build/{4982.05eda880.chunk.js → 4982.c2a311b7.chunk.js} +9 -9
  93. package/build/7379.d246dd38.chunk.js +1 -0
  94. package/build/{7841.91f793dc.chunk.js → 7841.4b67af3f.chunk.js} +8 -8
  95. package/build/{7866.1201afbd.chunk.js → 7866.5fbeb7e5.chunk.js} +10 -10
  96. package/build/{8380.8789ff76.chunk.js → 8380.9b53a31d.chunk.js} +7 -7
  97. package/build/{8549.133c4473.chunk.js → 8549.cf10b5d1.chunk.js} +4 -4
  98. package/build/8738.a30a2160.chunk.js +461 -0
  99. package/build/{9066.08049eb1.chunk.js → 9066.26faf397.chunk.js} +4 -4
  100. package/build/{9166.037339e0.chunk.js → 9166.8fcb3019.chunk.js} +5 -5
  101. package/build/{9420.43a86e7c.chunk.js → 9420.0fe11290.chunk.js} +6 -6
  102. package/build/962.8651ba3f.chunk.js +184 -0
  103. package/build/Admin-authenticatedApp.883449a5.chunk.js +80 -0
  104. package/build/{Admin_homePage.118926e0.chunk.js → Admin_homePage.4b2be829.chunk.js} +2 -2
  105. package/build/{Admin_profilePage.9d50ac44.chunk.js → Admin_profilePage.da32abbc.chunk.js} +1 -1
  106. package/build/{Admin_settingsPage.98a711e5.chunk.js → Admin_settingsPage.98e2a62b.chunk.js} +16 -16
  107. package/build/admin-app.a61d5c2e.chunk.js +112 -0
  108. package/build/admin-edit-roles-page.4dd6bcb9.chunk.js +1 -0
  109. package/build/{admin-users.97a08630.chunk.js → admin-users.d71f198a.chunk.js} +3 -3
  110. package/build/api-tokens-create-page.93dd0689.chunk.js +1 -0
  111. package/build/api-tokens-edit-page.b0adac81.chunk.js +1 -0
  112. package/build/api-tokens-list-page.bb36535f.chunk.js +16 -0
  113. package/build/{ca-json.a16899ae.chunk.js → ca-json.82df6eab.chunk.js} +1 -1
  114. package/build/content-manager.933dc286.chunk.js +1201 -0
  115. package/build/content-type-builder-list-view.5b3cd768.chunk.js +194 -0
  116. package/build/content-type-builder-translation-en-json.f985c9c4.chunk.js +1 -0
  117. package/build/content-type-builder.a6e29716.chunk.js +145 -0
  118. package/build/{de-json.aa6026b3.chunk.js → de-json.0ad554eb.chunk.js} +1 -1
  119. package/build/{dk-json.fac2bcfb.chunk.js → dk-json.e195ea1a.chunk.js} +1 -1
  120. package/build/{email-settings-page.64037147.chunk.js → email-settings-page.bfe6227f.chunk.js} +4 -4
  121. package/build/en-json.1889403c.chunk.js +1 -0
  122. package/build/{es-json.d672e181.chunk.js → es-json.09f80f6e.chunk.js} +1 -1
  123. package/build/{fr-json.71a16175.chunk.js → fr-json.606d056b.chunk.js} +1 -1
  124. package/build/{gu-json.ca345cd1.chunk.js → gu-json.9881264f.chunk.js} +1 -1
  125. package/build/{hi-json.50c7e6d4.chunk.js → hi-json.83dcf48f.chunk.js} +1 -1
  126. package/build/{hu-json.e0521dcc.chunk.js → hu-json.6f328bce.chunk.js} +1 -1
  127. package/build/{i18n-settings-page.0b73785d.chunk.js → i18n-settings-page.18166125.chunk.js} +4 -4
  128. package/build/{id-json.4b1ff8d6.chunk.js → id-json.1f3c4303.chunk.js} +1 -1
  129. package/build/index.html +1 -1
  130. package/build/{it-json.86bac220.chunk.js → it-json.494ac432.chunk.js} +1 -1
  131. package/build/{ja-json.4e44e36b.chunk.js → ja-json.6f262117.chunk.js} +1 -1
  132. package/build/{ko-json.1003756e.chunk.js → ko-json.36dc3b9a.chunk.js} +1 -1
  133. package/build/main.63e7ea0a.js +9338 -0
  134. package/build/{ml-json.c7774425.chunk.js → ml-json.9566bf9a.chunk.js} +1 -1
  135. package/build/{nl-json.f58ea235.chunk.js → nl-json.94c3a289.chunk.js} +1 -1
  136. package/build/{pl-json.fed96aba.chunk.js → pl-json.ccc6ef23.chunk.js} +1 -1
  137. package/build/{pt-BR-json.073799ab.chunk.js → pt-BR-json.744f024d.chunk.js} +1 -1
  138. package/build/{ru-json.7ad2cbbf.chunk.js → ru-json.d22ea13c.chunk.js} +1 -1
  139. package/build/{runtime~main.feeac6d3.js → runtime~main.3a5e1b07.js} +1 -1
  140. package/build/{sa-json.f0f704f0.chunk.js → sa-json.8fb1c04d.chunk.js} +1 -1
  141. package/build/{sk-json.a848961b.chunk.js → sk-json.6c7335d4.chunk.js} +1 -1
  142. package/build/sso-settings-page.9ceb0140.chunk.js +1 -0
  143. package/build/{sv-json.b038acbe.chunk.js → sv-json.2e589a7d.chunk.js} +1 -1
  144. package/build/{upload-settings.80ff0974.chunk.js → upload-settings.3d613216.chunk.js} +4 -4
  145. package/build/{upload-translation-en-json.004a86c1.chunk.js → upload-translation-en-json.86da7b0a.chunk.js} +1 -1
  146. package/build/{users-advanced-settings-page.a02f4806.chunk.js → users-advanced-settings-page.f4051d92.chunk.js} +4 -4
  147. package/build/{webhook-edit-page.d2ea3351.chunk.js → webhook-edit-page.9e46fc3f.chunk.js} +1 -1
  148. package/build/{webhook-list-page.2775a683.chunk.js → webhook-list-page.a712ae40.chunk.js} +4 -4
  149. package/build/{zh-Hans-json.03d2bda1.chunk.js → zh-Hans-json.a4d7dc69.chunk.js} +1 -1
  150. package/build/{zh-json.3d0cc664.chunk.js → zh-json.66aa2ae1.chunk.js} +1 -1
  151. package/ee/server/controllers/user.js +5 -3
  152. package/package.json +9 -8
  153. package/server/bootstrap.js +19 -1
  154. package/server/config/admin-actions.js +20 -0
  155. package/server/content-types/api-token-permission.js +36 -0
  156. package/server/content-types/api-token.js +25 -1
  157. package/server/content-types/index.js +1 -0
  158. package/server/controllers/admin.js +3 -0
  159. package/server/controllers/api-token.js +24 -1
  160. package/server/controllers/content-api.js +15 -0
  161. package/server/controllers/index.js +1 -0
  162. package/server/controllers/user.js +3 -2
  163. package/server/routes/api-tokens.js +11 -0
  164. package/server/routes/content-api.js +20 -0
  165. package/server/routes/index.js +2 -0
  166. package/server/services/api-token.js +309 -29
  167. package/server/services/constants.js +10 -0
  168. package/server/services/permission/engine.js +36 -226
  169. package/server/services/permission.js +4 -1
  170. package/server/strategies/admin.js +7 -1
  171. package/server/strategies/api-token.js +72 -11
  172. package/server/validation/api-tokens.js +12 -2
  173. package/utils/get-custom-app-config-file.js +5 -0
  174. package/build/1856.47226450.chunk.js +0 -173
  175. package/build/4715.58cd558f.chunk.js +0 -387
  176. package/build/7098.40dcd7bf.chunk.js +0 -1
  177. package/build/8851.e4ac62f2.chunk.js +0 -158
  178. package/build/Admin-authenticatedApp.e39f36c9.chunk.js +0 -80
  179. package/build/admin-app.4f7618a9.chunk.js +0 -112
  180. package/build/admin-edit-roles-page.554ba3fa.chunk.js +0 -1
  181. package/build/api-tokens-create-page.4c262d6e.chunk.js +0 -1
  182. package/build/api-tokens-edit-page.10a9d368.chunk.js +0 -1
  183. package/build/api-tokens-list-page.442c9f3c.chunk.js +0 -15
  184. package/build/content-manager.7d57c9d1.chunk.js +0 -1200
  185. package/build/content-type-builder-list-view.8cc534e0.chunk.js +0 -194
  186. package/build/content-type-builder-translation-en-json.201bfb78.chunk.js +0 -1
  187. package/build/content-type-builder.684df7a4.chunk.js +0 -142
  188. package/build/en-json.0c69c7d7.chunk.js +0 -1
  189. package/build/main.b47db1a3.js +0 -9337
  190. package/build/sso-settings-page.445184e0.chunk.js +0 -1
  191. package/server/services/permission/engine-hooks.js +0 -82
@@ -0,0 +1,80 @@
1
+ import invariant from 'invariant';
2
+
3
+ const ALLOWED_TYPES = [
4
+ 'biginteger',
5
+ 'boolean',
6
+ 'date',
7
+ 'datetime',
8
+ 'decimal',
9
+ 'email',
10
+ 'enumeration',
11
+ 'float',
12
+ 'integer',
13
+ 'json',
14
+ 'password',
15
+ 'richtext',
16
+ 'string',
17
+ 'text',
18
+ 'time',
19
+ 'timestamp',
20
+ 'uid',
21
+ ];
22
+
23
+ class CustomFields {
24
+ constructor() {
25
+ this.customFields = {};
26
+ }
27
+
28
+ register(customFields) {
29
+ if (Array.isArray(customFields)) {
30
+ // If several custom fields are passed, register them one by one
31
+ customFields.forEach((customField) => {
32
+ this.register(customField);
33
+ });
34
+ } else {
35
+ // Handle individual custom field
36
+ const { name, pluginId, type, intlLabel, intlDescription, components } = customFields;
37
+
38
+ // Ensure required attributes are provided
39
+ invariant(name, 'A name must be provided');
40
+ invariant(type, 'A type must be provided');
41
+ invariant(intlLabel, 'An intlLabel must be provided');
42
+ invariant(intlDescription, 'An intlDescription must be provided');
43
+ invariant(components, 'A components object must be provided');
44
+ invariant(components.Input, 'An Input component must be provided');
45
+
46
+ // Ensure the type is valid
47
+ invariant(
48
+ ALLOWED_TYPES.includes(type),
49
+ `Custom field type: '${type}' is not a valid Strapi type or it can't be used with a Custom Field`
50
+ );
51
+
52
+ // Ensure name has no special characters
53
+ const isValidObjectKey = /^(?![0-9])[a-zA-Z0-9$_-]+$/g;
54
+ invariant(
55
+ isValidObjectKey.test(name),
56
+ `Custom field name: '${name}' is not a valid object key`
57
+ );
58
+
59
+ // When no plugin is specified, default to the global namespace
60
+ const uid = pluginId ? `plugin::${pluginId}.${name}` : `global::${name}`;
61
+
62
+ // Ensure the uid is unique
63
+ const uidAlreadyUsed = Object.prototype.hasOwnProperty.call(this.customFields, uid);
64
+ invariant(!uidAlreadyUsed, `Custom field: '${uid}' has already been registered`);
65
+
66
+ this.customFields[uid] = customFields;
67
+ }
68
+ }
69
+
70
+ getAll() {
71
+ return this.customFields;
72
+ }
73
+
74
+ get(uid) {
75
+ return this.customFields[uid];
76
+ }
77
+ }
78
+
79
+ // Export an instance since it's a singleton
80
+ export default new CustomFields();
@@ -3,3 +3,4 @@ export { default as Components } from './Components';
3
3
  export { default as Middlewares } from './Middlewares';
4
4
  export { default as Plugin } from './Plugin';
5
5
  export { default as Reducers } from './Reducers';
6
+ export { default as customFields } from './CustomFields';
@@ -9,3 +9,4 @@ export { default as useSettingsForm } from './useSettingsForm';
9
9
  export { default as usePermissionsDataManager } from './usePermissionsDataManager';
10
10
  export { default as useReleaseNotification } from './useReleaseNotification';
11
11
  export { default as useThemeToggle } from './useThemeToggle';
12
+ export { default as useRegenerate } from './useRegenerate';
@@ -0,0 +1,34 @@
1
+ import { useState } from 'react';
2
+ import { get } from 'lodash';
3
+ import { useNotification } from '@strapi/helper-plugin';
4
+ import { axiosInstance } from '../../core/utils';
5
+
6
+ const useRegenerate = (id, onRegenerate) => {
7
+ const [isLoadingConfirmation, setIsLoadingConfirmation] = useState(false);
8
+ const toggleNotification = useNotification();
9
+
10
+ const regenerateData = async () => {
11
+ try {
12
+ const {
13
+ data: {
14
+ data: { accessKey },
15
+ },
16
+ } = await axiosInstance.post(`/admin/api-tokens/${id}/regenerate`);
17
+ setIsLoadingConfirmation(false);
18
+ onRegenerate(accessKey);
19
+ } catch (error) {
20
+ setIsLoadingConfirmation(false);
21
+ toggleNotification({
22
+ type: 'warning',
23
+ message: get(error, 'response.data.message', 'notification.error'),
24
+ });
25
+ }
26
+ };
27
+
28
+ return {
29
+ regenerateData,
30
+ isLoadingConfirmation,
31
+ };
32
+ };
33
+
34
+ export default useRegenerate;
@@ -79,7 +79,7 @@ const socialLinks = [
79
79
  },
80
80
  {
81
81
  name: 'Discord',
82
- link: 'https://slack.strapi.io/',
82
+ link: 'https://discord.strapi.io/',
83
83
  icon: <StyledDiscord />,
84
84
  alt: 'discord',
85
85
  },
@@ -0,0 +1,56 @@
1
+ import React from 'react';
2
+ import { useIntl } from 'react-intl';
3
+ import { Typography } from '@strapi/design-system/Typography';
4
+ import { Stack } from '@strapi/design-system/Stack';
5
+ import { GridItem } from '@strapi/design-system/Grid';
6
+ import BoundRoute from '../BoundRoute';
7
+ import { useApiTokenPermissionsContext } from '../../../../../../../contexts/ApiTokenPermissions';
8
+
9
+ const ActionBoundRoutes = () => {
10
+ const {
11
+ value: { selectedAction, routes },
12
+ } = useApiTokenPermissionsContext();
13
+ const { formatMessage } = useIntl();
14
+ const actionSection = selectedAction?.split('.')[0];
15
+
16
+ return (
17
+ <GridItem
18
+ col={5}
19
+ background="neutral150"
20
+ paddingTop={6}
21
+ paddingBottom={6}
22
+ paddingLeft={7}
23
+ paddingRight={7}
24
+ style={{ minHeight: '100%' }}
25
+ >
26
+ {selectedAction ? (
27
+ <Stack spacing={2}>
28
+ {routes[actionSection]?.map((route) => {
29
+ return route.config.auth?.scope?.includes(selectedAction) ||
30
+ route.handler === selectedAction ? (
31
+ <BoundRoute key={route.handler} route={route} />
32
+ ) : null;
33
+ })}
34
+ </Stack>
35
+ ) : (
36
+ <Stack spacing={2}>
37
+ <Typography variant="delta" as="h3">
38
+ {formatMessage({
39
+ id: 'Settings.apiTokens.createPage.permissions.header.title',
40
+ defaultMessage: 'Advanced settings',
41
+ })}
42
+ </Typography>
43
+ <Typography as="p" textColor="neutral600">
44
+ {formatMessage({
45
+ id: 'Settings.apiTokens.createPage.permissions.header.hint',
46
+ defaultMessage:
47
+ "Select the application's actions or the plugin's actions and click on the cog icon to display the bound route",
48
+ })}
49
+ </Typography>
50
+ </Stack>
51
+ )}
52
+ </GridItem>
53
+ );
54
+ };
55
+
56
+ export default ActionBoundRoutes;
@@ -0,0 +1,41 @@
1
+ const getMethodColor = (verb) => {
2
+ switch (verb) {
3
+ case 'POST': {
4
+ return {
5
+ text: 'success600',
6
+ border: 'success200',
7
+ background: 'success100',
8
+ };
9
+ }
10
+ case 'GET': {
11
+ return {
12
+ text: 'secondary600',
13
+ border: 'secondary200',
14
+ background: 'secondary100',
15
+ };
16
+ }
17
+ case 'PUT': {
18
+ return {
19
+ text: 'warning600',
20
+ border: 'warning200',
21
+ background: 'warning100',
22
+ };
23
+ }
24
+ case 'DELETE': {
25
+ return {
26
+ text: 'danger600',
27
+ border: 'danger200',
28
+ background: 'danger100',
29
+ };
30
+ }
31
+ default: {
32
+ return {
33
+ text: 'neutral600',
34
+ border: 'neutral200',
35
+ background: 'neutral100',
36
+ };
37
+ }
38
+ }
39
+ };
40
+
41
+ export default getMethodColor;
@@ -0,0 +1,72 @@
1
+ import React from 'react';
2
+ import styled from 'styled-components';
3
+ import { Stack } from '@strapi/design-system/Stack';
4
+ import { Box } from '@strapi/design-system/Box';
5
+ import { Typography } from '@strapi/design-system/Typography';
6
+ import map from 'lodash/map';
7
+ import tail from 'lodash/tail';
8
+ import { useIntl } from 'react-intl';
9
+ import PropTypes from 'prop-types';
10
+ import getMethodColor from './getMethodColor';
11
+
12
+ const MethodBox = styled(Box)`
13
+ margin: -1px;
14
+ border-radius: ${({ theme }) => theme.spaces[1]} 0 0 ${({ theme }) => theme.spaces[1]};
15
+ `;
16
+
17
+ function BoundRoute({ route }) {
18
+ const { formatMessage } = useIntl();
19
+
20
+ const { method, handler: title, path } = route;
21
+ const formattedRoute = path ? tail(path.split('/')) : [];
22
+ const [controller = '', action = ''] = title ? title.split('.') : [];
23
+ const colors = getMethodColor(route.method);
24
+
25
+ return (
26
+ <Stack spacing={2}>
27
+ <Typography variant="delta" as="h3">
28
+ {formatMessage({
29
+ id: 'Settings.apiTokens.createPage.BoundRoute.title',
30
+ defaultMessage: 'Bound route to',
31
+ })}
32
+ &nbsp;
33
+ <span>{controller}</span>
34
+ <Typography variant="delta" textColor="primary600">
35
+ .{action}
36
+ </Typography>
37
+ </Typography>
38
+ <Stack horizontal hasRadius background="neutral0" borderColor="neutral200" spacing={0}>
39
+ <MethodBox background={colors.background} borderColor={colors.border} padding={2}>
40
+ <Typography fontWeight="bold" textColor={colors.text}>
41
+ {method}
42
+ </Typography>
43
+ </MethodBox>
44
+ <Box paddingLeft={2} paddingRight={2}>
45
+ {map(formattedRoute, (value) => (
46
+ <Typography key={value} textColor={value.includes(':') ? 'neutral600' : 'neutral900'}>
47
+ /{value}
48
+ </Typography>
49
+ ))}
50
+ </Box>
51
+ </Stack>
52
+ </Stack>
53
+ );
54
+ }
55
+
56
+ BoundRoute.defaultProps = {
57
+ route: {
58
+ handler: 'Nocontroller.error',
59
+ method: 'GET',
60
+ path: '/there-is-no-path',
61
+ },
62
+ };
63
+
64
+ BoundRoute.propTypes = {
65
+ route: PropTypes.shape({
66
+ handler: PropTypes.string,
67
+ method: PropTypes.string,
68
+ path: PropTypes.string,
69
+ }),
70
+ };
71
+
72
+ export default BoundRoute;
@@ -0,0 +1,30 @@
1
+ import styled, { css } from 'styled-components';
2
+ import { Box } from '@strapi/design-system/Box';
3
+
4
+ const activeCheckboxWrapperStyles = css`
5
+ background: ${(props) => props.theme.colors.primary100};
6
+ svg {
7
+ opacity: 1;
8
+ }
9
+ `;
10
+
11
+ const CheckboxWrapper = styled(Box)`
12
+ display: flex;
13
+ justify-content: space-between;
14
+ align-items: center;
15
+
16
+ svg {
17
+ opacity: 0;
18
+ path {
19
+ fill: ${(props) => props.theme.colors.primary600};
20
+ }
21
+ }
22
+
23
+ /* Show active style both on hover and when the action is selected */
24
+ ${(props) => props.isActive && activeCheckboxWrapperStyles}
25
+ &:hover {
26
+ ${activeCheckboxWrapperStyles}
27
+ }
28
+ `;
29
+
30
+ export default CheckboxWrapper;
@@ -0,0 +1,150 @@
1
+ import React, { useState, useEffect } from 'react';
2
+ import { capitalize } from 'lodash';
3
+ import { Accordion, AccordionToggle, AccordionContent } from '@strapi/design-system/Accordion';
4
+ import { Checkbox } from '@strapi/design-system/Checkbox';
5
+ import { Grid, GridItem } from '@strapi/design-system/Grid';
6
+ import { Typography } from '@strapi/design-system/Typography';
7
+ import { Box } from '@strapi/design-system/Box';
8
+ import { Flex } from '@strapi/design-system/Flex';
9
+ import CogIcon from '@strapi/icons/Cog';
10
+ import styled from 'styled-components';
11
+ import PropTypes from 'prop-types';
12
+ import { useApiTokenPermissionsContext } from '../../../../../../../contexts/ApiTokenPermissions';
13
+ import CheckboxWrapper from './CheckBoxWrapper';
14
+
15
+ const Border = styled.div`
16
+ flex: 1;
17
+ align-self: center;
18
+ border-top: 1px solid ${({ theme }) => theme.colors.neutral150};
19
+ `;
20
+
21
+ const CollapsableContentType = ({
22
+ controllers,
23
+ label,
24
+ orderNumber,
25
+ disabled,
26
+ onExpanded,
27
+ indexExpandendCollapsedContent,
28
+ }) => {
29
+ const {
30
+ value: { onChangeSelectAll, onChange, selectedActions, setSelectedAction, selectedAction },
31
+ } = useApiTokenPermissionsContext();
32
+ const [expanded, setExpanded] = useState(false);
33
+
34
+ const handleExpandedAccordion = () => {
35
+ setExpanded((s) => !s);
36
+ onExpanded(orderNumber);
37
+ };
38
+
39
+ useEffect(() => {
40
+ if (
41
+ indexExpandendCollapsedContent !== null &&
42
+ indexExpandendCollapsedContent !== orderNumber &&
43
+ expanded
44
+ ) {
45
+ setExpanded(false);
46
+ }
47
+ }, [indexExpandendCollapsedContent, orderNumber, expanded]);
48
+
49
+ const isActionSelected = (actionId) => actionId === selectedAction;
50
+
51
+ return (
52
+ <Accordion
53
+ expanded={expanded}
54
+ onToggle={handleExpandedAccordion}
55
+ variant={orderNumber % 2 ? 'primary' : 'secondary'}
56
+ >
57
+ <AccordionToggle title={capitalize(label)} />
58
+ <AccordionContent>
59
+ {controllers?.map((controller) => {
60
+ const allActionsSelected = controller.actions.every((action) =>
61
+ selectedActions.includes(action.actionId)
62
+ );
63
+
64
+ const someActionsSelected = controller.actions.some((action) =>
65
+ selectedActions.includes(action.actionId)
66
+ );
67
+
68
+ return (
69
+ <Box key={`${label}.${controller?.controller}`}>
70
+ <Flex justifyContent="space-between" alignItems="center" padding={4}>
71
+ <Box paddingRight={4}>
72
+ <Typography variant="sigma" textColor="neutral600">
73
+ {controller?.controller}
74
+ </Typography>
75
+ </Box>
76
+ <Border />
77
+ <Box paddingLeft={4}>
78
+ <Checkbox
79
+ value={allActionsSelected}
80
+ indeterminate={!allActionsSelected && someActionsSelected}
81
+ onValueChange={() => {
82
+ onChangeSelectAll({ target: { value: [...controller.actions] } });
83
+ }}
84
+ disabled={disabled}
85
+ >
86
+ Select all
87
+ </Checkbox>
88
+ </Box>
89
+ </Flex>
90
+ <Grid gap={4} padding={4}>
91
+ {controller?.actions &&
92
+ controller?.actions.map((action) => {
93
+ return (
94
+ <GridItem col={6} key={action.actionId}>
95
+ <CheckboxWrapper
96
+ isActive={isActionSelected(action.actionId)}
97
+ padding={2}
98
+ hasRadius
99
+ >
100
+ <Checkbox
101
+ value={selectedActions.includes(action.actionId)}
102
+ name={action.actionId}
103
+ onValueChange={() => {
104
+ onChange({ target: { value: action.actionId } });
105
+ }}
106
+ disabled={disabled}
107
+ >
108
+ {action.action}
109
+ </Checkbox>
110
+ <button
111
+ type="button"
112
+ data-testid="action-cog"
113
+ onClick={() =>
114
+ setSelectedAction({ target: { value: action.actionId } })
115
+ }
116
+ style={{ display: 'inline-flex', alignItems: 'center' }}
117
+ >
118
+ <CogIcon />
119
+ </button>
120
+ </CheckboxWrapper>
121
+ </GridItem>
122
+ );
123
+ })}
124
+ </Grid>
125
+ </Box>
126
+ );
127
+ })}
128
+ </AccordionContent>
129
+ </Accordion>
130
+ );
131
+ };
132
+
133
+ CollapsableContentType.defaultProps = {
134
+ controllers: [],
135
+ orderNumber: 0,
136
+ disabled: false,
137
+ onExpanded: () => null,
138
+ indexExpandendCollapsedContent: null,
139
+ };
140
+
141
+ CollapsableContentType.propTypes = {
142
+ controllers: PropTypes.array,
143
+ orderNumber: PropTypes.number,
144
+ label: PropTypes.string.isRequired,
145
+ disabled: PropTypes.bool,
146
+ onExpanded: PropTypes.func,
147
+ indexExpandendCollapsedContent: PropTypes.number,
148
+ };
149
+
150
+ export default CollapsableContentType;
@@ -0,0 +1,37 @@
1
+ import React, { useState } from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { Box } from '@strapi/design-system/Box';
4
+ import CollapsableContentType from '../CollapsableContentType';
5
+
6
+ const ContentTypesSection = ({ section, ...props }) => {
7
+ const [indexExpandedCollpsedContent, setIndexExpandedCollpsedContent] = useState(null);
8
+ const handleExpandedCollpsedContentIndex = (index) => setIndexExpandedCollpsedContent(index);
9
+
10
+ return (
11
+ <Box padding={4} background="neutral0">
12
+ {section &&
13
+ section.map((api, index) => (
14
+ <CollapsableContentType
15
+ key={api.apiId}
16
+ label={api.label}
17
+ controllers={api.controllers}
18
+ orderNumber={index}
19
+ indexExpandendCollapsedContent={indexExpandedCollpsedContent}
20
+ onExpanded={handleExpandedCollpsedContentIndex}
21
+ name={api.apiId}
22
+ {...props}
23
+ />
24
+ ))}
25
+ </Box>
26
+ );
27
+ };
28
+
29
+ ContentTypesSection.defaultProps = {
30
+ section: null,
31
+ };
32
+
33
+ ContentTypesSection.propTypes = {
34
+ section: PropTypes.arrayOf(PropTypes.object),
35
+ };
36
+
37
+ export default ContentTypesSection;