@strapi/admin 4.14.4 → 4.14.6
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.
- package/admin/.eslintrc.js +12 -0
- package/admin/custom.d.ts +20 -0
- package/admin/src/StrapiApp.js +14 -16
- package/admin/src/components/AuthenticatedApp/index.js +4 -4
- package/admin/src/components/ConfigurationProvider.tsx +67 -0
- package/admin/src/components/LanguageProvider.tsx +129 -0
- package/admin/src/components/{LeftMenu/index.js → LeftMenu.tsx} +23 -18
- package/admin/src/components/{NpsSurvey/index.js → NpsSurvey.tsx} +68 -21
- package/admin/src/components/PluginsInitializer.tsx +124 -0
- package/admin/src/components/Providers/index.js +6 -6
- package/admin/src/components/UnauthenticatedLogo.tsx +2 -2
- package/admin/src/components/{LocalesProvider/__mocks__/useLocalesProvider.js → __mocks__/LanguageProvider.js} +1 -1
- package/admin/src/content-manager/components/BlocksEditor/BlocksInput/index.js +48 -8
- package/admin/src/content-manager/components/BlocksEditor/Toolbar/index.js +146 -68
- package/admin/src/content-manager/components/BlocksEditor/hooks/useBlocksStore.js +50 -47
- package/admin/src/content-manager/components/BlocksEditor/hooks/useModifiersStore.js +11 -9
- package/admin/src/content-manager/components/BlocksEditor/index.js +1 -14
- package/admin/src/contexts/admin.ts +18 -0
- package/admin/src/contexts/configuration.ts +14 -4
- package/admin/src/hooks/__mocks__/useConfigurations.ts +2 -2
- package/admin/src/hooks/index.js +0 -3
- package/admin/src/hooks/{useAdminRoles/index.js → useAdminRoles.ts} +26 -10
- package/admin/src/hooks/useAdminUsers.ts +64 -0
- package/admin/src/hooks/useConfiguration.ts +5 -0
- package/admin/src/hooks/{useEnterprise/useEnterprise.js → useEnterprise.ts} +15 -5
- package/admin/src/hooks/useMenu.ts +153 -0
- package/admin/src/index.js +5 -2
- package/admin/src/layouts/UnauthenticatedLayout/LocaleToggle/index.js +2 -2
- package/admin/src/pages/Admin/index.js +4 -3
- package/admin/src/pages/App/index.js +5 -3
- package/admin/src/pages/AuthPage/components/Register/index.js +28 -33
- package/admin/src/pages/AuthPage/index.js +2 -2
- package/admin/src/pages/ProfilePage/index.js +2 -2
- package/admin/src/pages/SettingsPage/components/Tokens/Table/index.js +119 -87
- package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/components/CustomizationInfos/index.js +2 -2
- package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/index.js +2 -2
- package/admin/src/pages/SettingsPage/pages/Roles/CreatePage/index.js +1 -1
- package/admin/src/pages/SettingsPage/pages/Roles/EditPage/components/ConditionsModal/index.js +1 -1
- package/admin/src/pages/SettingsPage/pages/Roles/EditPage/components/ContentTypeCollapse/Collapse/index.js +1 -1
- package/admin/src/pages/SettingsPage/pages/Roles/EditPage/components/ContentTypeCollapse/CollapsePropertyMatrix/ActionRow/index.js +1 -1
- package/admin/src/pages/SettingsPage/pages/Roles/EditPage/components/ContentTypeCollapse/CollapsePropertyMatrix/SubActionRow/index.js +1 -1
- package/admin/src/pages/SettingsPage/pages/Roles/EditPage/components/GlobalActions/index.js +1 -1
- package/admin/src/pages/SettingsPage/pages/Roles/EditPage/components/PermissionsDataManagerProvider/index.js +1 -1
- package/admin/src/pages/SettingsPage/pages/Roles/EditPage/components/PluginsAndSettings/SubCategory/index.js +1 -1
- package/admin/src/pages/SettingsPage/pages/Roles/EditPage/hooks/usePermissionsDataManager.ts +28 -0
- package/admin/src/pages/SettingsPage/pages/Roles/EditPage/index.js +1 -1
- package/admin/src/{hooks/useAdminRolePermissions/index.js → pages/SettingsPage/pages/Roles/hooks/useAdminRolePermissions.ts} +13 -6
- package/admin/src/pages/SettingsPage/pages/TransferTokens/ListView/index.js +3 -5
- package/admin/src/shared/hooks/index.js +0 -1
- package/admin/src/shared/hooks/useInjectionZone/index.js +2 -2
- package/admin/src/types/adminAPI.ts +29 -0
- package/admin/src/utils/createRoute.js +4 -1
- package/admin/tsconfig.build.json +4 -0
- package/admin/tsconfig.json +7 -1
- package/build/{1049.f7aed23d.chunk.js → 1049.9236e785.chunk.js} +1 -1
- package/build/1222.fe92c653.chunk.js +35 -0
- package/build/{1227.f9c74718.chunk.js → 1227.e0f7447b.chunk.js} +1 -1
- package/build/135.ad267b59.chunk.js +1 -0
- package/build/{1386.6b8819c6.chunk.js → 1386.07f2bbb3.chunk.js} +1 -1
- package/build/1835.eaa696ba.chunk.js +1 -0
- package/build/{2225.d1bcf7e3.chunk.js → 2225.a2147b8f.chunk.js} +2 -2
- package/build/2325.d705b39a.chunk.js +1 -0
- package/build/2379.b0bc4013.chunk.js +1 -0
- package/build/{2395.aca6ce66.chunk.js → 2395.d37b1025.chunk.js} +1 -1
- package/build/2421.79e5b3d0.chunk.js +1 -0
- package/build/267.073a3bcb.chunk.js +1 -0
- package/build/2801.12522720.chunk.js +1 -0
- package/build/2878.145ebf7c.chunk.js +1 -0
- package/build/2950.216f2e89.chunk.js +1 -0
- package/build/2953.284a63c0.chunk.js +1 -0
- package/build/{8743.31c921b1.chunk.js → 3019.0d74d080.chunk.js} +123 -139
- package/build/3021.33ad47fb.chunk.js +103 -0
- package/build/{3483.5df8e010.chunk.js → 3483.8f1b25f8.chunk.js} +1 -1
- package/build/3911.488fbde3.chunk.js +95 -0
- package/build/{4174.df9aa09a.chunk.js → 4174.2c4f958e.chunk.js} +1 -1
- package/build/4429.7f044dc7.chunk.js +1 -0
- package/build/4555.c883d697.chunk.js +1 -0
- package/build/4663.b906cc10.chunk.js +1 -0
- package/build/4916.480053a6.chunk.js +1 -0
- package/build/4996.d285c30b.chunk.js +1 -0
- package/build/502.b845473a.chunk.js +1 -0
- package/build/5858.493b31ec.chunk.js +1 -0
- package/build/6345.334e7678.chunk.js +1 -0
- package/build/6373.1a21d665.chunk.js +105 -0
- package/build/6453.4160b5b7.chunk.js +1 -0
- package/build/7448.6fd14dd3.chunk.js +1 -0
- package/build/7464.91341b4f.chunk.js +1 -0
- package/build/7735.9e7c9fdd.chunk.js +10 -0
- package/build/782.7243b183.chunk.js +1 -0
- package/build/7849.2a500ed8.chunk.js +1 -0
- package/build/7897.dffa5ad5.chunk.js +6 -0
- package/build/8162.7d1100a0.chunk.js +1 -0
- package/build/{8276.d4426fd8.chunk.js → 8276.e9698944.chunk.js} +2 -2
- package/build/8894.5ca4852a.chunk.js +26 -0
- package/build/8980.f0045cc1.chunk.js +1 -0
- package/build/9153.42c1428a.chunk.js +1 -0
- package/build/{9218.8bc01ab9.chunk.js → 9218.306ad178.chunk.js} +1 -1
- package/build/9285.5f174057.chunk.js +1 -0
- package/build/9302.550cf5b7.chunk.js +146 -0
- package/build/9547.62987774.chunk.js +1 -0
- package/build/9754.b4e73779.chunk.js +1 -0
- package/build/Admin-authenticatedApp.e0bf203f.chunk.js +79 -0
- package/build/{Admin_InternalErrorPage.b66ee9c1.chunk.js → Admin_InternalErrorPage.e2431a95.chunk.js} +1 -1
- package/build/Admin_homePage.71ef8d06.chunk.js +81 -0
- package/build/{Admin_marketplace.31b962b8.chunk.js → Admin_marketplace.0db78604.chunk.js} +1 -1
- package/build/{Admin_pluginsPage.9217101d.chunk.js → Admin_pluginsPage.1083f7f0.chunk.js} +1 -1
- package/build/{Admin_profilePage.680123d9.chunk.js → Admin_profilePage.61704b7d.chunk.js} +2 -2
- package/build/Admin_settingsPage.39cb9fca.chunk.js +111 -0
- package/build/{Upload_ConfigureTheView.b40eea4d.chunk.js → Upload_ConfigureTheView.3cfeb108.chunk.js} +1 -1
- package/build/admin-app.06f5e70a.chunk.js +69 -0
- package/build/admin-edit-roles-page.556fac52.chunk.js +267 -0
- package/build/admin-edit-users.64fd1318.chunk.js +10 -0
- package/build/admin-roles-list.15918328.chunk.js +22 -0
- package/build/admin-users.74fddc87.chunk.js +11 -0
- package/build/{api-tokens-create-page.0dd63e91.chunk.js → api-tokens-create-page.c08ae118.chunk.js} +1 -1
- package/build/{api-tokens-edit-page.78d877f8.chunk.js → api-tokens-edit-page.ce18efdc.chunk.js} +1 -1
- package/build/api-tokens-list-page.783b7569.chunk.js +16 -0
- package/build/audit-logs-settings-page.12aeea8c.chunk.js +1 -0
- package/build/content-manager.2e3f660b.chunk.js +1220 -0
- package/build/{content-type-builder-list-view.3fffae65.chunk.js → content-type-builder-list-view.38ed3935.chunk.js} +7 -7
- package/build/{content-type-builder.98c71164.chunk.js → content-type-builder.758a9d23.chunk.js} +4 -4
- package/build/email-settings-page.e08a587e.chunk.js +11 -0
- package/build/{i18n-settings-page.a9708926.chunk.js → i18n-settings-page.3186e3e9.chunk.js} +1 -1
- package/build/index.html +1 -1
- package/build/main.00ea6f5a.js +2665 -0
- package/build/{review-workflows-settings-create-view.b7b0c6c5.chunk.js → review-workflows-settings-create-view.5cdc4d64.chunk.js} +1 -1
- package/build/{review-workflows-settings-edit-view.c331b3fe.chunk.js → review-workflows-settings-edit-view.53bf7865.chunk.js} +1 -1
- package/build/review-workflows-settings-list-view.b4a8aefb.chunk.js +56 -0
- package/build/runtime~main.be0e0649.js +2 -0
- package/build/sso-settings-page.6a35d473.chunk.js +1 -0
- package/build/{transfer-tokens-create-page.e7f541d3.chunk.js → transfer-tokens-create-page.2662d519.chunk.js} +1 -1
- package/build/{transfer-tokens-edit-page.bd1276c2.chunk.js → transfer-tokens-edit-page.f64d8d8c.chunk.js} +1 -1
- package/build/transfer-tokens-list-page.e6fd5f87.chunk.js +16 -0
- package/build/{upload-settings.97ef4c92.chunk.js → upload-settings.450a1de0.chunk.js} +1 -1
- package/build/{upload.f08715a1.chunk.js → upload.0d53e7a3.chunk.js} +1 -1
- package/build/{users-advanced-settings-page.36a3c363.chunk.js → users-advanced-settings-page.4a1f1f6d.chunk.js} +1 -1
- package/build/users-email-settings-page.ea81fe82.chunk.js +9 -0
- package/build/users-providers-settings-page.10280cdb.chunk.js +14 -0
- package/build/{users-roles-settings-page.d5a8e8a1.chunk.js → users-roles-settings-page.4a7158be.chunk.js} +1 -1
- package/build/{webhook-edit-page.87456194.chunk.js → webhook-edit-page.65ac30ee.chunk.js} +2 -2
- package/build/{webhook-list-page.c88a382b.chunk.js → webhook-list-page.f57285ca.chunk.js} +1 -1
- package/jest.config.front.js +4 -0
- package/package.json +23 -17
- package/scripts/build.js +1 -1
- package/server/controllers/admin.js +3 -2
- package/shared/entities.ts +33 -0
- package/shared/permissions.ts +52 -0
- package/admin/src/components/ConfigurationsProvider/index.js +0 -66
- package/admin/src/components/ConfigurationsProvider/reducer.js +0 -29
- package/admin/src/components/LanguageProvider/index.js +0 -54
- package/admin/src/components/LanguageProvider/init.js +0 -13
- package/admin/src/components/LanguageProvider/reducer.js +0 -30
- package/admin/src/components/LanguageProvider/utils/localStorageKey.js +0 -3
- package/admin/src/components/LocalesProvider/context.js +0 -5
- package/admin/src/components/LocalesProvider/index.js +0 -21
- package/admin/src/components/LocalesProvider/useLocalesProvider.js +0 -11
- package/admin/src/components/NpsSurvey/hooks/useNpsSurveySettings.js +0 -17
- package/admin/src/components/PluginsInitializer/index.js +0 -68
- package/admin/src/components/PluginsInitializer/init.js +0 -11
- package/admin/src/components/PluginsInitializer/reducer.js +0 -22
- package/admin/src/contexts/Admin/index.js +0 -5
- package/admin/src/contexts/MarketPlace/index.js +0 -18
- package/admin/src/contexts/PermisssionsDataManagerContext/index.js +0 -5
- package/admin/src/contexts/index.js +0 -3
- package/admin/src/hooks/useAdminRoles/__mocks__/index.js +0 -5
- package/admin/src/hooks/useAdminUsers/index.js +0 -1
- package/admin/src/hooks/useAdminUsers/useAdminUsers.js +0 -47
- package/admin/src/hooks/useConfigurations.ts +0 -5
- package/admin/src/hooks/useEnterprise/index.js +0 -1
- package/admin/src/hooks/useMenu/index.js +0 -86
- package/admin/src/hooks/useMenu/utils/checkPermissions.js +0 -13
- package/admin/src/hooks/useMenu/utils/getGeneralLinks.js +0 -31
- package/admin/src/hooks/useMenu/utils/getPluginSectionLinks.js +0 -17
- package/admin/src/hooks/usePermissionsDataManager/index.js +0 -7
- package/admin/src/shared/hooks/useAdminProvider/index.js +0 -11
- package/build/2224.8af54440.chunk.js +0 -138
- package/build/2379.f0baf826.chunk.js +0 -1
- package/build/2421.a478ba24.chunk.js +0 -105
- package/build/2801.c49f88a1.chunk.js +0 -1
- package/build/3911.d4fada48.chunk.js +0 -95
- package/build/412.72afdf0c.chunk.js +0 -689
- package/build/502.8666bbef.chunk.js +0 -25
- package/build/5702.5b433d50.chunk.js +0 -1
- package/build/6186.c33ce082.chunk.js +0 -116
- package/build/6715.48e37308.chunk.js +0 -1
- package/build/6812.00ef5b0d.chunk.js +0 -26
- package/build/7464.43a4527c.chunk.js +0 -1
- package/build/7818.d2196a53.chunk.js +0 -29
- package/build/7897.5c03247b.chunk.js +0 -25
- package/build/8690.33243bba.chunk.js +0 -38
- package/build/Admin-authenticatedApp.27545a1b.chunk.js +0 -112
- package/build/Admin_homePage.a6281dd6.chunk.js +0 -124
- package/build/Admin_settingsPage.33378310.chunk.js +0 -111
- package/build/admin-app.e8c52c37.chunk.js +0 -36
- package/build/admin-edit-roles-page.fcf056bf.chunk.js +0 -275
- package/build/admin-edit-users.89efe3c4.chunk.js +0 -10
- package/build/admin-roles-list.8b77704a.chunk.js +0 -22
- package/build/admin-users.e3f1be14.chunk.js +0 -19
- package/build/api-tokens-list-page.ae13346c.chunk.js +0 -16
- package/build/audit-logs-settings-page.e9c92a75.chunk.js +0 -9
- package/build/content-manager.5849dbe3.chunk.js +0 -1226
- package/build/email-settings-page.ecfec9b3.chunk.js +0 -11
- package/build/email-translation-ar-json.88304564.chunk.js +0 -1
- package/build/email-translation-cs-json.6eaeec6a.chunk.js +0 -1
- package/build/email-translation-de-json.1b334230.chunk.js +0 -1
- package/build/email-translation-dk-json.85402492.chunk.js +0 -1
- package/build/email-translation-en-json.4211d4d0.chunk.js +0 -1
- package/build/email-translation-es-json.0b6b1006.chunk.js +0 -1
- package/build/email-translation-fr-json.78be2787.chunk.js +0 -1
- package/build/email-translation-id-json.c97239fe.chunk.js +0 -1
- package/build/email-translation-it-json.a2ed8c78.chunk.js +0 -1
- package/build/email-translation-ja-json.63eebd02.chunk.js +0 -1
- package/build/email-translation-ko-json.4de49b23.chunk.js +0 -1
- package/build/email-translation-ms-json.7390477e.chunk.js +0 -1
- package/build/email-translation-nl-json.377bdd9f.chunk.js +0 -1
- package/build/email-translation-pl-json.97d0db97.chunk.js +0 -1
- package/build/email-translation-pt-BR-json.81cca553.chunk.js +0 -1
- package/build/email-translation-pt-json.2a2a0643.chunk.js +0 -1
- package/build/email-translation-ru-json.6bce37dd.chunk.js +0 -1
- package/build/email-translation-sk-json.53da2fcd.chunk.js +0 -1
- package/build/email-translation-th-json.660fa9a8.chunk.js +0 -1
- package/build/email-translation-tr-json.e6c0f8fc.chunk.js +0 -1
- package/build/email-translation-uk-json.bd1fb6bf.chunk.js +0 -1
- package/build/email-translation-vi-json.9fb7e6d7.chunk.js +0 -1
- package/build/email-translation-zh-Hans-json.c6841563.chunk.js +0 -1
- package/build/email-translation-zh-json.7a2232ea.chunk.js +0 -1
- package/build/main.3abb6f34.js +0 -3278
- package/build/review-workflows-settings-list-view.70218dc1.chunk.js +0 -75
- package/build/runtime~main.450561b1.js +0 -2
- package/build/sso-settings-page.1a9e7f8f.chunk.js +0 -1
- package/build/transfer-tokens-list-page.5de6bb9f.chunk.js +0 -16
- package/build/users-email-settings-page.47b47962.chunk.js +0 -149
- package/build/users-providers-settings-page.1e0c8376.chunk.js +0 -154
- /package/admin/src/hooks/{useAdminUsers/__mocks__/index.js → __mocks__/useAdminUsers.ts} +0 -0
- /package/admin/src/{hooks/useAdminRolePermissions/__mocks__/index.js → pages/SettingsPage/pages/Roles/hooks/__mocks__/useAdminRolePermissions.ts} +0 -0
|
@@ -37,6 +37,10 @@ import styled, { css } from 'styled-components';
|
|
|
37
37
|
import { composeRefs } from '../../../utils';
|
|
38
38
|
import { editLink, removeLink } from '../utils/links';
|
|
39
39
|
|
|
40
|
+
const StyledBaseLink = styled(BaseLink)`
|
|
41
|
+
text-decoration: none;
|
|
42
|
+
`;
|
|
43
|
+
|
|
40
44
|
const H1 = styled(Typography).attrs({ as: 'h1' })`
|
|
41
45
|
font-size: ${42 / 16}rem;
|
|
42
46
|
line-height: ${({ theme }) => theme.lineHeights[1]};
|
|
@@ -67,33 +71,6 @@ const H6 = styled(Typography).attrs({ as: 'h6' })`
|
|
|
67
71
|
line-height: ${({ theme }) => theme.lineHeights[1]};
|
|
68
72
|
`;
|
|
69
73
|
|
|
70
|
-
const Heading = ({ attributes, children, element }) => {
|
|
71
|
-
switch (element.level) {
|
|
72
|
-
case 1:
|
|
73
|
-
return <H1 {...attributes}>{children}</H1>;
|
|
74
|
-
case 2:
|
|
75
|
-
return <H2 {...attributes}>{children}</H2>;
|
|
76
|
-
case 3:
|
|
77
|
-
return <H3 {...attributes}>{children}</H3>;
|
|
78
|
-
case 4:
|
|
79
|
-
return <H4 {...attributes}>{children}</H4>;
|
|
80
|
-
case 5:
|
|
81
|
-
return <H5 {...attributes}>{children}</H5>;
|
|
82
|
-
case 6:
|
|
83
|
-
return <H6 {...attributes}>{children}</H6>;
|
|
84
|
-
default: // do nothing
|
|
85
|
-
return null;
|
|
86
|
-
}
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
Heading.propTypes = {
|
|
90
|
-
attributes: PropTypes.object.isRequired,
|
|
91
|
-
children: PropTypes.node.isRequired,
|
|
92
|
-
element: PropTypes.shape({
|
|
93
|
-
level: PropTypes.oneOf([1, 2, 3, 4, 5, 6]).isRequired,
|
|
94
|
-
}).isRequired,
|
|
95
|
-
};
|
|
96
|
-
|
|
97
74
|
const CodeBlock = styled.pre.attrs({ role: 'code' })`
|
|
98
75
|
border-radius: ${({ theme }) => theme.borderRadius};
|
|
99
76
|
background-color: ${({ theme }) => theme.colors.neutral100};
|
|
@@ -113,8 +90,9 @@ const CodeBlock = styled.pre.attrs({ role: 'code' })`
|
|
|
113
90
|
const Blockquote = styled.blockquote.attrs({ role: 'blockquote' })`
|
|
114
91
|
margin: ${({ theme }) => `${theme.spaces[4]} 0`};
|
|
115
92
|
font-weight: ${({ theme }) => theme.fontWeights.regular};
|
|
116
|
-
border-left: ${({ theme }) => `${theme.spaces[1]} solid ${theme.colors.
|
|
93
|
+
border-left: ${({ theme }) => `${theme.spaces[1]} solid ${theme.colors.neutral200}`};
|
|
117
94
|
padding: ${({ theme }) => theme.spaces[2]} ${({ theme }) => theme.spaces[5]};
|
|
95
|
+
color: ${({ theme }) => theme.colors.neutral600};
|
|
118
96
|
`;
|
|
119
97
|
|
|
120
98
|
const listStyle = css`
|
|
@@ -227,8 +205,18 @@ const handleEnterKeyOnList = (editor) => {
|
|
|
227
205
|
// Move the selection to the newly created paragraph
|
|
228
206
|
Transforms.select(editor, createdParagraphPath);
|
|
229
207
|
} else {
|
|
230
|
-
//
|
|
231
|
-
|
|
208
|
+
// Check if the cursor is at the end of the list item
|
|
209
|
+
const isNodeEnd = Editor.isEnd(editor, editor.selection.anchor, currentListItemPath);
|
|
210
|
+
|
|
211
|
+
if (isNodeEnd) {
|
|
212
|
+
// If there was nothing after the cursor, create a fresh new list item,
|
|
213
|
+
// in order to avoid carrying over the modifiers from the previous list item
|
|
214
|
+
Transforms.insertNodes(editor, { type: 'list-item', children: [{ type: 'text', text: '' }] });
|
|
215
|
+
} else {
|
|
216
|
+
// If there is something after the cursor, split the current list item,
|
|
217
|
+
// so that we keep the content and the modifiers
|
|
218
|
+
Transforms.splitNodes(editor);
|
|
219
|
+
}
|
|
232
220
|
}
|
|
233
221
|
};
|
|
234
222
|
|
|
@@ -320,7 +308,7 @@ const Link = React.forwardRef(({ element, children, ...attributes }, forwardedRe
|
|
|
320
308
|
|
|
321
309
|
return (
|
|
322
310
|
<>
|
|
323
|
-
<
|
|
311
|
+
<StyledBaseLink
|
|
324
312
|
{...attributes}
|
|
325
313
|
ref={composedRefs}
|
|
326
314
|
href={element.url}
|
|
@@ -328,7 +316,7 @@ const Link = React.forwardRef(({ element, children, ...attributes }, forwardedRe
|
|
|
328
316
|
color="primary600"
|
|
329
317
|
>
|
|
330
318
|
{children}
|
|
331
|
-
</
|
|
319
|
+
</StyledBaseLink>
|
|
332
320
|
{popoverOpen && (
|
|
333
321
|
<Popover source={linkRef} onDismiss={handleDismiss} padding={4} contentEditable={false}>
|
|
334
322
|
{isEditing ? (
|
|
@@ -382,9 +370,11 @@ const Link = React.forwardRef(({ element, children, ...attributes }, forwardedRe
|
|
|
382
370
|
) : (
|
|
383
371
|
<Flex direction="column" gap={4} alignItems="start" width="400px">
|
|
384
372
|
<Typography>{elementText}</Typography>
|
|
385
|
-
<
|
|
386
|
-
{element.url}
|
|
387
|
-
|
|
373
|
+
<Typography>
|
|
374
|
+
<StyledBaseLink href={element.url} target="_blank" color="primary600">
|
|
375
|
+
{element.url}
|
|
376
|
+
</StyledBaseLink>
|
|
377
|
+
</Typography>
|
|
388
378
|
<Flex justifyContent="end" width="100%" gap={2}>
|
|
389
379
|
<IconButton
|
|
390
380
|
icon={<Trash />}
|
|
@@ -461,13 +451,18 @@ export function useBlocksStore() {
|
|
|
461
451
|
* after the cursor, while retaining all the children, modifiers etc.
|
|
462
452
|
*/
|
|
463
453
|
Transforms.splitNodes(editor, {
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
* even if there's nothing to the right of the cursor in the node.
|
|
467
|
-
*/
|
|
454
|
+
// Makes sure we always create a new node,
|
|
455
|
+
// even if there's nothing to the right of the cursor in the node.
|
|
468
456
|
always: true,
|
|
469
457
|
});
|
|
470
458
|
|
|
459
|
+
// Check if the created node is empty (if there was no text after the cursor in the node)
|
|
460
|
+
// This lets us know if we need to carry over the modifiers from the previous node
|
|
461
|
+
const [, parentBlockPath] = Editor.above(editor, {
|
|
462
|
+
match: (n) => n.type !== 'text',
|
|
463
|
+
});
|
|
464
|
+
const isNodeEnd = Editor.isEnd(editor, editor.selection.anchor, parentBlockPath);
|
|
465
|
+
|
|
471
466
|
/**
|
|
472
467
|
* Delete and recreate the node that was created at the right of the cursor.
|
|
473
468
|
* This is to avoid node pollution
|
|
@@ -481,12 +476,14 @@ export function useBlocksStore() {
|
|
|
481
476
|
// Check if after the current position there is another node
|
|
482
477
|
const hasNextNode = editor.children.length - anchorPathInitialPosition[0] > 1;
|
|
483
478
|
|
|
484
|
-
// Insert the new node at the right position.
|
|
479
|
+
// Insert the new node at the right position.
|
|
480
|
+
// The next line after the editor selection if present or otherwise at the end of the editor.
|
|
485
481
|
Transforms.insertNodes(
|
|
486
482
|
editor,
|
|
487
483
|
{
|
|
488
484
|
type: 'paragraph',
|
|
489
|
-
|
|
485
|
+
// Don't carry over the modifiers from the previous node if there was no text after the cursor
|
|
486
|
+
children: isNodeEnd ? [{ type: 'text', text: '' }] : fragmentedNode.children,
|
|
490
487
|
},
|
|
491
488
|
{
|
|
492
489
|
at: hasNextNode ? [anchorPathInitialPosition[0] + 1] : [editor.children.length],
|
|
@@ -503,7 +500,7 @@ export function useBlocksStore() {
|
|
|
503
500
|
},
|
|
504
501
|
},
|
|
505
502
|
'heading-one': {
|
|
506
|
-
renderElement: (props) => <
|
|
503
|
+
renderElement: (props) => <H1 {...props.attributes}>{props.children}</H1>,
|
|
507
504
|
icon: HeadingOne,
|
|
508
505
|
label: {
|
|
509
506
|
id: 'components.Blocks.blocks.heading1',
|
|
@@ -517,7 +514,7 @@ export function useBlocksStore() {
|
|
|
517
514
|
isInBlocksSelector: true,
|
|
518
515
|
},
|
|
519
516
|
'heading-two': {
|
|
520
|
-
renderElement: (props) => <
|
|
517
|
+
renderElement: (props) => <H2 {...props.attributes}>{props.children}</H2>,
|
|
521
518
|
icon: HeadingTwo,
|
|
522
519
|
label: {
|
|
523
520
|
id: 'components.Blocks.blocks.heading2',
|
|
@@ -531,7 +528,7 @@ export function useBlocksStore() {
|
|
|
531
528
|
isInBlocksSelector: true,
|
|
532
529
|
},
|
|
533
530
|
'heading-three': {
|
|
534
|
-
renderElement: (props) => <
|
|
531
|
+
renderElement: (props) => <H3 {...props.attributes}>{props.children}</H3>,
|
|
535
532
|
icon: HeadingThree,
|
|
536
533
|
label: {
|
|
537
534
|
id: 'components.Blocks.blocks.heading3',
|
|
@@ -545,7 +542,7 @@ export function useBlocksStore() {
|
|
|
545
542
|
isInBlocksSelector: true,
|
|
546
543
|
},
|
|
547
544
|
'heading-four': {
|
|
548
|
-
renderElement: (props) => <
|
|
545
|
+
renderElement: (props) => <H4 {...props.attributes}>{props.children}</H4>,
|
|
549
546
|
icon: HeadingFour,
|
|
550
547
|
label: {
|
|
551
548
|
id: 'components.Blocks.blocks.heading4',
|
|
@@ -559,7 +556,7 @@ export function useBlocksStore() {
|
|
|
559
556
|
isInBlocksSelector: true,
|
|
560
557
|
},
|
|
561
558
|
'heading-five': {
|
|
562
|
-
renderElement: (props) => <
|
|
559
|
+
renderElement: (props) => <H5 {...props.attributes}>{props.children}</H5>,
|
|
563
560
|
icon: HeadingFive,
|
|
564
561
|
label: {
|
|
565
562
|
id: 'components.Blocks.blocks.heading5',
|
|
@@ -573,7 +570,7 @@ export function useBlocksStore() {
|
|
|
573
570
|
isInBlocksSelector: true,
|
|
574
571
|
},
|
|
575
572
|
'heading-six': {
|
|
576
|
-
renderElement: (props) => <
|
|
573
|
+
renderElement: (props) => <H6 {...props.attributes}>{props.children}</H6>,
|
|
577
574
|
icon: HeadingSix,
|
|
578
575
|
label: {
|
|
579
576
|
id: 'components.Blocks.blocks.heading6',
|
|
@@ -690,6 +687,12 @@ export function useBlocksStore() {
|
|
|
690
687
|
} else {
|
|
691
688
|
// Otherwise insert a new line within the quote node
|
|
692
689
|
Transforms.insertText(editor, '\n');
|
|
690
|
+
|
|
691
|
+
// If there's nothing after the cursor, disable modifiers
|
|
692
|
+
if (isNodeEnd) {
|
|
693
|
+
Editor.removeMark(editor, 'bold');
|
|
694
|
+
Editor.removeMark(editor, 'italic');
|
|
695
|
+
}
|
|
693
696
|
}
|
|
694
697
|
},
|
|
695
698
|
},
|
|
@@ -4,27 +4,29 @@ import { Typography } from '@strapi/design-system';
|
|
|
4
4
|
import { Bold, Italic, Underline, StrikeThrough, Code } from '@strapi/icons';
|
|
5
5
|
import { Editor } from 'slate';
|
|
6
6
|
import { useSlate } from 'slate-react';
|
|
7
|
-
import styled from 'styled-components';
|
|
7
|
+
import styled, { css } from 'styled-components';
|
|
8
8
|
|
|
9
|
-
const
|
|
9
|
+
const stylesToInherit = css`
|
|
10
10
|
font-size: inherit;
|
|
11
11
|
color: inherit;
|
|
12
|
+
line-height: inherit;
|
|
13
|
+
`;
|
|
14
|
+
|
|
15
|
+
const BoldText = styled(Typography).attrs({ fontWeight: 'bold' })`
|
|
16
|
+
${stylesToInherit}
|
|
12
17
|
`;
|
|
13
18
|
|
|
14
19
|
const ItalicText = styled(Typography)`
|
|
15
20
|
font-style: italic;
|
|
16
|
-
|
|
17
|
-
color: inherit;
|
|
21
|
+
${stylesToInherit}
|
|
18
22
|
`;
|
|
19
23
|
|
|
20
24
|
const UnderlineText = styled(Typography).attrs({ textDecoration: 'underline' })`
|
|
21
|
-
|
|
22
|
-
color: inherit;
|
|
25
|
+
${stylesToInherit}
|
|
23
26
|
`;
|
|
24
27
|
|
|
25
28
|
const StrikeThroughText = styled(Typography).attrs({ textDecoration: 'line-through' })`
|
|
26
|
-
|
|
27
|
-
color: inherit;
|
|
29
|
+
${stylesToInherit}
|
|
28
30
|
`;
|
|
29
31
|
|
|
30
32
|
const InlineCode = styled.code`
|
|
@@ -70,7 +72,7 @@ export function useModifiersStore() {
|
|
|
70
72
|
* @param {string} name - The name of the modifier to toggle
|
|
71
73
|
*/
|
|
72
74
|
const baseHandleToggle = (name) => {
|
|
73
|
-
if (modifiers[name]) {
|
|
75
|
+
if (modifiers?.[name]) {
|
|
74
76
|
Editor.removeMark(editor, name);
|
|
75
77
|
} else {
|
|
76
78
|
Editor.addMark(editor, name, true);
|
|
@@ -28,17 +28,6 @@ const EditorDivider = styled(Divider)`
|
|
|
28
28
|
background: ${({ theme }) => theme.colors.neutral200};
|
|
29
29
|
`;
|
|
30
30
|
|
|
31
|
-
const Wrapper = styled(Box)`
|
|
32
|
-
width: 100%;
|
|
33
|
-
overflow: auto;
|
|
34
|
-
padding: ${({ theme }) => `${theme.spaces[3]} ${theme.spaces[4]}`};
|
|
35
|
-
font-size: ${({ theme }) => theme.fontSizes[2]};
|
|
36
|
-
background-color: ${({ theme }) => theme.colors.neutral0};
|
|
37
|
-
color: ${({ theme }) => theme.colors.neutral800};
|
|
38
|
-
line-height: ${({ theme }) => theme.lineHeights[6]};
|
|
39
|
-
border-radius: ${({ theme }) => theme.borderRadius};
|
|
40
|
-
`;
|
|
41
|
-
|
|
42
31
|
/**
|
|
43
32
|
* Images are void elements. They handle the rendering of their children instead of Slate.
|
|
44
33
|
* See the Slate documentation for more information:
|
|
@@ -164,9 +153,7 @@ const BlocksEditor = React.forwardRef(
|
|
|
164
153
|
<InputWrapper direction="column" alignItems="flex-start" height="512px">
|
|
165
154
|
<BlocksToolbar disabled={disabled} />
|
|
166
155
|
<EditorDivider width="100%" />
|
|
167
|
-
<
|
|
168
|
-
<BlocksInput disabled={disabled} placeholder={formattedPlaceholder} />
|
|
169
|
-
</Wrapper>
|
|
156
|
+
<BlocksInput disabled={disabled} placeholder={formattedPlaceholder} />
|
|
170
157
|
</InputWrapper>
|
|
171
158
|
</Slate>
|
|
172
159
|
<Hint hint={hint} name={name} error={error} />
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
interface AdminContextValue {
|
|
4
|
+
/**
|
|
5
|
+
* TODO: this should come from `StrapiApp['getAdminInjectedComponents']`
|
|
6
|
+
*/
|
|
7
|
+
getAdminInjectedComponents: () => unknown;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const AdminContext = React.createContext<AdminContextValue>({
|
|
11
|
+
getAdminInjectedComponents() {
|
|
12
|
+
throw new Error('AdminContext: getAdminInjectedComponents() not implemented');
|
|
13
|
+
},
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
const useAdmin = () => React.useContext(AdminContext);
|
|
17
|
+
|
|
18
|
+
export { AdminContext, useAdmin };
|
|
@@ -1,15 +1,25 @@
|
|
|
1
1
|
import { createContext } from 'react';
|
|
2
2
|
|
|
3
|
-
interface
|
|
3
|
+
export interface ConfigurationContextValue {
|
|
4
4
|
logos: {
|
|
5
|
-
auth: { custom?: string; default: string };
|
|
5
|
+
auth: { custom?: string | null; default: string };
|
|
6
|
+
menu: { custom?: string | null; default: string };
|
|
6
7
|
};
|
|
8
|
+
showTutorials: boolean;
|
|
9
|
+
showReleaseNotification: boolean;
|
|
10
|
+
updateProjectSettings: (settings: { authLogo?: string; menuLogo?: string }) => void;
|
|
7
11
|
}
|
|
8
12
|
|
|
9
|
-
const
|
|
13
|
+
const ConfigurationContext = createContext<ConfigurationContextValue>({
|
|
10
14
|
logos: {
|
|
11
15
|
auth: { default: '' },
|
|
16
|
+
menu: { default: '' },
|
|
17
|
+
},
|
|
18
|
+
showTutorials: false,
|
|
19
|
+
showReleaseNotification: false,
|
|
20
|
+
updateProjectSettings: () => {
|
|
21
|
+
throw new Error('updateProjectSettings was not implemented');
|
|
12
22
|
},
|
|
13
23
|
});
|
|
14
24
|
|
|
15
|
-
export {
|
|
25
|
+
export { ConfigurationContext };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const
|
|
1
|
+
const useConfiguration = () => {
|
|
2
2
|
return {
|
|
3
3
|
logos: {
|
|
4
4
|
auth: { custom: 'customAuthLogo.png', default: 'defaultAuthLogo.png' },
|
|
@@ -6,4 +6,4 @@ const useConfigurations = () => {
|
|
|
6
6
|
};
|
|
7
7
|
};
|
|
8
8
|
|
|
9
|
-
export {
|
|
9
|
+
export { useConfiguration };
|
package/admin/src/hooks/index.js
CHANGED
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
export { useConfigurations } from './useConfigurations';
|
|
2
1
|
export { useContentTypes } from './useContentTypes';
|
|
3
|
-
export { default as useMenu } from './useMenu';
|
|
4
|
-
export { default as usePermissionsDataManager } from './usePermissionsDataManager';
|
|
5
2
|
export { default as useSettingsForm } from './useSettingsForm';
|
|
6
3
|
export { default as useSettingsMenu } from './useSettingsMenu';
|
|
@@ -1,10 +1,18 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
|
|
3
3
|
import { useCollator, useFetchClient } from '@strapi/helper-plugin';
|
|
4
|
+
import { Entity } from '@strapi/types';
|
|
4
5
|
import { useIntl } from 'react-intl';
|
|
5
6
|
import { useQuery } from 'react-query';
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
import { RoleEntity } from '../../../shared/entities';
|
|
9
|
+
import { APIBaseParams, APIResponse } from '../types/adminAPI';
|
|
10
|
+
|
|
11
|
+
export interface APIRolesQueryParams extends APIBaseParams {
|
|
12
|
+
id?: null | Entity.ID;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const useAdminRoles = (params: APIRolesQueryParams = {}, queryOptions = {}) => {
|
|
8
16
|
const { id = '', ...queryParams } = params;
|
|
9
17
|
|
|
10
18
|
const { get } = useFetchClient();
|
|
@@ -15,9 +23,15 @@ export const useAdminRoles = (params = {}, queryOptions = {}) => {
|
|
|
15
23
|
const { data, error, isError, isLoading, refetch } = useQuery(
|
|
16
24
|
['roles', id, queryParams],
|
|
17
25
|
async () => {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
26
|
+
/**
|
|
27
|
+
* TODO: can we infer if it's an array or not based on the appearance of `id`?
|
|
28
|
+
*/
|
|
29
|
+
const { data } = await get<APIResponse<RoleEntity | RoleEntity[]>>(
|
|
30
|
+
`/admin/roles/${id ?? ''}`,
|
|
31
|
+
{
|
|
32
|
+
params: queryParams,
|
|
33
|
+
}
|
|
34
|
+
);
|
|
21
35
|
|
|
22
36
|
return data;
|
|
23
37
|
},
|
|
@@ -29,16 +43,18 @@ export const useAdminRoles = (params = {}, queryOptions = {}) => {
|
|
|
29
43
|
// value, which later on triggers infinite loops if used in the
|
|
30
44
|
// dependency arrays of other hooks
|
|
31
45
|
const roles = React.useMemo(() => {
|
|
32
|
-
let roles = [];
|
|
46
|
+
let roles: RoleEntity[] = [];
|
|
33
47
|
|
|
34
|
-
if (
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
48
|
+
if (data) {
|
|
49
|
+
if (Array.isArray(data.data)) {
|
|
50
|
+
roles = data.data;
|
|
51
|
+
} else {
|
|
52
|
+
roles = [data.data];
|
|
53
|
+
}
|
|
38
54
|
}
|
|
39
55
|
|
|
40
56
|
return [...roles].sort((a, b) => formatter.compare(a.name, b.name));
|
|
41
|
-
}, [data,
|
|
57
|
+
}, [data, formatter]);
|
|
42
58
|
|
|
43
59
|
return {
|
|
44
60
|
roles,
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
import { useFetchClient } from '@strapi/helper-plugin';
|
|
4
|
+
import { Entity } from '@strapi/types';
|
|
5
|
+
import { useQuery } from 'react-query';
|
|
6
|
+
|
|
7
|
+
import { UserEntity } from '../../../shared/entities';
|
|
8
|
+
import { APIBaseParams, APIResponsePagination, APIResponseUsersLegacy } from '../types/adminAPI';
|
|
9
|
+
|
|
10
|
+
export interface APIUsersQueryParams extends APIBaseParams {
|
|
11
|
+
id?: null | Entity.ID;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function useAdminUsers(params: APIUsersQueryParams = {}, queryOptions = {}) {
|
|
15
|
+
const { id = '', ...queryParams } = params;
|
|
16
|
+
|
|
17
|
+
const { get } = useFetchClient();
|
|
18
|
+
|
|
19
|
+
const { data, isError, isLoading, refetch } = useQuery(
|
|
20
|
+
['users', id, queryParams],
|
|
21
|
+
async () => {
|
|
22
|
+
const {
|
|
23
|
+
data: { data },
|
|
24
|
+
} = await get<
|
|
25
|
+
APIResponseUsersLegacy<
|
|
26
|
+
UserEntity | { pagination: APIResponsePagination; results: UserEntity[] }
|
|
27
|
+
>
|
|
28
|
+
>(`/admin/users/${id}`, {
|
|
29
|
+
params: queryParams,
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
return data;
|
|
33
|
+
},
|
|
34
|
+
queryOptions
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
// the return value needs to be memoized, because intantiating
|
|
38
|
+
// an empty array as default value would lead to an unstable return
|
|
39
|
+
// value, which later on triggers infinite loops if used in the
|
|
40
|
+
// dependency arrays of other hooks
|
|
41
|
+
const users = React.useMemo(() => {
|
|
42
|
+
let users: UserEntity[] = [];
|
|
43
|
+
|
|
44
|
+
if (data) {
|
|
45
|
+
if ('results' in data) {
|
|
46
|
+
if (Array.isArray(data.results)) {
|
|
47
|
+
users = data.results;
|
|
48
|
+
}
|
|
49
|
+
} else {
|
|
50
|
+
users = [data];
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return users;
|
|
55
|
+
}, [data]);
|
|
56
|
+
|
|
57
|
+
return {
|
|
58
|
+
users,
|
|
59
|
+
pagination: React.useMemo(() => (data && 'pagination' in data) ?? null, [data]),
|
|
60
|
+
isLoading,
|
|
61
|
+
isError,
|
|
62
|
+
refetch,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
@@ -6,17 +6,27 @@ function isEnterprise() {
|
|
|
6
6
|
return window.strapi.isEE;
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
-
export
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
export interface UseEnterpriseOptions<TCEData, TEEData, TCombinedData> {
|
|
10
|
+
defaultValue?: TCEData | TEEData | null;
|
|
11
|
+
combine?: (ceData: TCEData, eeData: TEEData) => TCEData | TEEData | TCombinedData;
|
|
12
|
+
enabled?: boolean;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function useEnterprise<TCEData, TEEData, TCombinedData = unknown>(
|
|
16
|
+
ceData: TCEData,
|
|
17
|
+
eeCallback: () => Promise<TEEData>,
|
|
18
|
+
{
|
|
19
|
+
defaultValue = null,
|
|
20
|
+
combine = (ceData: TCEData, eeData: TEEData) => eeData,
|
|
21
|
+
enabled = true,
|
|
22
|
+
}: UseEnterpriseOptions<TCEData, TEEData, TCombinedData> = {}
|
|
13
23
|
) {
|
|
14
24
|
const eeCallbackRef = useCallbackRef(eeCallback);
|
|
15
25
|
const combineCallbackRef = useCallbackRef(combine);
|
|
16
26
|
|
|
17
27
|
// We have to use a nested object here, because functions (e.g. Components)
|
|
18
28
|
// can not be stored as value directly
|
|
19
|
-
const [{ data }, setData] = React.useState({
|
|
29
|
+
const [{ data }, setData] = React.useState<{ data: TCEData | TEEData | TCombinedData | null }>({
|
|
20
30
|
data: isEnterprise() && enabled ? defaultValue : ceData,
|
|
21
31
|
});
|
|
22
32
|
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
Permission,
|
|
5
|
+
hasPermissions,
|
|
6
|
+
useAppInfo,
|
|
7
|
+
useRBACProvider,
|
|
8
|
+
useStrapiApp,
|
|
9
|
+
StrapiAppContextValue,
|
|
10
|
+
} from '@strapi/helper-plugin';
|
|
11
|
+
import { Cog, Puzzle, ShoppingCart } from '@strapi/icons';
|
|
12
|
+
import cloneDeep from 'lodash/cloneDeep';
|
|
13
|
+
import { useSelector } from 'react-redux';
|
|
14
|
+
|
|
15
|
+
// @ts-expect-error - no types, yet.
|
|
16
|
+
import { selectAdminPermissions } from '../pages/App/selectors';
|
|
17
|
+
|
|
18
|
+
/* -------------------------------------------------------------------------------------------------
|
|
19
|
+
* useMenu
|
|
20
|
+
* -----------------------------------------------------------------------------------------------*/
|
|
21
|
+
|
|
22
|
+
type MenuItem = StrapiAppContextValue['menu'][number];
|
|
23
|
+
|
|
24
|
+
export interface Menu {
|
|
25
|
+
generalSectionLinks: MenuItem[];
|
|
26
|
+
pluginsSectionLinks: MenuItem[];
|
|
27
|
+
isLoading: boolean;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const useMenu = () => {
|
|
31
|
+
const { allPermissions: userPermissions } = useRBACProvider();
|
|
32
|
+
const { shouldUpdateStrapi } = useAppInfo();
|
|
33
|
+
const { menu } = useStrapiApp();
|
|
34
|
+
const permissions = useSelector(selectAdminPermissions);
|
|
35
|
+
const [menuWithUserPermissions, setMenuWithUserPermissions] = React.useState<Menu>({
|
|
36
|
+
generalSectionLinks: [
|
|
37
|
+
{
|
|
38
|
+
icon: Puzzle,
|
|
39
|
+
intlLabel: {
|
|
40
|
+
id: 'global.plugins',
|
|
41
|
+
defaultMessage: 'Plugins',
|
|
42
|
+
},
|
|
43
|
+
to: '/list-plugins',
|
|
44
|
+
// @ts-expect-error - we need the permissions type from the plugin
|
|
45
|
+
permissions: permissions.marketplace.main,
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
icon: ShoppingCart,
|
|
49
|
+
intlLabel: {
|
|
50
|
+
id: 'global.marketplace',
|
|
51
|
+
defaultMessage: 'Marketplace',
|
|
52
|
+
},
|
|
53
|
+
to: '/marketplace',
|
|
54
|
+
// @ts-expect-error - we need the permissions type from the plugin
|
|
55
|
+
permissions: permissions.marketplace.main,
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
icon: Cog,
|
|
59
|
+
intlLabel: {
|
|
60
|
+
id: 'global.settings',
|
|
61
|
+
defaultMessage: 'Settings',
|
|
62
|
+
},
|
|
63
|
+
to: '/settings',
|
|
64
|
+
// Permissions of this link are retrieved in the init phase
|
|
65
|
+
// using the settings menu
|
|
66
|
+
permissions: [],
|
|
67
|
+
notificationsCount: 0,
|
|
68
|
+
},
|
|
69
|
+
],
|
|
70
|
+
pluginsSectionLinks: [],
|
|
71
|
+
isLoading: true,
|
|
72
|
+
});
|
|
73
|
+
const generalSectionLinksRef = React.useRef(menuWithUserPermissions.generalSectionLinks);
|
|
74
|
+
|
|
75
|
+
React.useEffect(() => {
|
|
76
|
+
async function applyMenuPermissions() {
|
|
77
|
+
const authorizedPluginSectionLinks = await getPluginSectionLinks(userPermissions, menu);
|
|
78
|
+
|
|
79
|
+
const authorizedGeneralSectionLinks = await getGeneralLinks(
|
|
80
|
+
userPermissions,
|
|
81
|
+
generalSectionLinksRef.current,
|
|
82
|
+
shouldUpdateStrapi
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
setMenuWithUserPermissions((state) => ({
|
|
86
|
+
...state,
|
|
87
|
+
generalSectionLinks: authorizedGeneralSectionLinks,
|
|
88
|
+
pluginsSectionLinks: authorizedPluginSectionLinks,
|
|
89
|
+
isLoading: false,
|
|
90
|
+
}));
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
applyMenuPermissions();
|
|
94
|
+
}, [
|
|
95
|
+
setMenuWithUserPermissions,
|
|
96
|
+
generalSectionLinksRef,
|
|
97
|
+
userPermissions,
|
|
98
|
+
menu,
|
|
99
|
+
permissions,
|
|
100
|
+
shouldUpdateStrapi,
|
|
101
|
+
]);
|
|
102
|
+
|
|
103
|
+
return menuWithUserPermissions;
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
/* -------------------------------------------------------------------------------------------------
|
|
107
|
+
* Utils
|
|
108
|
+
* -----------------------------------------------------------------------------------------------*/
|
|
109
|
+
|
|
110
|
+
const getGeneralLinks = async (
|
|
111
|
+
userPermissions: Permission[],
|
|
112
|
+
generalSectionRawLinks: MenuItem[],
|
|
113
|
+
shouldUpdateStrapi: boolean = false
|
|
114
|
+
) => {
|
|
115
|
+
const generalSectionLinksPermissions = await Promise.all(
|
|
116
|
+
generalSectionRawLinks.map(({ permissions }) => hasPermissions(userPermissions, permissions))
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
const authorizedGeneralSectionLinks = generalSectionRawLinks.filter(
|
|
120
|
+
(_, index) => generalSectionLinksPermissions[index]
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
const settingsLinkIndex = authorizedGeneralSectionLinks.findIndex(
|
|
124
|
+
(obj) => obj.to === '/settings'
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
if (settingsLinkIndex === -1) {
|
|
128
|
+
return [];
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const authorizedGeneralLinksClone = cloneDeep(authorizedGeneralSectionLinks);
|
|
132
|
+
|
|
133
|
+
authorizedGeneralLinksClone[settingsLinkIndex].notificationsCount = shouldUpdateStrapi ? 1 : 0;
|
|
134
|
+
|
|
135
|
+
return authorizedGeneralLinksClone;
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
const getPluginSectionLinks = async (
|
|
139
|
+
userPermissions: Permission[],
|
|
140
|
+
pluginsSectionRawLinks: MenuItem[]
|
|
141
|
+
) => {
|
|
142
|
+
const pluginSectionLinksPermissions = await Promise.all(
|
|
143
|
+
pluginsSectionRawLinks.map(({ permissions }) => hasPermissions(userPermissions, permissions))
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
const authorizedPluginSectionLinks = pluginsSectionRawLinks.filter(
|
|
147
|
+
(_, index) => pluginSectionLinksPermissions[index]
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
return authorizedPluginSectionLinks;
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
export { useMenu };
|