@strapi/admin 4.15.0-alpha.0 → 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 (472) hide show
  1. package/.eslintrc.js +4 -1
  2. package/admin/.eslintrc.js +28 -0
  3. package/admin/custom.d.ts +28 -0
  4. package/admin/src/StrapiApp.js +27 -28
  5. package/admin/src/components/AuthenticatedApp.tsx +187 -0
  6. package/admin/src/components/ConfigurationProvider.tsx +68 -0
  7. package/admin/src/components/{DragLayer/DragLayer.js → DragLayer.tsx} +18 -10
  8. package/admin/src/components/GuidedTour/Homepage.tsx +111 -0
  9. package/admin/src/components/GuidedTour/Modal.tsx +303 -0
  10. package/admin/src/components/GuidedTour/Ornaments.tsx +74 -0
  11. package/admin/src/components/GuidedTour/Provider.tsx +253 -0
  12. package/admin/src/components/GuidedTour/{layout.js → constants.ts} +13 -3
  13. package/admin/src/components/LanguageProvider.tsx +130 -0
  14. package/admin/src/components/{LeftMenu/index.js → LeftMenu.tsx} +23 -18
  15. package/admin/src/components/{NpsSurvey/index.js → NpsSurvey.tsx} +68 -21
  16. package/admin/src/components/PluginsInitializer.tsx +124 -0
  17. package/admin/src/components/PrivateRoute.tsx +42 -0
  18. package/admin/src/components/Providers.tsx +125 -0
  19. package/admin/src/components/RBACProvider.tsx +124 -0
  20. package/admin/src/components/Theme.tsx +41 -0
  21. package/admin/src/components/ThemeToggleProvider.tsx +64 -0
  22. package/admin/src/components/{UnauthenticatedLogo/index.js → UnauthenticatedLogo.tsx} +3 -5
  23. package/admin/src/components/{LocalesProvider/__mocks__/useLocalesProvider.js → __mocks__/LanguageProvider.ts} +3 -1
  24. package/admin/src/{constants.js → constants.ts} +48 -0
  25. package/admin/src/content-manager/components/BlocksEditor/BlocksInput/index.js +68 -9
  26. package/admin/src/content-manager/components/BlocksEditor/Toolbar/index.js +433 -202
  27. package/admin/src/content-manager/components/BlocksEditor/hooks/useBlocksStore.js +463 -135
  28. package/admin/src/content-manager/components/BlocksEditor/hooks/useModifiersStore.js +23 -6
  29. package/admin/src/content-manager/components/BlocksEditor/index.js +97 -20
  30. package/admin/src/content-manager/components/BlocksEditor/plugins/index.js +4 -0
  31. package/admin/src/content-manager/components/BlocksEditor/plugins/withLinks.js +61 -0
  32. package/admin/src/content-manager/components/BlocksEditor/plugins/withStrapiSchema.js +33 -0
  33. package/admin/src/content-manager/components/BlocksEditor/utils/links.js +90 -0
  34. package/admin/src/content-manager/components/InputUID/index.js +1 -1
  35. package/admin/src/content-manager/hooks/useAllowedAttributes.js +9 -1
  36. package/admin/src/content-manager/pages/App/selectors.js +1 -1
  37. package/admin/src/content-manager/pages/App/useContentManagerInitData.js +3 -1
  38. package/admin/src/content-manager/pages/EditSettingsView/index.js +1 -0
  39. package/admin/src/content-manager/pages/EditSettingsView/utils/createPossibleMainFieldsForModelsAndComponents.js +1 -0
  40. package/admin/src/content-manager/pages/EditView/selectors.js +1 -1
  41. package/admin/src/content-manager/pages/EditViewLayoutManager/index.js +3 -1
  42. package/admin/src/content-manager/pages/ListSettingsView/constants.js +1 -0
  43. package/admin/src/content-manager/pages/ListView/components/Body/index.js +53 -56
  44. package/admin/src/content-manager/pages/ListView/components/BulkActionButtons/SelectedEntriesModal/index.js +5 -3
  45. package/admin/src/content-manager/pages/ListView/components/TableRows/index.js +1 -1
  46. package/admin/src/content-manager/pages/ListView/index.js +35 -51
  47. package/admin/src/content-manager/pages/ListView/selectors.js +1 -1
  48. package/admin/src/content-manager/utils/checkIfAttributeIsDisplayable.js +1 -1
  49. package/admin/src/content-manager/utils/schema.js +2 -2
  50. package/admin/src/contexts/admin.ts +19 -0
  51. package/admin/src/contexts/apiTokenPermissions.tsx +64 -0
  52. package/admin/src/contexts/configuration.ts +25 -0
  53. package/admin/src/contexts/themeToggle.ts +18 -0
  54. package/admin/src/core/store/configure.ts +91 -0
  55. package/admin/src/core/store/hooks.ts +15 -0
  56. package/admin/src/hooks/{useConfigurations/__mocks__/index.js → __mocks__/useConfigurations.ts} +4 -2
  57. package/admin/src/hooks/index.js +0 -8
  58. package/admin/src/hooks/{useAdminRoles/index.js → useAdminRoles.ts} +26 -10
  59. package/admin/src/hooks/useAdminUsers.ts +64 -0
  60. package/admin/src/hooks/useConfiguration.ts +5 -0
  61. package/admin/src/hooks/{useContentTypes/useContentTypes.js → useContentTypes.ts} +39 -16
  62. package/admin/src/hooks/useDebounce.ts +17 -0
  63. package/admin/src/hooks/{useEnterprise/useEnterprise.js → useEnterprise.ts} +15 -5
  64. package/admin/src/hooks/useLicenseLimitNotification.ts +3 -0
  65. package/admin/src/hooks/useMenu.ts +153 -0
  66. package/admin/src/hooks/useSettingsForm/index.js +14 -2
  67. package/admin/src/hooks/useSettingsMenu/constants.js +39 -0
  68. package/admin/src/hooks/useThemeToggle.ts +9 -0
  69. package/admin/src/index.js +7 -6
  70. package/admin/src/layouts/{AppLayout/index.js → AppLayout.tsx} +7 -10
  71. package/admin/src/layouts/UnauthenticatedLayout.tsx +77 -0
  72. package/admin/src/pages/Admin/index.js +15 -8
  73. package/admin/src/pages/App/index.js +13 -8
  74. package/admin/src/pages/App/selectors.js +1 -1
  75. package/admin/src/pages/AuthPage/components/ForgotPassword/index.js +3 -2
  76. package/admin/src/pages/AuthPage/components/ForgotPasswordSuccess/index.js +3 -2
  77. package/admin/src/pages/AuthPage/components/Login/BaseLogin.js +1 -1
  78. package/admin/src/pages/AuthPage/components/Login/index.js +1 -1
  79. package/admin/src/pages/AuthPage/components/Oops/index.js +3 -2
  80. package/admin/src/pages/AuthPage/components/Register/index.js +30 -35
  81. package/admin/src/pages/AuthPage/components/ResetPassword/index.js +3 -2
  82. package/admin/src/pages/AuthPage/index.js +4 -5
  83. package/admin/src/pages/HomePage/index.js +6 -3
  84. package/admin/src/pages/{InternalErrorPage/index.js → InternalErrorPage.tsx} +10 -6
  85. package/admin/src/pages/MarketplacePage/components/NpmPackageCard/index.js +0 -2
  86. package/admin/src/pages/MarketplacePage/hooks/__mocks__/useNavigatorOnline.ts +1 -0
  87. package/admin/src/{hooks/useNavigatorOnLine/index.js → pages/MarketplacePage/hooks/useNavigatorOnline.ts} +4 -6
  88. package/admin/src/pages/MarketplacePage/index.js +3 -3
  89. package/admin/src/pages/{NotFoundPage/index.js → NotFoundPage.tsx} +9 -7
  90. package/admin/src/pages/ProfilePage/components/Preferences/index.js +23 -9
  91. package/admin/src/pages/ProfilePage/index.js +4 -4
  92. package/admin/src/pages/SettingsPage/components/SettingsNav/index.js +20 -0
  93. package/admin/src/pages/SettingsPage/components/Tokens/Regenerate/index.js +1 -1
  94. package/admin/src/pages/SettingsPage/components/Tokens/Table/index.js +119 -87
  95. package/admin/src/pages/SettingsPage/constants.js +33 -0
  96. package/admin/src/{hooks/useRegenerate/index.js → pages/SettingsPage/hooks/useRegenerate.ts} +13 -7
  97. package/admin/src/pages/SettingsPage/index.js +2 -2
  98. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/ActionBoundRoutes/index.js +1 -1
  99. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/CollapsableContentType/index.js +1 -1
  100. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/Permissions/index.js +1 -1
  101. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/Regenerate/index.js +1 -1
  102. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/index.js +2 -2
  103. package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/components/CustomizationInfos/index.js +2 -2
  104. package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/index.js +2 -2
  105. package/admin/src/pages/SettingsPage/pages/AuditLogs/SalesPage.js +50 -0
  106. package/admin/src/pages/SettingsPage/pages/ReviewWorkflows/SalesPage.js +53 -0
  107. package/admin/src/pages/SettingsPage/pages/Roles/CreatePage/index.js +1 -1
  108. package/admin/src/pages/SettingsPage/pages/Roles/EditPage/components/ConditionsModal/index.js +1 -1
  109. package/admin/src/pages/SettingsPage/pages/Roles/EditPage/components/ContentTypeCollapse/Collapse/index.js +1 -1
  110. package/admin/src/pages/SettingsPage/pages/Roles/EditPage/components/ContentTypeCollapse/CollapsePropertyMatrix/ActionRow/index.js +1 -1
  111. package/admin/src/pages/SettingsPage/pages/Roles/EditPage/components/ContentTypeCollapse/CollapsePropertyMatrix/SubActionRow/index.js +1 -1
  112. package/admin/src/pages/SettingsPage/pages/Roles/EditPage/components/GlobalActions/index.js +1 -1
  113. package/admin/src/pages/SettingsPage/pages/Roles/EditPage/components/PermissionsDataManagerProvider/index.js +1 -1
  114. package/admin/src/pages/SettingsPage/pages/Roles/EditPage/components/PluginsAndSettings/SubCategory/index.js +1 -1
  115. package/admin/src/pages/SettingsPage/pages/Roles/EditPage/hooks/usePermissionsDataManager.ts +28 -0
  116. package/admin/src/pages/SettingsPage/pages/Roles/EditPage/index.js +1 -1
  117. package/admin/src/{hooks/useAdminRolePermissions/index.js → pages/SettingsPage/pages/Roles/hooks/useAdminRolePermissions.ts} +13 -6
  118. package/admin/src/pages/SettingsPage/pages/SingleSignOn/SalesPage.js +53 -0
  119. package/admin/src/pages/SettingsPage/pages/TransferTokens/EditView/index.js +1 -1
  120. package/admin/src/pages/SettingsPage/pages/TransferTokens/ListView/index.js +3 -5
  121. package/admin/src/pages/SettingsPage/pages/Users/EditPage/index.js +2 -1
  122. package/admin/src/pages/SettingsPage/pages/Users/ListPage/DynamicTable/TableRows/index.js +1 -1
  123. package/admin/src/pages/{UseCasePage/index.js → UseCasePage.tsx} +10 -12
  124. package/admin/src/shared/hooks/index.js +0 -1
  125. package/admin/src/shared/hooks/useInjectionZone/index.js +2 -2
  126. package/admin/src/translations/en.json +13 -0
  127. package/admin/src/types/adminAPI.ts +29 -0
  128. package/admin/src/utils/createRoute.tsx +54 -0
  129. package/admin/src/utils/formatAPIErrors.ts +18 -0
  130. package/admin/src/utils/getFullName.ts +3 -0
  131. package/admin/src/utils/{uniqueAdminHash.js → hashAdminUserEmail.ts} +6 -3
  132. package/admin/src/utils/makeUniqueRoutes.ts +11 -0
  133. package/admin/tsconfig.build.json +4 -0
  134. package/admin/tsconfig.json +11 -0
  135. package/build/0cd5f8915b265d5b1856.png +0 -0
  136. package/build/1049.ecc10c97.chunk.js +1 -0
  137. package/build/1217.96155682.chunk.js +35 -0
  138. package/build/1227.947ceaf9.chunk.js +1 -0
  139. package/build/1306.2699df52.chunk.js +79 -0
  140. package/build/135.ad267b59.chunk.js +1 -0
  141. package/build/1386.eabd8a1e.chunk.js +7 -0
  142. package/build/1727.b49f0713.chunk.js +1 -0
  143. package/build/1835.eaa696ba.chunk.js +1 -0
  144. package/build/19eb2dfcf2603eb55733.png +0 -0
  145. package/build/2325.d705b39a.chunk.js +1 -0
  146. package/build/2379.7ce8e110.chunk.js +1 -0
  147. package/build/2395.acb961a8.chunk.js +26 -0
  148. package/build/2421.79e5b3d0.chunk.js +1 -0
  149. package/build/267.073a3bcb.chunk.js +1 -0
  150. package/build/27d16aefee06412db90a.png +0 -0
  151. package/build/2801.4711ea5a.chunk.js +1 -0
  152. package/build/2878.145ebf7c.chunk.js +1 -0
  153. package/build/2950.216f2e89.chunk.js +1 -0
  154. package/build/2953.284a63c0.chunk.js +1 -0
  155. package/build/3019.fde2e1be.chunk.js +181 -0
  156. package/build/3100.2ba4df95.chunk.js +1 -0
  157. package/build/311.cb0884bb.chunk.js +1 -0
  158. package/build/3460.8644e608.chunk.js +146 -0
  159. package/build/3483.db8c1520.chunk.js +1 -0
  160. package/build/3911.488fbde3.chunk.js +95 -0
  161. package/build/4174.49cedb6a.chunk.js +1 -0
  162. package/build/4429.7f044dc7.chunk.js +1 -0
  163. package/build/4555.c883d697.chunk.js +1 -0
  164. package/build/4663.b906cc10.chunk.js +1 -0
  165. package/build/4732.149f5f8f.chunk.js +1 -0
  166. package/build/4916.480053a6.chunk.js +1 -0
  167. package/build/4996.d285c30b.chunk.js +1 -0
  168. package/build/502.f536f78b.chunk.js +1 -0
  169. package/build/570.2f3b4c56.chunk.js +1 -0
  170. package/build/5858.493b31ec.chunk.js +1 -0
  171. package/build/6158.c3c13c20.chunk.js +1 -0
  172. package/build/6345.334e7678.chunk.js +1 -0
  173. package/build/6453.4160b5b7.chunk.js +1 -0
  174. package/build/7030.b98dcedf.chunk.js +1 -0
  175. package/build/70674f63fc3904c20de0.svg +7 -0
  176. package/build/7448.6fd14dd3.chunk.js +1 -0
  177. package/build/7464.579564ac.chunk.js +1 -0
  178. package/build/7735.9e7c9fdd.chunk.js +10 -0
  179. package/build/78.dcc6df5c.chunk.js +1 -0
  180. package/build/7811.fdbe09af.chunk.js +103 -0
  181. package/build/782.7243b183.chunk.js +1 -0
  182. package/build/7849.2a500ed8.chunk.js +1 -0
  183. package/build/7897.63ba0a00.chunk.js +6 -0
  184. package/build/7e9af4fb7e723fcebf1f.svg +48 -0
  185. package/build/8162.7d1100a0.chunk.js +1 -0
  186. package/build/8276.9abe4679.chunk.js +26 -0
  187. package/build/8773.ee67141c.chunk.js +48 -0
  188. package/build/8980.f0045cc1.chunk.js +1 -0
  189. package/build/9077.2cc01ac8.chunk.js +105 -0
  190. package/build/9153.42c1428a.chunk.js +1 -0
  191. package/build/918.54414509.chunk.js +1 -0
  192. package/build/9218.b2d367f8.chunk.js +1 -0
  193. package/build/9285.5f174057.chunk.js +1 -0
  194. package/build/9547.62987774.chunk.js +1 -0
  195. package/build/9754.b4e73779.chunk.js +1 -0
  196. package/build/9d5d788027e86620c234.svg +5 -0
  197. package/build/Admin-authenticatedApp.059dc48f.chunk.js +79 -0
  198. package/build/Admin_InternalErrorPage.06eeef20.chunk.js +1 -0
  199. package/build/Admin_homePage.56b9eb3f.chunk.js +81 -0
  200. package/build/Admin_marketplace.d693a435.chunk.js +44 -0
  201. package/build/Admin_pluginsPage.ae2c872a.chunk.js +6 -0
  202. package/build/Admin_profilePage.89099d5b.chunk.js +13 -0
  203. package/build/Admin_settingsPage.88c45586.chunk.js +12 -0
  204. package/build/Upload_ConfigureTheView.44f28145.chunk.js +1 -0
  205. package/build/admin-app.990e112f.chunk.js +69 -0
  206. package/build/admin-edit-roles-page.4e1eb4a9.chunk.js +267 -0
  207. package/build/admin-edit-users.5b91404e.chunk.js +10 -0
  208. package/build/admin-roles-list.89dd94fe.chunk.js +22 -0
  209. package/build/admin-users.7be4fc5f.chunk.js +11 -0
  210. package/build/api-tokens-create-page.571920e5.chunk.js +1 -0
  211. package/build/api-tokens-edit-page.cbdc81b1.chunk.js +1 -0
  212. package/build/api-tokens-list-page.de0c49e8.chunk.js +16 -0
  213. package/build/ar-json.74e40bc7.chunk.js +1 -0
  214. package/build/audit-logs-sales-page.2955db88.chunk.js +1 -0
  215. package/build/audit-logs-settings-page.b0cb5164.chunk.js +1 -0
  216. package/build/bb3108f7fd1e6179bde1.svg +1 -0
  217. package/build/bb4d0d527bdfb161bc5a.svg +1 -0
  218. package/build/ca-json.fc6001d3.chunk.js +1 -0
  219. package/build/content-manager.de7ae330.chunk.js +1241 -0
  220. package/build/content-type-builder-list-view.6c8d3213.chunk.js +211 -0
  221. package/build/content-type-builder-translation-ar-json.3e808e2f.chunk.js +1 -0
  222. package/build/content-type-builder-translation-cs-json.1ef9e106.chunk.js +1 -0
  223. package/build/content-type-builder-translation-de-json.63fcff7b.chunk.js +1 -0
  224. package/build/content-type-builder-translation-dk-json.fd626b67.chunk.js +1 -0
  225. package/build/content-type-builder-translation-en-json.74d80f18.chunk.js +1 -0
  226. package/build/content-type-builder-translation-es-json.a4a361a9.chunk.js +1 -0
  227. package/build/content-type-builder-translation-fr-json.499c3a46.chunk.js +1 -0
  228. package/build/content-type-builder-translation-id-json.65255f93.chunk.js +1 -0
  229. package/build/content-type-builder-translation-it-json.e268ab74.chunk.js +1 -0
  230. package/build/content-type-builder-translation-ja-json.9be0d5b2.chunk.js +1 -0
  231. package/build/content-type-builder-translation-ko-json.04cb309d.chunk.js +1 -0
  232. package/build/content-type-builder-translation-ms-json.f6b743b9.chunk.js +1 -0
  233. package/build/content-type-builder-translation-nl-json.997fe8cc.chunk.js +1 -0
  234. package/build/content-type-builder-translation-pl-json.634f638b.chunk.js +1 -0
  235. package/build/content-type-builder-translation-pt-BR-json.6a95dc71.chunk.js +1 -0
  236. package/build/content-type-builder-translation-pt-json.ddb44f8c.chunk.js +1 -0
  237. package/build/content-type-builder-translation-ru-json.3af65503.chunk.js +1 -0
  238. package/build/content-type-builder-translation-sk-json.c6078082.chunk.js +1 -0
  239. package/build/content-type-builder-translation-sv-json.a6df2462.chunk.js +1 -0
  240. package/build/content-type-builder-translation-th-json.122277cc.chunk.js +1 -0
  241. package/build/content-type-builder-translation-tr-json.41f44f77.chunk.js +1 -0
  242. package/build/content-type-builder-translation-uk-json.e1315acd.chunk.js +1 -0
  243. package/build/content-type-builder-translation-zh-Hans-json.6ff57db6.chunk.js +1 -0
  244. package/build/content-type-builder-translation-zh-json.3532b962.chunk.js +1 -0
  245. package/build/content-type-builder.0bc97051.chunk.js +136 -0
  246. package/build/cs-json.4b44411c.chunk.js +1 -0
  247. package/build/de-json.e72545cf.chunk.js +1 -0
  248. package/build/dk-json.e77140ef.chunk.js +1 -0
  249. package/build/email-settings-page.07712efc.chunk.js +11 -0
  250. package/build/en-json.5b907f67.chunk.js +1 -0
  251. package/build/es-json.b1f2284b.chunk.js +1 -0
  252. package/build/eu-json.63d0a898.chunk.js +1 -0
  253. package/build/fr-json.33c6428b.chunk.js +1 -0
  254. package/build/gu-json.7efe8cc2.chunk.js +1 -0
  255. package/build/he-json.3cf0b48a.chunk.js +1 -0
  256. package/build/hi-json.0d633692.chunk.js +1 -0
  257. package/build/highlight.js.28a1547e.chunk.js +85 -0
  258. package/build/hu-json.c74b6a1e.chunk.js +1 -0
  259. package/build/i18n-settings-page.5c34f012.chunk.js +9 -0
  260. package/build/i18n-translation-de-json.362384a6.chunk.js +1 -0
  261. package/build/i18n-translation-dk-json.89401417.chunk.js +1 -0
  262. package/build/i18n-translation-en-json.1ec7becf.chunk.js +1 -0
  263. package/build/i18n-translation-es-json.87b494d1.chunk.js +1 -0
  264. package/build/i18n-translation-fr-json.57ddc77e.chunk.js +1 -0
  265. package/build/i18n-translation-ko-json.ef4f9471.chunk.js +1 -0
  266. package/build/i18n-translation-pl-json.dfac513d.chunk.js +1 -0
  267. package/build/i18n-translation-ru-json.a3dbc125.chunk.js +1 -0
  268. package/build/i18n-translation-tr-json.3bfc812f.chunk.js +1 -0
  269. package/build/i18n-translation-zh-Hans-json.757ce62d.chunk.js +1 -0
  270. package/build/i18n-translation-zh-json.bef2dc07.chunk.js +1 -0
  271. package/build/id-json.41e07c46.chunk.js +1 -0
  272. package/build/index.html +1 -0
  273. package/build/it-json.bfe27ed8.chunk.js +1 -0
  274. package/build/ja-json.e1959a1c.chunk.js +1 -0
  275. package/build/ko-json.ce5d6d94.chunk.js +1 -0
  276. package/build/main.f84563f1.js +2665 -0
  277. package/build/ml-json.940d7ace.chunk.js +1 -0
  278. package/build/ms-json.0eddffd9.chunk.js +1 -0
  279. package/build/nl-json.fe38f0fb.chunk.js +1 -0
  280. package/build/no-json.19a2dbfa.chunk.js +1 -0
  281. package/build/pl-json.d55e8e78.chunk.js +1 -0
  282. package/build/pt-BR-json.ae0a0d2e.chunk.js +1 -0
  283. package/build/pt-json.ee554a41.chunk.js +1 -0
  284. package/build/review-workflows-sales-page.f46a8f00.chunk.js +1 -0
  285. package/build/review-workflows-settings-create-view.d0544fb0.chunk.js +1 -0
  286. package/build/review-workflows-settings-edit-view.aabf49ef.chunk.js +1 -0
  287. package/build/review-workflows-settings-list-view.8b0525ab.chunk.js +56 -0
  288. package/build/ru-json.1c976644.chunk.js +1 -0
  289. package/build/runtime~main.270fd45f.js +2 -0
  290. package/build/sa-json.2c03ef4e.chunk.js +1 -0
  291. package/build/sk-json.b41847e8.chunk.js +1 -0
  292. package/build/sso-sales-page.ef22e469.chunk.js +1 -0
  293. package/build/sso-settings-page.21e16ae4.chunk.js +1 -0
  294. package/build/sv-json.568cb7ae.chunk.js +1 -0
  295. package/build/th-json.5f659396.chunk.js +1 -0
  296. package/build/tr-json.c9f22432.chunk.js +1 -0
  297. package/build/transfer-tokens-create-page.3366204d.chunk.js +1 -0
  298. package/build/transfer-tokens-edit-page.15cf0f73.chunk.js +1 -0
  299. package/build/transfer-tokens-list-page.0bc0e682.chunk.js +16 -0
  300. package/build/uk-json.b7e38370.chunk.js +1 -0
  301. package/build/upload-settings.1319dca0.chunk.js +14 -0
  302. package/build/upload-translation-ca-json.57954414.chunk.js +1 -0
  303. package/build/upload-translation-de-json.420c943b.chunk.js +1 -0
  304. package/build/upload-translation-dk-json.bbb2fa05.chunk.js +1 -0
  305. package/build/upload-translation-en-json.8b7573ce.chunk.js +1 -0
  306. package/build/upload-translation-es-json.ba2eb03a.chunk.js +1 -0
  307. package/build/upload-translation-fr-json.baab9911.chunk.js +1 -0
  308. package/build/upload-translation-he-json.0a830937.chunk.js +1 -0
  309. package/build/upload-translation-it-json.e87d7966.chunk.js +1 -0
  310. package/build/upload-translation-ja-json.44b88e7a.chunk.js +1 -0
  311. package/build/upload-translation-ko-json.a52eab64.chunk.js +1 -0
  312. package/build/upload-translation-ms-json.74f6d746.chunk.js +1 -0
  313. package/build/upload-translation-pl-json.426f31c9.chunk.js +1 -0
  314. package/build/upload-translation-pt-BR-json.d1704f0b.chunk.js +1 -0
  315. package/build/upload-translation-pt-json.6b937fdf.chunk.js +1 -0
  316. package/build/upload-translation-ru-json.675f6b93.chunk.js +1 -0
  317. package/build/upload-translation-sk-json.483a18f6.chunk.js +1 -0
  318. package/build/upload-translation-th-json.98d35574.chunk.js +1 -0
  319. package/build/upload-translation-tr-json.74117e5c.chunk.js +1 -0
  320. package/build/upload-translation-uk-json.9950466a.chunk.js +1 -0
  321. package/build/upload-translation-zh-Hans-json.db163b6b.chunk.js +1 -0
  322. package/build/upload-translation-zh-json.e1dd6eb2.chunk.js +1 -0
  323. package/build/upload.1ced11be.chunk.js +58 -0
  324. package/build/users-advanced-settings-page.8e657084.chunk.js +9 -0
  325. package/build/users-email-settings-page.e57745e5.chunk.js +9 -0
  326. package/build/users-permissions-translation-ar-json.7d87d54d.chunk.js +1 -0
  327. package/build/users-permissions-translation-cs-json.7e23424a.chunk.js +1 -0
  328. package/build/users-permissions-translation-de-json.a6fb670f.chunk.js +1 -0
  329. package/build/users-permissions-translation-dk-json.60e50f48.chunk.js +1 -0
  330. package/build/users-permissions-translation-en-json.4b302272.chunk.js +1 -0
  331. package/build/users-permissions-translation-es-json.35007573.chunk.js +1 -0
  332. package/build/users-permissions-translation-fr-json.7e55bbbb.chunk.js +1 -0
  333. package/build/users-permissions-translation-id-json.a5a0fb59.chunk.js +1 -0
  334. package/build/users-permissions-translation-it-json.0705465d.chunk.js +1 -0
  335. package/build/users-permissions-translation-ja-json.891fe76e.chunk.js +1 -0
  336. package/build/users-permissions-translation-ko-json.357d7a33.chunk.js +1 -0
  337. package/build/users-permissions-translation-ms-json.c83f87c4.chunk.js +1 -0
  338. package/build/users-permissions-translation-nl-json.c9f92a3c.chunk.js +1 -0
  339. package/build/users-permissions-translation-pl-json.0a7287d1.chunk.js +1 -0
  340. package/build/users-permissions-translation-pt-BR-json.1b6d2920.chunk.js +1 -0
  341. package/build/users-permissions-translation-pt-json.a7eda429.chunk.js +1 -0
  342. package/build/users-permissions-translation-ru-json.8e883c67.chunk.js +1 -0
  343. package/build/users-permissions-translation-sk-json.7f37180f.chunk.js +1 -0
  344. package/build/users-permissions-translation-sv-json.17187818.chunk.js +1 -0
  345. package/build/users-permissions-translation-th-json.1e9c0247.chunk.js +1 -0
  346. package/build/users-permissions-translation-tr-json.2bd7ff98.chunk.js +1 -0
  347. package/build/users-permissions-translation-uk-json.6a0a1572.chunk.js +1 -0
  348. package/build/users-permissions-translation-vi-json.6722a8a2.chunk.js +1 -0
  349. package/build/users-permissions-translation-zh-Hans-json.8d82c809.chunk.js +1 -0
  350. package/build/users-permissions-translation-zh-json.7978eaa6.chunk.js +1 -0
  351. package/build/users-providers-settings-page.55796d13.chunk.js +14 -0
  352. package/build/users-roles-settings-page.57079245.chunk.js +55 -0
  353. package/build/vi-json.ee4c5537.chunk.js +1 -0
  354. package/build/webhook-edit-page.3a28b2e7.chunk.js +33 -0
  355. package/build/webhook-list-page.ee80767b.chunk.js +63 -0
  356. package/build/zh-Hans-json.97efd015.chunk.js +1 -0
  357. package/build/zh-json.bfc2e036.chunk.js +1 -0
  358. package/ee/admin/hooks/{useLicenseLimitNotification.js → useLicenseLimitNotification.ts} +4 -4
  359. package/ee/admin/pages/AuthPage/components/Login/index.js +1 -1
  360. package/ee/admin/pages/AuthPage/components/Providers/index.js +3 -2
  361. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/selectors.js +1 -1
  362. package/ee/admin/pages/SettingsPage/pages/Users/ListPage/index.js +1 -3
  363. package/ee/server/bootstrap.js +1 -1
  364. package/ee/server/controllers/admin.js +1 -1
  365. package/ee/server/controllers/user.js +1 -1
  366. package/ee/server/destroy.js +1 -1
  367. package/ee/server/register.js +1 -1
  368. package/ee/server/routes/utils.js +1 -1
  369. package/ee/server/services/audit-logs.js +1 -1
  370. package/ee/server/services/passport/sso.js +1 -1
  371. package/ee/server/services/passport.js +1 -1
  372. package/ee/server/services/seat-enforcement.js +1 -1
  373. package/ee/server/utils/sso-lock.js +1 -1
  374. package/ee/server/validation/role.js +1 -1
  375. package/ee/server/validation/user.js +1 -1
  376. package/jest.config.front.js +4 -0
  377. package/package.json +28 -22
  378. package/scripts/build.js +6 -2
  379. package/server/controllers/admin.js +4 -3
  380. package/shared/entities.ts +33 -0
  381. package/shared/permissions.ts +52 -0
  382. package/shared/schema.ts +9 -0
  383. package/webpack.config.js +1 -0
  384. package/admin/src/components/AuthenticatedApp/index.js +0 -120
  385. package/admin/src/components/AuthenticatedApp/utils/api.js +0 -85
  386. package/admin/src/components/AuthenticatedApp/utils/checkLatestStrapiVersion.js +0 -11
  387. package/admin/src/components/ConfigurationsProvider/index.js +0 -66
  388. package/admin/src/components/ConfigurationsProvider/reducer.js +0 -29
  389. package/admin/src/components/DragLayer/index.js +0 -1
  390. package/admin/src/components/GlobalStyle/index.js +0 -9
  391. package/admin/src/components/GuidedTour/Homepage/components/Step.js +0 -61
  392. package/admin/src/components/GuidedTour/Homepage/components/Stepper.js +0 -61
  393. package/admin/src/components/GuidedTour/Homepage/index.js +0 -71
  394. package/admin/src/components/GuidedTour/Modal/components/Content.js +0 -66
  395. package/admin/src/components/GuidedTour/Modal/components/Modal.js +0 -72
  396. package/admin/src/components/GuidedTour/Modal/components/StepNumberWithPadding.js +0 -26
  397. package/admin/src/components/GuidedTour/Modal/components/Stepper.js +0 -118
  398. package/admin/src/components/GuidedTour/Modal/index.js +0 -94
  399. package/admin/src/components/GuidedTour/Modal/reducer.js +0 -29
  400. package/admin/src/components/GuidedTour/Stepper/StepLine.js +0 -29
  401. package/admin/src/components/GuidedTour/Stepper/StepNumber.js +0 -71
  402. package/admin/src/components/GuidedTour/constants.js +0 -3
  403. package/admin/src/components/GuidedTour/index.js +0 -102
  404. package/admin/src/components/GuidedTour/init.js +0 -37
  405. package/admin/src/components/GuidedTour/reducer.js +0 -50
  406. package/admin/src/components/GuidedTour/utils/arePreviousSectionsDone.js +0 -13
  407. package/admin/src/components/GuidedTour/utils/arePreviousStepsDone.js +0 -12
  408. package/admin/src/components/GuidedTour/utils/isGuidedTourCompleted.js +0 -6
  409. package/admin/src/components/GuidedTour/utils/persistStateToLocaleStorage.js +0 -34
  410. package/admin/src/components/LanguageProvider/index.js +0 -54
  411. package/admin/src/components/LanguageProvider/init.js +0 -13
  412. package/admin/src/components/LanguageProvider/reducer.js +0 -30
  413. package/admin/src/components/LanguageProvider/utils/localStorageKey.js +0 -3
  414. package/admin/src/components/LocalesProvider/context.js +0 -5
  415. package/admin/src/components/LocalesProvider/index.js +0 -21
  416. package/admin/src/components/LocalesProvider/useLocalesProvider.js +0 -11
  417. package/admin/src/components/NpsSurvey/hooks/useNpsSurveySettings.js +0 -17
  418. package/admin/src/components/PluginsInitializer/index.js +0 -68
  419. package/admin/src/components/PluginsInitializer/init.js +0 -11
  420. package/admin/src/components/PluginsInitializer/reducer.js +0 -22
  421. package/admin/src/components/PrivateRoute/index.js +0 -46
  422. package/admin/src/components/Providers/index.js +0 -156
  423. package/admin/src/components/RBACProvider/actions.js +0 -10
  424. package/admin/src/components/RBACProvider/constants.js +0 -2
  425. package/admin/src/components/RBACProvider/index.js +0 -39
  426. package/admin/src/components/RBACProvider/reducer.js +0 -51
  427. package/admin/src/components/Theme/index.js +0 -26
  428. package/admin/src/components/ThemeToggleProvider/index.js +0 -79
  429. package/admin/src/contexts/Admin/index.js +0 -5
  430. package/admin/src/contexts/ApiTokenPermissions/index.js +0 -25
  431. package/admin/src/contexts/Configurations/index.js +0 -5
  432. package/admin/src/contexts/MarketPlace/index.js +0 -18
  433. package/admin/src/contexts/PermisssionsDataManagerContext/index.js +0 -5
  434. package/admin/src/contexts/ThemeToggle/index.js +0 -5
  435. package/admin/src/contexts/index.js +0 -4
  436. package/admin/src/core/store/configureStore.js +0 -47
  437. package/admin/src/exposedHooks.js +0 -27
  438. package/admin/src/hooks/useAdminRoles/__mocks__/index.js +0 -5
  439. package/admin/src/hooks/useAdminUsers/index.js +0 -1
  440. package/admin/src/hooks/useAdminUsers/useAdminUsers.js +0 -47
  441. package/admin/src/hooks/useConfigurations/index.js +0 -11
  442. package/admin/src/hooks/useContentTypes/index.js +0 -1
  443. package/admin/src/hooks/useDebounce/index.js +0 -19
  444. package/admin/src/hooks/useEnterprise/index.js +0 -1
  445. package/admin/src/hooks/useLicenseLimitNotification/index.js +0 -5
  446. package/admin/src/hooks/useMenu/index.js +0 -86
  447. package/admin/src/hooks/useMenu/utils/checkPermissions.js +0 -13
  448. package/admin/src/hooks/useMenu/utils/getGeneralLinks.js +0 -31
  449. package/admin/src/hooks/useMenu/utils/getPluginSectionLinks.js +0 -17
  450. package/admin/src/hooks/usePermissionsDataManager/index.js +0 -7
  451. package/admin/src/hooks/useReleaseNotification/index.js +0 -31
  452. package/admin/src/hooks/useReleaseNotification/utils/api.js +0 -20
  453. package/admin/src/hooks/useReleaseNotification/utils/checkLatestStrapiVersion.js +0 -11
  454. package/admin/src/hooks/useThemeToggle/index.js +0 -11
  455. package/admin/src/injectionZones.js +0 -25
  456. package/admin/src/layouts/UnauthenticatedLayout/LocaleToggle/index.js +0 -29
  457. package/admin/src/layouts/UnauthenticatedLayout/index.js +0 -55
  458. package/admin/src/reducers.js +0 -23
  459. package/admin/src/shared/hooks/useAdminProvider/index.js +0 -11
  460. package/admin/src/tsconfig.json +0 -10
  461. package/admin/src/utils/checkFormValidity.js +0 -15
  462. package/admin/src/utils/createRoute.js +0 -47
  463. package/admin/src/utils/formatAPIErrors.js +0 -17
  464. package/admin/src/utils/getAttributesToDisplay.js +0 -19
  465. package/admin/src/utils/getExistingActions.js +0 -32
  466. package/admin/src/utils/getFullName.js +0 -9
  467. package/admin/src/utils/index.js +0 -9
  468. package/admin/src/utils/makeUniqueRoutes.js +0 -6
  469. package/admin/src/utils/sortLinks.js +0 -5
  470. /package/admin/src/hooks/{useAdminUsers/__mocks__/index.js → __mocks__/useAdminUsers.ts} +0 -0
  471. /package/admin/src/hooks/{useContentTypes/__mocks__/index.js → __mocks__/useContentTypes.ts} +0 -0
  472. /package/admin/src/{hooks/useAdminRolePermissions/__mocks__/index.js → pages/SettingsPage/pages/Roles/hooks/__mocks__/useAdminRolePermissions.ts} +0 -0
@@ -1,17 +1,24 @@
1
1
  import * as React from 'react';
2
2
 
3
3
  import * as Toolbar from '@radix-ui/react-toolbar';
4
- import { Flex, Icon, Tooltip, Select, Option, Box, Typography } from '@strapi/design-system';
4
+ import { Flex, Icon, Tooltip, SingleSelect, SingleSelectOption, Box } from '@strapi/design-system';
5
5
  import { pxToRem, prefixFileUrlWithBackendUrl, useLibrary } from '@strapi/helper-plugin';
6
- import { BulletList, NumberList } from '@strapi/icons';
6
+ import { Link } from '@strapi/icons';
7
7
  import PropTypes from 'prop-types';
8
8
  import { useIntl } from 'react-intl';
9
9
  import { Editor, Transforms, Element as SlateElement } from 'slate';
10
- import { useSlate } from 'slate-react';
10
+ import { ReactEditor, useSlate } from 'slate-react';
11
11
  import styled from 'styled-components';
12
12
 
13
13
  import { useBlocksStore } from '../hooks/useBlocksStore';
14
14
  import { useModifiersStore } from '../hooks/useModifiersStore';
15
+ import { insertLink } from '../utils/links';
16
+
17
+ const ToolbarWrapper = styled(Flex)`
18
+ &[aria-disabled='true'] {
19
+ cursor: not-allowed;
20
+ }
21
+ `;
15
22
 
16
23
  const Separator = styled(Toolbar.Separator)`
17
24
  background: ${({ theme }) => theme.colors.neutral150};
@@ -20,32 +27,81 @@ const Separator = styled(Toolbar.Separator)`
20
27
  `;
21
28
 
22
29
  const FlexButton = styled(Flex).attrs({ as: 'button' })`
23
- &:hover {
24
- background: ${({ theme }) => theme.colors.primary100};
30
+ // Inherit the not-allowed cursor from ToolbarWrapper when disabled
31
+ &[aria-disabled] {
32
+ cursor: inherit;
33
+ }
34
+
35
+ &[aria-disabled='false'] {
36
+ cursor: pointer;
37
+
38
+ // Only apply hover styles if the button is enabled
39
+ &:hover {
40
+ background: ${({ theme }) => theme.colors.primary100};
41
+ }
42
+ }
43
+ `;
44
+
45
+ const SelectWrapper = styled(Box)`
46
+ // Styling changes to SingleSelect component don't work, so adding wrapper to target SingleSelect
47
+ div[role='combobox'] {
48
+ border: none;
49
+ cursor: pointer;
50
+
51
+ &[aria-disabled='false']:hover {
52
+ cursor: pointer;
53
+ background: ${({ theme }) => theme.colors.primary100};
54
+ }
55
+
56
+ &[aria-disabled] {
57
+ background: transparent;
58
+ cursor: inherit;
59
+
60
+ // Select text and icons should also have disabled color
61
+ span {
62
+ color: ${({ theme }) => theme.colors.neutral600};
63
+ }
64
+ }
25
65
  }
26
66
  `;
27
67
 
28
- const ToolbarButton = ({ icon, name, label, isActive, handleClick }) => {
68
+ const ToolbarButton = ({ icon, name, label, isActive, disabled, handleClick }) => {
69
+ const editor = useSlate();
29
70
  const { formatMessage } = useIntl();
30
71
  const labelMessage = formatMessage(label);
31
72
 
73
+ const enabledColor = isActive ? 'primary600' : 'neutral600';
74
+
32
75
  return (
33
76
  <Tooltip description={labelMessage}>
34
- <Toolbar.ToggleItem value={name} data-state={isActive ? 'on' : 'off'} asChild>
77
+ <Toolbar.ToggleItem
78
+ value={name}
79
+ data-state={isActive ? 'on' : 'off'}
80
+ onMouseDown={(e) => {
81
+ e.preventDefault();
82
+ handleClick();
83
+ }}
84
+ aria-disabled={disabled}
85
+ disabled={disabled}
86
+ aria-label={labelMessage}
87
+ asChild
88
+ >
35
89
  <FlexButton
90
+ disabled={disabled}
36
91
  background={isActive ? 'primary100' : ''}
37
92
  alignItems="center"
38
93
  justifyContent="center"
39
94
  width={7}
40
95
  height={7}
41
96
  hasRadius
42
- onMouseDown={(e) => {
43
- e.preventDefault();
97
+ onMouseDown={() => {
44
98
  handleClick();
99
+ // When a button is clicked it blurs the editor, restore the focus to the editor
100
+ ReactEditor.focus(editor);
45
101
  }}
46
102
  aria-label={labelMessage}
47
103
  >
48
- <Icon width={3} height={3} as={icon} color={isActive ? 'primary600' : 'neutral600'} />
104
+ <Icon width={3} height={3} as={icon} color={disabled ? 'neutral300' : enabledColor} />
49
105
  </FlexButton>
50
106
  </Toolbar.ToggleItem>
51
107
  </Tooltip>
@@ -60,77 +116,64 @@ ToolbarButton.propTypes = {
60
116
  defaultMessage: PropTypes.string.isRequired,
61
117
  }).isRequired,
62
118
  isActive: PropTypes.bool.isRequired,
119
+ disabled: PropTypes.bool.isRequired,
63
120
  handleClick: PropTypes.func.isRequired,
64
121
  };
65
122
 
66
- const ModifierButton = ({ icon, name, label }) => {
67
- const editor = useSlate();
68
-
69
- const isModifierActive = () => {
70
- const modifiers = Editor.marks(editor);
71
-
72
- if (!modifiers) return false;
73
-
74
- return Boolean(modifiers[name]);
75
- };
76
-
77
- const isActive = isModifierActive();
78
-
79
- const toggleModifier = () => {
80
- if (isActive) {
81
- Editor.removeMark(editor, name);
82
- } else {
83
- Editor.addMark(editor, name, true);
84
- }
85
- };
86
-
87
- return (
88
- <ToolbarButton
89
- icon={icon}
90
- name={name}
91
- label={label}
92
- isActive={isActive}
93
- handleClick={toggleModifier}
94
- />
95
- );
96
- };
97
-
98
- ModifierButton.propTypes = {
99
- icon: PropTypes.elementType.isRequired,
100
- name: PropTypes.string.isRequired,
101
- label: PropTypes.shape({
102
- id: PropTypes.string.isRequired,
103
- defaultMessage: PropTypes.string.isRequired,
104
- }).isRequired,
105
- };
106
-
107
- const isBlockActive = (editor, matchNode) => {
108
- const { selection } = editor;
109
-
110
- if (!selection) return false;
111
-
112
- const match = Array.from(
113
- Editor.nodes(editor, {
114
- at: Editor.unhangRange(editor, selection),
115
- match: (n) => !Editor.isEditor(n) && SlateElement.isElement(n) && matchNode(n),
116
- })
117
- );
118
-
119
- return match.length > 0;
120
- };
121
-
122
123
  const toggleBlock = (editor, value) => {
123
- const { type, level } = value;
124
+ const { type, level, format } = value;
124
125
 
125
- const newProperties = {
126
+ // Set the selected block properties received from the useBlockStore
127
+ const blockProperties = {
126
128
  type,
127
129
  level: level || null,
130
+ format: format || null,
128
131
  };
129
132
 
130
- Transforms.setNodes(editor, newProperties);
131
- };
133
+ if (editor.selection) {
134
+ // If the selection is inside a list, split the list so that the modified block is outside of it
135
+ Transforms.unwrapNodes(editor, {
136
+ match: (node) => node.type === 'list',
137
+ split: true,
138
+ });
132
139
 
133
- const ALLOWED_MEDIA_TYPE = 'images';
140
+ // When there is a selection, update the existing block in the tree
141
+ Transforms.setNodes(editor, blockProperties);
142
+ } else {
143
+ /**
144
+ * When there is no selection, we want to insert a new block just after
145
+ * the last node inserted and prevent the code to add an empty paragraph
146
+ * between them.
147
+ */
148
+ const [, lastNodePath] = Editor.last(editor, []);
149
+ const [parentNode] = Editor.parent(editor, lastNodePath, {
150
+ // Makes sure we get a block node, not an inline node
151
+ match: (node) => node.type !== 'text',
152
+ });
153
+ Transforms.removeNodes(editor, {
154
+ void: true,
155
+ hanging: true,
156
+ at: {
157
+ anchor: { path: lastNodePath, offset: 0 },
158
+ focus: { path: lastNodePath, offset: 0 },
159
+ },
160
+ });
161
+ Transforms.insertNodes(
162
+ editor,
163
+ {
164
+ ...blockProperties,
165
+ children: parentNode.children,
166
+ },
167
+ {
168
+ at: [lastNodePath[0]],
169
+ select: true,
170
+ }
171
+ );
172
+ }
173
+
174
+ // When the select is clicked it blurs the editor, restore the focus to the editor
175
+ ReactEditor.focus(editor);
176
+ };
134
177
 
135
178
  const IMAGE_SCHEMA_FIELDS = [
136
179
  'name',
@@ -167,15 +210,35 @@ const ImageDialog = ({ handleClose }) => {
167
210
  const MediaLibraryDialog = components['media-library'];
168
211
 
169
212
  const insertImages = (images) => {
170
- images.forEach((img) => {
171
- const image = { type: 'image', image: img, children: [{ type: 'text', text: '' }] };
172
- Transforms.insertNodes(editor, image);
213
+ // If the selection is inside a list, split the list so that the modified block is outside of it
214
+ Transforms.unwrapNodes(editor, {
215
+ match: (node) => node.type === 'list',
216
+ split: true,
217
+ });
218
+
219
+ // Save the path of the node that is being replaced by an image to insert the images there later
220
+ // It's the closest full block node above the selection
221
+ const [, pathToInsert] = Editor.above(editor, {
222
+ match(node) {
223
+ const isInlineNode = ['text', 'link'].includes(node.type);
224
+
225
+ return !isInlineNode;
226
+ },
227
+ });
228
+
229
+ // Remove the previous node that is being replaced by an image
230
+ Transforms.removeNodes(editor);
231
+
232
+ // Convert images to nodes and insert them
233
+ const nodesToInsert = images.map((image) => {
234
+ return { type: 'image', image, children: [{ type: 'text', text: '' }] };
173
235
  });
236
+ Transforms.insertNodes(editor, nodesToInsert, { at: pathToInsert });
174
237
  };
175
238
 
176
239
  const handleSelectAssets = (images) => {
177
240
  const formattedImages = images.map((image) => {
178
- // create an object with imageSchema defined and exclude unnecessary props coming from media library config
241
+ // Create an object with imageSchema defined and exclude unnecessary props coming from media library config
179
242
  const expectedImage = pick(image, IMAGE_SCHEMA_FIELDS);
180
243
 
181
244
  return {
@@ -186,12 +249,18 @@ const ImageDialog = ({ handleClose }) => {
186
249
  });
187
250
 
188
251
  insertImages(formattedImages);
252
+
253
+ if (isLastBlockType(editor, 'image')) {
254
+ // Insert blank line to add new blocks below image block
255
+ insertEmptyBlockAtLast(editor);
256
+ }
257
+
189
258
  handleClose();
190
259
  };
191
260
 
192
261
  return (
193
262
  <MediaLibraryDialog
194
- allowedTypes={[ALLOWED_MEDIA_TYPE]}
263
+ allowedTypes={['images']}
195
264
  onClose={handleClose}
196
265
  onSelectAssets={handleSelectAssets}
197
266
  />
@@ -202,18 +271,18 @@ ImageDialog.propTypes = {
202
271
  handleClose: PropTypes.func.isRequired,
203
272
  };
204
273
 
205
- const isLastBlockImageOrCode = (editor) => {
274
+ const isLastBlockType = (editor, type) => {
206
275
  const { selection } = editor;
207
276
 
208
277
  if (!selection) return false;
209
278
 
210
- const [currentImageORCodeBlock] = Editor.nodes(editor, {
279
+ const [currentBlock] = Editor.nodes(editor, {
211
280
  at: selection,
212
- match: (n) => n.type === 'image' || n.type === 'code',
281
+ match: (n) => n.type === type,
213
282
  });
214
283
 
215
- if (currentImageORCodeBlock) {
216
- const [, currentNodePath] = currentImageORCodeBlock;
284
+ if (currentBlock) {
285
+ const [, currentNodePath] = currentBlock;
217
286
 
218
287
  const isNodeAfter = Boolean(Editor.after(editor, currentNodePath));
219
288
 
@@ -223,7 +292,18 @@ const isLastBlockImageOrCode = (editor) => {
223
292
  return false;
224
293
  };
225
294
 
226
- export const BlocksDropdown = () => {
295
+ const insertEmptyBlockAtLast = (editor) => {
296
+ Transforms.insertNodes(
297
+ editor,
298
+ {
299
+ type: 'paragraph',
300
+ children: [{ type: 'text', text: '' }],
301
+ },
302
+ { at: [editor.children.length] }
303
+ );
304
+ };
305
+
306
+ const BlocksDropdown = ({ disabled }) => {
227
307
  const editor = useSlate();
228
308
  const { formatMessage } = useIntl();
229
309
  const [isMediaLibraryVisible, setIsMediaLibraryVisible] = React.useState(false);
@@ -241,20 +321,24 @@ export const BlocksDropdown = () => {
241
321
  * @param {string} optionKey - key of the heading selected
242
322
  */
243
323
  const selectOption = (optionKey) => {
244
- toggleBlock(editor, blocks[optionKey].value);
324
+ if (['list-ordered', 'list-unordered'].includes(optionKey)) {
325
+ // retrieve the list format
326
+ const listFormat = blocks[optionKey].value.format;
327
+
328
+ // check if the list is already active
329
+ const isActive = isListActive(editor, blocks[optionKey].matchNode);
330
+
331
+ // toggle the list
332
+ toggleList(editor, isActive, listFormat);
333
+ } else if (optionKey !== 'image') {
334
+ toggleBlock(editor, blocks[optionKey].value);
335
+ }
245
336
 
246
337
  setBlockSelected(optionKey);
247
338
 
248
- if (isLastBlockImageOrCode(editor)) {
249
- // insert blank line to add new blocks below code or image blocks
250
- Transforms.insertNodes(
251
- editor,
252
- {
253
- type: 'paragraph',
254
- children: [{ type: 'text', text: '' }],
255
- },
256
- { at: [editor.children.length] }
257
- );
339
+ if (optionKey === 'code' && isLastBlockType(editor, 'code')) {
340
+ // Insert blank line to add new blocks below code block
341
+ insertEmptyBlockAtLast(editor);
258
342
  }
259
343
 
260
344
  if (optionKey === 'image') {
@@ -262,55 +346,84 @@ export const BlocksDropdown = () => {
262
346
  }
263
347
  };
264
348
 
349
+ /**
350
+ * Prevent the select from focusing itself so ReactEditor.focus(editor) can focus the editor instead.
351
+ *
352
+ * The editor first loses focus to a blur event when clicking the select button. However,
353
+ * refocusing the editor is not enough since the select's default behavior is to refocus itself
354
+ * after an option is selected.
355
+ *
356
+ */
357
+ const preventSelectFocus = (e) => e.preventDefault();
358
+
359
+ // Listen to the selection change and update the selected block in the dropdown
360
+ React.useEffect(() => {
361
+ if (editor.selection) {
362
+ // Get the parent node of the anchor
363
+ // with a depth of two to retrieve also the list item parents
364
+ const [anchorNode] = Editor.parent(editor, editor.selection.anchor, {
365
+ edge: 'start',
366
+ depth: 2,
367
+ });
368
+ // Find the block key that matches the anchor node
369
+ const anchorBlockKey = Object.keys(blocks).find((blockKey) =>
370
+ blocks[blockKey].matchNode(anchorNode)
371
+ );
372
+
373
+ // Change the value selected in the dropdown if it doesn't match the anchor block key
374
+ if (anchorBlockKey && anchorBlockKey !== blockSelected) {
375
+ setBlockSelected(anchorBlockKey);
376
+ }
377
+ }
378
+ }, [editor.selection, editor, blocks, blockSelected]);
379
+
265
380
  return (
266
381
  <>
267
- <Select
268
- startIcon={<Icon as={blocks[blockSelected].icon} />}
269
- onChange={selectOption}
270
- placeholder={blocks[blockSelected].label}
271
- value={blockSelected}
272
- aria-label={formatMessage({
273
- id: 'components.Blocks.blocks.selectBlock',
274
- defaultMessage: 'Select a block',
275
- })}
276
- >
277
- {blockKeysToInclude.map((key) => (
278
- <BlockOption
279
- key={key}
280
- value={key}
281
- label={blocks[key].label}
282
- icon={blocks[key].icon}
283
- matchNode={blocks[key].matchNode}
284
- handleSelection={setBlockSelected}
285
- blockSelected={blockSelected}
286
- />
287
- ))}
288
- </Select>
382
+ <SelectWrapper>
383
+ <SingleSelect
384
+ startIcon={<Icon as={blocks[blockSelected].icon} />}
385
+ onChange={selectOption}
386
+ placeholder={blocks[blockSelected].label}
387
+ value={blockSelected}
388
+ onCloseAutoFocus={preventSelectFocus}
389
+ aria-label={formatMessage({
390
+ id: 'components.Blocks.blocks.selectBlock',
391
+ defaultMessage: 'Select a block',
392
+ })}
393
+ disabled={disabled}
394
+ >
395
+ {blockKeysToInclude.map((key) => (
396
+ <BlockOption
397
+ key={key}
398
+ value={key}
399
+ label={blocks[key].label}
400
+ icon={blocks[key].icon}
401
+ blockSelected={blockSelected}
402
+ />
403
+ ))}
404
+ </SingleSelect>
405
+ </SelectWrapper>
289
406
  {isMediaLibraryVisible && <ImageDialog handleClose={() => setIsMediaLibraryVisible(false)} />}
290
407
  </>
291
408
  );
292
409
  };
293
410
 
294
- const BlockOption = ({ value, icon, label, handleSelection, blockSelected, matchNode }) => {
411
+ BlocksDropdown.propTypes = {
412
+ disabled: PropTypes.bool.isRequired,
413
+ };
414
+
415
+ const BlockOption = ({ value, icon, label, blockSelected }) => {
295
416
  const { formatMessage } = useIntl();
296
- const editor = useSlate();
297
417
 
298
- const isActive = isBlockActive(editor, matchNode);
299
418
  const isSelected = value === blockSelected;
300
419
 
301
- React.useEffect(() => {
302
- if (isActive && !isSelected) {
303
- handleSelection(value);
304
- }
305
- }, [handleSelection, isActive, isSelected, value]);
306
-
307
420
  return (
308
- <Option
421
+ <SingleSelectOption
309
422
  startIcon={<Icon as={icon} color={isSelected ? 'primary600' : 'neutral600'} />}
310
423
  value={value}
311
424
  >
312
425
  {formatMessage(label)}
313
- </Option>
426
+ </SingleSelectOption>
314
427
  );
315
428
  };
316
429
 
@@ -321,58 +434,101 @@ BlockOption.propTypes = {
321
434
  id: PropTypes.string.isRequired,
322
435
  defaultMessage: PropTypes.string.isRequired,
323
436
  }).isRequired,
324
- matchNode: PropTypes.func.isRequired,
325
- handleSelection: PropTypes.func.isRequired,
326
437
  blockSelected: PropTypes.string.isRequired,
327
438
  };
328
439
 
329
- const ListButton = ({ icon, format, label }) => {
330
- const editor = useSlate();
331
-
332
- /**
333
- *
334
- * @param {import('slate').Node} node
335
- * @returns boolean
336
- */
337
- const isListNode = (node) => {
338
- return !Editor.isEditor(node) && SlateElement.isElement(node) && node.type === 'list';
339
- };
340
-
341
- const isListActive = () => {
342
- const { selection } = editor;
440
+ /**
441
+ *
442
+ * @param {import('slate').Node} node
443
+ * @returns boolean
444
+ */
445
+ const isListNode = (node) => {
446
+ return !Editor.isEditor(node) && SlateElement.isElement(node) && node.type === 'list';
447
+ };
343
448
 
344
- if (!selection) return false;
449
+ const isListActive = (editor, matchNode) => {
450
+ const { selection } = editor;
345
451
 
346
- const [match] = Array.from(
347
- Editor.nodes(editor, {
348
- at: Editor.unhangRange(editor, selection),
349
- match: (node) => isListNode(node) && node.format === format,
350
- })
351
- );
452
+ if (!selection) return false;
352
453
 
353
- return Boolean(match);
354
- };
454
+ const [match] = Array.from(
455
+ Editor.nodes(editor, {
456
+ at: Editor.unhangRange(editor, selection),
457
+ match: matchNode,
458
+ })
459
+ );
355
460
 
356
- const isActive = isListActive();
461
+ return Boolean(match);
462
+ };
357
463
 
358
- const toggleList = () => {
359
- // Delete the parent list so that we're left with only the list items directly
464
+ const toggleList = (editor, isActive, format) => {
465
+ // If we have selected a portion of content in the editor,
466
+ // we want to convert it to a list or if it is already a list,
467
+ // convert it back to a paragraph
468
+ if (editor.selection) {
360
469
  Transforms.unwrapNodes(editor, {
361
470
  match: (node) => isListNode(node) && ['ordered', 'unordered'].includes(node.format),
362
471
  split: true,
363
472
  });
364
473
 
365
- // Change the type of the current selection
366
474
  Transforms.setNodes(editor, {
367
475
  type: isActive ? 'paragraph' : 'list-item',
368
476
  });
369
477
 
370
- // If the selection is now a list item, wrap it inside a list
371
478
  if (!isActive) {
372
479
  const block = { type: 'list', format, children: [] };
373
480
  Transforms.wrapNodes(editor, block);
374
481
  }
375
- };
482
+ } else {
483
+ // There is no selection, convert the last inserted node to a list
484
+ // If it is already a list, convert it back to a paragraph
485
+ const [, lastNodePath] = Editor.last(editor, []);
486
+
487
+ const [parentNode] = Editor.parent(editor, lastNodePath, {
488
+ // Makes sure we get a block node, not an inline node
489
+ match: (node) => node.type !== 'text',
490
+ });
491
+
492
+ Transforms.removeNodes(editor, {
493
+ void: true,
494
+ hanging: true,
495
+ at: {
496
+ anchor: { path: lastNodePath, offset: 0 },
497
+ focus: { path: lastNodePath, offset: 0 },
498
+ },
499
+ });
500
+
501
+ Transforms.insertNodes(
502
+ editor,
503
+ {
504
+ type: isActive ? 'paragraph' : 'list-item',
505
+ children: [...parentNode.children],
506
+ },
507
+ {
508
+ at: [lastNodePath[0]],
509
+ select: true,
510
+ }
511
+ );
512
+
513
+ if (!isActive) {
514
+ // If the selection is now a list item, wrap it inside a list
515
+ const block = { type: 'list', format, children: [] };
516
+ Transforms.wrapNodes(editor, block);
517
+ }
518
+ }
519
+ };
520
+
521
+ const ListButton = ({ block, disabled }) => {
522
+ const editor = useSlate();
523
+
524
+ const {
525
+ icon,
526
+ matchNode,
527
+ value: { format },
528
+ label,
529
+ } = block;
530
+
531
+ const isActive = isListActive(editor, matchNode);
376
532
 
377
533
  return (
378
534
  <ToolbarButton
@@ -380,40 +536,131 @@ const ListButton = ({ icon, format, label }) => {
380
536
  name={format}
381
537
  label={label}
382
538
  isActive={isActive}
383
- handleClick={toggleList}
539
+ disabled={disabled}
540
+ handleClick={() => toggleList(editor, isActive, format)}
384
541
  />
385
542
  );
386
543
  };
387
544
 
388
545
  ListButton.propTypes = {
389
- icon: PropTypes.elementType.isRequired,
390
- format: PropTypes.string.isRequired,
391
- label: PropTypes.shape({
392
- id: PropTypes.string.isRequired,
393
- defaultMessage: PropTypes.string.isRequired,
546
+ block: PropTypes.shape({
547
+ icon: PropTypes.elementType.isRequired,
548
+ matchNode: PropTypes.func.isRequired,
549
+ value: PropTypes.shape({
550
+ format: PropTypes.string.isRequired,
551
+ }).isRequired,
552
+ label: PropTypes.shape({
553
+ id: PropTypes.string.isRequired,
554
+ defaultMessage: PropTypes.string.isRequired,
555
+ }).isRequired,
394
556
  }).isRequired,
557
+ disabled: PropTypes.bool.isRequired,
395
558
  };
396
559
 
397
- // TODO: Remove after the RTE Blocks Alpha release
398
- const AlphaTag = styled(Box)`
399
- background-color: ${({ theme }) => theme.colors.warning100};
400
- border: ${({ theme }) => `1px solid ${theme.colors.warning200}`};
401
- border-radius: ${({ theme }) => theme.borderRadius};
402
- font-size: ${({ theme }) => theme.fontSizes[0]};
403
- padding: ${({ theme }) => `${2 / 16}rem ${theme.spaces[1]}`};
404
- `;
560
+ const LinkButton = ({ disabled }) => {
561
+ const editor = useSlate();
562
+
563
+ const isLinkActive = () => {
564
+ const { selection } = editor;
405
565
 
406
- const BlocksToolbar = () => {
566
+ if (!selection) return false;
567
+
568
+ const [match] = Array.from(
569
+ Editor.nodes(editor, {
570
+ at: Editor.unhangRange(editor, selection),
571
+ match: (node) => SlateElement.isElement(node) && node.type === 'link',
572
+ })
573
+ );
574
+
575
+ return Boolean(match);
576
+ };
577
+
578
+ const isLinkDisabled = () => {
579
+ // Always disabled when the whole editor is disabled
580
+ if (disabled) {
581
+ return true;
582
+ }
583
+
584
+ // Always enabled when there's no selection
585
+ if (!editor.selection) {
586
+ return false;
587
+ }
588
+
589
+ // Get the block node closest to the anchor and focus
590
+ const anchorNodeEntry = Editor.above(editor, {
591
+ at: editor.selection.anchor,
592
+ match: (node) => node.type !== 'text',
593
+ });
594
+ const focusNodeEntry = Editor.above(editor, {
595
+ at: editor.selection.focus,
596
+ match: (node) => node.type !== 'text',
597
+ });
598
+
599
+ // Disabled if the anchor and focus are not in the same block
600
+ return anchorNodeEntry[0] !== focusNodeEntry[0];
601
+ };
602
+
603
+ const addLink = () => {
604
+ // We insert an empty anchor, so we split the DOM to have a element we can use as reference for the popover
605
+ insertLink(editor, { url: '' });
606
+ };
607
+
608
+ return (
609
+ <ToolbarButton
610
+ icon={Link}
611
+ name="link"
612
+ label={{
613
+ id: 'components.Blocks.link',
614
+ defaultMessage: 'Link',
615
+ }}
616
+ isActive={isLinkActive()}
617
+ handleClick={addLink}
618
+ disabled={isLinkDisabled()}
619
+ />
620
+ );
621
+ };
622
+
623
+ LinkButton.propTypes = {
624
+ disabled: PropTypes.bool.isRequired,
625
+ };
626
+
627
+ const BlocksToolbar = ({ disabled }) => {
407
628
  const modifiers = useModifiersStore();
629
+ const blocks = useBlocksStore();
630
+ const editor = useSlate();
631
+
632
+ /**
633
+ * The modifier buttons are disabled when an image is selected.
634
+ */
635
+
636
+ const checkButtonDisabled = () => {
637
+ // Always disabled when the whole editor is disabled
638
+ if (disabled) {
639
+ return true;
640
+ }
641
+
642
+ if (!editor.selection) {
643
+ return false;
644
+ }
645
+
646
+ const selectedNode = editor.children[editor.selection.anchor.path[0]];
647
+
648
+ if (['image', 'code'].includes(selectedNode.type)) {
649
+ return true;
650
+ }
651
+
652
+ return false;
653
+ };
654
+
655
+ const isButtonDisabled = checkButtonDisabled();
408
656
 
409
657
  return (
410
- <Toolbar.Root asChild>
411
- {/* Remove after the RTE Blocks Alpha release (paddingRight and width) */}
412
- <Flex gap={1} padding={2} paddingRight={4} width="100%">
413
- <BlocksDropdown />
658
+ <Toolbar.Root aria-disabled={disabled} asChild>
659
+ <ToolbarWrapper gap={2} padding={2}>
660
+ <BlocksDropdown disabled={disabled} />
414
661
  <Separator />
415
662
  <Toolbar.ToggleGroup type="multiple" asChild>
416
- <Flex gap={1}>
663
+ <Flex gap={1} marginLeft={1}>
417
664
  {Object.entries(modifiers).map(([name, modifier]) => (
418
665
  <ToolbarButton
419
666
  key={name}
@@ -422,42 +669,26 @@ const BlocksToolbar = () => {
422
669
  label={modifier.label}
423
670
  isActive={modifier.checkIsActive()}
424
671
  handleClick={modifier.handleToggle}
672
+ disabled={isButtonDisabled}
425
673
  />
426
674
  ))}
675
+ <LinkButton disabled={isButtonDisabled} />
427
676
  </Flex>
428
677
  </Toolbar.ToggleGroup>
429
678
  <Separator />
430
679
  <Toolbar.ToggleGroup type="single" asChild>
431
680
  <Flex gap={1}>
432
- <ListButton
433
- label={{
434
- id: 'components.Blocks.blocks.unorderedList',
435
- defaultMessage: 'Bulleted list',
436
- }}
437
- format="unordered"
438
- icon={BulletList}
439
- />
440
- <ListButton
441
- label={{
442
- id: 'components.Blocks.blocks.orderedList',
443
- defaultMessage: 'Numbered list',
444
- }}
445
- format="ordered"
446
- icon={NumberList}
447
- />
681
+ <ListButton block={blocks['list-unordered']} disabled={disabled} />
682
+ <ListButton block={blocks['list-ordered']} disabled={disabled} />
448
683
  </Flex>
449
684
  </Toolbar.ToggleGroup>
450
- {/* TODO: Remove after the RTE Blocks Alpha release */}
451
- <Flex grow={1} justifyContent="flex-end">
452
- <AlphaTag>
453
- <Typography textColor="warning600" variant="sigma">
454
- ALPHA
455
- </Typography>
456
- </AlphaTag>
457
- </Flex>
458
- </Flex>
685
+ </ToolbarWrapper>
459
686
  </Toolbar.Root>
460
687
  );
461
688
  };
462
689
 
690
+ BlocksToolbar.propTypes = {
691
+ disabled: PropTypes.bool.isRequired,
692
+ };
693
+
463
694
  export { BlocksToolbar };