@strapi/admin 4.12.5 → 4.12.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.
Files changed (159) hide show
  1. package/admin/src/StrapiApp.js +1 -1
  2. package/admin/src/components/AuthenticatedApp.js +229 -0
  3. package/admin/src/components/GuidedTour/Modal/index.js +1 -3
  4. package/admin/src/content-manager/pages/App/index.js +5 -16
  5. package/admin/src/content-manager/pages/EditView/Information/index.js +1 -1
  6. package/admin/src/content-manager/pages/ListView/components/BulkActionButtons/SelectedEntriesModal/index.js +2 -2
  7. package/admin/src/content-manager/pages/ListView/components/TableRows/index.js +1 -1
  8. package/admin/src/hooks/useSettingsForm/index.js +14 -3
  9. package/admin/src/hooks/useSettingsMenu/index.js +2 -2
  10. package/admin/src/hooks/useSettingsMenu/utils/formatLinks.js +1 -3
  11. package/admin/src/hooks/useSettingsMenu/utils/sortLinks.js +1 -3
  12. package/admin/src/index.js +1 -1
  13. package/admin/src/pages/Admin/Onboarding/index.js +1 -3
  14. package/admin/src/pages/Admin/index.js +80 -74
  15. package/admin/src/pages/App/constants.js +1 -1
  16. package/admin/src/pages/App/index.js +160 -122
  17. package/admin/src/pages/AuthPage/index.js +2 -4
  18. package/admin/src/pages/HomePage/index.js +1 -3
  19. package/admin/src/pages/InstalledPluginsPage/index.js +1 -3
  20. package/admin/src/pages/{InternalErrorPage/index.js → InternalErrorPage.js} +3 -4
  21. package/admin/src/pages/{NotFoundPage/index.js → NotFoundPage.js} +1 -3
  22. package/admin/src/pages/ProfilePage/index.js +2 -4
  23. package/admin/src/pages/SettingsPage/components/SettingsNav/index.js +3 -3
  24. package/admin/src/pages/SettingsPage/constants.js +67 -132
  25. package/admin/src/pages/SettingsPage/index.js +31 -36
  26. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/index.js +1 -1
  27. package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/index.js +69 -35
  28. package/admin/src/pages/SettingsPage/pages/TransferTokens/EditView/index.js +1 -1
  29. package/admin/src/pages/SettingsPage/pages/Users/EditPage/index.js +2 -1
  30. package/admin/src/pages/SettingsPage/pages/Users/ListPage/DynamicTable/TableRows/index.js +1 -1
  31. package/admin/src/pages/UseCasePage.js +174 -0
  32. package/admin/src/utils/createRoute.js +5 -7
  33. package/admin/src/utils/formatAPIErrors.js +1 -3
  34. package/admin/src/utils/getFullName.js +1 -1
  35. package/admin/src/utils/sortLinks.js +1 -3
  36. package/admin/src/utils/uniqueAdminHash.js +2 -9
  37. package/build/{1049.f76cb14b.chunk.js → 1049.9d69d231.chunk.js} +1 -1
  38. package/build/1504.eff012f7.chunk.js +95 -0
  39. package/build/2166.c837469a.chunk.js +1 -0
  40. package/build/2225.33287e1b.chunk.js +79 -0
  41. package/build/2237.03792b63.chunk.js +114 -0
  42. package/build/2379.401f56f3.chunk.js +1 -0
  43. package/build/2395.e6a79fbb.chunk.js +26 -0
  44. package/build/{9806.5d5a0e8d.chunk.js → 2747.d1442a90.chunk.js} +72 -64
  45. package/build/2801.31393ffe.chunk.js +1 -0
  46. package/build/3483.8517171f.chunk.js +1 -0
  47. package/build/502.8dd074ff.chunk.js +1 -0
  48. package/build/5483.5bfbb00d.chunk.js +6 -0
  49. package/build/7464.592a9295.chunk.js +1 -0
  50. package/build/748.fd2e5afd.chunk.js +105 -0
  51. package/build/773.6381d62d.chunk.js +18 -0
  52. package/build/7826.399afe81.chunk.js +103 -0
  53. package/build/8261.2525d35c.chunk.js +7 -0
  54. package/build/8276.e519a707.chunk.js +26 -0
  55. package/build/8299.62b67c72.chunk.js +1 -0
  56. package/build/Admin-AuthPage.90d64342.chunk.js +35 -0
  57. package/build/Admin-AuthenticatedApp.379ac945.chunk.js +24 -0
  58. package/build/Admin-UseCasePage.1f757db5.chunk.js +13 -0
  59. package/build/Admin_GuidedTourModal.8ccf1fbc.chunk.js +12 -0
  60. package/build/Admin_InternalErrorPage.9de92c6d.chunk.js +9 -0
  61. package/build/Admin_NotFoundPage.21620424.chunk.js +9 -0
  62. package/build/Admin_Onboarding.dbfa32f6.chunk.js +43 -0
  63. package/build/Admin_homePage.2000cbe9.chunk.js +86 -0
  64. package/build/Admin_marketplace.ec80e29b.chunk.js +63 -0
  65. package/build/Admin_pluginsPage.0c6851f8.chunk.js +14 -0
  66. package/build/Admin_profilePage.78cd8495.chunk.js +21 -0
  67. package/build/Admin_settingsPage.1760c3ce.chunk.js +119 -0
  68. package/build/StrapiApp.221fac30.chunk.js +5 -0
  69. package/build/{admin-edit-roles-page.6d567273.chunk.js → admin-edit-roles-page.24bdf746.chunk.js} +1 -1
  70. package/build/admin-edit-users.5d10d444.chunk.js +10 -0
  71. package/build/{admin-users.00e20017.chunk.js → admin-users.2b3e4305.chunk.js} +2 -2
  72. package/build/{content-manager.b40f79c0.chunk.js → content-manager.fb0833bd.chunk.js} +78 -78
  73. package/build/{content-type-builder.cd999f6e.chunk.js → content-type-builder.66066281.chunk.js} +18 -18
  74. package/build/email-settings-page.2f7e35c0.chunk.js +11 -0
  75. package/build/index.html +1 -1
  76. package/build/main.ee3c1938.js +2859 -0
  77. package/build/review-workflows-settings-create-view.d24a32b9.chunk.js +1 -0
  78. package/build/review-workflows-settings-edit-view.6044b022.chunk.js +1 -0
  79. package/build/review-workflows-settings-list-view.3f0ef4bc.chunk.js +56 -0
  80. package/build/runtime~main.397ee447.js +2 -0
  81. package/build/{sso-settings-page.12b6d8ae.chunk.js → sso-settings-page.4dba0670.chunk.js} +1 -1
  82. package/build/users-advanced-settings-page.17052d72.chunk.js +9 -0
  83. package/build/users-email-settings-page.3de8ea50.chunk.js +9 -0
  84. package/build/users-providers-settings-page.0eaa916d.chunk.js +14 -0
  85. package/build/users-roles-settings-page.957ad48b.chunk.js +55 -0
  86. package/build/webhook-edit-page.665210af.chunk.js +33 -0
  87. package/ee/admin/hooks/useAuthProviders.js +25 -0
  88. package/ee/admin/hooks/{useLicenseLimitNotification/index.js → useLicenseLimitNotification.js} +2 -4
  89. package/ee/admin/hooks/{useLicenseLimits/useLicenseLimits.js → useLicenseLimits.js} +4 -1
  90. package/ee/admin/pages/App/constants.js +6 -5
  91. package/ee/admin/pages/AuthPage/components/Login/index.js +8 -4
  92. package/ee/admin/pages/AuthPage/components/Providers/index.js +8 -5
  93. package/ee/admin/pages/HomePage/index.js +1 -1
  94. package/ee/admin/pages/SettingsPage/constants.js +27 -42
  95. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/pages/CreateView/CreateView.js +1 -1
  96. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/pages/EditView/EditView.js +1 -1
  97. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/pages/ListView/ListView.js +1 -1
  98. package/ee/admin/pages/SettingsPage/pages/Users/ListPage/CreateAction/index.js +1 -1
  99. package/ee/admin/pages/SettingsPage/pages/Users/ListPage/index.js +1 -1
  100. package/package.json +8 -8
  101. package/admin/src/components/AuthenticatedApp/index.js +0 -118
  102. package/admin/src/components/AuthenticatedApp/utils/api.js +0 -85
  103. package/admin/src/components/AuthenticatedApp/utils/checkLatestStrapiVersion.js +0 -11
  104. package/admin/src/components/PluginsInitializer/index.js +0 -68
  105. package/admin/src/components/PluginsInitializer/init.js +0 -11
  106. package/admin/src/components/PluginsInitializer/reducer.js +0 -22
  107. package/admin/src/layouts/AppLayout/index.js +0 -33
  108. package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/utils/api.js +0 -23
  109. package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/utils/prefixAllUrls.js +0 -17
  110. package/admin/src/pages/SettingsPage/utils/createSectionsRoutes.js +0 -11
  111. package/admin/src/pages/SettingsPage/utils/getSectionsToDisplay.js +0 -5
  112. package/admin/src/pages/SettingsPage/utils/index.js +0 -2
  113. package/admin/src/pages/UseCasePage/index.js +0 -175
  114. package/admin/src/utils/checkFormValidity.js +0 -15
  115. package/admin/src/utils/getAttributesToDisplay.js +0 -19
  116. package/admin/src/utils/getExistingActions.js +0 -32
  117. package/admin/src/utils/index.js +0 -9
  118. package/admin/src/utils/makeUniqueRoutes.js +0 -6
  119. package/build/1386.879bcd90.chunk.js +0 -7
  120. package/build/2225.c6244756.chunk.js +0 -79
  121. package/build/2379.f1641312.chunk.js +0 -1
  122. package/build/2395.46f8d0c1.chunk.js +0 -26
  123. package/build/2801.5cef5ec8.chunk.js +0 -1
  124. package/build/3483.03c24f96.chunk.js +0 -1
  125. package/build/3739.63e352f1.chunk.js +0 -103
  126. package/build/3929.5632f24d.chunk.js +0 -114
  127. package/build/448.829e1344.chunk.js +0 -1
  128. package/build/502.8ae8ef60.chunk.js +0 -1
  129. package/build/5483.6dd2e776.chunk.js +0 -6
  130. package/build/5542.2415a393.chunk.js +0 -63
  131. package/build/6691.4985ef22.chunk.js +0 -105
  132. package/build/7464.3e64a1d5.chunk.js +0 -1
  133. package/build/8276.10a3f883.chunk.js +0 -26
  134. package/build/9944.7af075a5.chunk.js +0 -26
  135. package/build/Admin-authenticatedApp.01fc56de.chunk.js +0 -79
  136. package/build/Admin_InternalErrorPage.f45f2462.chunk.js +0 -1
  137. package/build/Admin_homePage.ac9dfb86.chunk.js +0 -81
  138. package/build/Admin_marketplace.c94239f6.chunk.js +0 -55
  139. package/build/Admin_pluginsPage.bbe79434.chunk.js +0 -6
  140. package/build/Admin_profilePage.192edc52.chunk.js +0 -13
  141. package/build/Admin_settingsPage.97cb9d41.chunk.js +0 -111
  142. package/build/admin-app.91898385.chunk.js +0 -36
  143. package/build/admin-edit-users.acfd4128.chunk.js +0 -10
  144. package/build/email-settings-page.d494d1eb.chunk.js +0 -11
  145. package/build/main.9dbe4579.js +0 -2859
  146. package/build/review-workflows-settings-create-view.cb08cfa2.chunk.js +0 -1
  147. package/build/review-workflows-settings-edit-view.3c7cbe63.chunk.js +0 -1
  148. package/build/review-workflows-settings-list-view.1611dc1f.chunk.js +0 -56
  149. package/build/runtime~main.46a609e9.js +0 -2
  150. package/build/users-advanced-settings-page.f0760eb8.chunk.js +0 -9
  151. package/build/users-email-settings-page.ff4b32f3.chunk.js +0 -9
  152. package/build/users-providers-settings-page.48de0306.chunk.js +0 -14
  153. package/build/users-roles-settings-page.9d9a1eff.chunk.js +0 -30
  154. package/build/webhook-edit-page.6cb479ff.chunk.js +0 -33
  155. package/ee/admin/hooks/index.js +0 -4
  156. package/ee/admin/hooks/useAuthProviders/index.js +0 -50
  157. package/ee/admin/hooks/useAuthProviders/reducer.js +0 -26
  158. package/ee/admin/hooks/useLicenseLimits/index.js +0 -1
  159. /package/ee/admin/hooks/{useLicenseLimits/__mocks__/index.js → __mocks__/useLicenseLimits.js} +0 -0
@@ -22,7 +22,7 @@ import {
22
22
  } from './exposedHooks';
23
23
  import favicon from './favicon.png';
24
24
  import injectionZones from './injectionZones';
25
- import App from './pages/App';
25
+ import { App } from './pages/App';
26
26
  import languageNativeNames from './translations/languageNativeNames';
27
27
 
28
28
  class StrapiApp {
@@ -0,0 +1,229 @@
1
+ import * as React from 'react';
2
+
3
+ import {
4
+ AppInfoProvider,
5
+ auth,
6
+ LoadingIndicatorPage,
7
+ useFetchClient,
8
+ useGuidedTour,
9
+ useNotification,
10
+ useStrapiApp,
11
+ } from '@strapi/helper-plugin';
12
+ import { useQueries } from 'react-query';
13
+ import { valid, lt } from 'semver';
14
+
15
+ import packageJSON from '../../../package.json';
16
+ import { useConfigurations } from '../hooks';
17
+ import { Admin } from '../pages/Admin';
18
+ import { getFullName } from '../utils/getFullName';
19
+ import { hashAdminUserEmail } from '../utils/uniqueAdminHash';
20
+
21
+ import RBACProvider from './RBACProvider';
22
+
23
+ const strapiVersion = packageJSON.version;
24
+
25
+ const checkLatestStrapiVersion = (currentPackageVersion, latestPublishedVersion) => {
26
+ if (!valid(currentPackageVersion) || !valid(latestPublishedVersion)) {
27
+ return false;
28
+ }
29
+
30
+ return lt(currentPackageVersion, latestPublishedVersion);
31
+ };
32
+
33
+ export const AuthenticatedApp = () => {
34
+ const { setGuidedTourVisibility } = useGuidedTour();
35
+ const toggleNotification = useNotification();
36
+ const userInfo = auth.getUserInfo();
37
+ const { get } = useFetchClient();
38
+ // TODO: replace with getDisplayName()
39
+ const [userDisplayName, setUserDisplayName] = React.useState(
40
+ userInfo?.userName ?? getFullName(userInfo.firstname, userInfo.lastname)
41
+ );
42
+ const [userId, setUserId] = React.useState(null);
43
+ const { showReleaseNotification } = useConfigurations();
44
+ const { plugins: appPlugins = {} } = useStrapiApp();
45
+ const [plugins, setPlugins] = React.useState(appPlugins);
46
+ const [
47
+ { data: appInfos, isLoading: isLoadingAppInfos },
48
+ { data: tagName },
49
+ { data: permissions, isLoading: isLoadingPermissions, refetch },
50
+ { data: userRoles },
51
+ ] = useQueries([
52
+ {
53
+ queryKey: 'information',
54
+ async queryFn() {
55
+ const {
56
+ data: { data },
57
+ } = await get('/admin/information');
58
+
59
+ return data;
60
+ },
61
+ },
62
+
63
+ {
64
+ queryKey: 'strapi-release',
65
+ async queryFn() {
66
+ const res = await fetch('https://api.github.com/repos/strapi/strapi/releases/latest');
67
+
68
+ if (!res.ok) {
69
+ throw new Error('Failed to fetch latest Strapi version.');
70
+ }
71
+
72
+ const { tag_name } = await res.json();
73
+
74
+ return tag_name;
75
+ },
76
+ enabled: showReleaseNotification,
77
+ initialData: strapiVersion,
78
+ onSuccess(data) {
79
+ const shouldUpdateStrapi = checkLatestStrapiVersion(strapiVersion, data.tag_name);
80
+
81
+ if (shouldUpdateStrapi && !JSON.parse(localStorage.getItem('STRAPI_UPDATE_NOTIF'))) {
82
+ toggleNotification({
83
+ type: 'info',
84
+ message: { id: 'notification.version.update.message' },
85
+ link: {
86
+ url: `https://github.com/strapi/strapi/releases/tag/${data.tag_name}`,
87
+ label: {
88
+ id: 'global.see-more',
89
+ },
90
+ },
91
+ blockTransition: true,
92
+ onClose: () => localStorage.setItem('STRAPI_UPDATE_NOTIF', true),
93
+ });
94
+ }
95
+ },
96
+ retry: false,
97
+ },
98
+ {
99
+ queryKey: ['users', 'me', 'permissions'],
100
+ async queryFn() {
101
+ const {
102
+ data: { data },
103
+ } = await get('/admin/users/me/permissions');
104
+
105
+ return data;
106
+ },
107
+ initialData: [],
108
+ },
109
+
110
+ {
111
+ queryKey: ['users', 'me'],
112
+ async queryFn() {
113
+ const {
114
+ data: {
115
+ data: { roles },
116
+ },
117
+ } = await get('/admin/users/me');
118
+
119
+ return roles;
120
+ },
121
+ },
122
+ ]);
123
+
124
+ // Display the guided tour conditionally for super admins in development mode
125
+ React.useEffect(() => {
126
+ if (userRoles) {
127
+ const isUserSuperAdmin = userRoles.find(({ code }) => code === 'strapi-super-admin');
128
+
129
+ if (isUserSuperAdmin && appInfos?.currentEnvironment === 'development') {
130
+ setGuidedTourVisibility(true);
131
+ }
132
+ }
133
+ }, [userRoles, appInfos, setGuidedTourVisibility]);
134
+
135
+ // Create a hash of the users email adress and use it as ID for tracking
136
+ React.useEffect(() => {
137
+ const generateUserId = async (userInfo) => {
138
+ const userId = await hashAdminUserEmail(userInfo);
139
+ setUserId(userId);
140
+ };
141
+
142
+ if (userInfo) {
143
+ generateUserId(userInfo);
144
+ }
145
+ }, [userInfo]);
146
+
147
+ /**
148
+ *
149
+ * I have spent some time trying to understand what is happening here, and wanted to
150
+ * leave that knowledge for my future me:
151
+ *
152
+ * `initializer` is an undocumented property of the `registerPlugin` API. At the time
153
+ * of writing it seems only to be used by the i18n plugin.
154
+ *
155
+ * How does it work?
156
+ *
157
+ * Every plugin that has an `initializer` component defined, receives the
158
+ * `setPlugin` function as a component prop. In the case of i18n the plugin fetches locales
159
+ * first and calls `setPlugin` with `pluginId` once they are loaded, which then triggers the
160
+ * reducer of the admin app defined above.
161
+ *
162
+ * Once all plugins are set to `isReady: true` the app renders.
163
+ *
164
+ * This API is used to block rendering of the admin app. We should remove that in v5 completely
165
+ * and make sure plugins can inject data into the global store before they are initialized, to avoid
166
+ * having a new prop-callback based communication channel between plugins and the core admin app.
167
+ *
168
+ */
169
+
170
+ const hasApluginNotReady = Object.values(plugins).some((plugin) => plugin.isReady === false);
171
+
172
+ if (
173
+ !userDisplayName ||
174
+ !userId ||
175
+ isLoadingAppInfos ||
176
+ isLoadingPermissions ||
177
+ hasApluginNotReady
178
+ ) {
179
+ const initializers = Object.keys(plugins).reduce((acc, current) => {
180
+ const InitializerComponent = plugins[current].initializer;
181
+
182
+ if (InitializerComponent) {
183
+ const key = plugins[current].pluginId;
184
+
185
+ acc.push(
186
+ <InitializerComponent
187
+ key={key}
188
+ setPlugin={(pluginId) => {
189
+ setPlugins((prev) => ({
190
+ ...prev,
191
+ [pluginId]: {
192
+ ...prev[pluginId],
193
+ isReady: true,
194
+ },
195
+ }));
196
+ }}
197
+ />
198
+ );
199
+ }
200
+
201
+ return acc;
202
+ }, []);
203
+
204
+ return (
205
+ <>
206
+ {initializers}
207
+ <LoadingIndicatorPage />
208
+ </>
209
+ );
210
+ }
211
+
212
+ return (
213
+ <AppInfoProvider
214
+ {...appInfos}
215
+ userId={userId}
216
+ latestStrapiReleaseTag={tagName}
217
+ // TODO: setUserDisplayName should not exist and be removed, as it is only used
218
+ // to update the displayName immediately, in case a user updates their profile.
219
+ // This information should be derived from the state.
220
+ setUserDisplayName={setUserDisplayName}
221
+ shouldUpdateStrapi={checkLatestStrapiVersion(strapiVersion, tagName)}
222
+ userDisplayName={userDisplayName}
223
+ >
224
+ <RBACProvider permissions={permissions} refetchPermissions={refetch}>
225
+ <Admin />
226
+ </RBACProvider>
227
+ </AppInfoProvider>
228
+ );
229
+ };
@@ -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
- const GuidedTourModal = () => {
12
+ export const GuidedTourModal = () => {
13
13
  const {
14
14
  currentStep,
15
15
  guidedTourState,
@@ -90,5 +90,3 @@ const GuidedTourModal = () => {
90
90
 
91
91
  return null;
92
92
  };
93
-
94
- export default GuidedTourModal;
@@ -61,7 +61,7 @@ function renderDraglayerItem({ type, item }) {
61
61
  }
62
62
  }
63
63
 
64
- const App = () => {
64
+ export const ContentManger = () => {
65
65
  const contentTypeMatch = useRouteMatch(`/content-manager/:kind/:uid`);
66
66
  const { status, collectionTypeLinks, singleTypeLinks, models, refetchData } =
67
67
  useContentManagerInitData();
@@ -123,6 +123,10 @@ const App = () => {
123
123
 
124
124
  return (
125
125
  <Layout sideNav={<LeftMenu />}>
126
+ <Helmet
127
+ title={formatMessage({ id: getTrad('plugin.name'), defaultMessage: 'Content Manager' })}
128
+ />
129
+
126
130
  <DragLayer renderItem={renderDraglayerItem} />
127
131
  <ModelsContext.Provider value={{ refetchData }}>
128
132
  <Switch>
@@ -149,18 +153,3 @@ const App = () => {
149
153
  </Layout>
150
154
  );
151
155
  };
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/getFullName';
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 formatAPIError from '../../../../../../utils/formatAPIErrors';
35
+ import { formatAPIErrors } 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: formatAPIError(error),
304
+ message: formatAPIErrors(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/getFullName';
27
27
  import { usePluginsQueryParams } from '../../../../hooks';
28
28
  import { getTrad } from '../../../../utils';
29
29
  import CellContent from '../CellContent';
@@ -1,9 +1,14 @@
1
1
  import { useEffect, useReducer } from 'react';
2
2
 
3
- import { useFetchClient, useNotification, useOverlayBlocker } from '@strapi/helper-plugin';
3
+ import {
4
+ getYupInnerErrors,
5
+ useFetchClient,
6
+ useNotification,
7
+ useOverlayBlocker,
8
+ } from '@strapi/helper-plugin';
4
9
  import omit from 'lodash/omit';
5
10
 
6
- import { checkFormValidity, formatAPIErrors } from '../../utils';
11
+ import { formatAPIErrors } from '../../utils/formatAPIErrors';
7
12
 
8
13
  import init from './init';
9
14
  import { initialState, reducer } from './reducer';
@@ -76,7 +81,13 @@ const useSettingsForm = (endPoint, schema, cbSuccess, fieldsToPick) => {
76
81
  const handleSubmit = async (e) => {
77
82
  e.preventDefault();
78
83
 
79
- const errors = await checkFormValidity(modifiedData, schema);
84
+ let errors = null;
85
+
86
+ try {
87
+ await schema.validate(modifiedData, { abortEarly: false });
88
+ } catch (err) {
89
+ errors = getYupInnerErrors(err);
90
+ }
80
91
 
81
92
  dispatch({
82
93
  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 formatLinks from './utils/formatLinks';
11
- import sortLinks from './utils/sortLinks';
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
- const formatLinks = (menu) => {
1
+ export const formatLinks = (menu) => {
2
2
  return menu.map((menuSection) => {
3
3
  const formattedLinks = menuSection.links.map((link) => ({
4
4
  ...link,
@@ -8,5 +8,3 @@ const formatLinks = (menu) => {
8
8
  return { ...menuSection, links: formattedLinks };
9
9
  });
10
10
  };
11
-
12
- export default formatLinks;
@@ -1,5 +1,3 @@
1
1
  import sortBy from 'lodash/sortBy';
2
2
 
3
- const sortLinks = (links) => sortBy(links, (link) => link.id);
4
-
5
- export default sortLinks;
3
+ export const sortLinks = (links) => sortBy(links, (link) => link.id);
@@ -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: "admin-app" */ './StrapiApp');
55
+ const StrapiApp = await import(/* webpackChunkName: "StrapiApp" */ './StrapiApp');
56
56
 
57
57
  const app = StrapiApp.default({
58
58
  appPlugins: plugins,
@@ -75,7 +75,7 @@ const TextLink = styled(TypographyLineHeight)`
75
75
  }
76
76
  `;
77
77
 
78
- const Onboarding = () => {
78
+ export const Onboarding = () => {
79
79
  const triggerRef = useRef();
80
80
  const [isOpen, setIsOpen] = useState(false);
81
81
  const { formatMessage } = useIntl();
@@ -222,5 +222,3 @@ const Onboarding = () => {
222
222
  </Box>
223
223
  );
224
224
  };
225
-
226
- export default Onboarding;
@@ -4,80 +4,92 @@
4
4
  *
5
5
  */
6
6
 
7
- import React, { lazy, Suspense, useEffect, useMemo } from 'react';
7
+ import * as React from 'react';
8
8
 
9
+ import { Box, Flex } from '@strapi/design-system';
9
10
  import { LoadingIndicatorPage, useStrapiApp, useTracking } from '@strapi/helper-plugin';
10
11
  import { DndProvider } from 'react-dnd';
11
12
  import { HTML5Backend } from 'react-dnd-html5-backend';
12
13
  import { useDispatch, useSelector } from 'react-redux';
13
14
  import { Route, Switch } from 'react-router-dom';
14
15
 
15
- import GuidedTourModal from '../../components/GuidedTour/Modal';
16
16
  import LeftMenu from '../../components/LeftMenu';
17
- import { useConfigurations, useMenu } from '../../hooks';
18
- import AppLayout from '../../layouts/AppLayout';
19
- import { createRoute } from '../../utils';
17
+ import useConfigurations from '../../hooks/useConfigurations';
18
+ import useMenu from '../../hooks/useMenu';
19
+ import { createRoute } from '../../utils/createRoute';
20
20
  import { SET_APP_RUNTIME_STATUS } from '../App/constants';
21
21
 
22
- import Onboarding from './Onboarding';
23
-
24
- const CM = lazy(() =>
25
- import(/* webpackChunkName: "content-manager" */ '../../content-manager/pages/App')
22
+ const CM = React.lazy(() =>
23
+ import(/* webpackChunkName: "content-manager" */ '../../content-manager/pages/App').then(
24
+ (module) => ({ default: module.ContentManger })
25
+ )
26
26
  );
27
- const HomePage = lazy(() => import(/* webpackChunkName: "Admin_homePage" */ '../HomePage'));
28
- const InstalledPluginsPage = lazy(() =>
29
- import(/* webpackChunkName: "Admin_pluginsPage" */ '../InstalledPluginsPage')
27
+ const GuidedTourModal = React.lazy(() =>
28
+ import(/* webpackChunkName: "Admin_GuidedTourModal" */ '../../components/GuidedTour/Modal').then(
29
+ (module) => ({ default: module.GuidedTourModal })
30
+ )
30
31
  );
31
- const MarketplacePage = lazy(() =>
32
- import(/* webpackChunkName: "Admin_marketplace" */ '../MarketplacePage')
32
+ const HomePage = React.lazy(() =>
33
+ import(/* webpackChunkName: "Admin_homePage" */ '../HomePage').then((module) => ({
34
+ default: module.HomePage,
35
+ }))
33
36
  );
34
- const NotFoundPage = lazy(() =>
35
- import(/* webpackChunkName: "Admin_NotFoundPage" */ '../NotFoundPage')
37
+ const InstalledPluginsPage = React.lazy(() =>
38
+ import(/* webpackChunkName: "Admin_pluginsPage" */ '../InstalledPluginsPage').then((module) => ({
39
+ default: module.PluginsPage,
40
+ }))
36
41
  );
37
- const InternalErrorPage = lazy(() =>
38
- import(/* webpackChunkName: "Admin_InternalErrorPage" */ '../InternalErrorPage')
42
+ const MarketplacePage = React.lazy(() =>
43
+ import(/* webpackChunkName: "Admin_marketplace" */ '../MarketplacePage')
39
44
  );
40
-
41
- const ProfilePage = lazy(() =>
42
- import(/* webpackChunkName: "Admin_profilePage" */ '../ProfilePage')
45
+ const Onboarding = React.lazy(() =>
46
+ import(/* webpackChunkName: "Admin_Onboarding" */ './Onboarding').then((module) => ({
47
+ default: module.Onboarding,
48
+ }))
49
+ );
50
+ const ProfilePage = React.lazy(() =>
51
+ import(/* webpackChunkName: "Admin_profilePage" */ '../ProfilePage').then((module) => ({
52
+ default: module.ProfilePage,
53
+ }))
43
54
  );
44
- const SettingsPage = lazy(() =>
45
- import(/* webpackChunkName: "Admin_settingsPage" */ '../SettingsPage')
55
+ const SettingsPage = React.lazy(() =>
56
+ import(/* webpackChunkName: "Admin_settingsPage" */ '../SettingsPage').then((module) => ({
57
+ default: module.SettingsPage,
58
+ }))
46
59
  );
47
60
 
48
- // Simple hook easier for testing
49
- /**
50
- * TODO: remove this, it's bad.
51
- */
52
- const useTrackUsage = () => {
61
+ export const Admin = () => {
62
+ const { isLoading, generalSectionLinks, pluginsSectionLinks } = useMenu();
63
+ const { menu } = useStrapiApp();
64
+ const { showTutorials } = useConfigurations();
53
65
  const { trackUsage } = useTracking();
54
66
  const dispatch = useDispatch();
55
67
  const appStatus = useSelector((state) => state.admin_app.status);
56
68
 
57
- useEffect(() => {
69
+ React.useEffect(() => {
58
70
  // Make sure the event is only send once after accessing the admin panel
59
71
  // and not at runtime for example when regenerating the permissions with the ctb
60
72
  // or with i18n
61
73
  if (appStatus === 'init') {
62
74
  trackUsage('didAccessAuthenticatedAdministration');
63
-
64
75
  dispatch({ type: SET_APP_RUNTIME_STATUS });
65
76
  }
66
- // eslint-disable-next-line react-hooks/exhaustive-deps
67
- }, [appStatus]);
68
- };
77
+ }, [appStatus, dispatch, trackUsage]);
69
78
 
70
- const Admin = () => {
71
- useTrackUsage();
72
- const { isLoading, generalSectionLinks, pluginsSectionLinks } = useMenu();
73
- const { menu } = useStrapiApp();
74
- const { showTutorials } = useConfigurations();
79
+ const routes = menu
80
+ .filter((link) => link.Component)
75
81
 
76
- const routes = useMemo(() => {
77
- return menu
78
- .filter((link) => link.Component)
79
- .map(({ to, Component, exact }) => createRoute(Component, to, exact));
80
- }, [menu]);
82
+ /**
83
+ * `Component` is an async function, which is passed as property of the
84
+ * addMenuLink() API during the plugin registration step.
85
+ *
86
+ * Because of that we can't just render <Route component={Component} />,
87
+ * but have to await the function.
88
+ *
89
+ * This isn't a good React pattern and should be reconsidered.
90
+ */
91
+
92
+ .map(({ to, Component, exact }) => createRoute(Component, to, exact));
81
93
 
82
94
  if (isLoading) {
83
95
  return <LoadingIndicatorPage />;
@@ -85,40 +97,34 @@ const Admin = () => {
85
97
 
86
98
  return (
87
99
  <DndProvider backend={HTML5Backend}>
88
- <AppLayout
89
- sideNav={
90
- <LeftMenu
91
- generalSectionLinks={generalSectionLinks}
92
- pluginsSectionLinks={pluginsSectionLinks}
93
- />
94
- }
95
- >
96
- <Suspense fallback={<LoadingIndicatorPage />}>
97
- <Switch>
98
- <Route path="/" component={HomePage} exact />
99
- <Route path="/me" component={ProfilePage} exact />
100
- <Route path="/content-manager" component={CM} />
101
- {routes}
102
- <Route path="/settings/:settingId" component={SettingsPage} />
103
- <Route path="/settings" component={SettingsPage} exact />
104
- <Route path="/marketplace">
105
- <MarketplacePage />
106
- </Route>
107
- <Route path="/list-plugins" exact>
108
- <InstalledPluginsPage />
109
- </Route>
110
- <Route path="/404" component={NotFoundPage} />
111
- <Route path="/500" component={InternalErrorPage} />
112
- <Route path="" component={NotFoundPage} />
113
- </Switch>
114
- </Suspense>
100
+ <Flex alignItems="stretch">
101
+ <LeftMenu
102
+ generalSectionLinks={generalSectionLinks}
103
+ pluginsSectionLinks={pluginsSectionLinks}
104
+ />
105
+
106
+ <Box flex="1">
107
+ <React.Suspense fallback={<LoadingIndicatorPage />}>
108
+ <Switch>
109
+ <Route path="/" component={HomePage} exact />
110
+ <Route path="/me" component={ProfilePage} exact />
111
+ <Route path="/content-manager" component={CM} />
112
+ {routes}
113
+ <Route path="/settings/:settingId" component={SettingsPage} />
114
+ <Route path="/settings" component={SettingsPage} exact />
115
+ <Route path="/marketplace" component={MarketplacePage} />
116
+ <Route path="/list-plugins" component={InstalledPluginsPage} exact />
117
+ </Switch>
118
+ </React.Suspense>
119
+ </Box>
120
+
121
+ {/* TODO: we should move the logic to determine whether the guided tour is displayed
122
+ or not out of the component, to make the code-splitting more effective
123
+ */}
115
124
  <GuidedTourModal />
116
125
 
117
126
  {showTutorials && <Onboarding />}
118
- </AppLayout>
127
+ </Flex>
119
128
  </DndProvider>
120
129
  );
121
130
  };
122
-
123
- export default Admin;
124
- export { useTrackUsage };
@@ -1,4 +1,4 @@
1
1
  export const SET_APP_RUNTIME_STATUS = 'StrapiAdmin/APP/SET_APP_RUNTIME_STATUS';
2
2
  export const SET_ADMIN_PERMISSIONS = 'StrapiAdmin/App/SET_ADMIN_PERMISSIONS';
3
3
 
4
- export const ROUTES_CE = [];
4
+ export const AUTH_ROUTES_CE = [];