@strapi/admin 4.0.8 → 4.1.1

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 (215) hide show
  1. package/admin/src/components/AuthenticatedApp/index.js +25 -3
  2. package/admin/src/components/AuthenticatedApp/utils/api.js +15 -1
  3. package/admin/src/components/GuidedTour/Homepage/components/Step.js +61 -0
  4. package/admin/src/components/GuidedTour/Homepage/components/Stepper.js +58 -0
  5. package/admin/src/components/GuidedTour/Homepage/index.js +63 -0
  6. package/admin/src/components/GuidedTour/Modal/components/Content.js +50 -0
  7. package/admin/src/components/GuidedTour/Modal/components/Modal.js +75 -0
  8. package/admin/src/components/GuidedTour/Modal/components/StepNumberWithPadding.js +24 -0
  9. package/admin/src/components/GuidedTour/Modal/components/Stepper.js +119 -0
  10. package/admin/src/components/GuidedTour/Modal/index.js +90 -0
  11. package/admin/src/components/GuidedTour/Modal/reducer.js +29 -0
  12. package/admin/src/components/GuidedTour/Stepper/StepLine.js +27 -0
  13. package/admin/src/components/GuidedTour/Stepper/StepNumber.js +71 -0
  14. package/admin/src/components/GuidedTour/constants.js +3 -0
  15. package/admin/src/components/GuidedTour/index.js +100 -0
  16. package/admin/src/components/GuidedTour/init.js +36 -0
  17. package/admin/src/components/GuidedTour/layout.js +153 -0
  18. package/admin/src/components/GuidedTour/reducer.js +50 -0
  19. package/admin/src/components/GuidedTour/utils/arePreviousSectionsDone.js +13 -0
  20. package/admin/src/components/GuidedTour/utils/arePreviousStepsDone.js +12 -0
  21. package/admin/src/components/GuidedTour/utils/isGuidedTourCompleted.js +6 -0
  22. package/admin/src/components/GuidedTour/utils/persistStateToLocaleStorage.js +34 -0
  23. package/admin/src/components/Providers/index.js +4 -1
  24. package/admin/src/content-manager/components/CollectionTypeFormWrapper/index.js +14 -1
  25. package/admin/src/content-manager/components/DynamicTable/CellContent/CellValue.js +2 -1
  26. package/admin/src/content-manager/components/SingleTypeFormWrapper/index.js +5 -1
  27. package/admin/src/content-manager/pages/App/index.js +15 -2
  28. package/admin/src/content-manager/pages/ListSettingsView/components/DraggableCard.js +1 -1
  29. package/admin/src/content-manager/pages/ListSettingsView/components/SortDisplayedFields.js +22 -4
  30. package/admin/src/content-manager/pages/ListSettingsView/reducer.js +1 -1
  31. package/admin/src/pages/Admin/index.js +2 -0
  32. package/admin/src/pages/AuthPage/components/Register/index.js +11 -6
  33. package/admin/src/pages/AuthPage/index.js +15 -1
  34. package/admin/src/pages/HomePage/index.js +8 -2
  35. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/ContentBox/index.js +1 -1
  36. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/index.js +3 -0
  37. package/admin/src/pages/SettingsPage/pages/ApiTokens/ListView/index.js +10 -1
  38. package/admin/src/pages/SettingsPage/pages/Roles/ListPage/components/RoleRow/index.js +2 -2
  39. package/admin/src/translations/ar.json +0 -4
  40. package/admin/src/translations/cs.json +0 -6
  41. package/admin/src/translations/de.json +0 -12
  42. package/admin/src/translations/dk.json +158 -170
  43. package/admin/src/translations/en.json +43 -29
  44. package/admin/src/translations/es.json +15 -25
  45. package/admin/src/translations/fr.json +158 -169
  46. package/admin/src/translations/he.json +0 -10
  47. package/admin/src/translations/hu.json +16 -26
  48. package/admin/src/translations/id.json +0 -12
  49. package/admin/src/translations/it.json +0 -12
  50. package/admin/src/translations/ja.json +16 -28
  51. package/admin/src/translations/ko.json +663 -670
  52. package/admin/src/translations/ms.json +0 -6
  53. package/admin/src/translations/nl.json +16 -30
  54. package/admin/src/translations/no.json +0 -10
  55. package/admin/src/translations/pl.json +0 -12
  56. package/admin/src/translations/pt-BR.json +19 -29
  57. package/admin/src/translations/pt.json +0 -4
  58. package/admin/src/translations/ru.json +0 -12
  59. package/admin/src/translations/sk.json +0 -12
  60. package/admin/src/translations/sv.json +0 -4
  61. package/admin/src/translations/th.json +0 -12
  62. package/admin/src/translations/tr.json +0 -4
  63. package/admin/src/translations/uk.json +0 -6
  64. package/admin/src/translations/vi.json +0 -4
  65. package/admin/src/translations/zh-Hans.json +15 -25
  66. package/admin/src/translations/zh.json +24 -27
  67. package/build/2736.ee6e45c9.chunk.js +2 -0
  68. package/build/{460.639962f0.chunk.js.LICENSE.txt → 2736.ee6e45c9.chunk.js.LICENSE.txt} +0 -0
  69. package/build/4362.d0c1a04a.chunk.js +1 -0
  70. package/build/4800.18e59c83.chunk.js +1 -0
  71. package/build/{3215.4d042146.chunk.js → 8042.9b85175a.chunk.js} +2 -2
  72. package/build/{3215.4d042146.chunk.js.LICENSE.txt → 8042.9b85175a.chunk.js.LICENSE.txt} +0 -0
  73. package/build/9988.b4229043.chunk.js +2 -0
  74. package/build/{4741.c2bfe032.chunk.js.LICENSE.txt → 9988.b4229043.chunk.js.LICENSE.txt} +0 -0
  75. package/build/Admin-authenticatedApp.013e2774.chunk.js +1 -0
  76. package/build/Admin_homePage.e4779166.chunk.js +1 -0
  77. package/build/{Admin_settingsPage.05877e0b.chunk.js → Admin_settingsPage.2d0d2cca.chunk.js} +1 -1
  78. package/build/api-tokens-create-page.0981141a.chunk.js +1 -0
  79. package/build/api-tokens-edit-page.3faf1af1.chunk.js +1 -0
  80. package/build/{api-tokens-list-page.e071058b.chunk.js → api-tokens-list-page.26a05a21.chunk.js} +1 -1
  81. package/build/ar-json.6a2565af.chunk.js +1 -0
  82. package/build/content-manager.141d110d.chunk.js +1 -0
  83. package/build/{content-type-builder-translation-cs-json.2f7e2289.chunk.js → content-type-builder-translation-cs-json.89f7272e.chunk.js} +1 -1
  84. package/build/{content-type-builder-translation-de-json.46017754.chunk.js → content-type-builder-translation-de-json.0205697c.chunk.js} +1 -1
  85. package/build/content-type-builder-translation-dk-json.235ff56e.chunk.js +1 -0
  86. package/build/{content-type-builder-translation-en-json.d70fc3af.chunk.js → content-type-builder-translation-en-json.b3d8e9d4.chunk.js} +1 -1
  87. package/build/{content-type-builder-translation-es-json.20c177ee.chunk.js → content-type-builder-translation-es-json.13b2e2aa.chunk.js} +1 -1
  88. package/build/{content-type-builder-translation-fr-json.8f66eb66.chunk.js → content-type-builder-translation-fr-json.bee621f7.chunk.js} +1 -1
  89. package/build/{content-type-builder-translation-id-json.aab2f426.chunk.js → content-type-builder-translation-id-json.2fbf4f8c.chunk.js} +1 -1
  90. package/build/{content-type-builder-translation-it-json.4c91e895.chunk.js → content-type-builder-translation-it-json.a1afd7a9.chunk.js} +1 -1
  91. package/build/{content-type-builder-translation-ja-json.c239ba90.chunk.js → content-type-builder-translation-ja-json.1459fb88.chunk.js} +1 -1
  92. package/build/content-type-builder-translation-ko-json.d2080111.chunk.js +1 -0
  93. package/build/{content-type-builder-translation-ms-json.124be88c.chunk.js → content-type-builder-translation-ms-json.048122eb.chunk.js} +1 -1
  94. package/build/{content-type-builder-translation-nl-json.98a240b8.chunk.js → content-type-builder-translation-nl-json.8d59e86b.chunk.js} +1 -1
  95. package/build/{content-type-builder-translation-pl-json.2abc61bd.chunk.js → content-type-builder-translation-pl-json.01dc068c.chunk.js} +1 -1
  96. package/build/{content-type-builder-translation-pt-BR-json.c0415545.chunk.js → content-type-builder-translation-pt-BR-json.d311d056.chunk.js} +1 -1
  97. package/build/{content-type-builder-translation-pt-json.ab3e086d.chunk.js → content-type-builder-translation-pt-json.4893266f.chunk.js} +1 -1
  98. package/build/{content-type-builder-translation-ru-json.1a6779fd.chunk.js → content-type-builder-translation-ru-json.1285874d.chunk.js} +1 -1
  99. package/build/{content-type-builder-translation-sk-json.5c82f020.chunk.js → content-type-builder-translation-sk-json.0064156b.chunk.js} +1 -1
  100. package/build/{content-type-builder-translation-th-json.24ee19eb.chunk.js → content-type-builder-translation-th-json.5f690524.chunk.js} +1 -1
  101. package/build/{content-type-builder-translation-tr-json.30434835.chunk.js → content-type-builder-translation-tr-json.696283a5.chunk.js} +1 -1
  102. package/build/{content-type-builder-translation-uk-json.771662ef.chunk.js → content-type-builder-translation-uk-json.87496bf9.chunk.js} +1 -1
  103. package/build/{content-type-builder-translation-zh-Hans-json.070020ae.chunk.js → content-type-builder-translation-zh-Hans-json.283c640e.chunk.js} +1 -1
  104. package/build/{content-type-builder-translation-zh-json.9708310d.chunk.js → content-type-builder-translation-zh-json.77aa2275.chunk.js} +1 -1
  105. package/build/content-type-builder.f1cef05c.chunk.js +1 -0
  106. package/build/cs-json.8df09876.chunk.js +1 -0
  107. package/build/de-json.6e14f607.chunk.js +1 -0
  108. package/build/dk-json.be388470.chunk.js +1 -0
  109. package/build/en-json.bb614bb0.chunk.js +1 -0
  110. package/build/es-json.61553168.chunk.js +1 -0
  111. package/build/fr-json.a9ce0700.chunk.js +1 -0
  112. package/build/he-json.1742494e.chunk.js +1 -0
  113. package/build/hu-json.e667d285.chunk.js +1 -0
  114. package/build/i18n-translation-dk-json.ecf02d28.chunk.js +1 -0
  115. package/build/i18n-translation-en-json.4d823f62.chunk.js +1 -0
  116. package/build/i18n-translation-es-json.7049afa2.chunk.js +1 -0
  117. package/build/i18n-translation-fr-json.c6367bc9.chunk.js +1 -0
  118. package/build/i18n-translation-ko-json.aecb7e01.chunk.js +1 -0
  119. package/build/i18n-translation-zh-Hans-json.258b2e1a.chunk.js +1 -0
  120. package/build/id-json.d87ebb20.chunk.js +1 -0
  121. package/build/index.html +1 -1
  122. package/build/it-json.a2880b81.chunk.js +1 -0
  123. package/build/ja-json.46e29f04.chunk.js +1 -0
  124. package/build/ko-json.dd36fdc0.chunk.js +1 -0
  125. package/build/{main.59b96514.js → main.fc123ed7.js} +2 -2
  126. package/build/{main.59b96514.js.LICENSE.txt → main.fc123ed7.js.LICENSE.txt} +0 -0
  127. package/build/ms-json.3a062984.chunk.js +1 -0
  128. package/build/nl-json.30ce02cb.chunk.js +1 -0
  129. package/build/no-json.9af40e9d.chunk.js +1 -0
  130. package/build/pl-json.fd373053.chunk.js +1 -0
  131. package/build/pt-BR-json.30e2d716.chunk.js +1 -0
  132. package/build/pt-json.3aaf9e05.chunk.js +1 -0
  133. package/build/ru-json.78c56e1c.chunk.js +1 -0
  134. package/build/{runtime~main.75c67df1.js → runtime~main.0866074a.js} +1 -1
  135. package/build/sk-json.c0bf144c.chunk.js +1 -0
  136. package/build/sv-json.aad187b9.chunk.js +1 -0
  137. package/build/th-json.e2b4a0fb.chunk.js +1 -0
  138. package/build/tr-json.0add11cd.chunk.js +1 -0
  139. package/build/uk-json.eb78e77e.chunk.js +1 -0
  140. package/build/{upload-settings.62631a39.chunk.js → upload-settings.8e7cbc3b.chunk.js} +1 -1
  141. package/build/{upload-translation-de-json.00f90715.chunk.js → upload-translation-de-json.1308dce5.chunk.js} +1 -1
  142. package/build/upload-translation-dk-json.0d4e855f.chunk.js +1 -0
  143. package/build/upload-translation-en-json.c3373c8d.chunk.js +1 -0
  144. package/build/upload-translation-es-json.81b13eac.chunk.js +1 -0
  145. package/build/{upload-translation-fr-json.ccb4ad8b.chunk.js → upload-translation-fr-json.1bec79ec.chunk.js} +1 -1
  146. package/build/upload-translation-he-json.1d28982f.chunk.js +1 -0
  147. package/build/{upload-translation-it-json.c1809a47.chunk.js → upload-translation-it-json.7d4bdc5a.chunk.js} +1 -1
  148. package/build/{upload-translation-ja-json.71aa85eb.chunk.js → upload-translation-ja-json.97fcacd8.chunk.js} +1 -1
  149. package/build/upload-translation-ko-json.d7345fe1.chunk.js +1 -0
  150. package/build/{upload-translation-ms-json.be669f81.chunk.js → upload-translation-ms-json.081effd5.chunk.js} +1 -1
  151. package/build/{upload-translation-pl-json.67685825.chunk.js → upload-translation-pl-json.2dfe78bb.chunk.js} +1 -1
  152. package/build/{upload-translation-pt-BR-json.f7b1133d.chunk.js → upload-translation-pt-BR-json.65936d7b.chunk.js} +1 -1
  153. package/build/{upload-translation-ru-json.54c031aa.chunk.js → upload-translation-ru-json.2d3b6f69.chunk.js} +1 -1
  154. package/build/{upload-translation-sk-json.f643dfc2.chunk.js → upload-translation-sk-json.f15c7fd6.chunk.js} +1 -1
  155. package/build/upload-translation-th-json.6d3c2370.chunk.js +1 -0
  156. package/build/{upload-translation-uk-json.1a90e73c.chunk.js → upload-translation-uk-json.a6c38449.chunk.js} +1 -1
  157. package/build/{upload-translation-zh-Hans-json.ac1dc0b9.chunk.js → upload-translation-zh-Hans-json.f6b26c45.chunk.js} +1 -1
  158. package/build/{upload-translation-zh-json.164ac601.chunk.js → upload-translation-zh-json.06052336.chunk.js} +1 -1
  159. package/build/users-permissions-translation-dk-json.89d41c4b.chunk.js +1 -0
  160. package/build/vi-json.55a11ac0.chunk.js +1 -0
  161. package/build/zh-Hans-json.55f6475b.chunk.js +1 -0
  162. package/build/zh-json.c3c2b225.chunk.js +1 -0
  163. package/package.json +6 -6
  164. package/build/4362.e3d2d72b.chunk.js +0 -1
  165. package/build/460.639962f0.chunk.js +0 -2
  166. package/build/4741.c2bfe032.chunk.js +0 -2
  167. package/build/Admin-authenticatedApp.f65c428a.chunk.js +0 -1
  168. package/build/Admin_homePage.a20b5e76.chunk.js +0 -1
  169. package/build/api-tokens-create-page.10586e16.chunk.js +0 -1
  170. package/build/api-tokens-edit-page.f9e3038d.chunk.js +0 -1
  171. package/build/ar-json.d79e4709.chunk.js +0 -1
  172. package/build/content-manager.07db1dd9.chunk.js +0 -1
  173. package/build/content-type-builder-translation-dk-json.098bd218.chunk.js +0 -1
  174. package/build/content-type-builder-translation-ko-json.2a5e0769.chunk.js +0 -1
  175. package/build/content-type-builder.52f5975c.chunk.js +0 -1
  176. package/build/cs-json.b8ba75b8.chunk.js +0 -1
  177. package/build/de-json.e01bdeae.chunk.js +0 -1
  178. package/build/dk-json.7356ea4b.chunk.js +0 -1
  179. package/build/en-json.3422a59e.chunk.js +0 -1
  180. package/build/es-json.ed9c8bef.chunk.js +0 -1
  181. package/build/fr-json.390bcdeb.chunk.js +0 -1
  182. package/build/he-json.86f9e663.chunk.js +0 -1
  183. package/build/hu-json.a741d263.chunk.js +0 -1
  184. package/build/i18n-translation-dk-json.932d3cc2.chunk.js +0 -1
  185. package/build/i18n-translation-en-json.239b740f.chunk.js +0 -1
  186. package/build/i18n-translation-es-json.347904f3.chunk.js +0 -1
  187. package/build/i18n-translation-fr-json.b52474fc.chunk.js +0 -1
  188. package/build/i18n-translation-ko-json.e88e11ef.chunk.js +0 -1
  189. package/build/i18n-translation-zh-Hans-json.4c17fed0.chunk.js +0 -1
  190. package/build/id-json.0b0c9731.chunk.js +0 -1
  191. package/build/it-json.939916bc.chunk.js +0 -1
  192. package/build/ja-json.52581a2a.chunk.js +0 -1
  193. package/build/ko-json.29633034.chunk.js +0 -1
  194. package/build/ms-json.5e5d12f9.chunk.js +0 -1
  195. package/build/nl-json.ac661b7f.chunk.js +0 -1
  196. package/build/no-json.ff46b126.chunk.js +0 -1
  197. package/build/pl-json.6bff1d54.chunk.js +0 -1
  198. package/build/pt-BR-json.8b3f799d.chunk.js +0 -1
  199. package/build/pt-json.b23d9a79.chunk.js +0 -1
  200. package/build/ru-json.bff93229.chunk.js +0 -1
  201. package/build/sk-json.a40bc2c8.chunk.js +0 -1
  202. package/build/sv-json.8ac61ecf.chunk.js +0 -1
  203. package/build/th-json.6e4502a3.chunk.js +0 -1
  204. package/build/tr-json.eaca955b.chunk.js +0 -1
  205. package/build/uk-json.da2ed14e.chunk.js +0 -1
  206. package/build/upload-translation-dk-json.bc6af8b4.chunk.js +0 -1
  207. package/build/upload-translation-en-json.6b529046.chunk.js +0 -1
  208. package/build/upload-translation-es-json.b53d6641.chunk.js +0 -1
  209. package/build/upload-translation-he-json.5dc34ea8.chunk.js +0 -1
  210. package/build/upload-translation-ko-json.da369eef.chunk.js +0 -1
  211. package/build/upload-translation-th-json.88ee2090.chunk.js +0 -1
  212. package/build/users-permissions-translation-dk-json.3e0295e5.chunk.js +0 -1
  213. package/build/vi-json.e993857a.chunk.js +0 -1
  214. package/build/zh-Hans-json.5843950b.chunk.js +0 -1
  215. package/build/zh-json.2e4c9ef4.chunk.js +0 -1
@@ -0,0 +1,71 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { pxToRem } from '@strapi/helper-plugin';
4
+ import { Flex } from '@strapi/design-system/Flex';
5
+ import { Typography } from '@strapi/design-system/Typography';
6
+ import { Icon } from '@strapi/design-system/Icon';
7
+ import Check from '@strapi/icons/Check';
8
+ import { IS_DONE, IS_ACTIVE, IS_NOT_DONE } from '../constants';
9
+
10
+ const StepNumber = ({ type, number }) => {
11
+ if (type === IS_DONE) {
12
+ return (
13
+ <Flex
14
+ background="primary600"
15
+ padding={2}
16
+ borderRadius="50%"
17
+ width={pxToRem(30)}
18
+ height={pxToRem(30)}
19
+ justifyContent="center"
20
+ >
21
+ <Icon as={Check} aria-hidden width={pxToRem(16)} color="neutral0" />
22
+ </Flex>
23
+ );
24
+ }
25
+
26
+ if (type === IS_ACTIVE) {
27
+ return (
28
+ <Flex
29
+ background="primary600"
30
+ padding={2}
31
+ borderRadius="50%"
32
+ width={pxToRem(30)}
33
+ height={pxToRem(30)}
34
+ justifyContent="center"
35
+ >
36
+ <Typography fontWeight="semiBold" textColor="neutral0">
37
+ {number}
38
+ </Typography>
39
+ </Flex>
40
+ );
41
+ }
42
+
43
+ return (
44
+ <Flex
45
+ borderColor="neutral500"
46
+ borderWidth="1px"
47
+ borderStyle="solid"
48
+ padding={2}
49
+ borderRadius="50%"
50
+ width={pxToRem(30)}
51
+ height={pxToRem(30)}
52
+ justifyContent="center"
53
+ >
54
+ <Typography fontWeight="semiBold" textColor="neutral600">
55
+ {number}
56
+ </Typography>
57
+ </Flex>
58
+ );
59
+ };
60
+
61
+ StepNumber.defaultProps = {
62
+ number: undefined,
63
+ type: IS_NOT_DONE,
64
+ };
65
+
66
+ StepNumber.propTypes = {
67
+ number: PropTypes.number,
68
+ type: PropTypes.oneOf([IS_ACTIVE, IS_DONE, IS_NOT_DONE]),
69
+ };
70
+
71
+ export default StepNumber;
@@ -0,0 +1,3 @@
1
+ export const IS_ACTIVE = 'isActive';
2
+ export const IS_DONE = 'isDone';
3
+ export const IS_NOT_DONE = 'isNotDone';
@@ -0,0 +1,100 @@
1
+ import React, { useReducer } from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import get from 'lodash/get';
4
+ import { GuidedTourProvider } from '@strapi/helper-plugin';
5
+ import persistStateToLocaleStorage from './utils/persistStateToLocaleStorage';
6
+ import arePreviousSectionsDone from './utils/arePreviousSectionsDone';
7
+ import arePreviousStepsDone from './utils/arePreviousStepsDone';
8
+ import reducer, { initialState } from './reducer';
9
+ import init from './init';
10
+
11
+ const GuidedTour = ({ children }) => {
12
+ const [{ currentStep, guidedTourState, isGuidedTourVisible, isSkipped }, dispatch] = useReducer(
13
+ reducer,
14
+ initialState,
15
+ init
16
+ );
17
+
18
+ const setCurrentStep = step => {
19
+ // if step is null it is intentional, we need to dispatch it
20
+ if (step !== null) {
21
+ const isStepAlreadyDone = get(guidedTourState, step);
22
+ const isStepToShow = arePreviousStepsDone(step, guidedTourState);
23
+
24
+ if (isStepAlreadyDone || isSkipped || !isStepToShow) {
25
+ return null;
26
+ }
27
+ }
28
+
29
+ persistStateToLocaleStorage.addCurrentStep(step);
30
+
31
+ return dispatch({
32
+ type: 'SET_CURRENT_STEP',
33
+ step,
34
+ });
35
+ };
36
+
37
+ const setGuidedTourVisibility = value => {
38
+ dispatch({
39
+ type: 'SET_GUIDED_TOUR_VISIBILITY',
40
+ value,
41
+ });
42
+ };
43
+
44
+ const setStepState = (currentStep, value) => {
45
+ persistStateToLocaleStorage.addCompletedStep(currentStep);
46
+
47
+ dispatch({
48
+ type: 'SET_STEP_STATE',
49
+ currentStep,
50
+ value,
51
+ });
52
+ };
53
+
54
+ const startSection = sectionName => {
55
+ const sectionSteps = guidedTourState[sectionName];
56
+
57
+ if (sectionSteps) {
58
+ const isSectionToShow = arePreviousSectionsDone(sectionName, guidedTourState);
59
+ const firstStep = Object.keys(sectionSteps)[0];
60
+ const isFirstStepDone = sectionSteps[firstStep];
61
+
62
+ if (isSectionToShow && !currentStep && !isFirstStepDone) {
63
+ return setCurrentStep(`${sectionName}.${firstStep}`);
64
+ }
65
+ }
66
+
67
+ return null;
68
+ };
69
+
70
+ const setSkipped = value => {
71
+ persistStateToLocaleStorage.setSkipped(value);
72
+
73
+ dispatch({
74
+ type: 'SET_SKIPPED',
75
+ value,
76
+ });
77
+ };
78
+
79
+ return (
80
+ <GuidedTourProvider
81
+ guidedTourState={guidedTourState}
82
+ currentStep={currentStep}
83
+ setCurrentStep={setCurrentStep}
84
+ setGuidedTourVisibility={setGuidedTourVisibility}
85
+ setSkipped={setSkipped}
86
+ setStepState={setStepState}
87
+ startSection={startSection}
88
+ isGuidedTourVisible={isGuidedTourVisible}
89
+ isSkipped={isSkipped}
90
+ >
91
+ {children}
92
+ </GuidedTourProvider>
93
+ );
94
+ };
95
+
96
+ GuidedTour.propTypes = {
97
+ children: PropTypes.element.isRequired,
98
+ };
99
+
100
+ export default GuidedTour;
@@ -0,0 +1,36 @@
1
+ import set from 'lodash/set';
2
+ import persistStateToLocaleStorage, {
3
+ COMPLETED_STEPS,
4
+ CURRENT_STEP,
5
+ SKIPPED,
6
+ } from './utils/persistStateToLocaleStorage';
7
+
8
+ const init = initialState => {
9
+ const copyInitialState = { ...initialState };
10
+ const guidedTourLocaleStorage = persistStateToLocaleStorage.get(COMPLETED_STEPS);
11
+ const currentStepLocaleStorage = persistStateToLocaleStorage.get(CURRENT_STEP);
12
+ const skippedLocaleStorage = persistStateToLocaleStorage.get(SKIPPED);
13
+
14
+ if (guidedTourLocaleStorage) {
15
+ guidedTourLocaleStorage.forEach(step => {
16
+ const [sectionName, stepName] = step.split('.');
17
+ set(copyInitialState, ['guidedTourState', sectionName, stepName], true);
18
+ });
19
+ }
20
+
21
+ // if current step when initializing mark it as done
22
+ if (currentStepLocaleStorage) {
23
+ const [sectionName, stepName] = currentStepLocaleStorage.split('.');
24
+ set(copyInitialState, ['guidedTourState', sectionName, stepName], true);
25
+ persistStateToLocaleStorage.addCompletedStep(currentStepLocaleStorage);
26
+ persistStateToLocaleStorage.addCurrentStep(null);
27
+ }
28
+
29
+ if (skippedLocaleStorage !== null) {
30
+ set(copyInitialState, 'isSkipped', skippedLocaleStorage);
31
+ }
32
+
33
+ return copyInitialState;
34
+ };
35
+
36
+ export default init;
@@ -0,0 +1,153 @@
1
+ const layout = {
2
+ contentTypeBuilder: {
3
+ home: {
4
+ title: {
5
+ id: 'app.components.GuidedTour.home.CTB.title',
6
+ defaultMessage: '🧠 Build the content structure',
7
+ },
8
+ cta: {
9
+ title: {
10
+ id: 'app.components.GuidedTour.home.CTB.cta.title',
11
+ defaultMessage: 'Go to the Content type Builder',
12
+ },
13
+ type: 'REDIRECT',
14
+ target: '/plugins/content-type-builder',
15
+ },
16
+ },
17
+ create: {
18
+ title: {
19
+ id: 'app.components.GuidedTour.CTB.create.title',
20
+ defaultMessage: '🧠 Create a first Collection type',
21
+ },
22
+ content: {
23
+ id: 'app.components.GuidedTour.CTB.create.content',
24
+ defaultMessage:
25
+ '<p>Collection types help you manage several entries, Single types are suitable to manage only one entry.</p> <p>Ex: For a Blog website, Articles would be a Collection type whereas a Homepage would be a Single type.</p>',
26
+ },
27
+ cta: {
28
+ title: {
29
+ id: 'app.components.GuidedTour.CTB.create.cta.title',
30
+ defaultMessage: 'Build a Collection type',
31
+ },
32
+ type: 'CLOSE',
33
+ },
34
+ },
35
+ success: {
36
+ title: {
37
+ id: 'app.components.GuidedTour.CTB.success.title',
38
+ defaultMessage: 'Step 1: Completed ✅',
39
+ },
40
+ content: {
41
+ id: 'app.components.GuidedTour.CTB.success.content',
42
+ defaultMessage: '<p>Good going!</p><b>⚡️ What would you like to share with the world?</b>',
43
+ },
44
+ cta: {
45
+ title: {
46
+ id: 'app.components.GuidedTour.create-content',
47
+ defaultMessage: 'Create content',
48
+ },
49
+ type: 'REDIRECT',
50
+ target: '/content-manager',
51
+ },
52
+ },
53
+ },
54
+ contentManager: {
55
+ home: {
56
+ title: {
57
+ id: 'app.components.GuidedTour.home.CM.title',
58
+ defaultMessage: '⚡️ What would you like to share with the world?',
59
+ },
60
+ cta: {
61
+ title: {
62
+ id: 'app.components.GuidedTour.create-content',
63
+ defaultMessage: 'Create content',
64
+ },
65
+ type: 'REDIRECT',
66
+ target: '/content-manager',
67
+ },
68
+ },
69
+ create: {
70
+ title: {
71
+ id: 'app.components.GuidedTour.CM.create.title',
72
+ defaultMessage: '⚡️ Create content',
73
+ },
74
+ content: {
75
+ id: 'app.components.GuidedTour.CM.create.content',
76
+ defaultMessage:
77
+ "<p>Create and manage all the content here in the Content Manager.</p><p>Ex: Taking the Blog website example further, one can write an Article, save and publish it as they like.</p><p>💡 Quick tip - Don't forget to hit publish on the content you create.</p>",
78
+ },
79
+ cta: {
80
+ title: {
81
+ id: 'app.components.GuidedTour.create-content',
82
+ defaultMessage: 'Create content',
83
+ },
84
+ type: 'CLOSE',
85
+ },
86
+ },
87
+ success: {
88
+ title: {
89
+ id: 'app.components.GuidedTour.CM.success.title',
90
+ defaultMessage: 'Step 2: Completed ✅',
91
+ },
92
+ content: {
93
+ id: 'app.components.GuidedTour.CM.success.content',
94
+ defaultMessage: '<p>Awesome, one last step to go!</p><b>🚀 See content in action</b>',
95
+ },
96
+ cta: {
97
+ title: {
98
+ id: 'app.components.GuidedTour.CM.success.cta.title',
99
+ defaultMessage: 'Test the API',
100
+ },
101
+ type: 'REDIRECT',
102
+ target: '/settings/api-tokens',
103
+ },
104
+ },
105
+ },
106
+ apiTokens: {
107
+ home: {
108
+ title: {
109
+ id: 'app.components.GuidedTour.apiTokens.create.title',
110
+ defaultMessage: '🚀 See content in action',
111
+ },
112
+ cta: {
113
+ title: {
114
+ id: 'app.components.GuidedTour.home.apiTokens.cta.title',
115
+ defaultMessage: 'Test the API',
116
+ },
117
+ type: 'REDIRECT',
118
+ target: '/settings/api-tokens',
119
+ },
120
+ },
121
+ create: {
122
+ title: {
123
+ id: 'app.components.GuidedTour.apiTokens.create.title',
124
+ defaultMessage: '🚀 See content in action',
125
+ },
126
+ content: {
127
+ id: 'app.components.GuidedTour.apiTokens.create.content',
128
+ defaultMessage:
129
+ '<p>Generate an authentication token here and retrieve the content you just created.</p>',
130
+ },
131
+ cta: {
132
+ title: {
133
+ id: 'app.components.GuidedTour.apiTokens.create.cta.title',
134
+ defaultMessage: 'Generate an API Token',
135
+ },
136
+ type: 'CLOSE',
137
+ },
138
+ },
139
+ success: {
140
+ title: {
141
+ id: 'app.components.GuidedTour.apiTokens.success.title',
142
+ defaultMessage: 'Step 3: Completed ✅',
143
+ },
144
+ content: {
145
+ id: 'app.components.GuidedTour.apiTokens.success.content',
146
+ defaultMessage:
147
+ "<p>See content in action by making an HTTP request:</p><ul><li><p>To this URL: <light>https://'<'YOUR_DOMAIN'>'/api/'<'YOUR_CT'>'</light></p></li><li><p>With the header: <light>Authorization: bearer '<'YOUR_API_TOKEN'>'</light></p></li></ul><p>For more ways to interact with content, see the <documentationLink>documentation</documentationLink>.</p>",
148
+ },
149
+ },
150
+ },
151
+ };
152
+
153
+ export default layout;
@@ -0,0 +1,50 @@
1
+ /* eslint-disable consistent-return */
2
+ import produce from 'immer';
3
+
4
+ export const initialState = {
5
+ currentStep: null,
6
+ guidedTourState: {
7
+ contentTypeBuilder: {
8
+ create: false,
9
+ success: false,
10
+ },
11
+ contentManager: {
12
+ create: false,
13
+ success: false,
14
+ },
15
+ apiTokens: {
16
+ create: false,
17
+ success: false,
18
+ },
19
+ },
20
+ isGuidedTourVisible: false,
21
+ isSkipped: true,
22
+ };
23
+
24
+ const reducer = (state = initialState, action) =>
25
+ produce(state, draftState => {
26
+ switch (action.type) {
27
+ case 'SET_CURRENT_STEP': {
28
+ draftState.currentStep = action.step;
29
+ break;
30
+ }
31
+ case 'SET_STEP_STATE': {
32
+ const [section, step] = action.currentStep.split('.');
33
+ draftState.guidedTourState[section][step] = action.value;
34
+ break;
35
+ }
36
+ case 'SET_SKIPPED': {
37
+ draftState.isSkipped = action.value;
38
+ break;
39
+ }
40
+ case 'SET_GUIDED_TOUR_VISIBILITY': {
41
+ draftState.isGuidedTourVisible = action.value;
42
+ break;
43
+ }
44
+ default: {
45
+ return draftState;
46
+ }
47
+ }
48
+ });
49
+
50
+ export default reducer;
@@ -0,0 +1,13 @@
1
+ const arePreviousSectionsDone = (sectionName, guidedTourState) => {
2
+ const guidedTourArray = Object.entries(guidedTourState);
3
+
4
+ // Find current section position in the guidedTourArray
5
+ // Get only previous sections based on current section position
6
+ const currentSectionIndex = guidedTourArray.findIndex(([key]) => key === sectionName);
7
+ const previousSections = guidedTourArray.slice(0, currentSectionIndex);
8
+
9
+ // Check if every steps from previous section are done
10
+ return previousSections.every(([, sectionValue]) => Object.values(sectionValue).every(Boolean));
11
+ };
12
+
13
+ export default arePreviousSectionsDone;
@@ -0,0 +1,12 @@
1
+ const arePreviousStepsDone = (step, guidedTourState) => {
2
+ const stepSplit = step.split('.');
3
+ const stepName = stepSplit[1];
4
+ const sectionArray = Object.entries(guidedTourState[stepSplit[0]]);
5
+
6
+ const currentStepIndex = sectionArray.findIndex(([key]) => key === stepName);
7
+ const previousSteps = sectionArray.slice(0, currentStepIndex);
8
+
9
+ return previousSteps.every(([, sectionValue]) => sectionValue);
10
+ };
11
+
12
+ export default arePreviousStepsDone;
@@ -0,0 +1,6 @@
1
+ const isGuidedTourCompleted = guidedTourState =>
2
+ Object.entries(guidedTourState).every(([, section]) =>
3
+ Object.entries(section).every(([, step]) => step)
4
+ );
5
+
6
+ export default isGuidedTourCompleted;
@@ -0,0 +1,34 @@
1
+ export const CURRENT_STEP = 'GUIDED_TOUR_CURRENT_STEP';
2
+ export const COMPLETED_STEPS = 'GUIDED_TOUR_COMPLETED_STEPS';
3
+ export const SKIPPED = 'GUIDED_TOUR_SKIPPED';
4
+ const parse = JSON.parse;
5
+ const stringify = JSON.stringify;
6
+
7
+ const persistStateToLocaleStorage = {
8
+ clear() {
9
+ localStorage.removeItem(CURRENT_STEP);
10
+ localStorage.removeItem(COMPLETED_STEPS);
11
+ },
12
+ addCompletedStep: completedStep => {
13
+ const currentSteps = parse(localStorage.getItem(COMPLETED_STEPS))?.slice() || [];
14
+ const isAlreadyStored = currentSteps.includes(completedStep);
15
+
16
+ if (isAlreadyStored) {
17
+ return;
18
+ }
19
+
20
+ currentSteps.push(completedStep);
21
+ localStorage.setItem(COMPLETED_STEPS, stringify(currentSteps));
22
+ },
23
+ addCurrentStep: currentStep => {
24
+ localStorage.setItem(CURRENT_STEP, stringify(currentStep));
25
+ },
26
+ setSkipped: value => {
27
+ localStorage.setItem(SKIPPED, stringify(value));
28
+ },
29
+ get: item => {
30
+ return parse(localStorage.getItem(item));
31
+ },
32
+ };
33
+
34
+ export default persistStateToLocaleStorage;
@@ -5,6 +5,7 @@ import { LibraryProvider, StrapiAppProvider } from '@strapi/helper-plugin';
5
5
  import { Provider } from 'react-redux';
6
6
  import { AdminContext, ConfigurationsContext } from '../../contexts';
7
7
  import LanguageProvider from '../LanguageProvider';
8
+ import GuidedTour from '../GuidedTour';
8
9
  import AutoReloadOverlayBlockerProvider from '../AutoReloadOverlayBlockerProvider';
9
10
  import Notifications from '../Notifications';
10
11
  import OverlayBlocker from '../OverlayBlocker';
@@ -58,7 +59,9 @@ const Providers = ({
58
59
  <LanguageProvider messages={messages} localeNames={localeNames}>
59
60
  <AutoReloadOverlayBlockerProvider>
60
61
  <OverlayBlocker>
61
- <Notifications>{children}</Notifications>
62
+ <GuidedTour>
63
+ <Notifications>{children}</Notifications>
64
+ </GuidedTour>
62
65
  </OverlayBlocker>
63
66
  </AutoReloadOverlayBlockerProvider>
64
67
  </LanguageProvider>
@@ -8,6 +8,7 @@ import {
8
8
  useQueryParams,
9
9
  formatComponentData,
10
10
  contentManagementUtilRemoveFieldsFromData,
11
+ useGuidedTour,
11
12
  } from '@strapi/helper-plugin';
12
13
  import { useSelector, useDispatch } from 'react-redux';
13
14
  import PropTypes from 'prop-types';
@@ -34,6 +35,7 @@ import selectCrudReducer from '../../sharedReducers/crudReducer/selectors';
34
35
  // This container is used to handle the CRUD
35
36
  const CollectionTypeFormWrapper = ({ allLayoutData, children, slug, id, origin }) => {
36
37
  const toggleNotification = useNotification();
38
+ const { setCurrentStep } = useGuidedTour();
37
39
  const { trackUsage } = useTracking();
38
40
  const { push, replace } = useHistory();
39
41
  const [{ rawQuery }] = useQueryParams();
@@ -263,6 +265,8 @@ const CollectionTypeFormWrapper = ({ allLayoutData, children, slug, id, origin }
263
265
  message: { id: getTrad('success.record.save') },
264
266
  });
265
267
 
268
+ setCurrentStep('contentManager.success');
269
+
266
270
  dispatch(submitSucceeded(cleanReceivedData(data)));
267
271
  // Enable navigation and remove loaders
268
272
  dispatch(setStatus('resolved'));
@@ -274,7 +278,16 @@ const CollectionTypeFormWrapper = ({ allLayoutData, children, slug, id, origin }
274
278
  dispatch(setStatus('resolved'));
275
279
  }
276
280
  },
277
- [cleanReceivedData, displayErrors, replace, slug, dispatch, rawQuery, toggleNotification]
281
+ [
282
+ cleanReceivedData,
283
+ displayErrors,
284
+ replace,
285
+ slug,
286
+ dispatch,
287
+ rawQuery,
288
+ toggleNotification,
289
+ setCurrentStep,
290
+ ]
278
291
  );
279
292
 
280
293
  const onPublish = useCallback(async () => {
@@ -1,6 +1,7 @@
1
1
  import PropTypes from 'prop-types';
2
2
  import { useIntl } from 'react-intl';
3
3
  import toString from 'lodash/toString';
4
+ import parseISO from 'date-fns/parseISO';
4
5
  import { getNumberOfDecimals } from './utils/getNumberOfDecimals';
5
6
 
6
7
  const CellValue = ({ type, value }) => {
@@ -8,7 +9,7 @@ const CellValue = ({ type, value }) => {
8
9
  let formattedValue = value;
9
10
 
10
11
  if (type === 'date') {
11
- formattedValue = formatDate(value, { dateStyle: 'full' });
12
+ formattedValue = formatDate(parseISO(value), { dateStyle: 'full' });
12
13
  }
13
14
 
14
15
  if (type === 'datetime') {
@@ -6,6 +6,7 @@ import {
6
6
  formatComponentData,
7
7
  useQueryParams,
8
8
  useNotification,
9
+ useGuidedTour,
9
10
  } from '@strapi/helper-plugin';
10
11
  import { useSelector, useDispatch } from 'react-redux';
11
12
  import PropTypes from 'prop-types';
@@ -29,6 +30,7 @@ import buildQueryString from '../../pages/ListView/utils/buildQueryString';
29
30
  const SingleTypeFormWrapper = ({ allLayoutData, children, slug }) => {
30
31
  const { trackUsage } = useTracking();
31
32
  const { push } = useHistory();
33
+ const { setCurrentStep } = useGuidedTour();
32
34
  const trackUsageRef = useRef(trackUsage);
33
35
  const [isCreatingEntry, setIsCreatingEntry] = useState(true);
34
36
  const [{ query, rawQuery }] = useQueryParams();
@@ -203,6 +205,8 @@ const SingleTypeFormWrapper = ({ allLayoutData, children, slug }) => {
203
205
  message: { id: getTrad('success.record.save') },
204
206
  });
205
207
 
208
+ setCurrentStep('contentManager.success');
209
+
206
210
  dispatch(submitSucceeded(cleanReceivedData(data)));
207
211
  setIsCreatingEntry(false);
208
212
 
@@ -215,7 +219,7 @@ const SingleTypeFormWrapper = ({ allLayoutData, children, slug }) => {
215
219
  dispatch(setStatus('resolved'));
216
220
  }
217
221
  },
218
- [cleanReceivedData, displayErrors, slug, dispatch, rawQuery, toggleNotification]
222
+ [cleanReceivedData, displayErrors, slug, dispatch, rawQuery, toggleNotification, setCurrentStep]
219
223
  );
220
224
  const onPublish = useCallback(async () => {
221
225
  try {
@@ -1,7 +1,12 @@
1
- import React from 'react';
1
+ import React, { useEffect, useRef } from 'react';
2
2
  import { Helmet } from 'react-helmet';
3
3
  import { Switch, Route, useRouteMatch, Redirect, useLocation } from 'react-router-dom';
4
- import { CheckPagePermissions, LoadingIndicatorPage, NotFound } from '@strapi/helper-plugin';
4
+ import {
5
+ CheckPagePermissions,
6
+ LoadingIndicatorPage,
7
+ NotFound,
8
+ useGuidedTour,
9
+ } from '@strapi/helper-plugin';
5
10
  import { Layout, HeaderLayout } from '@strapi/design-system/Layout';
6
11
  import { Main } from '@strapi/design-system/Main';
7
12
  import { useIntl } from 'react-intl';
@@ -28,6 +33,14 @@ const App = () => {
28
33
  );
29
34
  const { pathname } = useLocation();
30
35
  const { formatMessage } = useIntl();
36
+ const { startSection } = useGuidedTour();
37
+ const startSectionRef = useRef(startSection);
38
+
39
+ useEffect(() => {
40
+ if (startSectionRef.current) {
41
+ startSectionRef.current('contentManager');
42
+ }
43
+ }, []);
31
44
 
32
45
  if (status === 'loading') {
33
46
  return (
@@ -195,7 +195,7 @@ const DraggableCard = ({
195
195
  >
196
196
  <Stack horizontal size={3}>
197
197
  <DragButton
198
- as='span'
198
+ as="span"
199
199
  aria-label={formatMessage(
200
200
  {
201
201
  id: getTrad('components.DraggableCard.move.field'),