@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
@@ -0,0 +1,74 @@
1
+ import { Box, BoxProps, Flex, FlexProps, Typography } from '@strapi/design-system';
2
+ import { pxToRem } from '@strapi/helper-plugin';
3
+ import { Check } from '@strapi/icons';
4
+
5
+ import { STATES, States } from './constants';
6
+
7
+ /* -------------------------------------------------------------------------------------------------
8
+ * Number
9
+ * -----------------------------------------------------------------------------------------------*/
10
+
11
+ interface NumberProps extends FlexProps {
12
+ children: number;
13
+ state: States;
14
+ }
15
+
16
+ const Number = ({ children, state, ...props }: NumberProps) => {
17
+ return state === STATES.IS_DONE || state === STATES.IS_ACTIVE ? (
18
+ <Flex
19
+ background="primary600"
20
+ padding={2}
21
+ borderRadius="50%"
22
+ width={pxToRem(30)}
23
+ height={pxToRem(30)}
24
+ justifyContent="center"
25
+ {...props}
26
+ >
27
+ {state === STATES.IS_DONE ? (
28
+ <Check aria-hidden width={pxToRem(16)} color="neutral0" />
29
+ ) : (
30
+ <Typography fontWeight="semiBold" textColor="neutral0">
31
+ {children}
32
+ </Typography>
33
+ )}
34
+ </Flex>
35
+ ) : (
36
+ <Flex
37
+ borderColor="neutral500"
38
+ borderWidth="1px"
39
+ borderStyle="solid"
40
+ padding={2}
41
+ borderRadius="50%"
42
+ width={pxToRem(30)}
43
+ height={pxToRem(30)}
44
+ justifyContent="center"
45
+ {...props}
46
+ >
47
+ <Typography fontWeight="semiBold" textColor="neutral600">
48
+ {children}
49
+ </Typography>
50
+ </Flex>
51
+ );
52
+ };
53
+
54
+ /* -------------------------------------------------------------------------------------------------
55
+ * VerticalDivider
56
+ * -----------------------------------------------------------------------------------------------*/
57
+
58
+ interface VerticalDividerProps extends BoxProps {
59
+ state: States;
60
+ }
61
+
62
+ const VerticalDivider = ({ state, ...props }: VerticalDividerProps) => (
63
+ <Box
64
+ width={pxToRem(2)}
65
+ height="100%"
66
+ background={state === STATES.IS_NOT_DONE ? 'neutral300' : 'primary500'}
67
+ hasRadius
68
+ minHeight={state === STATES.IS_ACTIVE ? pxToRem(85) : pxToRem(65)}
69
+ {...props}
70
+ />
71
+ );
72
+
73
+ export { Number, VerticalDivider };
74
+ export type { NumberProps, VerticalDividerProps };
@@ -0,0 +1,253 @@
1
+ import * as React from 'react';
2
+
3
+ import {
4
+ GuidedTourContextValue,
5
+ GuidedTourProvider as GuidedTourProviderComponent,
6
+ GuidedTourSectionKey,
7
+ GuidedTourStep,
8
+ GuidedTourStepKey,
9
+ auth,
10
+ } from '@strapi/helper-plugin';
11
+ import produce from 'immer';
12
+ import get from 'lodash/get';
13
+ import set from 'lodash/set';
14
+
15
+ /* -------------------------------------------------------------------------------------------------
16
+ * GuidedTourProvider
17
+ * -----------------------------------------------------------------------------------------------*/
18
+
19
+ interface GuidedTourProviderProps {
20
+ children: React.ReactNode;
21
+ }
22
+
23
+ const GuidedTourProvider = ({ children }: GuidedTourProviderProps) => {
24
+ const [{ currentStep, guidedTourState, isGuidedTourVisible, isSkipped }, dispatch] =
25
+ React.useReducer(reducer, initialState, initialiseState);
26
+
27
+ const setCurrentStep = (step: SetCurrentStepAction['step']) => {
28
+ // if step is null it is intentional, we need to dispatch it
29
+ if (step !== null) {
30
+ const isStepAlreadyDone = get(guidedTourState, step);
31
+ const [sectionName, stepName] = step.split('.') as [GuidedTourSectionKey, GuidedTourStepKey];
32
+ const sectionArray = Object.entries(guidedTourState[sectionName]);
33
+
34
+ const currentStepIndex = sectionArray.findIndex(([key]) => key === stepName);
35
+ const previousSteps = sectionArray.slice(0, currentStepIndex);
36
+
37
+ const isStepToShow = previousSteps.every(([, sectionValue]) => sectionValue);
38
+
39
+ if (isStepAlreadyDone || isSkipped || !isStepToShow) {
40
+ return null;
41
+ }
42
+ }
43
+
44
+ auth.set(null, 'GUIDED_TOUR_CURRENT_STEP', true);
45
+
46
+ return dispatch({
47
+ type: 'SET_CURRENT_STEP',
48
+ step,
49
+ });
50
+ };
51
+
52
+ const setGuidedTourVisibility = (value: SetGuidedTourVisibilityAction['value']) => {
53
+ dispatch({
54
+ type: 'SET_GUIDED_TOUR_VISIBILITY',
55
+ value,
56
+ });
57
+ };
58
+
59
+ const setStepState = (currentStep: GuidedTourStep, value: SetStepStateAction['value']) => {
60
+ addCompletedStep(currentStep);
61
+
62
+ dispatch({
63
+ type: 'SET_STEP_STATE',
64
+ currentStep,
65
+ value,
66
+ });
67
+ };
68
+
69
+ const startSection = (sectionName: GuidedTourSectionKey) => {
70
+ const sectionSteps = guidedTourState[sectionName];
71
+
72
+ if (sectionSteps) {
73
+ const guidedTourArray = Object.entries(guidedTourState);
74
+
75
+ // Find current section position in the guidedTourArray
76
+ // Get only previous sections based on current section position
77
+ const currentSectionIndex = guidedTourArray.findIndex(([key]) => key === sectionName);
78
+ const previousSections = guidedTourArray.slice(0, currentSectionIndex);
79
+
80
+ // Check if every steps from previous section are done
81
+ const isSectionToShow = previousSections.every(([, sectionValue]) =>
82
+ Object.values(sectionValue).every(Boolean)
83
+ );
84
+
85
+ const [firstStep] = Object.keys(sectionSteps) as [GuidedTourStepKey];
86
+ const isFirstStepDone = sectionSteps[firstStep];
87
+
88
+ if (isSectionToShow && !currentStep && !isFirstStepDone) {
89
+ setCurrentStep(`${sectionName}.${firstStep}`);
90
+ }
91
+ }
92
+ };
93
+
94
+ const setSkipped = (value: SetSkippedAction['value']) => {
95
+ auth.set(value, 'GUIDED_TOUR_SKIPPED', true);
96
+
97
+ dispatch({
98
+ type: 'SET_SKIPPED',
99
+ value,
100
+ });
101
+ };
102
+
103
+ return (
104
+ <GuidedTourProviderComponent
105
+ guidedTourState={guidedTourState}
106
+ currentStep={currentStep}
107
+ setCurrentStep={setCurrentStep}
108
+ setGuidedTourVisibility={setGuidedTourVisibility}
109
+ setSkipped={setSkipped}
110
+ setStepState={setStepState}
111
+ startSection={startSection}
112
+ isGuidedTourVisible={isGuidedTourVisible}
113
+ isSkipped={isSkipped}
114
+ >
115
+ {children}
116
+ </GuidedTourProviderComponent>
117
+ );
118
+ };
119
+
120
+ type State = Pick<
121
+ GuidedTourContextValue,
122
+ 'guidedTourState' | 'currentStep' | 'isGuidedTourVisible' | 'isSkipped'
123
+ >;
124
+
125
+ const initialState = {
126
+ currentStep: null,
127
+ guidedTourState: {
128
+ contentTypeBuilder: {
129
+ create: false,
130
+ success: false,
131
+ },
132
+ contentManager: {
133
+ create: false,
134
+ success: false,
135
+ },
136
+ apiTokens: {
137
+ create: false,
138
+ success: false,
139
+ },
140
+ },
141
+ isGuidedTourVisible: false,
142
+ isSkipped: false,
143
+ } satisfies State;
144
+
145
+ interface SetCurrentStepAction {
146
+ type: 'SET_CURRENT_STEP';
147
+ step: GuidedTourStep | null;
148
+ }
149
+
150
+ interface SetStepStateAction {
151
+ type: 'SET_STEP_STATE';
152
+ currentStep: GuidedTourStep;
153
+ value: boolean;
154
+ }
155
+
156
+ interface SetSkippedAction {
157
+ type: 'SET_SKIPPED';
158
+ value: boolean;
159
+ }
160
+
161
+ interface SetGuidedTourVisibilityAction {
162
+ type: 'SET_GUIDED_TOUR_VISIBILITY';
163
+ value: boolean;
164
+ }
165
+
166
+ type Action =
167
+ | SetCurrentStepAction
168
+ | SetStepStateAction
169
+ | SetSkippedAction
170
+ | SetGuidedTourVisibilityAction;
171
+
172
+ const reducer: React.Reducer<State, Action> = (state: State = initialState, action: Action) =>
173
+ produce(state, (draftState) => {
174
+ switch (action.type) {
175
+ case 'SET_CURRENT_STEP': {
176
+ draftState.currentStep = action.step;
177
+ break;
178
+ }
179
+ case 'SET_STEP_STATE': {
180
+ const [section, step] = action.currentStep.split('.') as [
181
+ GuidedTourSectionKey,
182
+ GuidedTourStepKey
183
+ ];
184
+ draftState.guidedTourState[section][step] = action.value;
185
+ break;
186
+ }
187
+ case 'SET_SKIPPED': {
188
+ draftState.isSkipped = action.value;
189
+ break;
190
+ }
191
+ case 'SET_GUIDED_TOUR_VISIBILITY': {
192
+ draftState.isGuidedTourVisible = action.value;
193
+ break;
194
+ }
195
+ default: {
196
+ return draftState;
197
+ }
198
+ }
199
+ });
200
+
201
+ const initialiseState = (initialState: State) => {
202
+ const copyInitialState = { ...initialState };
203
+ const guidedTourLocaleStorage = auth.get('GUIDED_TOUR_COMPLETED_STEPS');
204
+ const currentStepLocaleStorage = auth.get('GUIDED_TOUR_CURRENT_STEP');
205
+ const skippedLocaleStorage = auth.get('GUIDED_TOUR_SKIPPED');
206
+
207
+ if (Array.isArray(guidedTourLocaleStorage)) {
208
+ guidedTourLocaleStorage.forEach((step) => {
209
+ const [sectionName, stepName] = step.split('.');
210
+ set(copyInitialState, ['guidedTourState', sectionName, stepName], true);
211
+ });
212
+ }
213
+
214
+ // if current step when initializing mark it as done
215
+ if (currentStepLocaleStorage) {
216
+ const [sectionName, stepName] = currentStepLocaleStorage.split('.') as [
217
+ GuidedTourSectionKey,
218
+ GuidedTourStepKey
219
+ ];
220
+ set(copyInitialState, ['guidedTourState', sectionName, stepName], true);
221
+
222
+ addCompletedStep(currentStepLocaleStorage as GuidedTourStep);
223
+
224
+ auth.set(null, 'GUIDED_TOUR_CURRENT_STEP', true);
225
+ }
226
+
227
+ if (skippedLocaleStorage !== null) {
228
+ set(copyInitialState, 'isSkipped', skippedLocaleStorage);
229
+ }
230
+
231
+ return copyInitialState;
232
+ };
233
+
234
+ /**
235
+ * @description Add a completed step to the local storage if it does not already exist.
236
+ */
237
+ const addCompletedStep = (completedStep: GuidedTourStep) => {
238
+ const currentSteps = auth.get('GUIDED_TOUR_COMPLETED_STEPS') ?? [];
239
+
240
+ if (!Array.isArray(currentSteps)) {
241
+ return;
242
+ }
243
+
244
+ const isAlreadyStored = currentSteps.includes(completedStep);
245
+
246
+ if (isAlreadyStored) {
247
+ return;
248
+ }
249
+
250
+ auth.set([...currentSteps, completedStep], 'GUIDED_TOUR_COMPLETED_STEPS', true);
251
+ };
252
+
253
+ export { GuidedTourProvider };
@@ -1,4 +1,4 @@
1
- const layout = {
1
+ const LAYOUT_DATA = {
2
2
  contentTypeBuilder: {
3
3
  home: {
4
4
  title: {
@@ -157,6 +157,16 @@ const layout = {
157
157
  trackingEvent: 'didGenerateGuidedTourApiTokens',
158
158
  },
159
159
  },
160
- };
160
+ } as const;
161
161
 
162
- export default layout;
162
+ const STATES = {
163
+ IS_DONE: 'IS_DONE',
164
+ IS_ACTIVE: 'IS_ACTIVE',
165
+ IS_NOT_DONE: 'IS_NOT_DONE',
166
+ } as const;
167
+
168
+ type LayoutData = typeof LAYOUT_DATA;
169
+ type States = keyof typeof STATES;
170
+
171
+ export { LAYOUT_DATA, STATES };
172
+ export type { LayoutData, States };
@@ -127,3 +127,4 @@ const reducer = (state = initialState, action: Action) => {
127
127
  };
128
128
 
129
129
  export { LanguageProvider, useLocales, LANGUAGE_LOCAL_STORAGE_KEY };
130
+ export type { LanguageProviderProps, LocalesContextValue };
@@ -0,0 +1,125 @@
1
+ import * as React from 'react';
2
+
3
+ import {
4
+ AutoReloadOverlayBlockerProvider,
5
+ CustomFieldsProvider,
6
+ CustomFieldsProviderProps,
7
+ LibraryProvider,
8
+ LibraryProviderProps,
9
+ NotificationsProvider,
10
+ OverlayBlockerProvider,
11
+ StrapiAppProvider,
12
+ StrapiAppProviderProps,
13
+ } from '@strapi/helper-plugin';
14
+ import { QueryClient, QueryClientProvider } from 'react-query';
15
+ import { Provider } from 'react-redux';
16
+
17
+ import { AdminContext, AdminContextValue } from '../contexts/admin';
18
+
19
+ import { ConfigurationProvider, ConfigurationProviderProps } from './ConfigurationProvider';
20
+ import { GuidedTourProvider } from './GuidedTour/Provider';
21
+ import { LanguageProvider, LanguageProviderProps } from './LanguageProvider';
22
+ import { Theme } from './Theme';
23
+ import { ThemeToggleProvider, ThemeToggleProviderProps } from './ThemeToggleProvider';
24
+
25
+ import type { Store } from '../core/store/configure';
26
+
27
+ const queryClient = new QueryClient({
28
+ defaultOptions: {
29
+ queries: {
30
+ refetchOnWindowFocus: false,
31
+ },
32
+ },
33
+ });
34
+
35
+ interface ProvidersProps
36
+ extends Pick<ThemeToggleProviderProps, 'themes'>,
37
+ Pick<LanguageProviderProps, 'messages' | 'localeNames'>,
38
+ Pick<
39
+ ConfigurationProviderProps,
40
+ 'authLogo' | 'menuLogo' | 'showReleaseNotification' | 'showTutorials'
41
+ >,
42
+ Pick<AdminContextValue, 'getAdminInjectedComponents'>,
43
+ Pick<CustomFieldsProviderProps, 'customFields'>,
44
+ Pick<LibraryProviderProps, 'components' | 'fields'>,
45
+ Pick<
46
+ StrapiAppProviderProps,
47
+ | 'getPlugin'
48
+ | 'menu'
49
+ | 'plugins'
50
+ | 'runHookParallel'
51
+ | 'runHookSeries'
52
+ | 'runHookWaterfall'
53
+ | 'settings'
54
+ > {
55
+ children: React.ReactNode;
56
+ store: Store;
57
+ }
58
+
59
+ const Providers = ({
60
+ authLogo,
61
+ children,
62
+ components,
63
+ customFields,
64
+ fields,
65
+ getAdminInjectedComponents,
66
+ getPlugin,
67
+ localeNames,
68
+ menu,
69
+ menuLogo,
70
+ messages,
71
+ plugins,
72
+ runHookParallel,
73
+ runHookSeries,
74
+ runHookWaterfall,
75
+ settings,
76
+ showReleaseNotification,
77
+ showTutorials,
78
+ store,
79
+ themes,
80
+ }: ProvidersProps) => {
81
+ return (
82
+ <LanguageProvider messages={messages} localeNames={localeNames}>
83
+ <ThemeToggleProvider themes={themes}>
84
+ <Theme>
85
+ <QueryClientProvider client={queryClient}>
86
+ <Provider store={store}>
87
+ <AdminContext.Provider value={{ getAdminInjectedComponents }}>
88
+ <ConfigurationProvider
89
+ authLogo={authLogo}
90
+ menuLogo={menuLogo}
91
+ showReleaseNotification={showReleaseNotification}
92
+ showTutorials={showTutorials}
93
+ >
94
+ <StrapiAppProvider
95
+ getPlugin={getPlugin}
96
+ menu={menu}
97
+ plugins={plugins}
98
+ runHookParallel={runHookParallel}
99
+ runHookWaterfall={runHookWaterfall}
100
+ runHookSeries={runHookSeries}
101
+ settings={settings}
102
+ >
103
+ <LibraryProvider components={components} fields={fields}>
104
+ <CustomFieldsProvider customFields={customFields}>
105
+ <AutoReloadOverlayBlockerProvider>
106
+ <OverlayBlockerProvider>
107
+ <GuidedTourProvider>
108
+ <NotificationsProvider>{children}</NotificationsProvider>
109
+ </GuidedTourProvider>
110
+ </OverlayBlockerProvider>
111
+ </AutoReloadOverlayBlockerProvider>
112
+ </CustomFieldsProvider>
113
+ </LibraryProvider>
114
+ </StrapiAppProvider>
115
+ </ConfigurationProvider>
116
+ </AdminContext.Provider>
117
+ </Provider>
118
+ </QueryClientProvider>
119
+ </Theme>
120
+ </ThemeToggleProvider>
121
+ </LanguageProvider>
122
+ );
123
+ };
124
+
125
+ export { Providers };
@@ -0,0 +1,124 @@
1
+ import * as React from 'react';
2
+
3
+ import {
4
+ LoadingIndicatorPage,
5
+ Permission,
6
+ RBACContext,
7
+ RBACContextValue,
8
+ } from '@strapi/helper-plugin';
9
+ import produce from 'immer';
10
+
11
+ import { useTypedSelector, useTypedDispatch } from '../core/store/hooks';
12
+
13
+ /* -------------------------------------------------------------------------------------------------
14
+ * RBACProvider
15
+ * -----------------------------------------------------------------------------------------------*/
16
+
17
+ interface RBACProviderProps {
18
+ children: React.ReactNode;
19
+ permissions: Permission[];
20
+ refetchPermissions: RBACContextValue['refetchPermissions'];
21
+ }
22
+
23
+ const RBACProvider = ({ children, permissions, refetchPermissions }: RBACProviderProps) => {
24
+ const allPermissions = useTypedSelector((state) => state.rbacProvider.allPermissions);
25
+
26
+ const dispatch = useTypedDispatch();
27
+
28
+ React.useEffect(() => {
29
+ dispatch(setPermissionsAction(permissions));
30
+
31
+ return () => {
32
+ dispatch(resetStoreAction());
33
+ };
34
+ }, [permissions, dispatch]);
35
+
36
+ if (!allPermissions) {
37
+ return <LoadingIndicatorPage />;
38
+ }
39
+
40
+ return (
41
+ <RBACContext.Provider value={{ allPermissions, refetchPermissions }}>
42
+ {children}
43
+ </RBACContext.Provider>
44
+ );
45
+ };
46
+
47
+ /* -------------------------------------------------------------------------------------------------
48
+ * RBACReducer
49
+ * -----------------------------------------------------------------------------------------------*/
50
+
51
+ interface RBACState {
52
+ allPermissions: null | Permission[];
53
+ collectionTypesRelatedPermissions: Record<string, Record<string, Permission[]>>;
54
+ }
55
+
56
+ const initialState = {
57
+ allPermissions: null,
58
+ collectionTypesRelatedPermissions: {},
59
+ };
60
+
61
+ const RESET_STORE = 'StrapiAdmin/RBACProvider/RESET_STORE';
62
+ const SET_PERMISSIONS = 'StrapiAdmin/RBACProvider/SET_PERMISSIONS';
63
+
64
+ interface ResetStoreAction {
65
+ type: typeof RESET_STORE;
66
+ }
67
+
68
+ const resetStoreAction = (): ResetStoreAction => ({ type: RESET_STORE });
69
+
70
+ interface SetPermissionsAction {
71
+ type: typeof SET_PERMISSIONS;
72
+ permissions: Permission[];
73
+ }
74
+
75
+ const setPermissionsAction = (
76
+ permissions: SetPermissionsAction['permissions']
77
+ ): SetPermissionsAction => ({
78
+ type: SET_PERMISSIONS,
79
+ permissions,
80
+ });
81
+
82
+ type Actions = ResetStoreAction | SetPermissionsAction;
83
+
84
+ const RBACReducer = (state: RBACState = initialState, action: Actions) =>
85
+ produce(state, (draftState) => {
86
+ switch (action.type) {
87
+ case SET_PERMISSIONS: {
88
+ draftState.allPermissions = action.permissions;
89
+ draftState.collectionTypesRelatedPermissions = action.permissions
90
+ .filter((perm) => perm.subject)
91
+ .reduce<Record<string, Record<string, Permission[]>>>((acc, current) => {
92
+ const { subject, action } = current;
93
+
94
+ if (!subject) return acc;
95
+
96
+ if (!acc[subject]) {
97
+ acc[subject] = {};
98
+ }
99
+
100
+ acc[subject] = acc[subject][action]
101
+ ? { ...acc[subject], [action]: [...acc[subject][action], current] }
102
+ : { ...acc[subject], [action]: [current] };
103
+
104
+ return acc;
105
+ }, {});
106
+ break;
107
+ }
108
+ case RESET_STORE: {
109
+ return initialState;
110
+ }
111
+ default:
112
+ return state;
113
+ }
114
+ });
115
+
116
+ export { RBACProvider, RBACReducer, resetStoreAction, setPermissionsAction };
117
+ export type {
118
+ RBACState,
119
+ Actions,
120
+ RBACProviderProps,
121
+ ResetStoreAction,
122
+ SetPermissionsAction,
123
+ Permission,
124
+ };
@@ -11,9 +11,11 @@ interface ThemeProps {
11
11
  }
12
12
 
13
13
  const Theme = ({ children }: ThemeProps) => {
14
- const { currentTheme, themes } = useThemeToggle();
14
+ const { currentTheme, themes, systemTheme } = useThemeToggle();
15
15
  const { locale } = useIntl();
16
16
 
17
+ const computedThemeName = currentTheme === 'system' ? systemTheme : currentTheme;
18
+
17
19
  return (
18
20
  <DesignSystemProvider
19
21
  locale={locale}
@@ -22,7 +24,7 @@ const Theme = ({ children }: ThemeProps) => {
22
24
  * if it can't find it, that way the type is always fully defined and we're
23
25
  * not checking it all the time...
24
26
  */
25
- theme={currentTheme && themes ? themes[currentTheme] : themes?.light}
27
+ theme={themes?.[computedThemeName || 'light']}
26
28
  >
27
29
  {children}
28
30
  <GlobalStyle />
@@ -2,19 +2,14 @@ import * as React from 'react';
2
2
 
3
3
  import { DefaultTheme } from 'styled-components';
4
4
 
5
- import { ThemeToggleContext, ThemeName } from '../contexts/themeToggle';
5
+ import { ThemeToggleContext, ThemeName, NonSystemThemeName } from '../contexts/themeToggle';
6
6
 
7
7
  const THEME_KEY = 'STRAPI_THEME';
8
8
 
9
9
  const getDefaultTheme = () => {
10
- const browserTheme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
11
10
  const persistedTheme = localStorage.getItem(THEME_KEY) as ThemeName | null;
12
11
 
13
- if (!persistedTheme) {
14
- localStorage.setItem(THEME_KEY, browserTheme);
15
- }
16
-
17
- return persistedTheme || browserTheme;
12
+ return persistedTheme || 'system';
18
13
  };
19
14
 
20
15
  interface ThemeToggleProviderProps {
@@ -26,7 +21,8 @@ interface ThemeToggleProviderProps {
26
21
  }
27
22
 
28
23
  const ThemeToggleProvider = ({ children, themes }: ThemeToggleProviderProps) => {
29
- const [currentTheme, setCurrentTheme] = React.useState(getDefaultTheme());
24
+ const [currentTheme, setCurrentTheme] = React.useState<ThemeName>(getDefaultTheme());
25
+ const [systemTheme, setSystemTheme] = React.useState<NonSystemThemeName>();
30
26
 
31
27
  const handleChangeTheme = React.useCallback(
32
28
  (nextTheme: ThemeName) => {
@@ -36,15 +32,33 @@ const ThemeToggleProvider = ({ children, themes }: ThemeToggleProviderProps) =>
36
32
  [setCurrentTheme]
37
33
  );
38
34
 
35
+ // Listen to changes in the system theme
36
+ React.useEffect(() => {
37
+ const themeWatcher = window.matchMedia('(prefers-color-scheme: dark)');
38
+ setSystemTheme(themeWatcher.matches ? 'dark' : 'light');
39
+
40
+ const listener = (event: MediaQueryListEvent) => {
41
+ setSystemTheme(event.matches ? 'dark' : 'light');
42
+ };
43
+ themeWatcher.addEventListener('change', listener);
44
+
45
+ // Remove listener on cleanup
46
+ return () => {
47
+ themeWatcher.removeEventListener('change', listener);
48
+ };
49
+ }, []);
50
+
39
51
  const themeValues = React.useMemo(() => {
40
52
  return {
41
53
  currentTheme,
42
54
  onChangeTheme: handleChangeTheme,
43
55
  themes,
56
+ systemTheme,
44
57
  };
45
- }, [currentTheme, handleChangeTheme, themes]);
58
+ }, [currentTheme, handleChangeTheme, themes, systemTheme]);
46
59
 
47
60
  return <ThemeToggleContext.Provider value={themeValues}>{children}</ThemeToggleContext.Provider>;
48
61
  };
49
62
 
50
63
  export { ThemeToggleProvider };
64
+ export type { ThemeToggleProviderProps };
@@ -1,3 +1,5 @@
1
+ /* eslint-disable check-file/filename-naming-convention */
2
+
1
3
  export function useLocalesProvider() {
2
4
  return {
3
5
  changeLocale() {},