@strapi/admin 4.14.5 → 4.15.0

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 (226) hide show
  1. package/admin/src/StrapiApp.js +13 -12
  2. package/admin/src/components/AuthenticatedApp.tsx +187 -0
  3. package/admin/src/components/ConfigurationProvider.tsx +2 -1
  4. package/admin/src/components/GuidedTour/Homepage.tsx +111 -0
  5. package/admin/src/components/GuidedTour/Modal.tsx +303 -0
  6. package/admin/src/components/GuidedTour/Ornaments.tsx +74 -0
  7. package/admin/src/components/GuidedTour/Provider.tsx +253 -0
  8. package/admin/src/components/GuidedTour/{layout.js → constants.ts} +13 -3
  9. package/admin/src/components/LanguageProvider.tsx +1 -0
  10. package/admin/src/components/Providers.tsx +125 -0
  11. package/admin/src/components/RBACProvider.tsx +124 -0
  12. package/admin/src/components/Theme.tsx +4 -2
  13. package/admin/src/components/ThemeToggleProvider.tsx +23 -9
  14. package/admin/src/components/__mocks__/{LanguageProvider.js → LanguageProvider.ts} +2 -0
  15. package/admin/src/{constants.js → constants.ts} +48 -0
  16. package/admin/src/content-manager/components/BlocksEditor/Toolbar/index.js +75 -51
  17. package/admin/src/content-manager/components/BlocksEditor/hooks/useBlocksStore.js +72 -14
  18. package/admin/src/content-manager/pages/App/selectors.js +1 -1
  19. package/admin/src/content-manager/pages/App/useContentManagerInitData.js +3 -1
  20. package/admin/src/content-manager/pages/EditView/selectors.js +1 -1
  21. package/admin/src/content-manager/pages/EditViewLayoutManager/index.js +3 -1
  22. package/admin/src/content-manager/pages/ListView/components/Body/index.js +53 -56
  23. package/admin/src/content-manager/pages/ListView/components/BulkActionButtons/SelectedEntriesModal/index.js +5 -3
  24. package/admin/src/content-manager/pages/ListView/components/TableRows/index.js +1 -1
  25. package/admin/src/content-manager/pages/ListView/index.js +33 -50
  26. package/admin/src/content-manager/pages/ListView/selectors.js +1 -1
  27. package/admin/src/contexts/admin.ts +1 -0
  28. package/admin/src/contexts/apiTokenPermissions.tsx +64 -0
  29. package/admin/src/contexts/themeToggle.ts +3 -1
  30. package/admin/src/core/store/configure.ts +91 -0
  31. package/admin/src/core/store/hooks.ts +15 -0
  32. package/admin/src/hooks/index.js +0 -1
  33. package/admin/src/hooks/{useContentTypes/useContentTypes.js → useContentTypes.ts} +39 -16
  34. package/admin/src/hooks/useSettingsForm/index.js +14 -2
  35. package/admin/src/hooks/useSettingsMenu/constants.js +39 -0
  36. package/admin/src/index.js +2 -4
  37. package/admin/src/layouts/{AppLayout/index.js → AppLayout.tsx} +7 -10
  38. package/admin/src/layouts/UnauthenticatedLayout.tsx +77 -0
  39. package/admin/src/pages/Admin/index.js +11 -5
  40. package/admin/src/pages/App/index.js +7 -4
  41. package/admin/src/pages/App/selectors.js +1 -1
  42. package/admin/src/pages/AuthPage/components/ForgotPassword/index.js +2 -1
  43. package/admin/src/pages/AuthPage/components/ForgotPasswordSuccess/index.js +2 -1
  44. package/admin/src/pages/AuthPage/components/Login/index.js +1 -1
  45. package/admin/src/pages/AuthPage/components/Oops/index.js +2 -1
  46. package/admin/src/pages/AuthPage/components/Register/index.js +1 -1
  47. package/admin/src/pages/AuthPage/components/ResetPassword/index.js +2 -1
  48. package/admin/src/pages/AuthPage/index.js +2 -3
  49. package/admin/src/pages/HomePage/index.js +6 -3
  50. package/admin/src/pages/{InternalErrorPage/index.js → InternalErrorPage.tsx} +10 -6
  51. package/admin/src/pages/{NotFoundPage/index.js → NotFoundPage.tsx} +9 -7
  52. package/admin/src/pages/ProfilePage/components/Preferences/index.js +23 -9
  53. package/admin/src/pages/ProfilePage/index.js +1 -1
  54. package/admin/src/pages/SettingsPage/components/SettingsNav/index.js +20 -0
  55. package/admin/src/pages/SettingsPage/constants.js +33 -0
  56. package/admin/src/pages/SettingsPage/index.js +2 -2
  57. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/ActionBoundRoutes/index.js +1 -1
  58. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/CollapsableContentType/index.js +1 -1
  59. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/Permissions/index.js +1 -1
  60. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/index.js +2 -2
  61. package/admin/src/pages/SettingsPage/pages/AuditLogs/SalesPage.js +50 -0
  62. package/admin/src/pages/SettingsPage/pages/ReviewWorkflows/SalesPage.js +53 -0
  63. package/admin/src/pages/SettingsPage/pages/SingleSignOn/SalesPage.js +53 -0
  64. package/admin/src/pages/SettingsPage/pages/TransferTokens/EditView/index.js +1 -1
  65. package/admin/src/pages/SettingsPage/pages/Users/EditPage/index.js +2 -1
  66. package/admin/src/pages/SettingsPage/pages/Users/ListPage/DynamicTable/TableRows/index.js +1 -1
  67. package/admin/src/pages/{UseCasePage/index.js → UseCasePage.tsx} +10 -12
  68. package/admin/src/translations/en.json +5 -0
  69. package/admin/src/utils/createRoute.tsx +54 -0
  70. package/admin/src/utils/formatAPIErrors.ts +18 -0
  71. package/admin/src/utils/getFullName.ts +3 -0
  72. package/admin/src/utils/{uniqueAdminHash.js → hashAdminUserEmail.ts} +6 -3
  73. package/admin/src/utils/makeUniqueRoutes.ts +11 -0
  74. package/build/{1049.9236e785.chunk.js → 1049.ecc10c97.chunk.js} +1 -1
  75. package/build/1217.96155682.chunk.js +35 -0
  76. package/build/{1227.e0f7447b.chunk.js → 1227.947ceaf9.chunk.js} +1 -1
  77. package/build/1306.2699df52.chunk.js +79 -0
  78. package/build/{1386.07f2bbb3.chunk.js → 1386.eabd8a1e.chunk.js} +1 -1
  79. package/build/{2379.b0bc4013.chunk.js → 2379.7ce8e110.chunk.js} +1 -1
  80. package/build/{2395.d37b1025.chunk.js → 2395.acb961a8.chunk.js} +3 -3
  81. package/build/{2801.12522720.chunk.js → 2801.4711ea5a.chunk.js} +1 -1
  82. package/build/{3019.0d74d080.chunk.js → 3019.fde2e1be.chunk.js} +2 -2
  83. package/build/3460.8644e608.chunk.js +146 -0
  84. package/build/{3483.8f1b25f8.chunk.js → 3483.db8c1520.chunk.js} +1 -1
  85. package/build/{4174.2c4f958e.chunk.js → 4174.49cedb6a.chunk.js} +1 -1
  86. package/build/4732.149f5f8f.chunk.js +1 -0
  87. package/build/{502.b845473a.chunk.js → 502.f536f78b.chunk.js} +1 -1
  88. package/build/{7464.91341b4f.chunk.js → 7464.579564ac.chunk.js} +1 -1
  89. package/build/7811.fdbe09af.chunk.js +103 -0
  90. package/build/{7897.dffa5ad5.chunk.js → 7897.63ba0a00.chunk.js} +1 -1
  91. package/build/{8276.e9698944.chunk.js → 8276.9abe4679.chunk.js} +3 -3
  92. package/build/8773.ee67141c.chunk.js +48 -0
  93. package/build/9077.2cc01ac8.chunk.js +105 -0
  94. package/build/{9218.306ad178.chunk.js → 9218.b2d367f8.chunk.js} +1 -1
  95. package/build/Admin-authenticatedApp.059dc48f.chunk.js +79 -0
  96. package/build/Admin_InternalErrorPage.06eeef20.chunk.js +1 -0
  97. package/build/Admin_homePage.56b9eb3f.chunk.js +81 -0
  98. package/build/{Admin_marketplace.0db78604.chunk.js → Admin_marketplace.d693a435.chunk.js} +1 -1
  99. package/build/{Admin_pluginsPage.1083f7f0.chunk.js → Admin_pluginsPage.ae2c872a.chunk.js} +1 -1
  100. package/build/Admin_profilePage.89099d5b.chunk.js +13 -0
  101. package/build/Admin_settingsPage.88c45586.chunk.js +12 -0
  102. package/build/{Upload_ConfigureTheView.3cfeb108.chunk.js → Upload_ConfigureTheView.44f28145.chunk.js} +1 -1
  103. package/build/admin-app.990e112f.chunk.js +69 -0
  104. package/build/{admin-edit-roles-page.556fac52.chunk.js → admin-edit-roles-page.4e1eb4a9.chunk.js} +3 -3
  105. package/build/admin-edit-users.5b91404e.chunk.js +10 -0
  106. package/build/{admin-roles-list.15918328.chunk.js → admin-roles-list.89dd94fe.chunk.js} +1 -1
  107. package/build/{admin-users.74fddc87.chunk.js → admin-users.7be4fc5f.chunk.js} +2 -2
  108. package/build/{api-tokens-create-page.c08ae118.chunk.js → api-tokens-create-page.571920e5.chunk.js} +1 -1
  109. package/build/{api-tokens-edit-page.ce18efdc.chunk.js → api-tokens-edit-page.cbdc81b1.chunk.js} +1 -1
  110. package/build/{api-tokens-list-page.783b7569.chunk.js → api-tokens-list-page.de0c49e8.chunk.js} +2 -2
  111. package/build/audit-logs-sales-page.2955db88.chunk.js +1 -0
  112. package/build/{audit-logs-settings-page.12aeea8c.chunk.js → audit-logs-settings-page.b0cb5164.chunk.js} +1 -1
  113. package/build/content-manager.de7ae330.chunk.js +1241 -0
  114. package/build/{content-type-builder-list-view.38ed3935.chunk.js → content-type-builder-list-view.6c8d3213.chunk.js} +1 -1
  115. package/build/{content-type-builder-translation-en-json.43f9d7bc.chunk.js → content-type-builder-translation-en-json.74d80f18.chunk.js} +1 -1
  116. package/build/{content-type-builder.758a9d23.chunk.js → content-type-builder.0bc97051.chunk.js} +13 -23
  117. package/build/{email-settings-page.e08a587e.chunk.js → email-settings-page.07712efc.chunk.js} +1 -1
  118. package/build/en-json.5b907f67.chunk.js +1 -0
  119. package/build/{i18n-settings-page.3186e3e9.chunk.js → i18n-settings-page.5c34f012.chunk.js} +1 -1
  120. package/build/index.html +1 -1
  121. package/build/main.f84563f1.js +2665 -0
  122. package/build/review-workflows-sales-page.f46a8f00.chunk.js +1 -0
  123. package/build/{review-workflows-settings-create-view.5cdc4d64.chunk.js → review-workflows-settings-create-view.d0544fb0.chunk.js} +1 -1
  124. package/build/{review-workflows-settings-edit-view.53bf7865.chunk.js → review-workflows-settings-edit-view.aabf49ef.chunk.js} +1 -1
  125. package/build/review-workflows-settings-list-view.8b0525ab.chunk.js +56 -0
  126. package/build/runtime~main.270fd45f.js +2 -0
  127. package/build/sso-sales-page.ef22e469.chunk.js +1 -0
  128. package/build/sso-settings-page.21e16ae4.chunk.js +1 -0
  129. package/build/{transfer-tokens-create-page.2662d519.chunk.js → transfer-tokens-create-page.3366204d.chunk.js} +1 -1
  130. package/build/{transfer-tokens-edit-page.f64d8d8c.chunk.js → transfer-tokens-edit-page.15cf0f73.chunk.js} +1 -1
  131. package/build/{transfer-tokens-list-page.e6fd5f87.chunk.js → transfer-tokens-list-page.0bc0e682.chunk.js} +2 -2
  132. package/build/{upload-settings.450a1de0.chunk.js → upload-settings.1319dca0.chunk.js} +1 -1
  133. package/build/{upload.0d53e7a3.chunk.js → upload.1ced11be.chunk.js} +1 -1
  134. package/build/{users-advanced-settings-page.4a1f1f6d.chunk.js → users-advanced-settings-page.8e657084.chunk.js} +1 -1
  135. package/build/{users-email-settings-page.ea81fe82.chunk.js → users-email-settings-page.e57745e5.chunk.js} +1 -1
  136. package/build/{users-providers-settings-page.10280cdb.chunk.js → users-providers-settings-page.55796d13.chunk.js} +1 -1
  137. package/build/{users-roles-settings-page.4a7158be.chunk.js → users-roles-settings-page.57079245.chunk.js} +1 -1
  138. package/build/webhook-edit-page.3a28b2e7.chunk.js +33 -0
  139. package/build/{webhook-list-page.f57285ca.chunk.js → webhook-list-page.ee80767b.chunk.js} +1 -1
  140. package/ee/admin/pages/AuthPage/components/Login/index.js +1 -1
  141. package/ee/admin/pages/AuthPage/components/Providers/index.js +2 -1
  142. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/selectors.js +1 -1
  143. package/ee/server/bootstrap.js +1 -1
  144. package/ee/server/controllers/admin.js +1 -1
  145. package/ee/server/controllers/user.js +1 -1
  146. package/ee/server/destroy.js +1 -1
  147. package/ee/server/register.js +1 -1
  148. package/ee/server/routes/utils.js +1 -1
  149. package/ee/server/services/audit-logs.js +1 -1
  150. package/ee/server/services/passport/sso.js +1 -1
  151. package/ee/server/services/passport.js +1 -1
  152. package/ee/server/services/seat-enforcement.js +1 -1
  153. package/ee/server/utils/sso-lock.js +1 -1
  154. package/ee/server/validation/role.js +1 -1
  155. package/ee/server/validation/user.js +1 -1
  156. package/package.json +15 -16
  157. package/server/controllers/admin.js +1 -1
  158. package/shared/entities.ts +1 -1
  159. package/shared/permissions.ts +35 -35
  160. package/shared/schema.ts +9 -0
  161. package/admin/src/components/AuthenticatedApp/index.js +0 -116
  162. package/admin/src/components/AuthenticatedApp/utils/api.js +0 -47
  163. package/admin/src/components/AuthenticatedApp/utils/checkLatestStrapiVersion.ts +0 -13
  164. package/admin/src/components/AuthenticatedApp/utils/fetchStrapiLatestRelease.ts +0 -19
  165. package/admin/src/components/GuidedTour/Homepage/components/Step.js +0 -61
  166. package/admin/src/components/GuidedTour/Homepage/components/Stepper.js +0 -61
  167. package/admin/src/components/GuidedTour/Homepage/index.js +0 -71
  168. package/admin/src/components/GuidedTour/Modal/components/Content.js +0 -66
  169. package/admin/src/components/GuidedTour/Modal/components/Modal.js +0 -72
  170. package/admin/src/components/GuidedTour/Modal/components/StepNumberWithPadding.js +0 -26
  171. package/admin/src/components/GuidedTour/Modal/components/Stepper.js +0 -118
  172. package/admin/src/components/GuidedTour/Modal/index.js +0 -94
  173. package/admin/src/components/GuidedTour/Modal/reducer.js +0 -29
  174. package/admin/src/components/GuidedTour/Stepper/StepLine.js +0 -29
  175. package/admin/src/components/GuidedTour/Stepper/StepNumber.js +0 -71
  176. package/admin/src/components/GuidedTour/constants.js +0 -3
  177. package/admin/src/components/GuidedTour/index.js +0 -102
  178. package/admin/src/components/GuidedTour/init.js +0 -37
  179. package/admin/src/components/GuidedTour/reducer.js +0 -50
  180. package/admin/src/components/GuidedTour/utils/arePreviousSectionsDone.js +0 -13
  181. package/admin/src/components/GuidedTour/utils/arePreviousStepsDone.js +0 -12
  182. package/admin/src/components/GuidedTour/utils/isGuidedTourCompleted.js +0 -6
  183. package/admin/src/components/GuidedTour/utils/persistStateToLocaleStorage.js +0 -34
  184. package/admin/src/components/Providers/index.js +0 -156
  185. package/admin/src/components/RBACProvider/actions.js +0 -10
  186. package/admin/src/components/RBACProvider/constants.js +0 -2
  187. package/admin/src/components/RBACProvider/index.js +0 -39
  188. package/admin/src/components/RBACProvider/reducer.js +0 -51
  189. package/admin/src/contexts/ApiTokenPermissions/index.js +0 -25
  190. package/admin/src/core/store/configureStore.js +0 -47
  191. package/admin/src/exposedHooks.js +0 -27
  192. package/admin/src/hooks/useContentTypes/index.js +0 -1
  193. package/admin/src/injectionZones.js +0 -25
  194. package/admin/src/layouts/UnauthenticatedLayout/LocaleToggle/index.js +0 -29
  195. package/admin/src/layouts/UnauthenticatedLayout/index.js +0 -55
  196. package/admin/src/reducers.js +0 -23
  197. package/admin/src/utils/checkFormValidity.js +0 -15
  198. package/admin/src/utils/createRoute.js +0 -50
  199. package/admin/src/utils/formatAPIErrors.js +0 -17
  200. package/admin/src/utils/getAttributesToDisplay.js +0 -19
  201. package/admin/src/utils/getExistingActions.js +0 -32
  202. package/admin/src/utils/getFullName.js +0 -9
  203. package/admin/src/utils/index.js +0 -9
  204. package/admin/src/utils/makeUniqueRoutes.js +0 -6
  205. package/admin/src/utils/sortLinks.js +0 -5
  206. package/build/1222.fe92c653.chunk.js +0 -35
  207. package/build/2225.a2147b8f.chunk.js +0 -79
  208. package/build/3021.33ad47fb.chunk.js +0 -103
  209. package/build/6373.1a21d665.chunk.js +0 -105
  210. package/build/8894.5ca4852a.chunk.js +0 -26
  211. package/build/9302.550cf5b7.chunk.js +0 -146
  212. package/build/Admin-authenticatedApp.e897fccb.chunk.js +0 -79
  213. package/build/Admin_InternalErrorPage.e2431a95.chunk.js +0 -1
  214. package/build/Admin_homePage.71ef8d06.chunk.js +0 -81
  215. package/build/Admin_profilePage.61704b7d.chunk.js +0 -13
  216. package/build/Admin_settingsPage.39cb9fca.chunk.js +0 -111
  217. package/build/admin-app.06f5e70a.chunk.js +0 -69
  218. package/build/admin-edit-users.64fd1318.chunk.js +0 -10
  219. package/build/content-manager.2e3f660b.chunk.js +0 -1220
  220. package/build/en-json.bd611a8e.chunk.js +0 -1
  221. package/build/main.00ea6f5a.js +0 -2665
  222. package/build/review-workflows-settings-list-view.b4a8aefb.chunk.js +0 -56
  223. package/build/runtime~main.e3bf3980.js +0 -2
  224. package/build/sso-settings-page.6a35d473.chunk.js +0 -1
  225. package/build/webhook-edit-page.65ac30ee.chunk.js +0 -33
  226. /package/admin/src/hooks/{useContentTypes/__mocks__/index.js → __mocks__/useContentTypes.ts} +0 -0
@@ -10,23 +10,24 @@ import { BrowserRouter } from 'react-router-dom';
10
10
 
11
11
  import Logo from './assets/images/logo-strapi-2022.svg';
12
12
  import { LANGUAGE_LOCAL_STORAGE_KEY } from './components/LanguageProvider';
13
- import Providers from './components/Providers';
14
- import { customFields, Plugin } from './core/apis';
15
- import configureStore from './core/store/configureStore';
13
+ import { Providers } from './components/Providers';
14
+ import { HOOKS, INJECTION_ZONES } from './constants';
15
+ import { customFields, Plugin, Reducers } from './core/apis';
16
+ import { configureStore } from './core/store/configure';
16
17
  import { basename, createHook } from './core/utils';
17
- import {
18
+ import favicon from './favicon.png';
19
+ import App from './pages/App';
20
+ import languageNativeNames from './translations/languageNativeNames';
21
+
22
+ const {
18
23
  INJECT_COLUMN_IN_TABLE,
19
24
  MUTATE_COLLECTION_TYPES_LINKS,
20
25
  MUTATE_EDIT_VIEW_LAYOUT,
21
26
  MUTATE_SINGLE_TYPES_LINKS,
22
- } from './exposedHooks';
23
- import favicon from './favicon.png';
24
- import injectionZones from './injectionZones';
25
- import App from './pages/App';
26
- import languageNativeNames from './translations/languageNativeNames';
27
+ } = HOOKS;
27
28
 
28
29
  class StrapiApp {
29
- constructor({ adminConfig, appPlugins, library, middlewares, reducers }) {
30
+ constructor({ adminConfig, appPlugins, library, middlewares }) {
30
31
  this.customConfigurations = adminConfig.config;
31
32
  this.customBootstrapConfiguration = adminConfig.bootstrap;
32
33
  this.configurations = {
@@ -43,11 +44,11 @@ class StrapiApp {
43
44
  this.library = library;
44
45
  this.middlewares = middlewares;
45
46
  this.plugins = {};
46
- this.reducers = reducers;
47
+ this.reducers = Reducers({});
47
48
  this.translations = {};
48
49
  this.hooksDict = {};
49
50
  this.admin = {
50
- injectionZones,
51
+ injectionZones: INJECTION_ZONES,
51
52
  };
52
53
  this.customFields = customFields;
53
54
 
@@ -0,0 +1,187 @@
1
+ import * as React from 'react';
2
+
3
+ import {
4
+ AppInfoContextValue,
5
+ AppInfoProvider,
6
+ auth,
7
+ LoadingIndicatorPage,
8
+ useFetchClient,
9
+ useGuidedTour,
10
+ } from '@strapi/helper-plugin';
11
+ import { useQueries } from 'react-query';
12
+ import lt from 'semver/functions/lt';
13
+ import valid from 'semver/functions/valid';
14
+ // TODO: DS add loader
15
+
16
+ import packageJSON from '../../../package.json';
17
+ import { UserEntity } from '../../../shared/entities';
18
+ import { useConfiguration } from '../hooks/useConfiguration';
19
+ import { APIResponse, APIResponseUsersLegacy } from '../types/adminAPI';
20
+ import { getFullName } from '../utils/getFullName';
21
+ import { hashAdminUserEmail } from '../utils/hashAdminUserEmail';
22
+
23
+ import { NpsSurvey } from './NpsSurvey';
24
+ import { PluginsInitializer } from './PluginsInitializer';
25
+ import { RBACProvider, Permission } from './RBACProvider';
26
+
27
+ const strapiVersion = packageJSON.version;
28
+
29
+ const AuthenticatedApp = () => {
30
+ const { setGuidedTourVisibility } = useGuidedTour();
31
+ const userInfo = auth.get('userInfo');
32
+ const [userDisplayName, setUserDisplayName] = React.useState<string>(() =>
33
+ userInfo ? userInfo.username || getFullName(userInfo.firstname ?? '', userInfo.lastname) : ''
34
+ );
35
+ const [userId, setUserId] = React.useState<string>();
36
+ const { showReleaseNotification } = useConfiguration();
37
+ const { get } = useFetchClient();
38
+ const [
39
+ { data: appInfos, status },
40
+ { data: tagName, isLoading },
41
+ { data: permissions, status: fetchPermissionsStatus, refetch, isFetching },
42
+ { data: userRoles },
43
+ ] = useQueries([
44
+ {
45
+ queryKey: 'app-infos',
46
+ async queryFn() {
47
+ const { data } = await get<
48
+ APIResponse<
49
+ Pick<
50
+ AppInfoContextValue,
51
+ | 'currentEnvironment'
52
+ | 'autoReload'
53
+ | 'communityEdition'
54
+ | 'dependencies'
55
+ | 'useYarn'
56
+ | 'projectId'
57
+ | 'strapiVersion'
58
+ | 'nodeVersion'
59
+ >
60
+ >
61
+ >('/admin/information');
62
+
63
+ return data.data;
64
+ },
65
+ },
66
+ {
67
+ queryKey: 'strapi-release',
68
+ async queryFn() {
69
+ try {
70
+ const res = await fetch('https://api.github.com/repos/strapi/strapi/releases/latest');
71
+
72
+ if (!res.ok) {
73
+ throw new Error();
74
+ }
75
+
76
+ const response = (await res.json()) as { tag_name: string | null | undefined };
77
+
78
+ if (!response.tag_name) {
79
+ throw new Error();
80
+ }
81
+
82
+ return response.tag_name;
83
+ } catch (err) {
84
+ // Don't throw an error
85
+ return strapiVersion;
86
+ }
87
+ },
88
+ enabled: showReleaseNotification,
89
+ initialData: strapiVersion,
90
+ },
91
+ {
92
+ queryKey: 'admin-users-permission',
93
+ async queryFn() {
94
+ const { data } = await get<{ data: Permission[] }>('/admin/users/me/permissions');
95
+
96
+ return data.data;
97
+ },
98
+ initialData: [],
99
+ },
100
+ {
101
+ queryKey: 'user-roles',
102
+ async queryFn() {
103
+ const {
104
+ data: {
105
+ data: { roles },
106
+ },
107
+ } = await get<APIResponseUsersLegacy<UserEntity>>('/admin/users/me');
108
+
109
+ return roles;
110
+ },
111
+ },
112
+ ]);
113
+
114
+ const shouldUpdateStrapi = checkLatestStrapiVersion(strapiVersion, tagName);
115
+
116
+ /**
117
+ * TODO: does this actually need to be an effect?
118
+ */
119
+ React.useEffect(() => {
120
+ if (userRoles) {
121
+ const isUserSuperAdmin = userRoles.find(({ code }) => code === 'strapi-super-admin');
122
+
123
+ if (isUserSuperAdmin && appInfos?.autoReload) {
124
+ setGuidedTourVisibility(true);
125
+ }
126
+ }
127
+ }, [userRoles, appInfos, setGuidedTourVisibility]);
128
+
129
+ React.useEffect(() => {
130
+ const getUserId = async () => {
131
+ if (userInfo) {
132
+ const userId = await hashAdminUserEmail(userInfo);
133
+
134
+ if (userId) {
135
+ setUserId(userId);
136
+ }
137
+ }
138
+ };
139
+
140
+ getUserId();
141
+ }, [userInfo]);
142
+
143
+ // We don't need to wait for the release query to be fetched before rendering the plugins
144
+ // however, we need the appInfos and the permissions
145
+ const shouldShowNotDependentQueriesLoader =
146
+ isFetching || status === 'loading' || fetchPermissionsStatus === 'loading';
147
+
148
+ const shouldShowLoader = isLoading || shouldShowNotDependentQueriesLoader;
149
+
150
+ if (shouldShowLoader) {
151
+ return <LoadingIndicatorPage />;
152
+ }
153
+
154
+ // TODO: add error state
155
+ if (status === 'error') {
156
+ return <div>error...</div>;
157
+ }
158
+
159
+ return (
160
+ <AppInfoProvider
161
+ {...appInfos}
162
+ userId={userId}
163
+ latestStrapiReleaseTag={tagName}
164
+ setUserDisplayName={setUserDisplayName}
165
+ shouldUpdateStrapi={shouldUpdateStrapi}
166
+ userDisplayName={userDisplayName}
167
+ >
168
+ <RBACProvider permissions={permissions ?? []} refetchPermissions={refetch}>
169
+ <NpsSurvey />
170
+ <PluginsInitializer />
171
+ </RBACProvider>
172
+ </AppInfoProvider>
173
+ );
174
+ };
175
+
176
+ const checkLatestStrapiVersion = (
177
+ currentPackageVersion: string,
178
+ latestPublishedVersion: string = ''
179
+ ): boolean => {
180
+ if (!valid(currentPackageVersion) || !valid(latestPublishedVersion)) {
181
+ return false;
182
+ }
183
+
184
+ return lt(currentPackageVersion, latestPublishedVersion);
185
+ };
186
+
187
+ export { AuthenticatedApp };
@@ -2,7 +2,7 @@ import * as React from 'react';
2
2
 
3
3
  import { ConfigurationContext, ConfigurationContextValue } from '../contexts/configuration';
4
4
 
5
- export interface ConfigurationProviderProps {
5
+ interface ConfigurationProviderProps {
6
6
  children: React.ReactNode;
7
7
  authLogo: string;
8
8
  menuLogo: string;
@@ -65,3 +65,4 @@ const ConfigurationProvider = ({
65
65
  };
66
66
 
67
67
  export { ConfigurationProvider };
68
+ export type { ConfigurationProviderProps };
@@ -0,0 +1,111 @@
1
+ import { Box, Button, Flex, Typography } from '@strapi/design-system';
2
+ import { LinkButton } from '@strapi/design-system/v2';
3
+ import { GuidedTourContextValue, pxToRem, useGuidedTour, useTracking } from '@strapi/helper-plugin';
4
+ import { ArrowRight } from '@strapi/icons';
5
+ import { useIntl } from 'react-intl';
6
+ import { NavLink } from 'react-router-dom';
7
+
8
+ import { LAYOUT_DATA, States, STATES } from './constants';
9
+ import { Number, VerticalDivider } from './Ornaments';
10
+
11
+ const GuidedTourHomepage = () => {
12
+ const { guidedTourState, setSkipped } = useGuidedTour();
13
+ const { formatMessage } = useIntl();
14
+ const { trackUsage } = useTracking();
15
+
16
+ const sections = Object.entries(LAYOUT_DATA).map(([key, val]) => ({
17
+ key: key,
18
+ title: val.home.title,
19
+ content: (
20
+ <LinkButton
21
+ onClick={() => trackUsage(val.home.trackingEvent)}
22
+ as={NavLink}
23
+ // @ts-expect-error - types are not inferred correctly through the as prop.
24
+ to={val.home.cta.target}
25
+ endIcon={<ArrowRight />}
26
+ >
27
+ {formatMessage(val.home.cta.title)}
28
+ </LinkButton>
29
+ ),
30
+ isDone: Object.entries(
31
+ guidedTourState[key as keyof GuidedTourContextValue['guidedTourState']]
32
+ ).every(([, value]) => value),
33
+ }));
34
+
35
+ const activeSectionIndex = sections.findIndex((section) => !section.isDone);
36
+
37
+ const handleSkip = () => {
38
+ setSkipped(true);
39
+ trackUsage('didSkipGuidedtour');
40
+ };
41
+
42
+ return (
43
+ <Box
44
+ hasRadius
45
+ shadow="tableShadow"
46
+ paddingTop={7}
47
+ paddingRight={4}
48
+ paddingLeft={7}
49
+ paddingBottom={4}
50
+ background="neutral0"
51
+ >
52
+ <Flex direction="column" alignItems="stretch" gap={6}>
53
+ <Typography variant="beta" as="h2">
54
+ {formatMessage({
55
+ id: 'app.components.GuidedTour.title',
56
+ defaultMessage: '3 steps to get started',
57
+ })}
58
+ </Typography>
59
+ <Box>
60
+ {sections.map((section, index) => {
61
+ const state = getState(activeSectionIndex, index);
62
+ return (
63
+ <Box key={section.key}>
64
+ <Flex>
65
+ <Box minWidth={pxToRem(30)} marginRight={5}>
66
+ <Number state={state}>{index + 1}</Number>
67
+ </Box>
68
+ <Typography variant="delta" as="h3">
69
+ {formatMessage(section.title)}
70
+ </Typography>
71
+ </Flex>
72
+ <Flex alignItems="flex-start">
73
+ <Flex
74
+ justifyContent="center"
75
+ minWidth={pxToRem(30)}
76
+ marginBottom={3}
77
+ marginTop={3}
78
+ marginRight={5}
79
+ >
80
+ {index === sections.length - 1 ? null : <VerticalDivider state={state} />}
81
+ </Flex>
82
+ <Box marginTop={2}>{state === STATES.IS_ACTIVE ? section.content : null}</Box>
83
+ </Flex>
84
+ </Box>
85
+ );
86
+ })}
87
+ </Box>
88
+ </Flex>
89
+ <Flex justifyContent="flex-end">
90
+ <Button variant="tertiary" onClick={handleSkip}>
91
+ {formatMessage({ id: 'app.components.GuidedTour.skip', defaultMessage: 'Skip the tour' })}
92
+ </Button>
93
+ </Flex>
94
+ </Box>
95
+ );
96
+ };
97
+
98
+ const getState = (activeSectionIndex: number, index: number): States => {
99
+ if (activeSectionIndex === -1) {
100
+ return STATES.IS_DONE;
101
+ }
102
+ if (index < activeSectionIndex) {
103
+ return STATES.IS_DONE;
104
+ }
105
+ if (index > activeSectionIndex) {
106
+ return STATES.IS_NOT_DONE;
107
+ }
108
+ return STATES.IS_ACTIVE;
109
+ };
110
+
111
+ export { GuidedTourHomepage };
@@ -0,0 +1,303 @@
1
+ import * as React from 'react';
2
+
3
+ import {
4
+ Box,
5
+ Button,
6
+ Flex,
7
+ FocusTrap,
8
+ IconButton,
9
+ Portal,
10
+ Typography,
11
+ } from '@strapi/design-system';
12
+ import { LinkButton } from '@strapi/design-system/v2';
13
+ import { GuidedTourContextValue, pxToRem, useGuidedTour, useTracking } from '@strapi/helper-plugin';
14
+ import { ArrowRight, Cross } from '@strapi/icons';
15
+ import get from 'lodash/get';
16
+ import { MessageDescriptor, useIntl } from 'react-intl';
17
+ import { NavLink } from 'react-router-dom';
18
+ import styled from 'styled-components';
19
+
20
+ import { LAYOUT_DATA, STATES } from './constants';
21
+ import { Number, VerticalDivider } from './Ornaments';
22
+
23
+ /* -------------------------------------------------------------------------------------------------
24
+ * GuidedTourModal
25
+ * -----------------------------------------------------------------------------------------------*/
26
+
27
+ const GuidedTourModal = () => {
28
+ const {
29
+ currentStep,
30
+ guidedTourState,
31
+ setCurrentStep,
32
+ setStepState,
33
+ isGuidedTourVisible,
34
+ setSkipped,
35
+ } = useGuidedTour();
36
+ const { formatMessage } = useIntl();
37
+ const { trackUsage } = useTracking();
38
+
39
+ if (!currentStep || !isGuidedTourVisible) {
40
+ return null;
41
+ }
42
+
43
+ const stepData = get(LAYOUT_DATA, currentStep);
44
+ const sectionKeys = Object.keys(guidedTourState);
45
+ const [sectionName, stepName] = currentStep.split('.') as [
46
+ keyof GuidedTourContextValue['guidedTourState'],
47
+ string
48
+ ];
49
+ const sectionIndex = sectionKeys.indexOf(sectionName);
50
+ const stepIndex = Object.keys(guidedTourState[sectionName]).indexOf(stepName);
51
+ const hasSectionAfter = sectionIndex < sectionKeys.length - 1;
52
+ const hasStepAfter = stepIndex < Object.keys(guidedTourState[sectionName]).length - 1;
53
+
54
+ const handleCtaClick = () => {
55
+ setStepState(currentStep, true);
56
+ trackUsage(stepData.trackingEvent);
57
+
58
+ setCurrentStep(null);
59
+ };
60
+
61
+ const handleSkip = () => {
62
+ setSkipped(true);
63
+ setCurrentStep(null);
64
+ trackUsage('didSkipGuidedtour');
65
+ };
66
+
67
+ return (
68
+ <Portal>
69
+ <ModalWrapper onClick={handleCtaClick} padding={8} justifyContent="center">
70
+ <FocusTrap onEscape={handleCtaClick}>
71
+ <Flex
72
+ direction="column"
73
+ alignItems="stretch"
74
+ background="neutral0"
75
+ width={pxToRem(660)}
76
+ shadow="popupShadow"
77
+ hasRadius
78
+ padding={4}
79
+ gap={8}
80
+ role="dialog"
81
+ aria-modal
82
+ onClick={(e) => e.stopPropagation()}
83
+ >
84
+ <Flex justifyContent="flex-end">
85
+ <IconButton
86
+ onClick={handleCtaClick}
87
+ aria-label={formatMessage({
88
+ id: 'app.utils.close-label',
89
+ defaultMessage: 'Close',
90
+ })}
91
+ >
92
+ <Cross />
93
+ </IconButton>
94
+ </Flex>
95
+ <Box
96
+ paddingLeft={7}
97
+ paddingRight={7}
98
+ paddingBottom={!hasStepAfter && !hasSectionAfter ? 8 : 0}
99
+ >
100
+ <GuidedTourStepper
101
+ title={stepData.title}
102
+ cta={'cta' in stepData ? stepData.cta : undefined}
103
+ onCtaClick={handleCtaClick}
104
+ sectionIndex={sectionIndex}
105
+ stepIndex={stepIndex}
106
+ hasSectionAfter={hasSectionAfter}
107
+ >
108
+ <GuidedTourContent {...stepData.content} />
109
+ </GuidedTourStepper>
110
+ </Box>
111
+ {!(!hasStepAfter && !hasSectionAfter) && (
112
+ <Flex justifyContent="flex-end">
113
+ <Button variant="tertiary" onClick={handleSkip}>
114
+ {formatMessage({
115
+ id: 'app.components.GuidedTour.skip',
116
+ defaultMessage: 'Skip the tour',
117
+ })}
118
+ </Button>
119
+ </Flex>
120
+ )}
121
+ </Flex>
122
+ </FocusTrap>
123
+ </ModalWrapper>
124
+ </Portal>
125
+ );
126
+ };
127
+
128
+ const ModalWrapper = styled(Flex)`
129
+ position: fixed;
130
+ z-index: 4;
131
+ inset: 0;
132
+ /* this is theme.colors.neutral800 with opacity */
133
+ background: ${({ theme }) => `${theme.colors.neutral800}1F`};
134
+ `;
135
+
136
+ /* -------------------------------------------------------------------------------------------------
137
+ * GuidedTourStepper
138
+ * -----------------------------------------------------------------------------------------------*/
139
+
140
+ interface GuidedTourStepperProps {
141
+ title: MessageDescriptor;
142
+ children: React.ReactNode;
143
+ cta?: {
144
+ title: MessageDescriptor;
145
+ target?: string;
146
+ };
147
+ onCtaClick: () => void;
148
+ sectionIndex: number;
149
+ stepIndex: number;
150
+ hasSectionAfter: boolean;
151
+ }
152
+
153
+ const GuidedTourStepper = ({
154
+ title,
155
+ children,
156
+ cta,
157
+ onCtaClick,
158
+ sectionIndex,
159
+ stepIndex,
160
+ hasSectionAfter,
161
+ }: GuidedTourStepperProps) => {
162
+ const { formatMessage } = useIntl();
163
+
164
+ const hasSectionBefore = sectionIndex > 0;
165
+ const hasStepsBefore = stepIndex > 0;
166
+ const nextSectionIndex = sectionIndex + 1;
167
+
168
+ return (
169
+ <>
170
+ <Flex alignItems="stretch">
171
+ <Flex marginRight={8} justifyContent="center" minWidth={pxToRem(30)}>
172
+ {hasSectionBefore && <VerticalDivider state={STATES.IS_DONE} minHeight={pxToRem(24)} />}
173
+ </Flex>
174
+ <Typography variant="sigma" textColor="primary600">
175
+ {formatMessage({
176
+ id: 'app.components.GuidedTour.title',
177
+ defaultMessage: '3 steps to get started',
178
+ })}
179
+ </Typography>
180
+ </Flex>
181
+ <Flex>
182
+ <Flex marginRight={8} minWidth={pxToRem(30)}>
183
+ <Number
184
+ state={hasStepsBefore ? STATES.IS_DONE : STATES.IS_ACTIVE}
185
+ paddingTop={3}
186
+ paddingBottom={3}
187
+ >
188
+ {sectionIndex + 1}
189
+ </Number>
190
+ </Flex>
191
+ <Typography variant="alpha" fontWeight="bold" textColor="neutral800" as="h3" id="title">
192
+ {formatMessage(title)}
193
+ </Typography>
194
+ </Flex>
195
+ <Flex alignItems="stretch">
196
+ <Flex marginRight={8} direction="column" justifyContent="center" minWidth={pxToRem(30)}>
197
+ {hasSectionAfter && (
198
+ <>
199
+ <VerticalDivider state={STATES.IS_DONE} />
200
+ {hasStepsBefore && (
201
+ <Number state={STATES.IS_ACTIVE} paddingTop={3}>
202
+ {nextSectionIndex + 1}
203
+ </Number>
204
+ )}
205
+ </>
206
+ )}
207
+ </Flex>
208
+ <Box>
209
+ {children}
210
+ {cta &&
211
+ (cta.target ? (
212
+ <LinkButton
213
+ as={NavLink}
214
+ endIcon={<ArrowRight />}
215
+ onClick={onCtaClick}
216
+ // @ts-expect-error - types are not inferred correctly through the as prop.
217
+ to={cta.target}
218
+ >
219
+ {formatMessage(cta.title)}
220
+ </LinkButton>
221
+ ) : (
222
+ <Button endIcon={<ArrowRight />} onClick={onCtaClick}>
223
+ {formatMessage(cta.title)}
224
+ </Button>
225
+ ))}
226
+ </Box>
227
+ </Flex>
228
+ {hasStepsBefore && hasSectionAfter && (
229
+ <Box paddingTop={3}>
230
+ <Flex marginRight={8} justifyContent="center" width={pxToRem(30)}>
231
+ <VerticalDivider state={STATES.IS_DONE} minHeight={pxToRem(24)} />
232
+ </Flex>
233
+ </Box>
234
+ )}
235
+ </>
236
+ );
237
+ };
238
+
239
+ /* -------------------------------------------------------------------------------------------------
240
+ * GuidedTourContent
241
+ * -----------------------------------------------------------------------------------------------*/
242
+
243
+ interface GuidedTourContentProps
244
+ extends Required<Pick<MessageDescriptor, 'defaultMessage' | 'id'>> {}
245
+
246
+ const GuidedTourContent = ({ id, defaultMessage }: GuidedTourContentProps) => {
247
+ const { formatMessage } = useIntl();
248
+
249
+ return (
250
+ <Flex direction="column" alignItems="stretch" gap={4} paddingBottom={6}>
251
+ {formatMessage(
252
+ { id, defaultMessage },
253
+ {
254
+ documentationLink: DocumentationLink,
255
+ b: Bold,
256
+ p: Paragraph,
257
+ light: Light,
258
+ ul: List,
259
+ li: ListItem,
260
+ }
261
+ )}
262
+ </Flex>
263
+ );
264
+ };
265
+
266
+ const DocumentationLink = (children: React.ReactNode) => (
267
+ <Typography
268
+ as="a"
269
+ textColor="primary600"
270
+ target="_blank"
271
+ rel="noopener noreferrer"
272
+ href="https://docs.strapi.io/developer-docs/latest/developer-resources/database-apis-reference/rest-api.html#api-parameters"
273
+ >
274
+ {children}
275
+ </Typography>
276
+ );
277
+
278
+ const Bold = (children: React.ReactNode) => (
279
+ <Typography fontWeight="semiBold">{children}</Typography>
280
+ );
281
+
282
+ const Paragraph = (children: React.ReactNode) => <Typography>{children}</Typography>;
283
+
284
+ const Light = (children: React.ReactNode) => (
285
+ <Typography textColor="neutral600">{children}</Typography>
286
+ );
287
+
288
+ const List = (children: React.ReactNode) => (
289
+ <Box paddingLeft={6}>
290
+ <ul>{children}</ul>
291
+ </Box>
292
+ );
293
+
294
+ const LiStyled = styled.li`
295
+ list-style: disc;
296
+ &::marker {
297
+ color: ${({ theme }) => theme.colors.neutral800};
298
+ }
299
+ `;
300
+
301
+ const ListItem = (children: React.ReactNode) => <LiStyled>{children}</LiStyled>;
302
+
303
+ export { GuidedTourModal };