@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
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
LoadingIndicatorPage,
|
|
5
|
+
useStrapiApp,
|
|
6
|
+
type StrapiAppContextValue,
|
|
7
|
+
} from '@strapi/helper-plugin';
|
|
8
|
+
import produce from 'immer';
|
|
9
|
+
import set from 'lodash/set';
|
|
10
|
+
|
|
11
|
+
// @ts-expect-error pages/Admin has not been converted yet.
|
|
12
|
+
import Admin from '../pages/Admin';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* TODO: this isn't great, and we really should focus on fixing this.
|
|
16
|
+
*/
|
|
17
|
+
const PluginsInitializer = () => {
|
|
18
|
+
const { plugins: appPlugins } = useStrapiApp();
|
|
19
|
+
const [{ plugins }, dispatch] = React.useReducer<React.Reducer<State, Action>, State>(
|
|
20
|
+
reducer,
|
|
21
|
+
initialState,
|
|
22
|
+
() => init(appPlugins)
|
|
23
|
+
);
|
|
24
|
+
const setPlugin = React.useRef((pluginId: string) => {
|
|
25
|
+
dispatch({ type: 'SET_PLUGIN_READY', pluginId });
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
const hasApluginNotReady = Object.keys(plugins).some(
|
|
29
|
+
(plugin) => plugins[plugin].isReady === false
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
*
|
|
34
|
+
* I have spent some time trying to understand what is happening here, and wanted to
|
|
35
|
+
* leave that knowledge for my future me:
|
|
36
|
+
*
|
|
37
|
+
* `initializer` is an undocumented property of the `registerPlugin` API. At the time
|
|
38
|
+
* of writing it seems only to be used by the i18n plugin.
|
|
39
|
+
*
|
|
40
|
+
* How does it work?
|
|
41
|
+
*
|
|
42
|
+
* Every plugin that has an `initializer` component defined, receives the
|
|
43
|
+
* `setPlugin` function as a component prop. In the case of i18n the plugin fetches locales
|
|
44
|
+
* first and calls `setPlugin` with `pluginId` once they are loaded, which then triggers the
|
|
45
|
+
* reducer of the admin app defined above.
|
|
46
|
+
*
|
|
47
|
+
* Once all plugins are set to `isReady: true` the app renders.
|
|
48
|
+
*
|
|
49
|
+
* This API is used to block rendering of the admin app. We should remove that in v5 completely
|
|
50
|
+
* and make sure plugins can inject data into the global store before they are initialized, to avoid
|
|
51
|
+
* having a new prop-callback based communication channel between plugins and the core admin app.
|
|
52
|
+
*
|
|
53
|
+
*/
|
|
54
|
+
|
|
55
|
+
if (hasApluginNotReady) {
|
|
56
|
+
const initializers = Object.keys(plugins).reduce((acc, current) => {
|
|
57
|
+
const InitializerComponent = plugins[current].initializer;
|
|
58
|
+
|
|
59
|
+
if (InitializerComponent) {
|
|
60
|
+
const key = plugins[current].pluginId;
|
|
61
|
+
|
|
62
|
+
acc.push(<InitializerComponent key={key} setPlugin={setPlugin.current} />);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return acc;
|
|
66
|
+
}, [] as React.ReactNode[]);
|
|
67
|
+
|
|
68
|
+
return (
|
|
69
|
+
<>
|
|
70
|
+
{initializers}
|
|
71
|
+
<LoadingIndicatorPage />
|
|
72
|
+
</>
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return <Admin />;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
/* -------------------------------------------------------------------------------------------------
|
|
80
|
+
* Reducer
|
|
81
|
+
* -----------------------------------------------------------------------------------------------*/
|
|
82
|
+
|
|
83
|
+
interface State {
|
|
84
|
+
plugins: StrapiAppContextValue['plugins'];
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const initialState: State = {
|
|
88
|
+
plugins: {},
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
type SetPluginReadyAction = {
|
|
92
|
+
type: 'SET_PLUGIN_READY';
|
|
93
|
+
pluginId: string;
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
type Action = SetPluginReadyAction;
|
|
97
|
+
|
|
98
|
+
const reducer: React.Reducer<State, Action> = (state = initialState, action: Action): State =>
|
|
99
|
+
produce(state, (draftState) => {
|
|
100
|
+
switch (action.type) {
|
|
101
|
+
case 'SET_PLUGIN_READY': {
|
|
102
|
+
set(draftState, ['plugins', action.pluginId, 'isReady'], true);
|
|
103
|
+
break;
|
|
104
|
+
}
|
|
105
|
+
default:
|
|
106
|
+
return draftState;
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
/* -------------------------------------------------------------------------------------------------
|
|
111
|
+
* Init state
|
|
112
|
+
* -----------------------------------------------------------------------------------------------*/
|
|
113
|
+
|
|
114
|
+
const init = (plugins: State['plugins']): State => {
|
|
115
|
+
return {
|
|
116
|
+
plugins: Object.keys(plugins).reduce<State['plugins']>((acc, current) => {
|
|
117
|
+
acc[current] = { ...plugins[current] };
|
|
118
|
+
|
|
119
|
+
return acc;
|
|
120
|
+
}, {}),
|
|
121
|
+
};
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
export { PluginsInitializer };
|
|
@@ -12,10 +12,10 @@ import PropTypes from 'prop-types';
|
|
|
12
12
|
import { QueryClient, QueryClientProvider } from 'react-query';
|
|
13
13
|
import { Provider } from 'react-redux';
|
|
14
14
|
|
|
15
|
-
import { AdminContext } from '../../contexts';
|
|
16
|
-
import
|
|
15
|
+
import { AdminContext } from '../../contexts/admin';
|
|
16
|
+
import { ConfigurationProvider } from '../ConfigurationProvider';
|
|
17
17
|
import GuidedTour from '../GuidedTour';
|
|
18
|
-
import LanguageProvider from '../LanguageProvider';
|
|
18
|
+
import { LanguageProvider } from '../LanguageProvider';
|
|
19
19
|
import { Theme } from '../Theme';
|
|
20
20
|
import { ThemeToggleProvider } from '../ThemeToggleProvider';
|
|
21
21
|
|
|
@@ -56,7 +56,7 @@ const Providers = ({
|
|
|
56
56
|
<QueryClientProvider client={queryClient}>
|
|
57
57
|
<Provider store={store}>
|
|
58
58
|
<AdminContext.Provider value={{ getAdminInjectedComponents }}>
|
|
59
|
-
<
|
|
59
|
+
<ConfigurationProvider
|
|
60
60
|
authLogo={authLogo}
|
|
61
61
|
menuLogo={menuLogo}
|
|
62
62
|
showReleaseNotification={showReleaseNotification}
|
|
@@ -83,7 +83,7 @@ const Providers = ({
|
|
|
83
83
|
</CustomFieldsProvider>
|
|
84
84
|
</LibraryProvider>
|
|
85
85
|
</StrapiAppProvider>
|
|
86
|
-
</
|
|
86
|
+
</ConfigurationProvider>
|
|
87
87
|
</AdminContext.Provider>
|
|
88
88
|
</Provider>
|
|
89
89
|
</QueryClientProvider>
|
|
@@ -95,7 +95,7 @@ const Providers = ({
|
|
|
95
95
|
|
|
96
96
|
Providers.propTypes = {
|
|
97
97
|
authLogo: PropTypes.oneOfType([PropTypes.string, PropTypes.any]).isRequired,
|
|
98
|
-
children: PropTypes.
|
|
98
|
+
children: PropTypes.node.isRequired,
|
|
99
99
|
components: PropTypes.object.isRequired,
|
|
100
100
|
customFields: PropTypes.object.isRequired,
|
|
101
101
|
fields: PropTypes.object.isRequired,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import styled from 'styled-components';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { useConfiguration } from '../hooks/useConfiguration';
|
|
4
4
|
|
|
5
5
|
const Img = styled.img`
|
|
6
6
|
height: ${72 / 16}rem;
|
|
@@ -9,7 +9,7 @@ const Img = styled.img`
|
|
|
9
9
|
const Logo = () => {
|
|
10
10
|
const {
|
|
11
11
|
logos: { auth },
|
|
12
|
-
} =
|
|
12
|
+
} = useConfiguration();
|
|
13
13
|
|
|
14
14
|
return <Img src={auth?.custom ?? auth.default} aria-hidden alt="" />;
|
|
15
15
|
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
|
|
3
|
+
import { Box } from '@strapi/design-system';
|
|
3
4
|
import PropTypes from 'prop-types';
|
|
4
5
|
import { Editable, useSlate } from 'slate-react';
|
|
5
6
|
import { useTheme } from 'styled-components';
|
|
@@ -41,6 +42,7 @@ const baseRenderElement = (props, blocks) => {
|
|
|
41
42
|
const BlocksInput = ({ disabled, placeholder }) => {
|
|
42
43
|
const theme = useTheme();
|
|
43
44
|
const editor = useSlate();
|
|
45
|
+
const blocksRef = React.useRef();
|
|
44
46
|
|
|
45
47
|
// Create renderLeaf function based on the modifiers store
|
|
46
48
|
const modifiers = useModifiersStore();
|
|
@@ -82,15 +84,53 @@ const BlocksInput = ({ disabled, placeholder }) => {
|
|
|
82
84
|
}
|
|
83
85
|
};
|
|
84
86
|
|
|
87
|
+
/**
|
|
88
|
+
* scrollSelectionIntoView : Slate's default method to scroll a DOM selection into the view,
|
|
89
|
+
* thats shifting layout for us when there is a overflowY:scroll on the viewport.
|
|
90
|
+
* We are overriding it to check if the selection is not fully within the visible area of the editor,
|
|
91
|
+
* we use scrollBy one line to the bottom
|
|
92
|
+
*/
|
|
93
|
+
const handleScrollSelectionIntoView = (_, domRange) => {
|
|
94
|
+
const domRect = domRange.getBoundingClientRect();
|
|
95
|
+
const blocksInput = blocksRef.current;
|
|
96
|
+
const editorRect = blocksInput.getBoundingClientRect();
|
|
97
|
+
|
|
98
|
+
// Check if the selection is not fully within the visible area of the editor
|
|
99
|
+
if (domRect.top < editorRect.top || domRect.bottom > editorRect.bottom) {
|
|
100
|
+
// Scroll by one line to the bottom
|
|
101
|
+
blocksInput.scrollBy({
|
|
102
|
+
top: 28, // 20px is the line-height + 8px line gap
|
|
103
|
+
behavior: 'smooth',
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
|
|
85
108
|
return (
|
|
86
|
-
<
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
109
|
+
<Box
|
|
110
|
+
ref={blocksRef}
|
|
111
|
+
grow={1}
|
|
112
|
+
width="100%"
|
|
113
|
+
overflow="auto"
|
|
114
|
+
fontSize={2}
|
|
115
|
+
background="neutral0"
|
|
116
|
+
color="neutral800"
|
|
117
|
+
lineHeight={6}
|
|
118
|
+
hasRadius
|
|
119
|
+
paddingLeft={4}
|
|
120
|
+
paddingRight={4}
|
|
121
|
+
marginTop={3}
|
|
122
|
+
marginBottom={3}
|
|
123
|
+
>
|
|
124
|
+
<Editable
|
|
125
|
+
readOnly={disabled}
|
|
126
|
+
placeholder={placeholder}
|
|
127
|
+
style={getEditorStyle(theme)}
|
|
128
|
+
renderElement={renderElement}
|
|
129
|
+
renderLeaf={renderLeaf}
|
|
130
|
+
onKeyDown={handleKeyDown}
|
|
131
|
+
scrollSelectionIntoView={handleScrollSelectionIntoView}
|
|
132
|
+
/>
|
|
133
|
+
</Box>
|
|
94
134
|
);
|
|
95
135
|
};
|
|
96
136
|
|
|
@@ -97,49 +97,6 @@ ToolbarButton.propTypes = {
|
|
|
97
97
|
handleClick: PropTypes.func.isRequired,
|
|
98
98
|
};
|
|
99
99
|
|
|
100
|
-
const ModifierButton = ({ icon, name, label, disabled }) => {
|
|
101
|
-
const editor = useSlate();
|
|
102
|
-
|
|
103
|
-
const isModifierActive = () => {
|
|
104
|
-
const modifiers = Editor.marks(editor);
|
|
105
|
-
|
|
106
|
-
if (!modifiers) return false;
|
|
107
|
-
|
|
108
|
-
return Boolean(modifiers[name]);
|
|
109
|
-
};
|
|
110
|
-
|
|
111
|
-
const isActive = isModifierActive();
|
|
112
|
-
|
|
113
|
-
const toggleModifier = () => {
|
|
114
|
-
if (isActive) {
|
|
115
|
-
Editor.removeMark(editor, name);
|
|
116
|
-
} else {
|
|
117
|
-
Editor.addMark(editor, name, true);
|
|
118
|
-
}
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
return (
|
|
122
|
-
<ToolbarButton
|
|
123
|
-
icon={icon}
|
|
124
|
-
name={name}
|
|
125
|
-
label={label}
|
|
126
|
-
isActive={isActive}
|
|
127
|
-
disabled={disabled}
|
|
128
|
-
handleClick={toggleModifier}
|
|
129
|
-
/>
|
|
130
|
-
);
|
|
131
|
-
};
|
|
132
|
-
|
|
133
|
-
ModifierButton.propTypes = {
|
|
134
|
-
icon: PropTypes.elementType.isRequired,
|
|
135
|
-
name: PropTypes.string.isRequired,
|
|
136
|
-
label: PropTypes.shape({
|
|
137
|
-
id: PropTypes.string.isRequired,
|
|
138
|
-
defaultMessage: PropTypes.string.isRequired,
|
|
139
|
-
}).isRequired,
|
|
140
|
-
disabled: PropTypes.bool.isRequired,
|
|
141
|
-
};
|
|
142
|
-
|
|
143
100
|
const toggleBlock = (editor, value) => {
|
|
144
101
|
const { type, level, format } = value;
|
|
145
102
|
|
|
@@ -151,11 +108,44 @@ const toggleBlock = (editor, value) => {
|
|
|
151
108
|
};
|
|
152
109
|
|
|
153
110
|
if (editor.selection) {
|
|
111
|
+
// If the selection is inside a list, split the list so that the modified block is outside of it
|
|
112
|
+
Transforms.unwrapNodes(editor, {
|
|
113
|
+
match: (node) => node.type === 'list',
|
|
114
|
+
split: true,
|
|
115
|
+
});
|
|
116
|
+
|
|
154
117
|
// When there is a selection, update the existing block in the tree
|
|
155
118
|
Transforms.setNodes(editor, blockProperties);
|
|
156
119
|
} else {
|
|
157
|
-
|
|
158
|
-
|
|
120
|
+
/**
|
|
121
|
+
* When there is no selection, we want to insert a new block just after
|
|
122
|
+
* the last node inserted and prevent the code to add an empty paragraph
|
|
123
|
+
* between them.
|
|
124
|
+
*/
|
|
125
|
+
const [, lastNodePath] = Editor.last(editor, []);
|
|
126
|
+
const [parentNode] = Editor.parent(editor, lastNodePath, {
|
|
127
|
+
// Makes sure we get a block node, not an inline node
|
|
128
|
+
match: (node) => node.type !== 'text',
|
|
129
|
+
});
|
|
130
|
+
Transforms.removeNodes(editor, {
|
|
131
|
+
void: true,
|
|
132
|
+
hanging: true,
|
|
133
|
+
at: {
|
|
134
|
+
anchor: { path: lastNodePath, offset: 0 },
|
|
135
|
+
focus: { path: lastNodePath, offset: 0 },
|
|
136
|
+
},
|
|
137
|
+
});
|
|
138
|
+
Transforms.insertNodes(
|
|
139
|
+
editor,
|
|
140
|
+
{
|
|
141
|
+
...blockProperties,
|
|
142
|
+
children: parentNode.children,
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
at: [lastNodePath[0]],
|
|
146
|
+
select: true,
|
|
147
|
+
}
|
|
148
|
+
);
|
|
159
149
|
}
|
|
160
150
|
|
|
161
151
|
// When the select is clicked it blurs the editor, restore the focus to the editor
|
|
@@ -199,6 +189,8 @@ const ImageDialog = ({ handleClose }) => {
|
|
|
199
189
|
const MediaLibraryDialog = components['media-library'];
|
|
200
190
|
|
|
201
191
|
const insertImages = (images) => {
|
|
192
|
+
// Image node created using select or existing selection node needs to be deleted before adding new image nodes
|
|
193
|
+
Transforms.removeNodes(editor);
|
|
202
194
|
images.forEach((img) => {
|
|
203
195
|
const image = { type: 'image', image: img, children: [{ type: 'text', text: '' }] };
|
|
204
196
|
Transforms.insertNodes(editor, image);
|
|
@@ -272,7 +264,7 @@ const insertEmptyBlockAtLast = (editor) => {
|
|
|
272
264
|
);
|
|
273
265
|
};
|
|
274
266
|
|
|
275
|
-
|
|
267
|
+
const BlocksDropdown = ({ disabled }) => {
|
|
276
268
|
const editor = useSlate();
|
|
277
269
|
const { formatMessage } = useIntl();
|
|
278
270
|
const [isMediaLibraryVisible, setIsMediaLibraryVisible] = React.useState(false);
|
|
@@ -290,10 +282,7 @@ export const BlocksDropdown = ({ disabled }) => {
|
|
|
290
282
|
* @param {string} optionKey - key of the heading selected
|
|
291
283
|
*/
|
|
292
284
|
const selectOption = (optionKey) => {
|
|
293
|
-
if (
|
|
294
|
-
// Image node created using select or existing selection node needs to be deleted before adding new image nodes
|
|
295
|
-
Transforms.removeNodes(editor);
|
|
296
|
-
} else if (['list-ordered', 'list-unordered'].includes(optionKey)) {
|
|
285
|
+
if (['list-ordered', 'list-unordered'].includes(optionKey)) {
|
|
297
286
|
// retrieve the list format
|
|
298
287
|
const listFormat = blocks[optionKey].value.format;
|
|
299
288
|
|
|
@@ -302,7 +291,7 @@ export const BlocksDropdown = ({ disabled }) => {
|
|
|
302
291
|
|
|
303
292
|
// toggle the list
|
|
304
293
|
toggleList(editor, isActive, listFormat);
|
|
305
|
-
} else {
|
|
294
|
+
} else if (optionKey !== 'image') {
|
|
306
295
|
toggleBlock(editor, blocks[optionKey].value);
|
|
307
296
|
}
|
|
308
297
|
|
|
@@ -432,21 +421,59 @@ const isListActive = (editor, matchNode) => {
|
|
|
432
421
|
};
|
|
433
422
|
|
|
434
423
|
const toggleList = (editor, isActive, format) => {
|
|
435
|
-
//
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
424
|
+
// If we have selected a portion of content in the editor,
|
|
425
|
+
// we want to convert it to a list or if it is already a list,
|
|
426
|
+
// convert it back to a paragraph
|
|
427
|
+
if (editor.selection) {
|
|
428
|
+
Transforms.unwrapNodes(editor, {
|
|
429
|
+
match: (node) => isListNode(node) && ['ordered', 'unordered'].includes(node.format),
|
|
430
|
+
split: true,
|
|
431
|
+
});
|
|
440
432
|
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
433
|
+
Transforms.setNodes(editor, {
|
|
434
|
+
type: isActive ? 'paragraph' : 'list-item',
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
if (!isActive) {
|
|
438
|
+
const block = { type: 'list', format, children: [] };
|
|
439
|
+
Transforms.wrapNodes(editor, block);
|
|
440
|
+
}
|
|
441
|
+
} else {
|
|
442
|
+
// There is no selection, convert the last inserted node to a list
|
|
443
|
+
// If it is already a list, convert it back to a paragraph
|
|
444
|
+
const [, lastNodePath] = Editor.last(editor, []);
|
|
445
|
+
|
|
446
|
+
const [parentNode] = Editor.parent(editor, lastNodePath, {
|
|
447
|
+
// Makes sure we get a block node, not an inline node
|
|
448
|
+
match: (node) => node.type !== 'text',
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
Transforms.removeNodes(editor, {
|
|
452
|
+
void: true,
|
|
453
|
+
hanging: true,
|
|
454
|
+
at: {
|
|
455
|
+
anchor: { path: lastNodePath, offset: 0 },
|
|
456
|
+
focus: { path: lastNodePath, offset: 0 },
|
|
457
|
+
},
|
|
458
|
+
});
|
|
445
459
|
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
460
|
+
Transforms.insertNodes(
|
|
461
|
+
editor,
|
|
462
|
+
{
|
|
463
|
+
type: isActive ? 'paragraph' : 'list-item',
|
|
464
|
+
children: [...parentNode.children],
|
|
465
|
+
},
|
|
466
|
+
{
|
|
467
|
+
at: [lastNodePath[0]],
|
|
468
|
+
select: true,
|
|
469
|
+
}
|
|
470
|
+
);
|
|
471
|
+
|
|
472
|
+
if (!isActive) {
|
|
473
|
+
// If the selection is now a list item, wrap it inside a list
|
|
474
|
+
const block = { type: 'list', format, children: [] };
|
|
475
|
+
Transforms.wrapNodes(editor, block);
|
|
476
|
+
}
|
|
450
477
|
}
|
|
451
478
|
};
|
|
452
479
|
|
|
@@ -507,6 +534,31 @@ const LinkButton = ({ disabled }) => {
|
|
|
507
534
|
return Boolean(match);
|
|
508
535
|
};
|
|
509
536
|
|
|
537
|
+
const isLinkDisabled = () => {
|
|
538
|
+
// Always disabled when the whole editor is disabled
|
|
539
|
+
if (disabled) {
|
|
540
|
+
return true;
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
// Always enabled when there's no selection
|
|
544
|
+
if (!editor.selection) {
|
|
545
|
+
return false;
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
// Get the block node closest to the anchor and focus
|
|
549
|
+
const anchorNodeEntry = Editor.above(editor, {
|
|
550
|
+
at: editor.selection.anchor,
|
|
551
|
+
match: (node) => node.type !== 'text',
|
|
552
|
+
});
|
|
553
|
+
const focusNodeEntry = Editor.above(editor, {
|
|
554
|
+
at: editor.selection.focus,
|
|
555
|
+
match: (node) => node.type !== 'text',
|
|
556
|
+
});
|
|
557
|
+
|
|
558
|
+
// Disabled if the anchor and focus are not in the same block
|
|
559
|
+
return anchorNodeEntry[0] !== focusNodeEntry[0];
|
|
560
|
+
};
|
|
561
|
+
|
|
510
562
|
const addLink = () => {
|
|
511
563
|
// We insert an empty anchor, so we split the DOM to have a element we can use as reference for the popover
|
|
512
564
|
insertLink(editor, { url: '' });
|
|
@@ -522,7 +574,7 @@ const LinkButton = ({ disabled }) => {
|
|
|
522
574
|
}}
|
|
523
575
|
isActive={isLinkActive()}
|
|
524
576
|
handleClick={addLink}
|
|
525
|
-
disabled={
|
|
577
|
+
disabled={isLinkDisabled()}
|
|
526
578
|
/>
|
|
527
579
|
);
|
|
528
580
|
};
|
|
@@ -543,11 +595,37 @@ const BetaTag = styled(Box)`
|
|
|
543
595
|
const BlocksToolbar = ({ disabled }) => {
|
|
544
596
|
const modifiers = useModifiersStore();
|
|
545
597
|
const blocks = useBlocksStore();
|
|
598
|
+
const editor = useSlate();
|
|
599
|
+
|
|
600
|
+
/**
|
|
601
|
+
* The modifier buttons are disabled when an image is selected.
|
|
602
|
+
*/
|
|
603
|
+
|
|
604
|
+
const checkButtonDisabled = () => {
|
|
605
|
+
// Always disabled when the whole editor is disabled
|
|
606
|
+
if (disabled) {
|
|
607
|
+
return true;
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
if (!editor.selection) {
|
|
611
|
+
return false;
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
const selectedNode = editor.children[editor.selection.anchor.path[0]];
|
|
615
|
+
|
|
616
|
+
if (['image', 'code'].includes(selectedNode.type)) {
|
|
617
|
+
return true;
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
return false;
|
|
621
|
+
};
|
|
622
|
+
|
|
623
|
+
const isButtonDisabled = checkButtonDisabled();
|
|
546
624
|
|
|
547
625
|
return (
|
|
548
626
|
<Toolbar.Root aria-disabled={disabled} asChild>
|
|
549
627
|
{/* Remove after the RTE Blocks Beta release (paddingRight and width) */}
|
|
550
|
-
<ToolbarWrapper gap={
|
|
628
|
+
<ToolbarWrapper gap={2} padding={2} paddingRight={4} width="100%">
|
|
551
629
|
<BlocksDropdown disabled={disabled} />
|
|
552
630
|
<Toolbar.ToggleGroup type="multiple" asChild>
|
|
553
631
|
<Flex gap={1} marginLeft={1}>
|
|
@@ -559,10 +637,10 @@ const BlocksToolbar = ({ disabled }) => {
|
|
|
559
637
|
label={modifier.label}
|
|
560
638
|
isActive={modifier.checkIsActive()}
|
|
561
639
|
handleClick={modifier.handleToggle}
|
|
562
|
-
disabled={
|
|
640
|
+
disabled={isButtonDisabled}
|
|
563
641
|
/>
|
|
564
642
|
))}
|
|
565
|
-
<LinkButton disabled={
|
|
643
|
+
<LinkButton disabled={isButtonDisabled} />
|
|
566
644
|
</Flex>
|
|
567
645
|
</Toolbar.ToggleGroup>
|
|
568
646
|
<Separator />
|