@strapi/admin 4.5.0-alpha.0 → 4.5.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 (317) hide show
  1. package/admin/src/StrapiApp.js +21 -18
  2. package/admin/src/assets/images/hot-air-balloon.png +0 -0
  3. package/admin/src/assets/images/icon_offline-cloud.svg +3 -3
  4. package/admin/src/assets/images/logo-strapi-2022.svg +7 -0
  5. package/admin/src/assets/images/upgrade-details.png +0 -0
  6. package/admin/src/components/Providers/index.js +14 -10
  7. package/admin/src/content-manager/components/CollectionTypeFormWrapper/index.js +24 -0
  8. package/admin/src/content-manager/components/DynamicTable/CellContent/CellValue.js +1 -1
  9. package/admin/src/content-manager/components/DynamicTable/CellContent/RelationMultiple/index.js +5 -4
  10. package/admin/src/content-manager/components/DynamicTable/CellContent/index.js +10 -0
  11. package/admin/src/content-manager/components/DynamicTable/TableRows/index.js +20 -15
  12. package/admin/src/content-manager/components/DynamicTable/index.js +21 -4
  13. package/admin/src/content-manager/components/DynamicZone/components/Component/index.js +19 -9
  14. package/admin/src/content-manager/components/DynamicZone/index.js +6 -2
  15. package/admin/src/content-manager/components/EditViewDataManagerProvider/index.js +153 -63
  16. package/admin/src/content-manager/components/EditViewDataManagerProvider/reducer.js +180 -132
  17. package/admin/src/content-manager/components/EditViewDataManagerProvider/utils/cleanData.js +70 -16
  18. package/admin/src/content-manager/components/EditViewDataManagerProvider/utils/findLeafByPathAndReplace.js +52 -0
  19. package/admin/src/content-manager/components/EditViewDataManagerProvider/utils/index.js +2 -0
  20. package/admin/src/content-manager/components/EditViewDataManagerProvider/utils/recursivelyFindPathsBasedOnCondition.js +72 -0
  21. package/admin/src/content-manager/components/FieldComponent/index.js +9 -2
  22. package/admin/src/content-manager/components/FieldTypeIcon/index.js +31 -1
  23. package/admin/src/content-manager/components/Inputs/index.js +36 -14
  24. package/admin/src/content-manager/components/NonRepeatableComponent/index.js +2 -0
  25. package/admin/src/content-manager/components/PreviewWysiwyg/index.js +1 -1
  26. package/admin/src/content-manager/components/RelationInput/RelationInput.js +163 -96
  27. package/admin/src/content-manager/components/RelationInput/components/RelationItem.js +2 -2
  28. package/admin/src/content-manager/components/RelationInput/constants.js +1 -1
  29. package/admin/src/content-manager/components/RelationInputDataManager/RelationInputDataManager.js +116 -73
  30. package/admin/src/content-manager/components/RelationInputDataManager/utils/diffRelations.js +24 -0
  31. package/admin/src/content-manager/components/RelationInputDataManager/utils/index.js +3 -1
  32. package/admin/src/content-manager/components/RelationInputDataManager/utils/normalizeRelations.js +17 -31
  33. package/admin/src/content-manager/components/RelationInputDataManager/utils/normalizeSearchResults.js +16 -0
  34. package/admin/src/content-manager/components/RelationInputDataManager/utils/select.js +35 -11
  35. package/admin/src/content-manager/components/RepeatableComponent/DraggedItem/index.js +5 -0
  36. package/admin/src/content-manager/components/RepeatableComponent/index.js +4 -3
  37. package/admin/src/content-manager/components/SingleTypeFormWrapper/index.js +23 -0
  38. package/admin/src/content-manager/hooks/__test__/usePrev.test.js +26 -0
  39. package/admin/src/content-manager/hooks/index.js +1 -0
  40. package/admin/src/content-manager/hooks/useFetchContentTypeLayout/utils/formatLayouts.js +19 -48
  41. package/admin/src/content-manager/hooks/usePrev.js +14 -0
  42. package/admin/src/content-manager/hooks/useRelation/useRelation.js +116 -15
  43. package/admin/src/content-manager/pages/App/reducer.js +3 -0
  44. package/admin/src/content-manager/pages/EditSettingsView/components/FormModal.js +7 -2
  45. package/admin/src/content-manager/pages/EditSettingsView/index.js +2 -1
  46. package/admin/src/content-manager/pages/EditView/Header/index.js +118 -50
  47. package/admin/src/content-manager/pages/EditView/Header/utils/select.js +4 -0
  48. package/admin/src/content-manager/pages/EditView/index.js +102 -93
  49. package/admin/src/content-manager/pages/ListSettingsView/components/DraggableCard.js +3 -3
  50. package/admin/src/content-manager/pages/ListSettingsView/components/Settings.js +2 -2
  51. package/admin/src/content-manager/pages/ListSettingsView/components/SortDisplayedFields.js +1 -1
  52. package/admin/src/content-manager/pages/ListView/index.js +24 -15
  53. package/admin/src/content-manager/pages/ListView/utils/buildQueryString.js +14 -2
  54. package/admin/src/contexts/ApiTokenPermissions/index.js +24 -0
  55. package/admin/src/core/apis/CustomFields.js +79 -0
  56. package/admin/src/core/apis/index.js +1 -0
  57. package/admin/src/core/store/configureStore.js +17 -2
  58. package/admin/src/favicon.png +0 -0
  59. package/admin/src/hooks/index.js +1 -0
  60. package/admin/src/hooks/useFetchMarketplacePlugins/index.js +2 -2
  61. package/admin/src/hooks/useFetchMarketplacePlugins/utils/api.js +4 -2
  62. package/admin/src/hooks/useFetchMarketplaceProviders/index.js +3 -3
  63. package/admin/src/hooks/useFetchMarketplaceProviders/utils/api.js +5 -3
  64. package/admin/src/hooks/useRegenerate/index.js +34 -0
  65. package/admin/src/index.js +1 -0
  66. package/admin/src/pages/App/index.js +1 -1
  67. package/admin/src/pages/HomePage/SocialLinks.js +1 -1
  68. package/admin/src/pages/HomePage/assets/corner-ornament.svg +48 -0
  69. package/admin/src/pages/HomePage/index.js +3 -2
  70. package/admin/src/pages/MarketplacePage/components/NpmPackageCard/CardButton.js +110 -0
  71. package/admin/src/pages/MarketplacePage/components/NpmPackageCard/InstallPluginButton.js +32 -21
  72. package/admin/src/pages/MarketplacePage/components/NpmPackageCard/PackageStats.js +79 -0
  73. package/admin/src/pages/MarketplacePage/components/NpmPackageCard/index.js +28 -11
  74. package/admin/src/pages/MarketplacePage/components/NpmPackagesFilters/FilterSelect.js +41 -0
  75. package/admin/src/pages/MarketplacePage/components/NpmPackagesFilters/FiltersPopover.js +96 -0
  76. package/admin/src/pages/MarketplacePage/components/NpmPackagesFilters/index.js +106 -0
  77. package/admin/src/pages/MarketplacePage/components/NpmPackagesGrid/index.js +4 -0
  78. package/admin/src/pages/MarketplacePage/components/SortSelect/index.js +70 -0
  79. package/admin/src/pages/MarketplacePage/index.js +68 -8
  80. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/ActionBoundRoutes/index.js +56 -0
  81. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/BoundRoute/getMethodColor.js +41 -0
  82. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/BoundRoute/index.js +72 -0
  83. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/CollapsableContentType/CheckBoxWrapper.js +30 -0
  84. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/CollapsableContentType/index.js +150 -0
  85. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/ContenTypesSection/index.js +37 -0
  86. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/FormApiTokenContainer/index.js +255 -0
  87. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/FormBody/index.js +78 -0
  88. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/FormHead/index.js +89 -0
  89. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/Permissions/index.js +40 -0
  90. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/Regenerate/index.js +68 -0
  91. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/index.js +216 -197
  92. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/init.js +13 -0
  93. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/reducer.js +72 -0
  94. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/utils/getDateOfExpiration.js +16 -0
  95. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/utils/index.js +5 -0
  96. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/utils/schema.js +2 -1
  97. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/utils/transformPermissionsData.js +36 -0
  98. package/admin/src/pages/SettingsPage/pages/ApiTokens/ListView/DynamicTable/DefaultButton/index.js +63 -0
  99. package/admin/src/pages/SettingsPage/pages/ApiTokens/ListView/DynamicTable/DeleteButton/index.js +1 -0
  100. package/admin/src/pages/SettingsPage/pages/ApiTokens/ListView/DynamicTable/ReadButton/index.js +19 -0
  101. package/admin/src/pages/SettingsPage/pages/ApiTokens/ListView/DynamicTable/UpdateButton/index.js +3 -36
  102. package/admin/src/pages/SettingsPage/pages/ApiTokens/ListView/DynamicTable/index.js +13 -11
  103. package/admin/src/pages/SettingsPage/pages/ApiTokens/ListView/index.js +3 -2
  104. package/admin/src/pages/SettingsPage/pages/ApiTokens/ListView/utils/tableHeaders.js +8 -8
  105. package/admin/src/pages/SettingsPage/pages/ApiTokens/ProtectedEditView/index.js +1 -1
  106. package/admin/src/pages/SettingsPage/pages/Roles/EditPage/components/ConditionsModal/ActionRow/index.js +7 -38
  107. package/admin/src/pages/SettingsPage/pages/Roles/EditPage/components/ConditionsModal/ActionRow/utils/options.js +31 -0
  108. package/admin/src/pages/SettingsPage/pages/Roles/EditPage/components/ConditionsModal/index.js +32 -43
  109. package/admin/src/pages/SettingsPage/pages/Roles/EditPage/components/ContentTypeCollapse/Collapse/index.js +1 -1
  110. package/admin/src/pages/SettingsPage/pages/Roles/ListPage/components/RoleRow/index.js +3 -1
  111. package/admin/src/pages/SettingsPage/pages/Roles/ListPage/index.js +2 -1
  112. package/admin/src/pages/SettingsPage/pages/Users/ListPage/ModalForm/index.js +2 -2
  113. package/admin/src/pages/SettingsPage/pages/Webhooks/EditView/components/EventInput/index.js +2 -2
  114. package/admin/src/permissions/defaultPermissions.js +2 -6
  115. package/admin/src/translations/ca.json +4 -2
  116. package/admin/src/translations/de.json +5 -2
  117. package/admin/src/translations/dk.json +4 -1
  118. package/admin/src/translations/en.json +38 -3
  119. package/admin/src/translations/es.json +157 -158
  120. package/admin/src/translations/fr.json +4 -1
  121. package/admin/src/translations/gu.json +608 -606
  122. package/admin/src/translations/he.json +1 -1
  123. package/admin/src/translations/hi.json +689 -687
  124. package/admin/src/translations/hu.json +3 -1
  125. package/admin/src/translations/id.json +3 -1
  126. package/admin/src/translations/it.json +3 -1
  127. package/admin/src/translations/ja.json +3 -1
  128. package/admin/src/translations/ko.json +3 -1
  129. package/admin/src/translations/ml.json +689 -687
  130. package/admin/src/translations/nl.json +4 -1
  131. package/admin/src/translations/no.json +1 -1
  132. package/admin/src/translations/pl.json +3 -1
  133. package/admin/src/translations/pt-BR.json +4 -1
  134. package/admin/src/translations/ru.json +489 -491
  135. package/admin/src/translations/sa.json +86 -83
  136. package/admin/src/translations/sk.json +4 -1
  137. package/admin/src/translations/sv.json +4 -1
  138. package/admin/src/translations/th.json +1 -1
  139. package/admin/src/translations/zh-Hans.json +5 -2
  140. package/admin/src/translations/zh.json +4 -1
  141. package/build/1856.172d5fa0.chunk.js +174 -0
  142. package/build/2077.058590f4.chunk.js +206 -0
  143. package/build/2912.2c42c07b.chunk.js +259 -0
  144. package/build/4318.5e670740.chunk.js +30 -0
  145. package/build/4715.22747b59.chunk.js +387 -0
  146. package/build/{4800.d09f1225.chunk.js → 4800.a6935af6.chunk.js} +1 -1
  147. package/build/4982.1b75ddb1.chunk.js +325 -0
  148. package/build/617f9c948fa79e6d73bd.png +0 -0
  149. package/build/6d21938306785f176538.png +0 -0
  150. package/build/70674f63fc3904c20de0.svg +7 -0
  151. package/build/7379.d246dd38.chunk.js +1 -0
  152. package/build/7692.a36fb2c2.chunk.js +470 -0
  153. package/build/7841.c50e9509.chunk.js +259 -0
  154. package/build/7866.ba215f99.chunk.js +505 -0
  155. package/build/7e9af4fb7e723fcebf1f.svg +48 -0
  156. package/build/8380.e53e7207.chunk.js +299 -0
  157. package/build/8549.832ed79d.chunk.js +159 -0
  158. package/build/8738.0fe8a61e.chunk.js +463 -0
  159. package/build/{9066.08049eb1.chunk.js → 9066.eaf76ff3.chunk.js} +5 -5
  160. package/build/{9166.037339e0.chunk.js → 9166.90876521.chunk.js} +16 -15
  161. package/build/{9420.43a86e7c.chunk.js → 9420.5292d1d2.chunk.js} +38 -37
  162. package/build/9649.468667d9.chunk.js +199 -0
  163. package/build/9d5d788027e86620c234.svg +5 -0
  164. package/build/{Admin-authenticatedApp.e39f36c9.chunk.js → Admin-authenticatedApp.c4f68103.chunk.js} +3 -3
  165. package/build/{Admin_homePage.118926e0.chunk.js → Admin_homePage.26d32e30.chunk.js} +6 -5
  166. package/build/Admin_marketplace.32375885.chunk.js +22 -0
  167. package/build/{Admin_profilePage.9d50ac44.chunk.js → Admin_profilePage.da32abbc.chunk.js} +1 -1
  168. package/build/Admin_settingsPage.bf2234e1.chunk.js +178 -0
  169. package/build/admin-app.9049056c.chunk.js +112 -0
  170. package/build/admin-edit-roles-page.69d9fcb2.chunk.js +1 -0
  171. package/build/{admin-users.97a08630.chunk.js → admin-users.d71f198a.chunk.js} +3 -3
  172. package/build/api-tokens-create-page.93dd0689.chunk.js +1 -0
  173. package/build/api-tokens-edit-page.b0adac81.chunk.js +1 -0
  174. package/build/api-tokens-list-page.bb36535f.chunk.js +16 -0
  175. package/build/ca-json.07ae0f2c.chunk.js +1 -0
  176. package/build/content-manager.ff998bed.chunk.js +1204 -0
  177. package/build/content-type-builder-list-view.5b3cd768.chunk.js +194 -0
  178. package/build/content-type-builder-translation-en-json.f985c9c4.chunk.js +1 -0
  179. package/build/content-type-builder-translation-sv-json.6deff030.chunk.js +1 -0
  180. package/build/content-type-builder.16af63a6.chunk.js +145 -0
  181. package/build/de-json.6b3e1894.chunk.js +1 -0
  182. package/build/dk-json.144c6a8e.chunk.js +1 -0
  183. package/build/{email-settings-page.64037147.chunk.js → email-settings-page.c3469093.chunk.js} +6 -6
  184. package/build/en-json.4a269f6b.chunk.js +1 -0
  185. package/build/es-json.6d123a82.chunk.js +1 -0
  186. package/build/fr-json.28ab54cb.chunk.js +1 -0
  187. package/build/gu-json.9a50ea64.chunk.js +1 -0
  188. package/build/he-json.72f18790.chunk.js +1 -0
  189. package/build/hi-json.0301b7ba.chunk.js +1 -0
  190. package/build/hu-json.c4b641bb.chunk.js +1 -0
  191. package/build/{i18n-settings-page.0b73785d.chunk.js → i18n-settings-page.46d894ff.chunk.js} +5 -5
  192. package/build/id-json.86035797.chunk.js +1 -0
  193. package/build/index.html +1 -1
  194. package/build/it-json.bbdc8993.chunk.js +1 -0
  195. package/build/ja-json.1c9eeeec.chunk.js +1 -0
  196. package/build/ko-json.e1f66398.chunk.js +1 -0
  197. package/build/main.91328e7a.js +9381 -0
  198. package/build/ml-json.963c889f.chunk.js +1 -0
  199. package/build/nl-json.2b8cc3a0.chunk.js +1 -0
  200. package/build/no-json.a58c28bd.chunk.js +1 -0
  201. package/build/pl-json.249626b3.chunk.js +1 -0
  202. package/build/pt-BR-json.7852f808.chunk.js +1 -0
  203. package/build/ru-json.d7cfc2ff.chunk.js +1 -0
  204. package/build/runtime~main.c9c319c0.js +2 -0
  205. package/build/sa-json.44e95991.chunk.js +1 -0
  206. package/build/sk-json.7ba4b330.chunk.js +1 -0
  207. package/build/sso-settings-page.9ceb0140.chunk.js +1 -0
  208. package/build/sv-json.8e5a7911.chunk.js +1 -0
  209. package/build/th-json.a67309b1.chunk.js +1 -0
  210. package/build/{upload-settings.80ff0974.chunk.js → upload-settings.53b690f3.chunk.js} +5 -5
  211. package/build/{upload-translation-en-json.004a86c1.chunk.js → upload-translation-en-json.86da7b0a.chunk.js} +1 -1
  212. package/build/{users-advanced-settings-page.a02f4806.chunk.js → users-advanced-settings-page.3f4ee86e.chunk.js} +5 -5
  213. package/build/{webhook-edit-page.d2ea3351.chunk.js → webhook-edit-page.dc9442ce.chunk.js} +2 -2
  214. package/build/webhook-list-page.02191138.chunk.js +134 -0
  215. package/build/zh-Hans-json.21617c24.chunk.js +1 -0
  216. package/build/zh-json.608aaf24.chunk.js +1 -0
  217. package/ee/admin/pages/SettingsPage/pages/Roles/ListPage/index.js +3 -2
  218. package/ee/server/controllers/user.js +5 -3
  219. package/env.js +1 -0
  220. package/package.json +13 -11
  221. package/scripts/build.js +11 -0
  222. package/server/bootstrap.js +19 -1
  223. package/server/config/admin-actions.js +20 -0
  224. package/server/content-types/api-token-permission.js +36 -0
  225. package/server/content-types/api-token.js +25 -1
  226. package/server/content-types/index.js +1 -0
  227. package/server/controllers/admin.js +3 -0
  228. package/server/controllers/api-token.js +24 -1
  229. package/server/controllers/content-api.js +15 -0
  230. package/server/controllers/index.js +1 -0
  231. package/server/controllers/user.js +3 -2
  232. package/server/routes/api-tokens.js +11 -0
  233. package/server/routes/content-api.js +20 -0
  234. package/server/routes/index.js +2 -0
  235. package/server/services/api-token.js +309 -29
  236. package/server/services/constants.js +10 -0
  237. package/server/services/permission/engine.js +36 -226
  238. package/server/services/permission.js +4 -1
  239. package/server/strategies/admin.js +7 -1
  240. package/server/strategies/api-token.js +72 -11
  241. package/server/validation/api-tokens.js +12 -2
  242. package/utils/create-plugins-exclude-path.js +40 -0
  243. package/utils/get-custom-app-config-file.js +5 -0
  244. package/webpack.alias.js +0 -13
  245. package/webpack.config.js +4 -1
  246. package/admin/src/assets/images/banner_strapi-rocket.png +0 -0
  247. package/admin/src/assets/images/big-logo-home.png +0 -0
  248. package/admin/src/assets/images/homepage-logo.png +0 -0
  249. package/admin/src/assets/images/icon_made-by-strapi.svg +0 -5
  250. package/admin/src/assets/images/logo_strapi_auth.png +0 -0
  251. package/admin/src/assets/images/logo_strapi_auth_v4.png +0 -0
  252. package/admin/src/assets/images/logo_strapi_menu.png +0 -0
  253. package/admin/src/assets/images/oops.png +0 -0
  254. package/admin/src/content-manager/components/State/index.js +0 -37
  255. package/admin/src/favicon.ico +0 -0
  256. package/build/15026a3d58aeb2828134.png +0 -0
  257. package/build/1856.47226450.chunk.js +0 -173
  258. package/build/2077.c935ee42.chunk.js +0 -205
  259. package/build/2912.a015078a.chunk.js +0 -258
  260. package/build/4715.58cd558f.chunk.js +0 -387
  261. package/build/4982.05eda880.chunk.js +0 -324
  262. package/build/7098.40dcd7bf.chunk.js +0 -1
  263. package/build/7841.91f793dc.chunk.js +0 -258
  264. package/build/7866.1201afbd.chunk.js +0 -504
  265. package/build/8380.8789ff76.chunk.js +0 -284
  266. package/build/8549.133c4473.chunk.js +0 -158
  267. package/build/8851.e4ac62f2.chunk.js +0 -158
  268. package/build/90f49a385afb000fb1d4.svg +0 -5
  269. package/build/9311.7cc03f29.chunk.js +0 -508
  270. package/build/Admin_marketplace.82c0570b.chunk.js +0 -11
  271. package/build/Admin_settingsPage.98a711e5.chunk.js +0 -178
  272. package/build/a6b842e0b6d2b61135d1.svg +0 -5
  273. package/build/admin-app.4f7618a9.chunk.js +0 -112
  274. package/build/admin-edit-roles-page.554ba3fa.chunk.js +0 -1
  275. package/build/api-tokens-create-page.4c262d6e.chunk.js +0 -1
  276. package/build/api-tokens-edit-page.10a9d368.chunk.js +0 -1
  277. package/build/api-tokens-list-page.442c9f3c.chunk.js +0 -15
  278. package/build/b997a22a2e0b87ef1fa2.ico +0 -0
  279. package/build/bd81ba6c07827282255d.png +0 -0
  280. package/build/c3de6118ef47086ad05c.png +0 -0
  281. package/build/ca-json.a16899ae.chunk.js +0 -1
  282. package/build/content-manager.7d57c9d1.chunk.js +0 -1200
  283. package/build/content-type-builder-list-view.8cc534e0.chunk.js +0 -194
  284. package/build/content-type-builder-translation-en-json.201bfb78.chunk.js +0 -1
  285. package/build/content-type-builder.684df7a4.chunk.js +0 -142
  286. package/build/de-json.aa6026b3.chunk.js +0 -1
  287. package/build/dk-json.fac2bcfb.chunk.js +0 -1
  288. package/build/en-json.0c69c7d7.chunk.js +0 -1
  289. package/build/es-json.d672e181.chunk.js +0 -1
  290. package/build/fb376b132d18bf4522ca.png +0 -0
  291. package/build/fde9b1ad0670d29a2516.png +0 -0
  292. package/build/fr-json.71a16175.chunk.js +0 -1
  293. package/build/gu-json.ca345cd1.chunk.js +0 -1
  294. package/build/he-json.3b825d80.chunk.js +0 -1
  295. package/build/hi-json.50c7e6d4.chunk.js +0 -1
  296. package/build/hu-json.e0521dcc.chunk.js +0 -1
  297. package/build/id-json.4b1ff8d6.chunk.js +0 -1
  298. package/build/it-json.86bac220.chunk.js +0 -1
  299. package/build/ja-json.4e44e36b.chunk.js +0 -1
  300. package/build/ko-json.1003756e.chunk.js +0 -1
  301. package/build/main.b47db1a3.js +0 -9337
  302. package/build/ml-json.c7774425.chunk.js +0 -1
  303. package/build/nl-json.f58ea235.chunk.js +0 -1
  304. package/build/no-json.40386397.chunk.js +0 -1
  305. package/build/pl-json.fed96aba.chunk.js +0 -1
  306. package/build/pt-BR-json.073799ab.chunk.js +0 -1
  307. package/build/ru-json.7ad2cbbf.chunk.js +0 -1
  308. package/build/runtime~main.feeac6d3.js +0 -2
  309. package/build/sa-json.f0f704f0.chunk.js +0 -1
  310. package/build/sk-json.a848961b.chunk.js +0 -1
  311. package/build/sso-settings-page.445184e0.chunk.js +0 -1
  312. package/build/sv-json.b038acbe.chunk.js +0 -1
  313. package/build/th-json.72e8de3d.chunk.js +0 -1
  314. package/build/webhook-list-page.2775a683.chunk.js +0 -134
  315. package/build/zh-Hans-json.03d2bda1.chunk.js +0 -1
  316. package/build/zh-json.3d0cc664.chunk.js +0 -1
  317. package/server/services/permission/engine-hooks.js +0 -82
@@ -6,21 +6,19 @@ const getRelationModel = (targetModel, models) => models.find((model) => model.u
6
6
  const formatLayouts = (initialData, models) => {
7
7
  const data = createMetasSchema(initialData, models);
8
8
 
9
- const formattedCTEditLayout = formatLayoutWithMetas(data.contentType, null, models);
10
- const ctUid = data.contentType.uid;
9
+ const formattedCTEditLayout = formatLayoutWithMetas(data.contentType, models);
11
10
  const formattedListLayout = formatListLayoutWithMetas(data.contentType, data.components);
12
11
 
13
12
  set(data, ['contentType', 'layouts', 'edit'], formattedCTEditLayout);
14
13
  set(data, ['contentType', 'layouts', 'list'], formattedListLayout);
15
14
 
16
- Object.keys(data.components).forEach((compoUID) => {
17
- const formattedCompoEditLayout = formatLayoutWithMetas(
18
- data.components[compoUID],
19
- ctUid,
15
+ Object.keys(data.components).forEach((componentUid) => {
16
+ const formattedComponentEditLayout = formatLayoutWithMetas(
17
+ data.components[componentUid],
20
18
  models
21
19
  );
22
20
 
23
- set(data, ['components', compoUID, 'layouts', 'edit'], formattedCompoEditLayout);
21
+ set(data, ['components', componentUid, 'layouts', 'edit'], formattedComponentEditLayout);
24
22
  });
25
23
 
26
24
  return data;
@@ -73,8 +71,8 @@ const createMetasSchema = (initialData, models) => {
73
71
  return data;
74
72
  };
75
73
 
76
- const formatLayoutWithMetas = (contentTypeConfiguration, ctUid, models) => {
77
- const formatted = contentTypeConfiguration.layouts.edit.reduce((acc, current) => {
74
+ const formatLayoutWithMetas = (contentTypeConfiguration, models) =>
75
+ contentTypeConfiguration.layouts.edit.reduce((acc, current) => {
78
76
  const row = current.map((attribute) => {
79
77
  const fieldSchema = get(contentTypeConfiguration, ['attributes', attribute.name], {});
80
78
 
@@ -85,20 +83,17 @@ const formatLayoutWithMetas = (contentTypeConfiguration, ctUid, models) => {
85
83
  };
86
84
 
87
85
  if (fieldSchema.type === 'relation') {
88
- const targetModelUID = fieldSchema.targetModel;
89
- const targetModelSchema = getRelationModel(targetModelUID, models);
86
+ const targetModelSchema = getRelationModel(fieldSchema.targetModel, models);
90
87
  const targetModelPluginOptions = targetModelSchema.pluginOptions || {};
91
88
 
92
- const queryInfos = ctUid
93
- ? generateRelationQueryInfosForComponents(
94
- contentTypeConfiguration,
95
- attribute.name,
96
- models
97
- )
98
- : generateRelationQueryInfos(contentTypeConfiguration, attribute.name, models);
99
-
100
89
  set(data, 'targetModelPluginOptions', targetModelPluginOptions);
101
- set(data, 'queryInfos', queryInfos);
90
+ set(data, 'queryInfos', {
91
+ shouldDisplayRelationLink: shouldDisplayRelationLink(
92
+ contentTypeConfiguration,
93
+ attribute.name,
94
+ models
95
+ ),
96
+ });
102
97
  }
103
98
 
104
99
  return data;
@@ -109,9 +104,6 @@ const formatLayoutWithMetas = (contentTypeConfiguration, ctUid, models) => {
109
104
  return acc;
110
105
  }, []);
111
106
 
112
- return formatted;
113
- };
114
-
115
107
  const formatListLayoutWithMetas = (contentTypeConfiguration, components) => {
116
108
  const formatted = contentTypeConfiguration.layouts.list.reduce((acc, current) => {
117
109
  const fieldSchema = get(contentTypeConfiguration, ['attributes', current], {});
@@ -120,11 +112,7 @@ const formatListLayoutWithMetas = (contentTypeConfiguration, components) => {
120
112
  const type = fieldSchema.type;
121
113
 
122
114
  if (type === 'relation') {
123
- const queryInfos = {
124
- defaultParams: {},
125
- };
126
-
127
- acc.push({ key: `__${current}_key__`, name: current, fieldSchema, metadatas, queryInfos });
115
+ acc.push({ key: `__${current}_key__`, name: current, fieldSchema, metadatas });
128
116
 
129
117
  return acc;
130
118
  }
@@ -158,26 +146,10 @@ const formatListLayoutWithMetas = (contentTypeConfiguration, components) => {
158
146
  return formatted;
159
147
  };
160
148
 
161
- const generateRelationQueryInfos = (contentTypeConfiguration, fieldName, models) => {
149
+ const shouldDisplayRelationLink = (contentTypeConfiguration, fieldName, models) => {
162
150
  const targetModel = get(contentTypeConfiguration, ['attributes', fieldName, 'targetModel'], '');
163
- const shouldDisplayRelationLink = getDisplayedModels(models).includes(targetModel);
164
151
 
165
- return {
166
- defaultParams: {},
167
- shouldDisplayRelationLink,
168
- };
169
- };
170
-
171
- const generateRelationQueryInfosForComponents = (contentTypeConfiguration, fieldName, models) => {
172
- const targetModel = get(contentTypeConfiguration, ['attributes', fieldName, 'targetModel'], '');
173
- const shouldDisplayRelationLink = getDisplayedModels(models).includes(targetModel);
174
-
175
- return {
176
- defaultParams: {
177
- component: contentTypeConfiguration.uid,
178
- },
179
- shouldDisplayRelationLink,
180
- };
152
+ return getDisplayedModels(models).includes(targetModel);
181
153
  };
182
154
 
183
155
  const getDisplayedModels = (models) =>
@@ -187,7 +159,6 @@ export default formatLayouts;
187
159
  export {
188
160
  formatLayoutWithMetas,
189
161
  formatListLayoutWithMetas,
190
- generateRelationQueryInfos,
191
- generateRelationQueryInfosForComponents,
162
+ shouldDisplayRelationLink,
192
163
  getDisplayedModels,
193
164
  };
@@ -0,0 +1,14 @@
1
+ import { useEffect, useRef } from 'react';
2
+
3
+ /**
4
+ * @type {<T>(value: T) => T | undefined}
5
+ */
6
+ export const usePrev = (value) => {
7
+ const ref = useRef();
8
+
9
+ useEffect(() => {
10
+ ref.current = value;
11
+ }, [value]);
12
+
13
+ return ref.current;
14
+ };
@@ -1,11 +1,16 @@
1
- import { useState } from 'react';
1
+ import { useState, useEffect } from 'react';
2
2
  import { useInfiniteQuery } from 'react-query';
3
3
 
4
4
  import { axiosInstance } from '../../../core/utils';
5
5
 
6
- export const useRelation = (cacheKey, { relation, search }) => {
7
- const [searchParams, setSearchParams] = useState({});
6
+ import { normalizeRelations } from '../../components/RelationInputDataManager/utils';
8
7
 
8
+ export const useRelation = (cacheKey, { name, relation, search }) => {
9
+ const [searchParams, setSearchParams] = useState({});
10
+ const [currentPage, setCurrentPage] = useState(0);
11
+ /**
12
+ * This runs in `useInfiniteQuery` to actually fetch the data
13
+ */
9
14
  const fetchRelations = async ({ pageParam = 1 }) => {
10
15
  try {
11
16
  const { data } = await axiosInstance.get(relation?.endpoint, {
@@ -15,6 +20,8 @@ export const useRelation = (cacheKey, { relation, search }) => {
15
20
  },
16
21
  });
17
22
 
23
+ setCurrentPage(pageParam);
24
+
18
25
  return data;
19
26
  } catch (err) {
20
27
  return null;
@@ -22,37 +29,131 @@ export const useRelation = (cacheKey, { relation, search }) => {
22
29
  };
23
30
 
24
31
  const fetchSearch = async ({ pageParam = 1 }) => {
25
- const { data } = await axiosInstance.get(search.endpoint, {
26
- params: {
27
- ...(search.pageParams ?? {}),
28
- ...searchParams,
29
- page: pageParam,
30
- },
31
- });
32
+ try {
33
+ const { data } = await axiosInstance.get(search.endpoint, {
34
+ params: {
35
+ ...(search.pageParams ?? {}),
36
+ ...searchParams,
37
+ page: pageParam,
38
+ },
39
+ });
32
40
 
33
- return data;
41
+ return data;
42
+ } catch (err) {
43
+ return null;
44
+ }
34
45
  };
35
46
 
47
+ const { onLoad: onLoadRelationsCallback, normalizeArguments = {} } = relation;
48
+
36
49
  const relationsRes = useInfiniteQuery(['relation', cacheKey], fetchRelations, {
50
+ cacheTime: 0,
37
51
  enabled: relation.enabled,
52
+ /**
53
+ * @type {(lastPage:
54
+ * | { data: null }
55
+ * | { results: any[],
56
+ * pagination: {
57
+ * page: number,
58
+ * pageCount: number,
59
+ * pageSize: number,
60
+ * total: number
61
+ * }
62
+ * }
63
+ * ) => number}
64
+ */
38
65
  getNextPageParam(lastPage) {
39
- // the API may send an empty 204 response
40
- if (!lastPage || lastPage.pagination.page >= lastPage.pagination.pageCount) {
66
+ const isXToOneRelation = !lastPage?.pagination;
67
+
68
+ if (
69
+ !lastPage || // the API may send an empty 204 response
70
+ isXToOneRelation || // xToOne relations do not have a pagination
71
+ lastPage?.pagination.page >= lastPage?.pagination.pageCount
72
+ ) {
41
73
  return undefined;
42
74
  }
43
75
 
44
76
  // eslint-disable-next-line consistent-return
45
77
  return lastPage.pagination.page + 1;
46
78
  },
79
+ select: (data) => ({
80
+ ...data,
81
+ pages: data.pages.map((page) => {
82
+ if (!page) {
83
+ return page;
84
+ }
85
+
86
+ const { data, results, pagination } = page;
87
+ const isXToOneRelation = !!data;
88
+ let normalizedResults = [];
89
+
90
+ // xToOne relations return an object, which we normalize so that relations
91
+ // always have the same shape
92
+ if (isXToOneRelation) {
93
+ normalizedResults = [data];
94
+ } else if (results) {
95
+ normalizedResults = [...results].reverse();
96
+ }
97
+
98
+ return {
99
+ pagination,
100
+ results: normalizedResults,
101
+ };
102
+ }),
103
+ }),
47
104
  });
48
105
 
106
+ const { pageGoal } = relation;
107
+
108
+ const { status, data, fetchNextPage, hasNextPage } = relationsRes;
109
+
110
+ useEffect(() => {
111
+ /**
112
+ * This ensures the infiniteQuery hook fetching has caught-up with the modifiedData
113
+ * state i.e. in circumstances where you add 10 relations, the browserState knows this,
114
+ * but the hook would think it could fetch more, when in reality, it can't.
115
+ */
116
+ if (pageGoal > currentPage && hasNextPage && status === 'success') {
117
+ fetchNextPage({
118
+ pageParam: currentPage + 1,
119
+ });
120
+ }
121
+ }, [pageGoal, currentPage, fetchNextPage, hasNextPage, status]);
122
+
123
+ useEffect(() => {
124
+ if (status === 'success' && data && data.pages?.at(-1)?.results && onLoadRelationsCallback) {
125
+ // everytime we fetch, we normalize prior to adding to redux
126
+ const normalizedResults = normalizeRelations(data.pages.at(-1).results, normalizeArguments);
127
+
128
+ // this is loadRelation from EditViewDataManagerProvider
129
+ onLoadRelationsCallback({
130
+ target: { name, value: normalizedResults },
131
+ });
132
+ }
133
+
134
+ // eslint-disable-next-line react-hooks/exhaustive-deps
135
+ }, [status, onLoadRelationsCallback, name, data]);
136
+
49
137
  const searchRes = useInfiniteQuery(
50
138
  ['relation', cacheKey, 'search', JSON.stringify(searchParams)],
51
139
  fetchSearch,
52
140
  {
53
141
  enabled: Object.keys(searchParams).length > 0,
142
+ /**
143
+ * @type {(lastPage:
144
+ * | { data: null }
145
+ * | { results: any[],
146
+ * pagination: {
147
+ * page: number,
148
+ * pageCount: number,
149
+ * pageSize: number,
150
+ * total: number
151
+ * }
152
+ * }
153
+ * ) => number}
154
+ */
54
155
  getNextPageParam(lastPage) {
55
- if (lastPage.pagination.page >= lastPage.pagination.pageCount) {
156
+ if (!lastPage?.pagination || lastPage.pagination.page >= lastPage.pagination.pageCount) {
56
157
  return undefined;
57
158
  }
58
159
 
@@ -65,7 +166,7 @@ export const useRelation = (cacheKey, { relation, search }) => {
65
166
  const searchFor = (term, options = {}) => {
66
167
  setSearchParams({
67
168
  ...options,
68
- _q: encodeURIComponent(term),
169
+ _q: term,
69
170
  });
70
171
  };
71
172
 
@@ -14,6 +14,9 @@ const initialState = {
14
14
  singleTypeLinks: [],
15
15
  };
16
16
 
17
+ /**
18
+ * Known as content-manager_app in the redux store
19
+ */
17
20
  const mainReducer = (state = initialState, action) =>
18
21
  produce(state, (draftState) => {
19
22
  switch (action.type) {
@@ -26,7 +26,7 @@ const HeaderContainer = styled(Flex)`
26
26
  }
27
27
  `;
28
28
 
29
- const FormModal = ({ onToggle, onMetaChange, onSizeChange, onSubmit, type }) => {
29
+ const FormModal = ({ onToggle, onMetaChange, onSizeChange, onSubmit, type, customFieldUid }) => {
30
30
  const { selectedField } = useLayoutDnd();
31
31
  const { formatMessage } = useIntl();
32
32
 
@@ -47,7 +47,7 @@ const FormModal = ({ onToggle, onMetaChange, onSizeChange, onSubmit, type }) =>
47
47
  <form onSubmit={onSubmit}>
48
48
  <ModalHeader>
49
49
  <HeaderContainer>
50
- <FieldTypeIcon type={getAttrType(type)} />
50
+ <FieldTypeIcon type={getAttrType()} customFieldUid={customFieldUid} />
51
51
  <Typography fontWeight="bold" textColor="neutral800" as="h2" id="title">
52
52
  {formatMessage(
53
53
  {
@@ -81,7 +81,12 @@ const FormModal = ({ onToggle, onMetaChange, onSizeChange, onSubmit, type }) =>
81
81
  );
82
82
  };
83
83
 
84
+ FormModal.defaultProps = {
85
+ customFieldUid: null,
86
+ };
87
+
84
88
  FormModal.propTypes = {
89
+ customFieldUid: PropTypes.string,
85
90
  onSubmit: PropTypes.func.isRequired,
86
91
  onToggle: PropTypes.func.isRequired,
87
92
  onMetaChange: PropTypes.func.isRequired,
@@ -344,9 +344,10 @@ const EditSettingsView = ({ mainLayout, components, isContentTypeView, slug, upd
344
344
  <ModalForm
345
345
  onSubmit={handleMetaSubmit}
346
346
  onToggle={handleToggleModal}
347
- type={get(attributes, [metaToEdit, 'type'], '')}
348
347
  onMetaChange={handleMetaChange}
349
348
  onSizeChange={handleSizeChange}
349
+ type={get(attributes, [metaToEdit, 'type'], '')}
350
+ customFieldUid={get(attributes, [metaToEdit, 'customField'], '')}
350
351
  />
351
352
  )}
352
353
  </Main>
@@ -17,9 +17,15 @@ import { Typography } from '@strapi/design-system/Typography';
17
17
  import { Stack } from '@strapi/design-system/Stack';
18
18
  import ExclamationMarkCircle from '@strapi/icons/ExclamationMarkCircle';
19
19
  import Check from '@strapi/icons/Check';
20
+ import styled from 'styled-components';
20
21
  import { getTrad } from '../../../utils';
21
22
  import { connect, select } from './utils';
22
23
 
24
+ // TODO: replace with textAlign Typography props when available
25
+ const FlexTextAlign = styled(Flex)`
26
+ text-align: center;
27
+ `;
28
+
23
29
  const Header = ({
24
30
  allowedActions: { canUpdate, canCreate, canPublish },
25
31
  initialData,
@@ -31,6 +37,8 @@ const Header = ({
31
37
  onPublish,
32
38
  onUnpublish,
33
39
  status,
40
+ publishConfirmation: { show: showPublishConfirmation, draftCount },
41
+ onPublishPromptDismissal,
34
42
  }) => {
35
43
  const { goBack } = useHistory();
36
44
  const [showWarningUnpublish, setWarningUnpublish] = useState(false);
@@ -150,60 +158,115 @@ const Header = ({
150
158
  </Link>
151
159
  }
152
160
  />
153
- {showWarningUnpublish && (
154
- <Dialog
155
- onClose={toggleWarningUnpublish}
156
- title="Confirmation"
157
- labelledBy="confirmation"
158
- describedBy="confirm-description"
159
- isOpen={showWarningUnpublish}
160
- >
161
- <DialogBody icon={<ExclamationMarkCircle />}>
162
- <Stack spacing={2}>
163
- <Flex justifyContent="center" style={{ textAlign: 'center' }}>
164
- <Typography id="confirm-description">
165
- {formatMessage(
166
- {
167
- id: getTrad('popUpWarning.warning.unpublish'),
168
- defaultMessage:
169
- 'Unpublish this content will automatically change it to a draft.',
170
- },
171
- {
172
- br: () => <br />,
173
- }
174
- )}
175
- </Typography>
176
- </Flex>
177
- <Flex justifyContent="center" style={{ textAlign: 'center' }}>
178
- <Typography id="confirm-description">
179
- {formatMessage({
180
- id: getTrad('popUpWarning.warning.unpublish-question'),
181
- defaultMessage: 'Are you sure you want to unpublish it?',
182
- })}
183
- </Typography>
184
- </Flex>
185
- </Stack>
186
- </DialogBody>
187
- <DialogFooter
188
- startAction={
189
- <Button onClick={toggleWarningUnpublish} variant="tertiary">
161
+ <Dialog
162
+ onClose={toggleWarningUnpublish}
163
+ title="Confirmation"
164
+ labelledBy="confirmation"
165
+ describedBy="confirm-description"
166
+ isOpen={showWarningUnpublish}
167
+ >
168
+ <DialogBody icon={<ExclamationMarkCircle />}>
169
+ <Stack spacing={2}>
170
+ <Flex justifyContent="center" style={{ textAlign: 'center' }}>
171
+ <Typography id="confirm-description">
172
+ {formatMessage(
173
+ {
174
+ id: getTrad('popUpWarning.warning.unpublish'),
175
+ defaultMessage:
176
+ 'Unpublish this content will automatically change it to a draft.',
177
+ },
178
+ {
179
+ br: () => <br />,
180
+ }
181
+ )}
182
+ </Typography>
183
+ </Flex>
184
+ <Flex justifyContent="center" style={{ textAlign: 'center' }}>
185
+ <Typography id="confirm-description">
190
186
  {formatMessage({
191
- id: 'components.popUpWarning.button.cancel',
192
- defaultMessage: 'No, cancel',
187
+ id: getTrad('popUpWarning.warning.unpublish-question'),
188
+ defaultMessage: 'Are you sure you want to unpublish it?',
193
189
  })}
194
- </Button>
195
- }
196
- endAction={
197
- <Button variant="danger-light" onClick={handleUnpublish}>
190
+ </Typography>
191
+ </Flex>
192
+ </Stack>
193
+ </DialogBody>
194
+ <DialogFooter
195
+ startAction={
196
+ <Button onClick={toggleWarningUnpublish} variant="tertiary">
197
+ {formatMessage({
198
+ id: 'components.popUpWarning.button.cancel',
199
+ defaultMessage: 'Cancel',
200
+ })}
201
+ </Button>
202
+ }
203
+ endAction={
204
+ <Button variant="danger-light" onClick={handleUnpublish}>
205
+ {formatMessage({
206
+ id: 'components.popUpWarning.button.confirm',
207
+ defaultMessage: 'Confirm',
208
+ })}
209
+ </Button>
210
+ }
211
+ />
212
+ </Dialog>
213
+ <Dialog
214
+ onClose={onPublishPromptDismissal}
215
+ title={formatMessage({
216
+ id: getTrad(`popUpWarning.warning.has-draft-relations.title`),
217
+ defaultMessage: 'Confirmation',
218
+ })}
219
+ labelledBy="confirmation"
220
+ describedBy="confirm-description"
221
+ isOpen={showPublishConfirmation}
222
+ >
223
+ <DialogBody icon={<ExclamationMarkCircle />}>
224
+ <Stack spacing={2}>
225
+ <FlexTextAlign justifyContent="center">
226
+ <Typography id="confirm-description">
227
+ {draftCount}
228
+ {formatMessage(
229
+ {
230
+ id: getTrad(`popUpwarning.warning.has-draft-relations.message`),
231
+ defaultMessage:
232
+ '<b>{count, plural, one { relation is} other { relations are}}</b> not published yet and might lead to unexpected behavior.',
233
+ },
234
+ {
235
+ b: (chunks) => <Typography fontWeight="bold">{chunks}</Typography>,
236
+ count: draftCount,
237
+ }
238
+ )}
239
+ </Typography>
240
+ </FlexTextAlign>
241
+ <FlexTextAlign justifyContent="center">
242
+ <Typography id="confirm-description">
198
243
  {formatMessage({
199
- id: 'components.popUpWarning.button.confirm',
200
- defaultMessage: 'Yes, confirm',
244
+ id: getTrad('popUpWarning.warning.publish-question'),
245
+ defaultMessage: 'Do you still want to publish?',
201
246
  })}
202
- </Button>
203
- }
204
- />
205
- </Dialog>
206
- )}
247
+ </Typography>
248
+ </FlexTextAlign>
249
+ </Stack>
250
+ </DialogBody>
251
+ <DialogFooter
252
+ startAction={
253
+ <Button onClick={onPublishPromptDismissal} variant="tertiary">
254
+ {formatMessage({
255
+ id: 'components.popUpWarning.button.cancel',
256
+ defaultMessage: 'Cancel',
257
+ })}
258
+ </Button>
259
+ }
260
+ endAction={
261
+ <Button variant="success" onClick={onPublish}>
262
+ {formatMessage({
263
+ id: getTrad('popUpwarning.warning.has-draft-relations.button-confirm'),
264
+ defaultMessage: 'Publish',
265
+ })}
266
+ </Button>
267
+ }
268
+ />
269
+ </Dialog>
207
270
  </>
208
271
  );
209
272
  };
@@ -223,6 +286,11 @@ Header.propTypes = {
223
286
  modifiedData: PropTypes.object.isRequired,
224
287
  onPublish: PropTypes.func.isRequired,
225
288
  onUnpublish: PropTypes.func.isRequired,
289
+ publishConfirmation: PropTypes.shape({
290
+ show: PropTypes.bool.isRequired,
291
+ draftCount: PropTypes.number.isRequired,
292
+ }).isRequired,
293
+ onPublishPromptDismissal: PropTypes.func.isRequired,
226
294
  };
227
295
 
228
296
  const Memoized = memo(Header, isEqualFastCompare);
@@ -11,6 +11,8 @@ function useSelect() {
11
11
  modifiedData,
12
12
  onPublish,
13
13
  onUnpublish,
14
+ publishConfirmation,
15
+ onPublishPromptDismissal,
14
16
  } = useCMEditViewDataManager();
15
17
 
16
18
  return {
@@ -23,6 +25,8 @@ function useSelect() {
23
25
  modifiedData,
24
26
  onPublish,
25
27
  onUnpublish,
28
+ publishConfirmation,
29
+ onPublishPromptDismissal,
26
30
  };
27
31
  }
28
32