@strapi/admin 4.4.0-alpha.0 → 4.4.0-beta.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 (138) hide show
  1. package/admin/src/StrapiApp.js +12 -4
  2. package/admin/src/components/Providers/index.js +10 -14
  3. package/admin/src/content-manager/components/DynamicTable/CellContent/RelationSingle/index.js +1 -1
  4. package/admin/src/content-manager/components/FieldTypeIcon/index.js +1 -31
  5. package/admin/src/content-manager/components/Inputs/index.js +10 -30
  6. package/admin/src/content-manager/components/SelectMany/index.js +3 -0
  7. package/admin/src/content-manager/components/SelectOne/SingleValue.js +2 -2
  8. package/admin/src/content-manager/components/SelectOne/index.js +3 -0
  9. package/admin/src/content-manager/components/SelectWrapper/Option.js +2 -2
  10. package/admin/src/content-manager/components/SelectWrapper/index.js +6 -0
  11. package/admin/src/content-manager/pages/EditSettingsView/components/FormModal.js +2 -7
  12. package/admin/src/content-manager/pages/EditSettingsView/index.js +1 -2
  13. package/admin/src/content-manager/pages/EditView/index.js +84 -91
  14. package/admin/src/content-manager/pages/ListSettingsView/index.js +1 -1
  15. package/admin/src/contexts/ApiTokenPermissions/index.js +24 -0
  16. package/admin/src/core/apis/index.js +0 -1
  17. package/admin/src/hooks/index.js +1 -0
  18. package/admin/src/hooks/useRegenerate/index.js +34 -0
  19. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/ActionBoundRoutes/index.js +56 -0
  20. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/BoundRoute/getMethodColor.js +41 -0
  21. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/BoundRoute/index.js +72 -0
  22. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/CollapsableContentType/CheckBoxWrapper.js +30 -0
  23. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/CollapsableContentType/index.js +150 -0
  24. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/ContenTypesSection/index.js +37 -0
  25. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/Permissions/index.js +40 -0
  26. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/Regenerate/index.js +68 -0
  27. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/index.js +452 -180
  28. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/init.js +13 -0
  29. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/reducer.js +55 -0
  30. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/utils/getDateOfExpiration.js +16 -0
  31. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/utils/index.js +5 -0
  32. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/utils/schema.js +2 -1
  33. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/utils/transformPermissionsData.js +36 -0
  34. package/admin/src/pages/SettingsPage/pages/ApiTokens/ListView/DynamicTable/DefaultButton/index.js +63 -0
  35. package/admin/src/pages/SettingsPage/pages/ApiTokens/ListView/DynamicTable/DeleteButton/index.js +1 -0
  36. package/admin/src/pages/SettingsPage/pages/ApiTokens/ListView/DynamicTable/ReadButton/index.js +19 -0
  37. package/admin/src/pages/SettingsPage/pages/ApiTokens/ListView/DynamicTable/UpdateButton/index.js +3 -36
  38. package/admin/src/pages/SettingsPage/pages/ApiTokens/ListView/DynamicTable/index.js +13 -11
  39. package/admin/src/pages/SettingsPage/pages/ApiTokens/ListView/index.js +4 -3
  40. package/admin/src/pages/SettingsPage/pages/ApiTokens/ListView/utils/tableHeaders.js +8 -8
  41. package/admin/src/pages/SettingsPage/pages/ApiTokens/ProtectedEditView/index.js +1 -1
  42. package/admin/src/pages/SettingsPage/pages/Roles/ListPage/index.js +1 -1
  43. package/admin/src/pages/SettingsPage/pages/Users/ListPage/index.js +1 -1
  44. package/admin/src/pages/SettingsPage/pages/Webhooks/EditView/components/EventInput/index.js +10 -10
  45. package/admin/src/pages/SettingsPage/pages/Webhooks/ListView/index.js +1 -1
  46. package/admin/src/permissions/defaultPermissions.js +2 -6
  47. package/admin/src/translations/en.json +18 -0
  48. package/admin/src/translations/es.json +1 -1
  49. package/admin/src/translations/fr.json +33 -0
  50. package/build/1669.d1b29c28.chunk.js +1 -0
  51. package/build/{1856.d3da2fcd.chunk.js → 1856.47226450.chunk.js} +6 -6
  52. package/build/{2077.b25a0b57.chunk.js → 2077.61cebc93.chunk.js} +4 -4
  53. package/build/{2912.da8a70aa.chunk.js → 2912.a015078a.chunk.js} +10 -10
  54. package/build/4235.982b5799.chunk.js +30 -0
  55. package/build/{4715.3787be19.chunk.js → 4715.3f6cac0a.chunk.js} +30 -30
  56. package/build/{4800.d3ebc81d.chunk.js → 4800.d09f1225.chunk.js} +1 -1
  57. package/build/{4982.a4e36c9a.chunk.js → 4982.c6f88c5d.chunk.js} +8 -8
  58. package/build/611.a91aff91.chunk.js +158 -0
  59. package/build/7379.d246dd38.chunk.js +1 -0
  60. package/build/{7841.922b96eb.chunk.js → 7841.91f793dc.chunk.js} +9 -9
  61. package/build/{7866.22e3c9f8.chunk.js → 7866.c793a31d.chunk.js} +23 -23
  62. package/build/{8380.ab3939f3.chunk.js → 8380.8789ff76.chunk.js} +8 -8
  63. package/build/{8549.0e30f86d.chunk.js → 8549.133c4473.chunk.js} +5 -5
  64. package/build/{8773.4e36117f.chunk.js → 8773.eccaa5f3.chunk.js} +9 -9
  65. package/build/{9066.2847fdff.chunk.js → 9066.08049eb1.chunk.js} +4 -4
  66. package/build/{9166.280c7521.chunk.js → 9166.037339e0.chunk.js} +2 -2
  67. package/build/{9420.ee1ccff7.chunk.js → 9420.43a86e7c.chunk.js} +30 -30
  68. package/build/{Admin-authenticatedApp.aaa66872.chunk.js → Admin-authenticatedApp.3a31a087.chunk.js} +3 -3
  69. package/build/{Admin_homePage.118926e0.chunk.js → Admin_homePage.6d5e3236.chunk.js} +1 -1
  70. package/build/{Admin_marketplace.2d181ad7.chunk.js → Admin_marketplace.82c0570b.chunk.js} +1 -1
  71. package/build/{Admin_profilePage.8617313a.chunk.js → Admin_profilePage.83991a6c.chunk.js} +1 -1
  72. package/build/{Admin_settingsPage.e58753c8.chunk.js → Admin_settingsPage.fc9c607a.chunk.js} +16 -16
  73. package/build/admin-app.41b6472c.chunk.js +112 -0
  74. package/build/admin-edit-roles-page.4dd6bcb9.chunk.js +1 -0
  75. package/build/{admin-users.1d0aa7a0.chunk.js → admin-users.dccd5f4c.chunk.js} +2 -2
  76. package/build/api-tokens-create-page.29cc87b6.chunk.js +1 -0
  77. package/build/api-tokens-edit-page.c294a88f.chunk.js +1 -0
  78. package/build/api-tokens-list-page.bb36535f.chunk.js +16 -0
  79. package/build/content-manager.fb5ee865.chunk.js +1178 -0
  80. package/build/content-type-builder-list-view.8cc534e0.chunk.js +194 -0
  81. package/build/content-type-builder-translation-en-json.201bfb78.chunk.js +1 -0
  82. package/build/content-type-builder.42cecba9.chunk.js +142 -0
  83. package/build/{email-settings-page.818761d5.chunk.js → email-settings-page.64037147.chunk.js} +5 -5
  84. package/build/en-json.a9918c93.chunk.js +1 -0
  85. package/build/{es-json.bb1fc425.chunk.js → es-json.3a9c7c09.chunk.js} +1 -1
  86. package/build/fr-json.4ed1fc2c.chunk.js +1 -0
  87. package/build/{i18n-settings-page.bf1304b0.chunk.js → i18n-settings-page.0b73785d.chunk.js} +5 -5
  88. package/build/index.html +1 -1
  89. package/build/{main.7db3414f.js → main.cdfda31e.js} +1235 -1235
  90. package/build/{runtime~main.c1c5510b.js → runtime~main.fa8f8898.js} +1 -1
  91. package/build/sso-settings-page.9ceb0140.chunk.js +1 -0
  92. package/build/{upload-settings.5dfe0fe2.chunk.js → upload-settings.80ff0974.chunk.js} +7 -7
  93. package/build/upload-translation-ca-json.db8ed7ba.chunk.js +1 -0
  94. package/build/{users-advanced-settings-page.f11c8af4.chunk.js → users-advanced-settings-page.a02f4806.chunk.js} +5 -5
  95. package/build/{users-roles-settings-page.cafb4fe5.chunk.js → users-roles-settings-page.b33ec5e5.chunk.js} +1 -1
  96. package/build/{webhook-edit-page.9aba79b2.chunk.js → webhook-edit-page.9e46fc3f.chunk.js} +3 -3
  97. package/build/{webhook-list-page.912becb8.chunk.js → webhook-list-page.2775a683.chunk.js} +5 -5
  98. package/ee/admin/pages/SettingsPage/pages/Roles/ListPage/index.js +1 -1
  99. package/package.json +14 -13
  100. package/scripts/build.js +2 -4
  101. package/server/bootstrap.js +19 -1
  102. package/server/config/admin-actions.js +20 -0
  103. package/server/content-types/api-token-permission.js +36 -0
  104. package/server/content-types/api-token.js +25 -1
  105. package/server/content-types/index.js +1 -0
  106. package/server/controllers/api-token.js +24 -1
  107. package/server/controllers/content-api.js +15 -0
  108. package/server/controllers/index.js +1 -0
  109. package/server/routes/api-tokens.js +11 -0
  110. package/server/routes/content-api.js +20 -0
  111. package/server/routes/index.js +2 -0
  112. package/server/services/api-token.js +310 -29
  113. package/server/services/constants.js +10 -0
  114. package/server/services/permission/engine.js +36 -226
  115. package/server/services/permission/permissions-manager/query-builers.js +3 -2
  116. package/server/services/permission/queries.js +1 -1
  117. package/server/services/permission.js +4 -1
  118. package/server/strategies/admin.js +7 -1
  119. package/server/strategies/api-token.js +71 -11
  120. package/server/validation/api-tokens.js +12 -2
  121. package/server/validation/common-functions/check-fields-are-correctly-nested.js +1 -1
  122. package/admin/src/core/apis/CustomFields.js +0 -80
  123. package/build/1669.4ce92b2f.chunk.js +0 -1
  124. package/build/524.2437fb56.chunk.js +0 -644
  125. package/build/admin-app.1f9e13f8.chunk.js +0 -112
  126. package/build/admin-edit-roles-page.554ba3fa.chunk.js +0 -1
  127. package/build/api-tokens-create-page.b4a9987d.chunk.js +0 -1
  128. package/build/api-tokens-edit-page.6f5b4e26.chunk.js +0 -1
  129. package/build/api-tokens-list-page.06938769.chunk.js +0 -15
  130. package/build/content-manager.86f7594d.chunk.js +0 -1178
  131. package/build/content-type-builder-list-view.9b874fd4.chunk.js +0 -194
  132. package/build/content-type-builder-translation-en-json.f985c9c4.chunk.js +0 -1
  133. package/build/content-type-builder.47ab07ad.chunk.js +0 -145
  134. package/build/en-json.1bf20384.chunk.js +0 -1
  135. package/build/fr-json.a3cf2e0b.chunk.js +0 -1
  136. package/build/sso-settings-page.445184e0.chunk.js +0 -1
  137. package/build/upload-translation-ca-json.00dc1f33.chunk.js +0 -1
  138. package/server/services/permission/engine-hooks.js +0 -82
@@ -0,0 +1,13 @@
1
+ import { transformPermissionsData } from './utils';
2
+
3
+ const init = (state, permissions = []) => {
4
+ return {
5
+ ...state,
6
+ selectedAction: null,
7
+ routes: [],
8
+ selectedActions: [],
9
+ data: transformPermissionsData(permissions),
10
+ };
11
+ };
12
+
13
+ export default init;
@@ -0,0 +1,55 @@
1
+ /* eslint-disable consistent-return */
2
+ import produce from 'immer';
3
+ import { pull } from 'lodash';
4
+ import { transformPermissionsData } from './utils';
5
+
6
+ export const initialState = {
7
+ data: {},
8
+ selectedActions: [],
9
+ };
10
+
11
+ const reducer = (state, action) =>
12
+ produce(state, (draftState) => {
13
+ switch (action.type) {
14
+ case 'ON_CHANGE': {
15
+ if (draftState.selectedActions.includes(action.value)) {
16
+ pull(draftState.selectedActions, action.value);
17
+ } else {
18
+ draftState.selectedActions.push(action.value);
19
+ }
20
+ break;
21
+ }
22
+ case 'SELECT_ALL_ACTIONS': {
23
+ draftState.selectedActions = [...draftState.data.allActionsIds];
24
+
25
+ break;
26
+ }
27
+ case 'ON_CHANGE_READ_ONLY': {
28
+ const onlyReadOnlyActions = draftState.data.allActionsIds.filter(
29
+ (actionId) => actionId.includes('find') || actionId.includes('findOne')
30
+ );
31
+ draftState.selectedActions = [...onlyReadOnlyActions];
32
+ break;
33
+ }
34
+ case 'UPDATE_PERMISSIONS_LAYOUT': {
35
+ draftState.data = transformPermissionsData(action.value);
36
+ break;
37
+ }
38
+ case 'UPDATE_ROUTES': {
39
+ draftState.routes = { ...action.value };
40
+ break;
41
+ }
42
+ case 'UPDATE_PERMISSIONS': {
43
+ draftState.selectedActions = [...action.value];
44
+ break;
45
+ }
46
+ case 'SET_SELECTED_ACTION': {
47
+ draftState.selectedAction = action.value;
48
+ break;
49
+ }
50
+ default:
51
+ return draftState;
52
+ }
53
+ });
54
+
55
+ export default reducer;
@@ -0,0 +1,16 @@
1
+ import { addDays, format } from 'date-fns';
2
+ import * as locales from 'date-fns/locale';
3
+
4
+ const getDateOfExpiration = (createdAt, duration, language = 'en') => {
5
+ if (duration && typeof duration === 'number') {
6
+ const durationInDays = duration / 24 / 60 / 60 / 1000;
7
+
8
+ return format(addDays(new Date(createdAt), durationInDays), 'PPP', {
9
+ locale: locales[language],
10
+ });
11
+ }
12
+
13
+ return 'Unlimited';
14
+ };
15
+
16
+ export default getDateOfExpiration;
@@ -0,0 +1,5 @@
1
+ import getDateOfExpiration from './getDateOfExpiration';
2
+ import schema from './schema';
3
+ import transformPermissionsData from './transformPermissionsData';
4
+
5
+ export { getDateOfExpiration, schema, transformPermissionsData };
@@ -5,9 +5,10 @@ const schema = yup.object().shape({
5
5
  name: yup.string(translatedErrors.string).required(translatedErrors.required),
6
6
  type: yup
7
7
  .string(translatedErrors.string)
8
- .oneOf(['read-only', 'full-access'])
8
+ .oneOf(['read-only', 'full-access', 'custom'])
9
9
  .required(translatedErrors.required),
10
10
  description: yup.string().nullable(),
11
+ lifespan: yup.number().integer().min(1).nullable().defined(translatedErrors.required),
11
12
  });
12
13
 
13
14
  export default schema;
@@ -0,0 +1,36 @@
1
+ import { flatten } from 'lodash';
2
+
3
+ const transformPermissionsData = (data) => {
4
+ const layout = {
5
+ allActionsIds: [],
6
+ permissions: [],
7
+ };
8
+
9
+ layout.permissions = Object.keys(data).map((apiId) => ({
10
+ apiId,
11
+ label: apiId.split('::')[1],
12
+ controllers: flatten(
13
+ Object.keys(data[apiId].controllers).map((controller) => ({
14
+ controller,
15
+ actions: flatten(
16
+ data[apiId].controllers[controller].map((action) => {
17
+ const actionId = `${apiId}.${controller}.${action}`;
18
+
19
+ if (apiId.includes('api::')) {
20
+ layout.allActionsIds.push(actionId);
21
+ }
22
+
23
+ return {
24
+ action,
25
+ actionId,
26
+ };
27
+ })
28
+ ),
29
+ }))
30
+ ),
31
+ }));
32
+
33
+ return layout;
34
+ };
35
+
36
+ export default transformPermissionsData;
@@ -0,0 +1,63 @@
1
+ import React from 'react';
2
+ import { useIntl } from 'react-intl';
3
+ import PropTypes from 'prop-types';
4
+ import { Link } from '@strapi/helper-plugin';
5
+ import { useHistory } from 'react-router-dom';
6
+ import styled from 'styled-components';
7
+
8
+ const MESSAGES_MAP = {
9
+ edit: {
10
+ id: 'app.component.table.edit',
11
+ defaultMessage: 'Edit {target}',
12
+ },
13
+ read: {
14
+ id: 'app.component.table.read',
15
+ defaultMessage: 'Read {target}',
16
+ },
17
+ };
18
+
19
+ const LinkStyled = styled(Link)`
20
+ svg {
21
+ path {
22
+ fill: ${({ theme }) => theme.colors.neutral500};
23
+ }
24
+ }
25
+
26
+ &:hover,
27
+ &:focus {
28
+ svg {
29
+ path {
30
+ fill: ${({ theme }) => theme.colors.neutral800};
31
+ }
32
+ }
33
+ }
34
+ `;
35
+
36
+ const DefaultButton = ({ tokenName, tokenId, buttonType, children }) => {
37
+ const { formatMessage } = useIntl();
38
+ const {
39
+ location: { pathname },
40
+ } = useHistory();
41
+
42
+ return (
43
+ <LinkStyled
44
+ to={`${pathname}/${tokenId}`}
45
+ title={formatMessage(MESSAGES_MAP[buttonType], { target: tokenName })}
46
+ >
47
+ {children}
48
+ </LinkStyled>
49
+ );
50
+ };
51
+
52
+ DefaultButton.propTypes = {
53
+ tokenName: PropTypes.string.isRequired,
54
+ tokenId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
55
+ buttonType: PropTypes.string,
56
+ children: PropTypes.node.isRequired,
57
+ };
58
+
59
+ DefaultButton.defaultProps = {
60
+ buttonType: 'edit',
61
+ };
62
+
63
+ export default DefaultButton;
@@ -24,6 +24,7 @@ const DeleteButton = ({ tokenName, onClickDelete }) => {
24
24
  },
25
25
  { target: `${tokenName}` }
26
26
  )}
27
+ name="delete"
27
28
  noBorder
28
29
  icon={<Trash />}
29
30
  />
@@ -0,0 +1,19 @@
1
+ import React from 'react';
2
+ import Eye from '@strapi/icons/Eye';
3
+ import PropTypes from 'prop-types';
4
+ import DefaultButton from '../DefaultButton';
5
+
6
+ const ReadButton = ({ tokenName, tokenId }) => {
7
+ return (
8
+ <DefaultButton tokenName={tokenName} tokenId={tokenId} buttonType="read">
9
+ <Eye />
10
+ </DefaultButton>
11
+ );
12
+ };
13
+
14
+ ReadButton.propTypes = {
15
+ tokenName: PropTypes.string.isRequired,
16
+ tokenId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
17
+ };
18
+
19
+ export default ReadButton;
@@ -1,46 +1,13 @@
1
1
  import React from 'react';
2
2
  import Pencil from '@strapi/icons/Pencil';
3
- import { useIntl } from 'react-intl';
4
3
  import PropTypes from 'prop-types';
5
- import { Link } from '@strapi/helper-plugin';
6
- import { useHistory } from 'react-router-dom';
7
- import styled from 'styled-components';
8
-
9
- const LinkUpdate = styled(Link)`
10
- svg {
11
- path {
12
- fill: ${({ theme }) => theme.colors.neutral500};
13
- }
14
- }
15
-
16
- &:hover {
17
- svg {
18
- path {
19
- fill: ${({ theme }) => theme.colors.neutral800};
20
- }
21
- }
22
- }
23
- `;
4
+ import DefaultButton from '../DefaultButton';
24
5
 
25
6
  const UpdateButton = ({ tokenName, tokenId }) => {
26
- const { formatMessage } = useIntl();
27
- const {
28
- location: { pathname },
29
- } = useHistory();
30
-
31
7
  return (
32
- <LinkUpdate
33
- to={`${pathname}/${tokenId}`}
34
- title={formatMessage(
35
- {
36
- id: 'app.component.table.edit',
37
- defaultMessage: 'Edit {target}',
38
- },
39
- { target: `${tokenName}` }
40
- )}
41
- >
8
+ <DefaultButton tokenName={tokenName} tokenId={tokenId}>
42
9
  <Pencil />
43
- </LinkUpdate>
10
+ </DefaultButton>
44
11
  );
45
12
  };
46
13
 
@@ -1,5 +1,4 @@
1
1
  import React from 'react';
2
- import { useIntl } from 'react-intl';
3
2
  import PropTypes from 'prop-types';
4
3
  import { useHistory } from 'react-router-dom';
5
4
 
@@ -13,12 +12,11 @@ import {
13
12
  pxToRem,
14
13
  useTracking,
15
14
  } from '@strapi/helper-plugin';
16
-
17
15
  import DeleteButton from './DeleteButton';
18
16
  import UpdateButton from './UpdateButton';
17
+ import ReadButton from './ReadButton';
19
18
 
20
- const TableRows = ({ canDelete, canUpdate, onClickDelete, withBulkActions, rows }) => {
21
- const { formatMessage } = useIntl();
19
+ const TableRows = ({ canDelete, canUpdate, canRead, onClickDelete, withBulkActions, rows }) => {
22
20
  const [{ query }] = useQueryParams();
23
21
  const [, sortOrder] = query.sort.split(':');
24
22
  const {
@@ -59,22 +57,24 @@ const TableRows = ({ canDelete, canUpdate, onClickDelete, withBulkActions, rows
59
57
  </Td>
60
58
  <Td>
61
59
  <Typography textColor="neutral800">
62
- {formatMessage({
63
- id: `Settings.apiTokens.types.${apiToken.type}`,
64
- defaultMessage: 'Type unknown',
65
- })}
60
+ <RelativeTime timestamp={new Date(apiToken.createdAt)} />
66
61
  </Typography>
67
62
  </Td>
68
63
  <Td>
69
- <Typography textColor="neutral800">
70
- <RelativeTime timestamp={new Date(apiToken.createdAt)} />
71
- </Typography>
64
+ {apiToken.lastUsedAt && (
65
+ <Typography textColor="neutral800">
66
+ <RelativeTime timestamp={new Date(apiToken.lastUsedAt)} />
67
+ </Typography>
68
+ )}
72
69
  </Td>
73
70
 
74
71
  {withBulkActions && (
75
72
  <Td>
76
73
  <Flex justifyContent="end">
77
74
  {canUpdate && <UpdateButton tokenName={apiToken.name} tokenId={apiToken.id} />}
75
+ {!canUpdate && canRead && (
76
+ <ReadButton tokenName={apiToken.name} tokenId={apiToken.id} />
77
+ )}
78
78
  {canDelete && (
79
79
  <DeleteButton
80
80
  tokenName={apiToken.name}
@@ -94,6 +94,7 @@ const TableRows = ({ canDelete, canUpdate, onClickDelete, withBulkActions, rows
94
94
  TableRows.defaultProps = {
95
95
  canDelete: false,
96
96
  canUpdate: false,
97
+ canRead: false,
97
98
  onClickDelete() {},
98
99
  rows: [],
99
100
  withBulkActions: false,
@@ -102,6 +103,7 @@ TableRows.defaultProps = {
102
103
  TableRows.propTypes = {
103
104
  canDelete: PropTypes.bool,
104
105
  canUpdate: PropTypes.bool,
106
+ canRead: PropTypes.bool,
105
107
  onClickDelete: PropTypes.func,
106
108
  rows: PropTypes.array,
107
109
  withBulkActions: PropTypes.bool,
@@ -128,7 +128,7 @@ const ApiTokenListView = () => {
128
128
  <LinkButton
129
129
  data-testid="create-api-token-button"
130
130
  startIcon={<Plus />}
131
- size="L"
131
+ size="S"
132
132
  onClick={() => trackUsage('willAddTokenFromList')}
133
133
  to="/settings/api-tokens/create"
134
134
  >
@@ -147,15 +147,16 @@ const ApiTokenListView = () => {
147
147
  headers={headers}
148
148
  contentType="api-tokens"
149
149
  rows={apiTokens}
150
- withBulkActions={canDelete || canUpdate}
150
+ withBulkActions={canDelete || canUpdate || canRead}
151
151
  isLoading={isLoading}
152
152
  onConfirmDelete={(id) => deleteMutation.mutateAsync(id)}
153
153
  >
154
154
  <TableRows
155
+ canRead={canRead}
155
156
  canDelete={canDelete}
156
157
  canUpdate={canUpdate}
157
158
  rows={apiTokens}
158
- withBulkActions={canDelete || canUpdate}
159
+ withBulkActions={canDelete || canUpdate || canRead}
159
160
  />
160
161
  </DynamicTable>
161
162
  )}
@@ -22,23 +22,23 @@ const tableHeaders = [
22
22
  },
23
23
  },
24
24
  {
25
- name: 'type',
26
- key: 'type',
25
+ name: 'createdAt',
26
+ key: 'createdAt',
27
27
  metadatas: {
28
28
  label: {
29
- id: 'Settings.apiTokens.ListView.headers.type',
30
- defaultMessage: 'Token type',
29
+ id: 'Settings.apiTokens.ListView.headers.createdAt',
30
+ defaultMessage: 'Created at',
31
31
  },
32
32
  sortable: false,
33
33
  },
34
34
  },
35
35
  {
36
- name: 'createdAt',
37
- key: 'createdAt',
36
+ name: 'lastUsedAt',
37
+ key: 'lastUsedAt',
38
38
  metadatas: {
39
39
  label: {
40
- id: 'Settings.apiTokens.ListView.headers.createdAt',
41
- defaultMessage: 'Created at',
40
+ id: 'Settings.apiTokens.ListView.headers.lastUsedAt',
41
+ defaultMessage: 'Last used',
42
42
  },
43
43
  sortable: false,
44
44
  },
@@ -5,7 +5,7 @@ import EditView from '../EditView';
5
5
 
6
6
  const ProtectedApiTokenCreateView = () => {
7
7
  return (
8
- <CheckPagePermissions permissions={adminPermissions.settings['api-tokens'].update}>
8
+ <CheckPagePermissions permissions={adminPermissions.settings['api-tokens'].read}>
9
9
  <EditView />
10
10
  </CheckPagePermissions>
11
11
  );
@@ -102,7 +102,7 @@ const RoleListPage = () => {
102
102
  <SettingsPageTitle name="Roles" />
103
103
  <HeaderLayout
104
104
  primaryAction={
105
- <Button onClick={handleToggleModalForCreatingRole} startIcon={<Plus />} size="L">
105
+ <Button onClick={handleToggleModalForCreatingRole} startIcon={<Plus />} size="S">
106
106
  {formatMessage({
107
107
  id: 'Settings.roles.list.button.add',
108
108
  defaultMessage: 'Add new role',
@@ -105,7 +105,7 @@ const ListPage = () => {
105
105
  data-testid="create-user-button"
106
106
  onClick={handleToggle}
107
107
  startIcon={<Envelop />}
108
- size="L"
108
+ size="S"
109
109
  >
110
110
  {formatMessage({
111
111
  id: 'Settings.permissions.users.create',
@@ -29,16 +29,16 @@ const StyledTable = styled.table`
29
29
  const displayedData = {
30
30
  headers: {
31
31
  default: [
32
- 'Settings.webhooks.events.create',
33
- 'Settings.webhooks.events.update',
34
- 'app.utils.delete',
32
+ { id: 'Settings.webhooks.events.create', defaultMessage: 'Create' },
33
+ { id: 'Settings.webhooks.events.update', defaultMessage: 'Update' },
34
+ { id: 'app.utils.delete', defaultMessage: 'Delete' },
35
35
  ],
36
36
  draftAndPublish: [
37
- 'Settings.webhooks.events.create',
38
- 'Settings.webhooks.events.update',
39
- 'app.utils.delete',
40
- 'app.utils.publish',
41
- 'app.utils.unpublish',
37
+ { id: 'Settings.webhooks.events.create', defaultMessage: 'Create' },
38
+ { id: 'Settings.webhooks.events.update', defaultMessage: 'Update' },
39
+ { id: 'app.utils.delete', defaultMessage: 'Delete' },
40
+ { id: 'app.utils.publish', defaultMessage: 'Publish' },
41
+ { id: 'app.utils.unpublish', defaultMessage: 'Unpublish' },
42
42
  ],
43
43
  },
44
44
  events: {
@@ -122,7 +122,7 @@ const EventInput = ({ isDraftAndPublish }) => {
122
122
  })}
123
123
  >
124
124
  <Typography variant="sigma" textColor="neutral600">
125
- {formatMessage({ id: header, defaultMessage: header })}
125
+ {formatMessage(header)}
126
126
  </Typography>
127
127
  </td>
128
128
  );
@@ -131,7 +131,7 @@ const EventInput = ({ isDraftAndPublish }) => {
131
131
  return (
132
132
  <td key={header}>
133
133
  <Typography variant="sigma" textColor="neutral600">
134
- {formatMessage({ id: header, defaultMessage: header })}
134
+ {formatMessage(header)}
135
135
  </Typography>
136
136
  </td>
137
137
  );
@@ -252,7 +252,7 @@ const ListView = () => {
252
252
  primaryAction={
253
253
  canCreate &&
254
254
  !loadingWebhooks && (
255
- <LinkButton startIcon={<Plus />} variant="default" to={`${pathname}/create`} size="L">
255
+ <LinkButton startIcon={<Plus />} variant="default" to={`${pathname}/create`} size="S">
256
256
  {formatMessage({
257
257
  id: 'Settings.webhooks.list.button.add',
258
258
  defaultMessage: 'Create new webhook',
@@ -76,16 +76,12 @@ const permissions = {
76
76
  update: [{ action: 'admin::webhooks.update', subject: null }],
77
77
  },
78
78
  'api-tokens': {
79
- main: [
80
- { action: 'admin::api-tokens.create', subject: null },
81
- { action: 'admin::api-tokens.read', subject: null },
82
- { action: 'admin::api-tokens.update', subject: null },
83
- { action: 'admin::api-tokens.delete', subject: null },
84
- ],
79
+ main: [{ action: 'admin::api-tokens.access', subject: null }],
85
80
  create: [{ action: 'admin::api-tokens.create', subject: null }],
86
81
  delete: [{ action: 'admin::api-tokens.delete', subject: null }],
87
82
  read: [{ action: 'admin::api-tokens.read', subject: null }],
88
83
  update: [{ action: 'admin::api-tokens.update', subject: null }],
84
+ regenerate: [{ action: 'admin::api-tokens.regenerate', subject: null }],
89
85
  },
90
86
  },
91
87
  };
@@ -91,10 +91,24 @@
91
91
  "Settings.apiTokens.ListView.headers.description": "Description",
92
92
  "Settings.apiTokens.ListView.headers.type": "Token type",
93
93
  "Settings.apiTokens.ListView.headers.createdAt": "Created at",
94
+ "Settings.apiTokens.ListView.headers.lastUsedAt": "Last used",
94
95
  "Settings.apiTokens.notification.copied": "Token copied to clipboard.",
95
96
  "Settings.apiTokens.title": "API Tokens",
96
97
  "Settings.apiTokens.types.full-access": "Full access",
97
98
  "Settings.apiTokens.types.read-only": "Read-only",
99
+ "Settings.apiTokens.duration.7-days": "7 days",
100
+ "Settings.apiTokens.duration.30-days": "30 days",
101
+ "Settings.apiTokens.duration.90-days": "90 days",
102
+ "Settings.apiTokens.duration.unlimited": "Unlimited",
103
+ "Settings.apiTokens.form.duration":"Token duration",
104
+ "Settings.apiTokens.form.type":"Token type",
105
+ "Settings.apiTokens.duration.expiration-date":"Expiration date",
106
+ "Settings.apiTokens.createPage.permissions.title":"Permissions",
107
+ "Settings.apiTokens.createPage.permissions.description":"Only actions bound by a route are listed below.",
108
+ "Settings.apiTokens.RegenerateDialog.title": "Regenerate token",
109
+ "Settings.apiTokens.popUpWarning.message": "Are you sure you want to regenerate this token?",
110
+ "Settings.apiTokens.Button.cancel": "Cancel",
111
+ "Settings.apiTokens.Button.regenerate": "Regenerate",
98
112
  "Settings.application.description": "Administration panel’s global information",
99
113
  "Settings.application.edition-title": "current plan",
100
114
  "Settings.application.get-help": "Get help",
@@ -416,6 +430,7 @@
416
430
  "app.utils.defaultMessage": " ",
417
431
  "app.utils.duplicate": "Duplicate",
418
432
  "app.utils.edit": "Edit",
433
+ "app.utils.delete": "Delete",
419
434
  "app.utils.errors.file-too-big.message": "The file is too big",
420
435
  "app.utils.filter-value": "Filter value",
421
436
  "app.utils.filters": "Filters",
@@ -757,6 +772,9 @@
757
772
  "notification.success.delete": "The item has been deleted",
758
773
  "notification.success.saved": "Saved",
759
774
  "notification.success.title": "Success:",
775
+ "notification.success.tokencreated": "API Token successfully created",
776
+ "notification.success.tokenedited": "API Token successfully edited",
777
+ "notification.error.tokennamenotunique": "Name already assigned to another token",
760
778
  "notification.version.update.message": "A new version of Strapi is available!",
761
779
  "notification.warning.title": "Warning:",
762
780
  "notification.warning.404": "404 - Not found",
@@ -759,7 +759,7 @@
759
759
  "global.table.header.roles": "Roles",
760
760
  "global.table.header.username": "Nombre de usuario",
761
761
  "global.type": "Tipo",
762
- "global.users": "Useuarios",
762
+ "global.users": "Usuarios",
763
763
  "notification.warning.404": "404 - No Encontrado"
764
764
 
765
765
  }
@@ -314,6 +314,7 @@
314
314
  "app.utils.defaultMessage": " ",
315
315
  "app.utils.duplicate": "Dupliquer",
316
316
  "app.utils.edit": "Modifier",
317
+ "app.utils.delete": "Supprimer",
317
318
  "app.utils.errors.file-too-big.message": "Le fichier est trop lourd",
318
319
  "app.utils.filter-value": "Valeur du filtre",
319
320
  "app.utils.filters": "Filtres",
@@ -587,6 +588,38 @@
587
588
  "content-manager.success.record.save": "Sauvegardé",
588
589
  "content-manager.success.record.unpublish": "Publication annulée",
589
590
  "content-manager.utils.data-loaded": "{number, plural, =1 {L'entrée a été chargée} other {Les entrées on été chargées} avec succès",
591
+ "content-manager.apiError.This attribute must be unique": "Le champ {field} doit être unique",
592
+ "form.button.continue": "Continuer",
593
+ "global.search": "Rechercher",
594
+ "global.actions": "Actions",
595
+ "global.back": "Retour",
596
+ "global.cancel": "Annuler",
597
+ "global.change-password": "Modifier le mot de passe",
598
+ "global.content-manager": "Gestion du contenu",
599
+ "global.continue": "Continuer",
600
+ "global.delete": "Supprimer",
601
+ "global.delete-target": "Supprimer {target}",
602
+ "global.description": "Description",
603
+ "global.details": "Détails",
604
+ "global.disabled": "Désactivé",
605
+ "global.documentation": "Documentation",
606
+ "global.enabled": "Activé",
607
+ "global.finish": "Terminer",
608
+ "global.marketplace": "Marketplace",
609
+ "global.name": "Nom",
610
+ "global.none": "Aucun",
611
+ "global.password": "Mot de passe",
612
+ "global.plugins": "Plugins",
613
+ "global.profile": "Profil",
614
+ "global.reset-password": "Réinitialiser le mot de passe",
615
+ "global.roles": "Rôles",
616
+ "global.save": "Enregistrer",
617
+ "global.see-more": "Voir plus",
618
+ "global.select": "Sélectionner",
619
+ "global.select-all-entries": "Sélectionner toutes les entrées",
620
+ "global.settings": "Paramètres",
621
+ "global.type": "Type",
622
+ "global.users": "Utilisateurs",
590
623
  "form.button.done": "Terminer",
591
624
  "global.prompt.unsaved": "Êtes-vous sûr de vouloir quitter cette page? Toutes vos modifications seront perdues",
592
625
  "notification.contentType.relations.conflict": "Le Type de Contenu à des relations qui rentrent en conflit",