@strapi/admin 4.12.6 → 4.12.7
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/src/StrapiApp.js +1 -1
- package/admin/src/components/AuthenticatedApp/index.js +118 -0
- package/admin/src/components/AuthenticatedApp/utils/api.js +85 -0
- package/admin/src/components/AuthenticatedApp/utils/checkLatestStrapiVersion.js +11 -0
- package/admin/src/components/GuidedTour/Modal/index.js +3 -1
- package/admin/src/components/PluginsInitializer/index.js +68 -0
- package/admin/src/components/PluginsInitializer/init.js +11 -0
- package/admin/src/components/PluginsInitializer/reducer.js +22 -0
- package/admin/src/content-manager/pages/App/index.js +16 -5
- package/admin/src/content-manager/pages/EditView/Information/index.js +1 -1
- package/admin/src/content-manager/pages/ListView/components/BulkActionButtons/SelectedEntriesModal/index.js +2 -2
- package/admin/src/content-manager/pages/ListView/components/TableRows/index.js +1 -1
- package/admin/src/hooks/useSettingsForm/index.js +3 -14
- package/admin/src/hooks/useSettingsMenu/index.js +2 -2
- package/admin/src/hooks/useSettingsMenu/utils/formatLinks.js +3 -1
- package/admin/src/hooks/useSettingsMenu/utils/sortLinks.js +3 -1
- package/admin/src/index.js +1 -1
- package/admin/src/layouts/AppLayout/index.js +33 -0
- package/admin/src/pages/Admin/Onboarding/index.js +3 -1
- package/admin/src/pages/Admin/index.js +74 -80
- package/admin/src/pages/App/constants.js +1 -1
- package/admin/src/pages/App/index.js +122 -160
- package/admin/src/pages/AuthPage/index.js +4 -2
- package/admin/src/pages/HomePage/index.js +3 -1
- package/admin/src/pages/InstalledPluginsPage/index.js +3 -1
- package/admin/src/pages/{InternalErrorPage.js → InternalErrorPage/index.js} +4 -3
- package/admin/src/pages/{NotFoundPage.js → NotFoundPage/index.js} +3 -1
- package/admin/src/pages/ProfilePage/index.js +4 -2
- package/admin/src/pages/SettingsPage/components/SettingsNav/index.js +3 -3
- package/admin/src/pages/SettingsPage/constants.js +132 -67
- package/admin/src/pages/SettingsPage/index.js +36 -31
- package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/index.js +1 -1
- package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/index.js +35 -69
- package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/utils/api.js +23 -0
- package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/utils/prefixAllUrls.js +17 -0
- package/admin/src/pages/SettingsPage/pages/TransferTokens/EditView/index.js +1 -1
- package/admin/src/pages/SettingsPage/pages/Users/EditPage/index.js +1 -2
- package/admin/src/pages/SettingsPage/pages/Users/ListPage/DynamicTable/TableRows/index.js +1 -1
- package/admin/src/pages/SettingsPage/utils/createSectionsRoutes.js +11 -0
- package/admin/src/pages/SettingsPage/utils/getSectionsToDisplay.js +5 -0
- package/admin/src/pages/SettingsPage/utils/index.js +2 -0
- package/admin/src/pages/UseCasePage/index.js +175 -0
- package/admin/src/utils/checkFormValidity.js +15 -0
- package/admin/src/utils/createRoute.js +7 -5
- package/admin/src/utils/formatAPIErrors.js +3 -1
- package/admin/src/utils/getAttributesToDisplay.js +19 -0
- package/admin/src/utils/getExistingActions.js +32 -0
- package/admin/src/utils/getFullName.js +1 -1
- package/admin/src/utils/index.js +9 -0
- package/admin/src/utils/makeUniqueRoutes.js +6 -0
- package/admin/src/utils/sortLinks.js +3 -1
- package/admin/src/utils/uniqueAdminHash.js +9 -2
- package/build/{1049.9d69d231.chunk.js → 1049.f76cb14b.chunk.js} +1 -1
- package/build/1386.879bcd90.chunk.js +7 -0
- package/build/2225.c6244756.chunk.js +79 -0
- package/build/2379.f1641312.chunk.js +1 -0
- package/build/2395.46f8d0c1.chunk.js +26 -0
- package/build/2801.5cef5ec8.chunk.js +1 -0
- package/build/3483.03c24f96.chunk.js +1 -0
- package/build/3739.63e352f1.chunk.js +103 -0
- package/build/3929.5632f24d.chunk.js +114 -0
- package/build/448.829e1344.chunk.js +1 -0
- package/build/502.8ae8ef60.chunk.js +1 -0
- package/build/5483.6dd2e776.chunk.js +6 -0
- package/build/5542.2415a393.chunk.js +63 -0
- package/build/6691.4985ef22.chunk.js +105 -0
- package/build/7464.3e64a1d5.chunk.js +1 -0
- package/build/8276.10a3f883.chunk.js +26 -0
- package/build/{2747.d1442a90.chunk.js → 9806.5d5a0e8d.chunk.js} +64 -72
- package/build/9944.7af075a5.chunk.js +26 -0
- package/build/Admin-authenticatedApp.31497f74.chunk.js +79 -0
- package/build/Admin_InternalErrorPage.f45f2462.chunk.js +1 -0
- package/build/Admin_homePage.ac9dfb86.chunk.js +81 -0
- package/build/Admin_marketplace.c94239f6.chunk.js +55 -0
- package/build/Admin_pluginsPage.bbe79434.chunk.js +6 -0
- package/build/Admin_profilePage.192edc52.chunk.js +13 -0
- package/build/Admin_settingsPage.97cb9d41.chunk.js +111 -0
- package/build/admin-app.91898385.chunk.js +36 -0
- package/build/{admin-edit-roles-page.24bdf746.chunk.js → admin-edit-roles-page.6d567273.chunk.js} +1 -1
- package/build/admin-edit-users.acfd4128.chunk.js +10 -0
- package/build/{admin-users.2b3e4305.chunk.js → admin-users.00e20017.chunk.js} +2 -2
- package/build/{content-manager.fb0833bd.chunk.js → content-manager.b40f79c0.chunk.js} +78 -78
- package/build/{content-type-builder.66066281.chunk.js → content-type-builder.cd999f6e.chunk.js} +18 -18
- package/build/email-settings-page.d494d1eb.chunk.js +11 -0
- package/build/index.html +1 -1
- package/build/main.9dbe4579.js +2859 -0
- package/build/review-workflows-settings-create-view.cb08cfa2.chunk.js +1 -0
- package/build/review-workflows-settings-edit-view.3c7cbe63.chunk.js +1 -0
- package/build/review-workflows-settings-list-view.1611dc1f.chunk.js +56 -0
- package/build/runtime~main.d515c521.js +2 -0
- package/build/{sso-settings-page.4dba0670.chunk.js → sso-settings-page.12b6d8ae.chunk.js} +1 -1
- package/build/users-advanced-settings-page.f0760eb8.chunk.js +9 -0
- package/build/users-email-settings-page.ff4b32f3.chunk.js +9 -0
- package/build/users-providers-settings-page.48de0306.chunk.js +14 -0
- package/build/users-roles-settings-page.9d9a1eff.chunk.js +30 -0
- package/build/webhook-edit-page.6cb479ff.chunk.js +33 -0
- package/ee/admin/hooks/index.js +4 -0
- package/ee/admin/hooks/useAuthProviders/index.js +50 -0
- package/ee/admin/hooks/useAuthProviders/reducer.js +26 -0
- package/ee/admin/hooks/{useLicenseLimitNotification.js → useLicenseLimitNotification/index.js} +4 -2
- package/ee/admin/hooks/useLicenseLimits/index.js +1 -0
- package/ee/admin/hooks/{useLicenseLimits.js → useLicenseLimits/useLicenseLimits.js} +1 -4
- package/ee/admin/pages/App/constants.js +5 -6
- package/ee/admin/pages/AuthPage/components/Login/index.js +4 -8
- package/ee/admin/pages/AuthPage/components/Providers/index.js +5 -8
- package/ee/admin/pages/HomePage/index.js +1 -1
- package/ee/admin/pages/SettingsPage/constants.js +42 -27
- package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/pages/CreateView/CreateView.js +1 -1
- package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/pages/EditView/EditView.js +1 -1
- package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/pages/ListView/ListView.js +1 -1
- package/ee/admin/pages/SettingsPage/pages/Users/ListPage/CreateAction/index.js +1 -1
- package/ee/admin/pages/SettingsPage/pages/Users/ListPage/index.js +1 -1
- package/package.json +8 -8
- package/admin/src/components/AuthenticatedApp.js +0 -229
- package/admin/src/pages/UseCasePage.js +0 -174
- package/build/1504.eff012f7.chunk.js +0 -95
- package/build/2166.c837469a.chunk.js +0 -1
- package/build/2225.33287e1b.chunk.js +0 -79
- package/build/2237.03792b63.chunk.js +0 -114
- package/build/2379.401f56f3.chunk.js +0 -1
- package/build/2395.e6a79fbb.chunk.js +0 -26
- package/build/2801.31393ffe.chunk.js +0 -1
- package/build/3483.8517171f.chunk.js +0 -1
- package/build/502.8dd074ff.chunk.js +0 -1
- package/build/5483.5bfbb00d.chunk.js +0 -6
- package/build/7464.592a9295.chunk.js +0 -1
- package/build/748.fd2e5afd.chunk.js +0 -105
- package/build/773.6381d62d.chunk.js +0 -18
- package/build/7826.399afe81.chunk.js +0 -103
- package/build/8261.2525d35c.chunk.js +0 -7
- package/build/8276.e519a707.chunk.js +0 -26
- package/build/8299.62b67c72.chunk.js +0 -1
- package/build/Admin-AuthPage.90d64342.chunk.js +0 -35
- package/build/Admin-AuthenticatedApp.379ac945.chunk.js +0 -24
- package/build/Admin-UseCasePage.1f757db5.chunk.js +0 -13
- package/build/Admin_GuidedTourModal.8ccf1fbc.chunk.js +0 -12
- package/build/Admin_InternalErrorPage.9de92c6d.chunk.js +0 -9
- package/build/Admin_NotFoundPage.21620424.chunk.js +0 -9
- package/build/Admin_Onboarding.dbfa32f6.chunk.js +0 -43
- package/build/Admin_homePage.2000cbe9.chunk.js +0 -86
- package/build/Admin_marketplace.ec80e29b.chunk.js +0 -63
- package/build/Admin_pluginsPage.0c6851f8.chunk.js +0 -14
- package/build/Admin_profilePage.78cd8495.chunk.js +0 -21
- package/build/Admin_settingsPage.1760c3ce.chunk.js +0 -119
- package/build/StrapiApp.221fac30.chunk.js +0 -5
- package/build/admin-edit-users.5d10d444.chunk.js +0 -10
- package/build/email-settings-page.2f7e35c0.chunk.js +0 -11
- package/build/main.ee3c1938.js +0 -2859
- package/build/review-workflows-settings-create-view.d24a32b9.chunk.js +0 -1
- package/build/review-workflows-settings-edit-view.6044b022.chunk.js +0 -1
- package/build/review-workflows-settings-list-view.3f0ef4bc.chunk.js +0 -56
- package/build/runtime~main.397ee447.js +0 -2
- package/build/users-advanced-settings-page.17052d72.chunk.js +0 -9
- package/build/users-email-settings-page.3de8ea50.chunk.js +0 -9
- package/build/users-providers-settings-page.0eaa916d.chunk.js +0 -14
- package/build/users-roles-settings-page.957ad48b.chunk.js +0 -55
- package/build/webhook-edit-page.665210af.chunk.js +0 -33
- package/ee/admin/hooks/useAuthProviders.js +0 -25
- /package/ee/admin/hooks/{__mocks__/useLicenseLimits.js → useLicenseLimits/__mocks__/index.js} +0 -0
package/admin/src/StrapiApp.js
CHANGED
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
} from './exposedHooks';
|
|
23
23
|
import favicon from './favicon.png';
|
|
24
24
|
import injectionZones from './injectionZones';
|
|
25
|
-
import
|
|
25
|
+
import App from './pages/App';
|
|
26
26
|
import languageNativeNames from './translations/languageNativeNames';
|
|
27
27
|
|
|
28
28
|
class StrapiApp {
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import React, { useEffect, useState } from 'react';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
AppInfoProvider,
|
|
5
|
+
auth,
|
|
6
|
+
LoadingIndicatorPage,
|
|
7
|
+
useGuidedTour,
|
|
8
|
+
useNotification,
|
|
9
|
+
} from '@strapi/helper-plugin';
|
|
10
|
+
import get from 'lodash/get';
|
|
11
|
+
import { useQueries } from 'react-query';
|
|
12
|
+
// TODO: DS add loader
|
|
13
|
+
|
|
14
|
+
import packageJSON from '../../../../package.json';
|
|
15
|
+
import { useConfigurations } from '../../hooks';
|
|
16
|
+
import { getFullName, hashAdminUserEmail } from '../../utils';
|
|
17
|
+
import PluginsInitializer from '../PluginsInitializer';
|
|
18
|
+
import RBACProvider from '../RBACProvider';
|
|
19
|
+
|
|
20
|
+
import {
|
|
21
|
+
fetchAppInfo,
|
|
22
|
+
fetchCurrentUserPermissions,
|
|
23
|
+
fetchStrapiLatestRelease,
|
|
24
|
+
fetchUserRoles,
|
|
25
|
+
} from './utils/api';
|
|
26
|
+
import checkLatestStrapiVersion from './utils/checkLatestStrapiVersion';
|
|
27
|
+
|
|
28
|
+
const strapiVersion = packageJSON.version;
|
|
29
|
+
|
|
30
|
+
const AuthenticatedApp = () => {
|
|
31
|
+
const { setGuidedTourVisibility } = useGuidedTour();
|
|
32
|
+
const toggleNotification = useNotification();
|
|
33
|
+
const userInfo = auth.getUserInfo();
|
|
34
|
+
const userName = get(userInfo, 'username') || getFullName(userInfo.firstname, userInfo.lastname);
|
|
35
|
+
const [userDisplayName, setUserDisplayName] = useState(userName);
|
|
36
|
+
const [userId, setUserId] = useState(null);
|
|
37
|
+
const { showReleaseNotification } = useConfigurations();
|
|
38
|
+
const [
|
|
39
|
+
{ data: appInfos, status },
|
|
40
|
+
{ data: tagName, isLoading },
|
|
41
|
+
{ data: permissions, status: fetchPermissionsStatus, refetch, isFetching },
|
|
42
|
+
{ data: userRoles },
|
|
43
|
+
] = useQueries([
|
|
44
|
+
{ queryKey: 'app-infos', queryFn: fetchAppInfo },
|
|
45
|
+
{
|
|
46
|
+
queryKey: 'strapi-release',
|
|
47
|
+
queryFn: () => fetchStrapiLatestRelease(toggleNotification),
|
|
48
|
+
enabled: showReleaseNotification,
|
|
49
|
+
initialData: strapiVersion,
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
queryKey: 'admin-users-permission',
|
|
53
|
+
queryFn: fetchCurrentUserPermissions,
|
|
54
|
+
initialData: [],
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
queryKey: 'user-roles',
|
|
58
|
+
queryFn: fetchUserRoles,
|
|
59
|
+
},
|
|
60
|
+
]);
|
|
61
|
+
|
|
62
|
+
const shouldUpdateStrapi = checkLatestStrapiVersion(strapiVersion, tagName);
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* TODO: does this actually need to be an effect?
|
|
66
|
+
*/
|
|
67
|
+
useEffect(() => {
|
|
68
|
+
if (userRoles) {
|
|
69
|
+
const isUserSuperAdmin = userRoles.find(({ code }) => code === 'strapi-super-admin');
|
|
70
|
+
|
|
71
|
+
if (isUserSuperAdmin && appInfos?.autoReload) {
|
|
72
|
+
setGuidedTourVisibility(true);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}, [userRoles, appInfos, setGuidedTourVisibility]);
|
|
76
|
+
|
|
77
|
+
useEffect(() => {
|
|
78
|
+
const getUserId = async () => {
|
|
79
|
+
const userId = await hashAdminUserEmail(userInfo);
|
|
80
|
+
setUserId(userId);
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
getUserId();
|
|
84
|
+
}, [userInfo]);
|
|
85
|
+
|
|
86
|
+
// We don't need to wait for the release query to be fetched before rendering the plugins
|
|
87
|
+
// however, we need the appInfos and the permissions
|
|
88
|
+
const shouldShowNotDependentQueriesLoader =
|
|
89
|
+
isFetching || status === 'loading' || fetchPermissionsStatus === 'loading';
|
|
90
|
+
|
|
91
|
+
const shouldShowLoader = isLoading || shouldShowNotDependentQueriesLoader;
|
|
92
|
+
|
|
93
|
+
if (shouldShowLoader) {
|
|
94
|
+
return <LoadingIndicatorPage />;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// TODO: add error state
|
|
98
|
+
if (status === 'error') {
|
|
99
|
+
return <div>error...</div>;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return (
|
|
103
|
+
<AppInfoProvider
|
|
104
|
+
{...appInfos}
|
|
105
|
+
userId={userId}
|
|
106
|
+
latestStrapiReleaseTag={tagName}
|
|
107
|
+
setUserDisplayName={setUserDisplayName}
|
|
108
|
+
shouldUpdateStrapi={shouldUpdateStrapi}
|
|
109
|
+
userDisplayName={userDisplayName}
|
|
110
|
+
>
|
|
111
|
+
<RBACProvider permissions={permissions} refetchPermissions={refetch}>
|
|
112
|
+
<PluginsInitializer />
|
|
113
|
+
</RBACProvider>
|
|
114
|
+
</AppInfoProvider>
|
|
115
|
+
);
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
export default AuthenticatedApp;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { getFetchClient } from '@strapi/helper-plugin';
|
|
2
|
+
|
|
3
|
+
import packageJSON from '../../../../../package.json';
|
|
4
|
+
|
|
5
|
+
import checkLatestStrapiVersion from './checkLatestStrapiVersion';
|
|
6
|
+
|
|
7
|
+
const strapiVersion = packageJSON.version;
|
|
8
|
+
const showUpdateNotif = !JSON.parse(localStorage.getItem('STRAPI_UPDATE_NOTIF'));
|
|
9
|
+
const { get } = getFetchClient();
|
|
10
|
+
|
|
11
|
+
const fetchStrapiLatestRelease = async (toggleNotification) => {
|
|
12
|
+
try {
|
|
13
|
+
const res = await fetch('https://api.github.com/repos/strapi/strapi/releases/latest');
|
|
14
|
+
|
|
15
|
+
if (!res.ok) {
|
|
16
|
+
throw new Error('Failed to fetch latest Strapi version.');
|
|
17
|
+
}
|
|
18
|
+
const { tag_name } = await res.json();
|
|
19
|
+
const shouldUpdateStrapi = checkLatestStrapiVersion(strapiVersion, tag_name);
|
|
20
|
+
|
|
21
|
+
if (shouldUpdateStrapi && showUpdateNotif) {
|
|
22
|
+
toggleNotification({
|
|
23
|
+
type: 'info',
|
|
24
|
+
message: { id: 'notification.version.update.message' },
|
|
25
|
+
link: {
|
|
26
|
+
url: `https://github.com/strapi/strapi/releases/tag/${tag_name}`,
|
|
27
|
+
label: {
|
|
28
|
+
id: 'global.see-more',
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
blockTransition: true,
|
|
32
|
+
onClose: () => localStorage.setItem('STRAPI_UPDATE_NOTIF', true),
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return tag_name;
|
|
37
|
+
} catch (err) {
|
|
38
|
+
// Don't throw an error
|
|
39
|
+
return strapiVersion;
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const fetchAppInfo = async () => {
|
|
44
|
+
try {
|
|
45
|
+
const { data, headers } = await get('/admin/information');
|
|
46
|
+
|
|
47
|
+
if (!headers['content-type'].includes('application/json')) {
|
|
48
|
+
throw new Error('Not found');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return data.data;
|
|
52
|
+
} catch (error) {
|
|
53
|
+
throw new Error(error);
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const fetchCurrentUserPermissions = async () => {
|
|
58
|
+
try {
|
|
59
|
+
const { data, headers } = await get('/admin/users/me/permissions');
|
|
60
|
+
|
|
61
|
+
if (!headers['content-type'].includes('application/json')) {
|
|
62
|
+
throw new Error('Not found');
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return data.data;
|
|
66
|
+
} catch (err) {
|
|
67
|
+
throw new Error(err);
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const fetchUserRoles = async () => {
|
|
72
|
+
try {
|
|
73
|
+
const {
|
|
74
|
+
data: {
|
|
75
|
+
data: { roles },
|
|
76
|
+
},
|
|
77
|
+
} = await get('/admin/users/me');
|
|
78
|
+
|
|
79
|
+
return roles;
|
|
80
|
+
} catch (err) {
|
|
81
|
+
throw new Error(err);
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
export { fetchAppInfo, fetchCurrentUserPermissions, fetchStrapiLatestRelease, fetchUserRoles };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import semver from 'semver';
|
|
2
|
+
|
|
3
|
+
const checkLatestStrapiVersion = (currentPackageVersion, latestPublishedVersion) => {
|
|
4
|
+
if (!semver.valid(currentPackageVersion) || !semver.valid(latestPublishedVersion)) {
|
|
5
|
+
return false;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
return semver.lt(currentPackageVersion, latestPublishedVersion);
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export default checkLatestStrapiVersion;
|
|
@@ -9,7 +9,7 @@ import Modal from './components/Modal';
|
|
|
9
9
|
import StepperModal from './components/Stepper';
|
|
10
10
|
import reducer, { initialState } from './reducer';
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
const GuidedTourModal = () => {
|
|
13
13
|
const {
|
|
14
14
|
currentStep,
|
|
15
15
|
guidedTourState,
|
|
@@ -90,3 +90,5 @@ export const GuidedTourModal = () => {
|
|
|
90
90
|
|
|
91
91
|
return null;
|
|
92
92
|
};
|
|
93
|
+
|
|
94
|
+
export default GuidedTourModal;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import React, { useReducer, useRef } from 'react';
|
|
2
|
+
|
|
3
|
+
import { LoadingIndicatorPage, useStrapiApp } from '@strapi/helper-plugin';
|
|
4
|
+
|
|
5
|
+
import Admin from '../../pages/Admin';
|
|
6
|
+
|
|
7
|
+
import init from './init';
|
|
8
|
+
import reducer, { initialState } from './reducer';
|
|
9
|
+
|
|
10
|
+
const PluginsInitializer = () => {
|
|
11
|
+
const { plugins: appPlugins } = useStrapiApp();
|
|
12
|
+
const [{ plugins }, dispatch] = useReducer(reducer, initialState, () => init(appPlugins));
|
|
13
|
+
const setPlugin = useRef((pluginId) => {
|
|
14
|
+
dispatch({ type: 'SET_PLUGIN_READY', pluginId });
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
const hasApluginNotReady = Object.keys(plugins).some(
|
|
18
|
+
(plugin) => plugins[plugin].isReady === false
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
*
|
|
23
|
+
* I have spent some time trying to understand what is happening here, and wanted to
|
|
24
|
+
* leave that knowledge for my future me:
|
|
25
|
+
*
|
|
26
|
+
* `initializer` is an undocumented property of the `registerPlugin` API. At the time
|
|
27
|
+
* of writing it seems only to be used by the i18n plugin.
|
|
28
|
+
*
|
|
29
|
+
* How does it work?
|
|
30
|
+
*
|
|
31
|
+
* Every plugin that has an `initializer` component defined, receives the
|
|
32
|
+
* `setPlugin` function as a component prop. In the case of i18n the plugin fetches locales
|
|
33
|
+
* first and calls `setPlugin` with `pluginId` once they are loaded, which then triggers the
|
|
34
|
+
* reducer of the admin app defined above.
|
|
35
|
+
*
|
|
36
|
+
* Once all plugins are set to `isReady: true` the app renders.
|
|
37
|
+
*
|
|
38
|
+
* This API is used to block rendering of the admin app. We should remove that in v5 completely
|
|
39
|
+
* and make sure plugins can inject data into the global store before they are initialized, to avoid
|
|
40
|
+
* having a new prop-callback based communication channel between plugins and the core admin app.
|
|
41
|
+
*
|
|
42
|
+
*/
|
|
43
|
+
|
|
44
|
+
if (hasApluginNotReady) {
|
|
45
|
+
const initializers = Object.keys(plugins).reduce((acc, current) => {
|
|
46
|
+
const InitializerComponent = plugins[current].initializer;
|
|
47
|
+
|
|
48
|
+
if (InitializerComponent) {
|
|
49
|
+
const key = plugins[current].pluginId;
|
|
50
|
+
|
|
51
|
+
acc.push(<InitializerComponent key={key} setPlugin={setPlugin.current} />);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return acc;
|
|
55
|
+
}, []);
|
|
56
|
+
|
|
57
|
+
return (
|
|
58
|
+
<>
|
|
59
|
+
{initializers}
|
|
60
|
+
<LoadingIndicatorPage />
|
|
61
|
+
</>
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return <Admin />;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export default PluginsInitializer;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import produce from 'immer';
|
|
2
|
+
import set from 'lodash/set';
|
|
3
|
+
|
|
4
|
+
const initialState = {
|
|
5
|
+
plugins: null,
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
const reducer = (state = initialState, action) =>
|
|
9
|
+
/* eslint-disable-next-line consistent-return */
|
|
10
|
+
produce(state, (draftState) => {
|
|
11
|
+
switch (action.type) {
|
|
12
|
+
case 'SET_PLUGIN_READY': {
|
|
13
|
+
set(draftState, ['plugins', action.pluginId, 'isReady'], true);
|
|
14
|
+
break;
|
|
15
|
+
}
|
|
16
|
+
default:
|
|
17
|
+
return draftState;
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
export { initialState };
|
|
22
|
+
export default reducer;
|
|
@@ -61,7 +61,7 @@ function renderDraglayerItem({ type, item }) {
|
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
|
|
64
|
+
const App = () => {
|
|
65
65
|
const contentTypeMatch = useRouteMatch(`/content-manager/:kind/:uid`);
|
|
66
66
|
const { status, collectionTypeLinks, singleTypeLinks, models, refetchData } =
|
|
67
67
|
useContentManagerInitData();
|
|
@@ -123,10 +123,6 @@ export const ContentManger = () => {
|
|
|
123
123
|
|
|
124
124
|
return (
|
|
125
125
|
<Layout sideNav={<LeftMenu />}>
|
|
126
|
-
<Helmet
|
|
127
|
-
title={formatMessage({ id: getTrad('plugin.name'), defaultMessage: 'Content Manager' })}
|
|
128
|
-
/>
|
|
129
|
-
|
|
130
126
|
<DragLayer renderItem={renderDraglayerItem} />
|
|
131
127
|
<ModelsContext.Provider value={{ refetchData }}>
|
|
132
128
|
<Switch>
|
|
@@ -153,3 +149,18 @@ export const ContentManger = () => {
|
|
|
153
149
|
</Layout>
|
|
154
150
|
);
|
|
155
151
|
};
|
|
152
|
+
|
|
153
|
+
export { App };
|
|
154
|
+
|
|
155
|
+
export default function () {
|
|
156
|
+
const { formatMessage } = useIntl();
|
|
157
|
+
|
|
158
|
+
return (
|
|
159
|
+
<>
|
|
160
|
+
<Helmet
|
|
161
|
+
title={formatMessage({ id: getTrad('plugin.name'), defaultMessage: 'Content Manager' })}
|
|
162
|
+
/>
|
|
163
|
+
<App />
|
|
164
|
+
</>
|
|
165
|
+
);
|
|
166
|
+
}
|
|
@@ -5,7 +5,7 @@ import { useCMEditViewDataManager } from '@strapi/helper-plugin';
|
|
|
5
5
|
import PropTypes from 'prop-types';
|
|
6
6
|
import { useIntl } from 'react-intl';
|
|
7
7
|
|
|
8
|
-
import { getFullName } from '../../../../utils
|
|
8
|
+
import { getFullName } from '../../../../utils';
|
|
9
9
|
import { getTrad } from '../../../utils';
|
|
10
10
|
|
|
11
11
|
import getUnits from './utils/getUnits';
|
|
@@ -32,7 +32,7 @@ import { useSelector } from 'react-redux';
|
|
|
32
32
|
import { Link, useHistory } from 'react-router-dom';
|
|
33
33
|
import styled from 'styled-components';
|
|
34
34
|
|
|
35
|
-
import
|
|
35
|
+
import formatAPIError from '../../../../../../utils/formatAPIErrors';
|
|
36
36
|
import { getTrad, createYupSchema } from '../../../../../utils';
|
|
37
37
|
import { listViewDomain } from '../../../selectors';
|
|
38
38
|
import { Body } from '../../Body';
|
|
@@ -301,7 +301,7 @@ const SelectedEntriesModalContent = ({
|
|
|
301
301
|
onError(error) {
|
|
302
302
|
toggleNotification({
|
|
303
303
|
type: 'warning',
|
|
304
|
-
message:
|
|
304
|
+
message: formatAPIError(error),
|
|
305
305
|
});
|
|
306
306
|
},
|
|
307
307
|
}
|
|
@@ -23,7 +23,7 @@ import { useIntl } from 'react-intl';
|
|
|
23
23
|
import { Link, useHistory } from 'react-router-dom';
|
|
24
24
|
|
|
25
25
|
import { useEnterprise } from '../../../../../hooks/useEnterprise';
|
|
26
|
-
import { getFullName } from '../../../../../utils
|
|
26
|
+
import { getFullName } from '../../../../../utils';
|
|
27
27
|
import { usePluginsQueryParams } from '../../../../hooks';
|
|
28
28
|
import { getTrad } from '../../../../utils';
|
|
29
29
|
import CellContent from '../CellContent';
|
|
@@ -1,14 +1,9 @@
|
|
|
1
1
|
import { useEffect, useReducer } from 'react';
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
getYupInnerErrors,
|
|
5
|
-
useFetchClient,
|
|
6
|
-
useNotification,
|
|
7
|
-
useOverlayBlocker,
|
|
8
|
-
} from '@strapi/helper-plugin';
|
|
3
|
+
import { useFetchClient, useNotification, useOverlayBlocker } from '@strapi/helper-plugin';
|
|
9
4
|
import omit from 'lodash/omit';
|
|
10
5
|
|
|
11
|
-
import { formatAPIErrors } from '../../utils
|
|
6
|
+
import { checkFormValidity, formatAPIErrors } from '../../utils';
|
|
12
7
|
|
|
13
8
|
import init from './init';
|
|
14
9
|
import { initialState, reducer } from './reducer';
|
|
@@ -81,13 +76,7 @@ const useSettingsForm = (endPoint, schema, cbSuccess, fieldsToPick) => {
|
|
|
81
76
|
const handleSubmit = async (e) => {
|
|
82
77
|
e.preventDefault();
|
|
83
78
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
try {
|
|
87
|
-
await schema.validate(modifiedData, { abortEarly: false });
|
|
88
|
-
} catch (err) {
|
|
89
|
-
errors = getYupInnerErrors(err);
|
|
90
|
-
}
|
|
79
|
+
const errors = await checkFormValidity(modifiedData, schema);
|
|
91
80
|
|
|
92
81
|
dispatch({
|
|
93
82
|
type: 'SET_ERRORS',
|
|
@@ -7,8 +7,8 @@ import { selectAdminPermissions } from '../../pages/App/selectors';
|
|
|
7
7
|
import { useEnterprise } from '../useEnterprise';
|
|
8
8
|
|
|
9
9
|
import { LINKS_CE } from './constants';
|
|
10
|
-
import
|
|
11
|
-
import
|
|
10
|
+
import formatLinks from './utils/formatLinks';
|
|
11
|
+
import sortLinks from './utils/sortLinks';
|
|
12
12
|
|
|
13
13
|
const useSettingsMenu = () => {
|
|
14
14
|
const [{ isLoading, menu }, setData] = useState({
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
const formatLinks = (menu) => {
|
|
2
2
|
return menu.map((menuSection) => {
|
|
3
3
|
const formattedLinks = menuSection.links.map((link) => ({
|
|
4
4
|
...link,
|
|
@@ -8,3 +8,5 @@ export const formatLinks = (menu) => {
|
|
|
8
8
|
return { ...menuSection, links: formattedLinks };
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
|
+
|
|
12
|
+
export default formatLinks;
|
package/admin/src/index.js
CHANGED
|
@@ -52,7 +52,7 @@ const run = async () => {
|
|
|
52
52
|
|
|
53
53
|
// We need to make sure to fetch the project type before importing the StrapiApp
|
|
54
54
|
// otherwise the strapi-babel-plugin does not work correctly
|
|
55
|
-
const StrapiApp = await import(/* webpackChunkName: "
|
|
55
|
+
const StrapiApp = await import(/* webpackChunkName: "admin-app" */ './StrapiApp');
|
|
56
56
|
|
|
57
57
|
const app = StrapiApp.default({
|
|
58
58
|
appPlugins: plugins,
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import { Box, Flex, SkipToContent } from '@strapi/design-system';
|
|
4
|
+
import PropTypes from 'prop-types';
|
|
5
|
+
import { useIntl } from 'react-intl';
|
|
6
|
+
import styled from 'styled-components';
|
|
7
|
+
|
|
8
|
+
const FlexBox = styled(Box)`
|
|
9
|
+
flex: 1;
|
|
10
|
+
`;
|
|
11
|
+
|
|
12
|
+
const AppLayout = ({ children, sideNav }) => {
|
|
13
|
+
const { formatMessage } = useIntl();
|
|
14
|
+
|
|
15
|
+
return (
|
|
16
|
+
<Box background="neutral100">
|
|
17
|
+
<SkipToContent>
|
|
18
|
+
{formatMessage({ id: 'skipToContent', defaultMessage: 'Skip to content' })}
|
|
19
|
+
</SkipToContent>
|
|
20
|
+
<Flex alignItems="flex-start">
|
|
21
|
+
{sideNav}
|
|
22
|
+
<FlexBox>{children}</FlexBox>
|
|
23
|
+
</Flex>
|
|
24
|
+
</Box>
|
|
25
|
+
);
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
AppLayout.propTypes = {
|
|
29
|
+
children: PropTypes.node.isRequired,
|
|
30
|
+
sideNav: PropTypes.node.isRequired,
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export default AppLayout;
|
|
@@ -75,7 +75,7 @@ const TextLink = styled(TypographyLineHeight)`
|
|
|
75
75
|
}
|
|
76
76
|
`;
|
|
77
77
|
|
|
78
|
-
|
|
78
|
+
const Onboarding = () => {
|
|
79
79
|
const triggerRef = useRef();
|
|
80
80
|
const [isOpen, setIsOpen] = useState(false);
|
|
81
81
|
const { formatMessage } = useIntl();
|
|
@@ -222,3 +222,5 @@ export const Onboarding = () => {
|
|
|
222
222
|
</Box>
|
|
223
223
|
);
|
|
224
224
|
};
|
|
225
|
+
|
|
226
|
+
export default Onboarding;
|