@strapi/content-manager 0.0.0-experimental.1bca8e0e074de8b0775bcddc7656fbc9e9f1393b → 0.0.0-experimental.2019e9d1599c648cb3408174e7bec18596215a78

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 (159) hide show
  1. package/dist/_chunks/{ComponentConfigurationPage-BAgyHiMm.mjs → ComponentConfigurationPage-CIjXcRAB.mjs} +4 -4
  2. package/dist/_chunks/{ComponentConfigurationPage-BAgyHiMm.mjs.map → ComponentConfigurationPage-CIjXcRAB.mjs.map} +1 -1
  3. package/dist/_chunks/{ComponentConfigurationPage-5ukroXAh.js → ComponentConfigurationPage-gsCd80MU.js} +4 -4
  4. package/dist/_chunks/{ComponentConfigurationPage-5ukroXAh.js.map → ComponentConfigurationPage-gsCd80MU.js.map} +1 -1
  5. package/dist/_chunks/{EditConfigurationPage-DmoXawIh.mjs → EditConfigurationPage-BglmD_BF.mjs} +4 -4
  6. package/dist/_chunks/{EditConfigurationPage-DmoXawIh.mjs.map → EditConfigurationPage-BglmD_BF.mjs.map} +1 -1
  7. package/dist/_chunks/{EditConfigurationPage-Xp7lun0f.js → EditConfigurationPage-DHDQKBzw.js} +4 -4
  8. package/dist/_chunks/{EditConfigurationPage-Xp7lun0f.js.map → EditConfigurationPage-DHDQKBzw.js.map} +1 -1
  9. package/dist/_chunks/{EditViewPage-C-ukDOB7.js → EditViewPage-C4iTxUPU.js} +30 -9
  10. package/dist/_chunks/EditViewPage-C4iTxUPU.js.map +1 -0
  11. package/dist/_chunks/{EditViewPage-BLsjc5F-.mjs → EditViewPage-CiwVPMaK.mjs} +30 -9
  12. package/dist/_chunks/EditViewPage-CiwVPMaK.mjs.map +1 -0
  13. package/dist/_chunks/{Field-Cs7duwWd.mjs → Field-DIjL1b5d.mjs} +173 -101
  14. package/dist/_chunks/Field-DIjL1b5d.mjs.map +1 -0
  15. package/dist/_chunks/{Field-Bfph5SOd.js → Field-DhXEK8y1.js} +175 -103
  16. package/dist/_chunks/Field-DhXEK8y1.js.map +1 -0
  17. package/dist/_chunks/{Form-Dg_GS5TQ.mjs → Form-CmNesrvR.mjs} +36 -17
  18. package/dist/_chunks/Form-CmNesrvR.mjs.map +1 -0
  19. package/dist/_chunks/{Form-CPYqIWDG.js → Form-CwmJ4sWe.js} +36 -17
  20. package/dist/_chunks/Form-CwmJ4sWe.js.map +1 -0
  21. package/dist/_chunks/{History-DNQkXANT.js → History-BLCCNgCt.js} +24 -11
  22. package/dist/_chunks/History-BLCCNgCt.js.map +1 -0
  23. package/dist/_chunks/{History-wrnHqf09.mjs → History-D-99Wh30.mjs} +25 -12
  24. package/dist/_chunks/History-D-99Wh30.mjs.map +1 -0
  25. package/dist/_chunks/{ListConfigurationPage-CUQxfpjT.js → ListConfigurationPage-DxWpeZrO.js} +15 -5
  26. package/dist/_chunks/ListConfigurationPage-DxWpeZrO.js.map +1 -0
  27. package/dist/_chunks/{ListConfigurationPage-DScmJVkW.mjs → ListConfigurationPage-JPWZz7Kg.mjs} +15 -5
  28. package/dist/_chunks/ListConfigurationPage-JPWZz7Kg.mjs.map +1 -0
  29. package/dist/_chunks/{ListViewPage-BsLiH2-2.js → ListViewPage-CIQekSFz.js} +61 -41
  30. package/dist/_chunks/ListViewPage-CIQekSFz.js.map +1 -0
  31. package/dist/_chunks/{ListViewPage-C4IvrMgY.mjs → ListViewPage-DSK3f0ST.mjs} +59 -39
  32. package/dist/_chunks/ListViewPage-DSK3f0ST.mjs.map +1 -0
  33. package/dist/_chunks/{NoContentTypePage-BZ-PnGAf.js → NoContentTypePage-C5cxKvC2.js} +2 -2
  34. package/dist/_chunks/{NoContentTypePage-BZ-PnGAf.js.map → NoContentTypePage-C5cxKvC2.js.map} +1 -1
  35. package/dist/_chunks/{NoContentTypePage-Djg8nPlj.mjs → NoContentTypePage-D99LU1YP.mjs} +2 -2
  36. package/dist/_chunks/{NoContentTypePage-Djg8nPlj.mjs.map → NoContentTypePage-D99LU1YP.mjs.map} +1 -1
  37. package/dist/_chunks/{NoPermissionsPage-DSP7R-hv.mjs → NoPermissionsPage-DBrBw-0y.mjs} +2 -2
  38. package/dist/_chunks/{NoPermissionsPage-DSP7R-hv.mjs.map → NoPermissionsPage-DBrBw-0y.mjs.map} +1 -1
  39. package/dist/_chunks/{NoPermissionsPage-_lUqjGW3.js → NoPermissionsPage-Oy4tmUrW.js} +2 -2
  40. package/dist/_chunks/{NoPermissionsPage-_lUqjGW3.js.map → NoPermissionsPage-Oy4tmUrW.js.map} +1 -1
  41. package/dist/_chunks/{Relations-BZr8tL0R.mjs → Relations-BBmhcWFV.mjs} +70 -37
  42. package/dist/_chunks/Relations-BBmhcWFV.mjs.map +1 -0
  43. package/dist/_chunks/{Relations-CtELXYIK.js → Relations-eG-9p_qS.js} +69 -36
  44. package/dist/_chunks/Relations-eG-9p_qS.js.map +1 -0
  45. package/dist/_chunks/{en-uOUIxfcQ.js → en-Bm0D0IWz.js} +13 -12
  46. package/dist/_chunks/{en-uOUIxfcQ.js.map → en-Bm0D0IWz.js.map} +1 -1
  47. package/dist/_chunks/{en-BrCTWlZv.mjs → en-DKV44jRb.mjs} +13 -12
  48. package/dist/_chunks/{en-BrCTWlZv.mjs.map → en-DKV44jRb.mjs.map} +1 -1
  49. package/dist/_chunks/{index-OerGjbAN.js → index-BIWDoFLK.js} +1968 -1781
  50. package/dist/_chunks/index-BIWDoFLK.js.map +1 -0
  51. package/dist/_chunks/{index-c_5DdJi-.mjs → index-BrUzbQ30.mjs} +1987 -1801
  52. package/dist/_chunks/index-BrUzbQ30.mjs.map +1 -0
  53. package/dist/_chunks/{layout-oPBiO7RY.mjs → layout-_5-cXs34.mjs} +22 -9
  54. package/dist/_chunks/layout-_5-cXs34.mjs.map +1 -0
  55. package/dist/_chunks/{layout-Ci7qHlFb.js → layout-lMc9i1-Z.js} +21 -8
  56. package/dist/_chunks/layout-lMc9i1-Z.js.map +1 -0
  57. package/dist/_chunks/{objects-gigeqt7s.js → objects-BcXOv6_9.js} +2 -4
  58. package/dist/_chunks/{objects-gigeqt7s.js.map → objects-BcXOv6_9.js.map} +1 -1
  59. package/dist/_chunks/{objects-mKMAmfec.mjs → objects-D6yBsdmx.mjs} +2 -4
  60. package/dist/_chunks/{objects-mKMAmfec.mjs.map → objects-D6yBsdmx.mjs.map} +1 -1
  61. package/dist/_chunks/{relations-COBpStiF.js → relations-BRHithi8.js} +3 -7
  62. package/dist/_chunks/relations-BRHithi8.js.map +1 -0
  63. package/dist/_chunks/{relations-BIdWFjdq.mjs → relations-B_VLk-DD.mjs} +3 -7
  64. package/dist/_chunks/relations-B_VLk-DD.mjs.map +1 -0
  65. package/dist/_chunks/{usePrev-B9w_-eYc.js → useDebounce-CtcjDB3L.js} +14 -1
  66. package/dist/_chunks/useDebounce-CtcjDB3L.js.map +1 -0
  67. package/dist/_chunks/useDebounce-DmuSJIF3.mjs +29 -0
  68. package/dist/_chunks/useDebounce-DmuSJIF3.mjs.map +1 -0
  69. package/dist/admin/index.js +2 -1
  70. package/dist/admin/index.js.map +1 -1
  71. package/dist/admin/index.mjs +5 -4
  72. package/dist/admin/src/exports.d.ts +1 -1
  73. package/dist/admin/src/history/services/historyVersion.d.ts +1 -1
  74. package/dist/admin/src/hooks/useDocument.d.ts +32 -1
  75. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/EditorLayout.d.ts +2 -2
  76. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygFooter.d.ts +2 -2
  77. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygStyles.d.ts +4 -48
  78. package/dist/admin/src/pages/EditView/components/Header.d.ts +11 -11
  79. package/dist/admin/src/preview/constants.d.ts +1 -0
  80. package/dist/admin/src/preview/index.d.ts +4 -0
  81. package/dist/admin/src/services/api.d.ts +1 -1
  82. package/dist/admin/src/services/components.d.ts +2 -2
  83. package/dist/admin/src/services/contentTypes.d.ts +3 -3
  84. package/dist/admin/src/services/documents.d.ts +19 -17
  85. package/dist/admin/src/services/init.d.ts +1 -1
  86. package/dist/admin/src/services/relations.d.ts +2 -2
  87. package/dist/admin/src/services/uid.d.ts +3 -3
  88. package/dist/admin/src/utils/validation.d.ts +4 -1
  89. package/dist/server/index.js +284 -120
  90. package/dist/server/index.js.map +1 -1
  91. package/dist/server/index.mjs +285 -121
  92. package/dist/server/index.mjs.map +1 -1
  93. package/dist/server/src/bootstrap.d.ts.map +1 -1
  94. package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
  95. package/dist/server/src/controllers/index.d.ts.map +1 -1
  96. package/dist/server/src/controllers/relations.d.ts.map +1 -1
  97. package/dist/server/src/controllers/utils/metadata.d.ts +15 -1
  98. package/dist/server/src/controllers/utils/metadata.d.ts.map +1 -1
  99. package/dist/server/src/history/services/history.d.ts.map +1 -1
  100. package/dist/server/src/history/services/lifecycles.d.ts.map +1 -1
  101. package/dist/server/src/history/services/utils.d.ts +2 -1
  102. package/dist/server/src/history/services/utils.d.ts.map +1 -1
  103. package/dist/server/src/index.d.ts +4 -4
  104. package/dist/server/src/policies/hasPermissions.d.ts.map +1 -1
  105. package/dist/server/src/preview/constants.d.ts +2 -0
  106. package/dist/server/src/preview/constants.d.ts.map +1 -0
  107. package/dist/server/src/preview/controllers/index.d.ts +2 -0
  108. package/dist/server/src/preview/controllers/index.d.ts.map +1 -0
  109. package/dist/server/src/preview/controllers/preview.d.ts +9 -0
  110. package/dist/server/src/preview/controllers/preview.d.ts.map +1 -0
  111. package/dist/server/src/preview/index.d.ts +4 -0
  112. package/dist/server/src/preview/index.d.ts.map +1 -0
  113. package/dist/server/src/preview/routes/index.d.ts +8 -0
  114. package/dist/server/src/preview/routes/index.d.ts.map +1 -0
  115. package/dist/server/src/preview/routes/preview.d.ts +4 -0
  116. package/dist/server/src/preview/routes/preview.d.ts.map +1 -0
  117. package/dist/server/src/preview/services/index.d.ts +4 -0
  118. package/dist/server/src/preview/services/index.d.ts.map +1 -0
  119. package/dist/server/src/preview/services/preview.d.ts +6 -0
  120. package/dist/server/src/preview/services/preview.d.ts.map +1 -0
  121. package/dist/server/src/preview/utils.d.ts +7 -0
  122. package/dist/server/src/preview/utils.d.ts.map +1 -0
  123. package/dist/server/src/routes/index.d.ts.map +1 -1
  124. package/dist/server/src/services/document-metadata.d.ts +8 -8
  125. package/dist/server/src/services/document-metadata.d.ts.map +1 -1
  126. package/dist/server/src/services/index.d.ts +4 -4
  127. package/dist/server/src/services/index.d.ts.map +1 -1
  128. package/dist/server/src/services/permission-checker.d.ts.map +1 -1
  129. package/dist/server/src/services/utils/configuration/index.d.ts +2 -2
  130. package/dist/server/src/services/utils/configuration/layouts.d.ts +2 -2
  131. package/dist/server/src/utils/index.d.ts +2 -0
  132. package/dist/server/src/utils/index.d.ts.map +1 -1
  133. package/dist/shared/contracts/collection-types.d.ts +3 -1
  134. package/dist/shared/contracts/collection-types.d.ts.map +1 -1
  135. package/package.json +12 -12
  136. package/dist/_chunks/EditViewPage-BLsjc5F-.mjs.map +0 -1
  137. package/dist/_chunks/EditViewPage-C-ukDOB7.js.map +0 -1
  138. package/dist/_chunks/Field-Bfph5SOd.js.map +0 -1
  139. package/dist/_chunks/Field-Cs7duwWd.mjs.map +0 -1
  140. package/dist/_chunks/Form-CPYqIWDG.js.map +0 -1
  141. package/dist/_chunks/Form-Dg_GS5TQ.mjs.map +0 -1
  142. package/dist/_chunks/History-DNQkXANT.js.map +0 -1
  143. package/dist/_chunks/History-wrnHqf09.mjs.map +0 -1
  144. package/dist/_chunks/ListConfigurationPage-CUQxfpjT.js.map +0 -1
  145. package/dist/_chunks/ListConfigurationPage-DScmJVkW.mjs.map +0 -1
  146. package/dist/_chunks/ListViewPage-BsLiH2-2.js.map +0 -1
  147. package/dist/_chunks/ListViewPage-C4IvrMgY.mjs.map +0 -1
  148. package/dist/_chunks/Relations-BZr8tL0R.mjs.map +0 -1
  149. package/dist/_chunks/Relations-CtELXYIK.js.map +0 -1
  150. package/dist/_chunks/index-OerGjbAN.js.map +0 -1
  151. package/dist/_chunks/index-c_5DdJi-.mjs.map +0 -1
  152. package/dist/_chunks/layout-Ci7qHlFb.js.map +0 -1
  153. package/dist/_chunks/layout-oPBiO7RY.mjs.map +0 -1
  154. package/dist/_chunks/relations-BIdWFjdq.mjs.map +0 -1
  155. package/dist/_chunks/relations-COBpStiF.js.map +0 -1
  156. package/dist/_chunks/usePrev-B9w_-eYc.js.map +0 -1
  157. package/dist/_chunks/usePrev-DH6iah0A.mjs +0 -16
  158. package/dist/_chunks/usePrev-DH6iah0A.mjs.map +0 -1
  159. package/strapi-server.js +0 -3
@@ -1,5 +1,5 @@
1
1
  import strapiUtils, { validateYupSchema, errors, async, contentTypes as contentTypes$1, yup as yup$1, validateYupSchemaSync, policy, traverse, setCreatorFields, isOperatorOfType, relations as relations$1, traverseEntity, pagination } from "@strapi/utils";
2
- import { pick, omit, difference, intersection, pipe, propOr, isEqual, isEmpty, set, has, prop, assoc, mapValues, flow, uniq, uniqBy, concat, isNil as isNil$1, getOr, propEq, merge, groupBy, castArray } from "lodash/fp";
2
+ import { pick, omit, difference, castArray, intersection, pipe, propOr, isEqual, isEmpty, set, isNil as isNil$1, has, prop, assoc, mapValues, flow, uniq, uniqBy, concat, getOr, propEq, merge, groupBy } from "lodash/fp";
3
3
  import "@strapi/types";
4
4
  import * as yup from "yup";
5
5
  import { scheduleJob } from "node-schedule";
@@ -95,7 +95,7 @@ const createHistoryVersionController = ({ strapi: strapi2 }) => {
95
95
  }
96
96
  };
97
97
  };
98
- const controllers$1 = {
98
+ const controllers$2 = {
99
99
  "history-version": createHistoryVersionController
100
100
  /**
101
101
  * Casting is needed because the types aren't aware that Strapi supports
@@ -173,7 +173,9 @@ const createServiceUtils = ({ strapi: strapi2 }) => {
173
173
  return strapi2.db.query("plugin::upload.file").findOne({ where: { id: versionRelationData.id } });
174
174
  };
175
175
  const localesService = strapi2.plugin("i18n")?.service("locales");
176
+ const i18nContentTypeService = strapi2.plugin("i18n")?.service("content-types");
176
177
  const getDefaultLocale = async () => localesService ? localesService.getDefaultLocale() : null;
178
+ const isLocalizedContentType = (model) => i18nContentTypeService ? i18nContentTypeService.isLocalizedContentType(model) : false;
177
179
  const getLocaleDictionary = async () => {
178
180
  if (!localesService)
179
181
  return {};
@@ -200,9 +202,10 @@ const createServiceUtils = ({ strapi: strapi2 }) => {
200
202
  const meta = await documentMetadataService.getMetadata(contentTypeUid, document);
201
203
  return documentMetadataService.getStatus(document, meta.availableStatus);
202
204
  };
203
- const getDeepPopulate2 = (uid2) => {
205
+ const getDeepPopulate2 = (uid2, useDatabaseSyntax = false) => {
204
206
  const model = strapi2.getModel(uid2);
205
207
  const attributes = Object.entries(model.attributes);
208
+ const fieldSelector = useDatabaseSyntax ? "select" : "fields";
206
209
  return attributes.reduce((acc, [attributeName, attribute]) => {
207
210
  switch (attribute.type) {
208
211
  case "relation": {
@@ -212,12 +215,12 @@ const createServiceUtils = ({ strapi: strapi2 }) => {
212
215
  }
213
216
  const isVisible2 = contentTypes$1.isVisibleAttribute(model, attributeName);
214
217
  if (isVisible2) {
215
- acc[attributeName] = { fields: ["documentId", "locale", "publishedAt"] };
218
+ acc[attributeName] = { [fieldSelector]: ["documentId", "locale", "publishedAt"] };
216
219
  }
217
220
  break;
218
221
  }
219
222
  case "media": {
220
- acc[attributeName] = { fields: ["id"] };
223
+ acc[attributeName] = { [fieldSelector]: ["id"] };
221
224
  break;
222
225
  }
223
226
  case "component": {
@@ -290,6 +293,7 @@ const createServiceUtils = ({ strapi: strapi2 }) => {
290
293
  getRelationRestoreValue,
291
294
  getMediaRestoreValue,
292
295
  getDefaultLocale,
296
+ isLocalizedContentType,
293
297
  getLocaleDictionary,
294
298
  getRetentionDays,
295
299
  getVersionStatus,
@@ -312,7 +316,13 @@ const createHistoryService = ({ strapi: strapi2 }) => {
312
316
  });
313
317
  },
314
318
  async findVersionsPage(params) {
315
- const locale = params.query.locale || await serviceUtils.getDefaultLocale();
319
+ const model = strapi2.getModel(params.query.contentType);
320
+ const isLocalizedContentType = serviceUtils.isLocalizedContentType(model);
321
+ const defaultLocale = await serviceUtils.getDefaultLocale();
322
+ let locale = null;
323
+ if (isLocalizedContentType) {
324
+ locale = params.query.locale || defaultLocale;
325
+ }
316
326
  const [{ results, pagination: pagination2 }, localeDictionary] = await Promise.all([
317
327
  query.findPage({
318
328
  ...params.query,
@@ -357,7 +367,12 @@ const createHistoryService = ({ strapi: strapi2 }) => {
357
367
  if (userToPopulate == null) {
358
368
  return null;
359
369
  }
360
- return strapi2.query("admin::user").findOne({ where: { id: userToPopulate.id } });
370
+ return strapi2.query("admin::user").findOne({
371
+ where: {
372
+ ...userToPopulate.id ? { id: userToPopulate.id } : {},
373
+ ...userToPopulate.documentId ? { documentId: userToPopulate.documentId } : {}
374
+ }
375
+ });
361
376
  })
362
377
  );
363
378
  return {
@@ -468,6 +483,42 @@ const createHistoryService = ({ strapi: strapi2 }) => {
468
483
  }
469
484
  };
470
485
  };
486
+ const shouldCreateHistoryVersion = (context) => {
487
+ if (!strapi.requestContext.get()?.request.url.startsWith("/content-manager")) {
488
+ return false;
489
+ }
490
+ if (context.action !== "create" && context.action !== "update" && context.action !== "clone" && context.action !== "publish" && context.action !== "unpublish" && context.action !== "discardDraft") {
491
+ return false;
492
+ }
493
+ if (context.action === "update" && strapi.requestContext.get()?.request.url.endsWith("/actions/publish")) {
494
+ return false;
495
+ }
496
+ if (!context.contentType.uid.startsWith("api::")) {
497
+ return false;
498
+ }
499
+ return true;
500
+ };
501
+ const getSchemas = (uid2) => {
502
+ const attributesSchema = strapi.getModel(uid2).attributes;
503
+ const componentsSchemas = Object.keys(attributesSchema).reduce(
504
+ (currentComponentSchemas, key) => {
505
+ const fieldSchema = attributesSchema[key];
506
+ if (fieldSchema.type === "component") {
507
+ const componentSchema = strapi.getModel(fieldSchema.component).attributes;
508
+ return {
509
+ ...currentComponentSchemas,
510
+ [fieldSchema.component]: componentSchema
511
+ };
512
+ }
513
+ return currentComponentSchemas;
514
+ },
515
+ {}
516
+ );
517
+ return {
518
+ schema: omit(FIELDS_TO_IGNORE, attributesSchema),
519
+ componentsSchemas
520
+ };
521
+ };
471
522
  const createLifecyclesService = ({ strapi: strapi2 }) => {
472
523
  const state = {
473
524
  deleteExpiredJob: null,
@@ -480,63 +531,45 @@ const createLifecyclesService = ({ strapi: strapi2 }) => {
480
531
  return;
481
532
  }
482
533
  strapi2.documents.use(async (context, next) => {
483
- if (!strapi2.requestContext.get()?.request.url.startsWith("/content-manager")) {
484
- return next();
485
- }
486
- if (context.action !== "create" && context.action !== "update" && context.action !== "clone" && context.action !== "publish" && context.action !== "unpublish" && context.action !== "discardDraft") {
487
- return next();
488
- }
489
- if (context.action === "update" && strapi2.requestContext.get()?.request.url.endsWith("/actions/publish")) {
490
- return next();
491
- }
492
- const contentTypeUid = context.contentType.uid;
493
- if (!contentTypeUid.startsWith("api::")) {
494
- return next();
495
- }
496
534
  const result = await next();
497
- const documentContext = {
498
- documentId: context.action === "create" || context.action === "clone" ? result.documentId : context.params.documentId,
499
- locale: context.params?.locale
500
- };
535
+ if (!shouldCreateHistoryVersion(context)) {
536
+ return result;
537
+ }
538
+ const documentId = context.action === "create" || context.action === "clone" ? result.documentId : context.params.documentId;
501
539
  const defaultLocale = await serviceUtils.getDefaultLocale();
502
- const locale = documentContext.locale || defaultLocale;
503
- if (Array.isArray(locale)) {
504
- strapi2.log.warn(
505
- "[Content manager history middleware]: An array of locales was provided, but only a single locale is supported for the findOne operation."
506
- );
507
- return next();
540
+ const locales = castArray(context.params?.locale || defaultLocale);
541
+ if (!locales.length) {
542
+ return result;
508
543
  }
509
- const document = await strapi2.documents(contentTypeUid).findOne({
510
- documentId: documentContext.documentId,
511
- locale,
512
- populate: serviceUtils.getDeepPopulate(contentTypeUid)
544
+ const uid2 = context.contentType.uid;
545
+ const schemas = getSchemas(uid2);
546
+ const model = strapi2.getModel(uid2);
547
+ const isLocalizedContentType = serviceUtils.isLocalizedContentType(model);
548
+ const localeEntries = await strapi2.db.query(uid2).findMany({
549
+ where: {
550
+ documentId,
551
+ ...isLocalizedContentType ? { locale: { $in: locales } } : {},
552
+ ...contentTypes$1.hasDraftAndPublish(strapi2.contentTypes[uid2]) ? { publishedAt: null } : {}
553
+ },
554
+ populate: serviceUtils.getDeepPopulate(
555
+ uid2,
556
+ true
557
+ /* use database syntax */
558
+ )
513
559
  });
514
- const status = await serviceUtils.getVersionStatus(contentTypeUid, document);
515
- const attributesSchema = strapi2.getModel(contentTypeUid).attributes;
516
- const componentsSchemas = Object.keys(
517
- attributesSchema
518
- ).reduce((currentComponentSchemas, key) => {
519
- const fieldSchema = attributesSchema[key];
520
- if (fieldSchema.type === "component") {
521
- const componentSchema = strapi2.getModel(fieldSchema.component).attributes;
522
- return {
523
- ...currentComponentSchemas,
524
- [fieldSchema.component]: componentSchema
525
- };
526
- }
527
- return currentComponentSchemas;
528
- }, {});
529
560
  await strapi2.db.transaction(async ({ onCommit }) => {
530
- onCommit(() => {
531
- getService(strapi2, "history").createVersion({
532
- contentType: contentTypeUid,
533
- data: omit(FIELDS_TO_IGNORE, document),
534
- schema: omit(FIELDS_TO_IGNORE, attributesSchema),
535
- componentsSchemas,
536
- relatedDocumentId: documentContext.documentId,
537
- locale,
538
- status
539
- });
561
+ onCommit(async () => {
562
+ for (const entry of localeEntries) {
563
+ const status = await serviceUtils.getVersionStatus(uid2, entry);
564
+ await getService(strapi2, "history").createVersion({
565
+ contentType: uid2,
566
+ data: omit(FIELDS_TO_IGNORE, entry),
567
+ relatedDocumentId: documentId,
568
+ locale: entry.locale,
569
+ status,
570
+ ...schemas
571
+ });
572
+ }
540
573
  });
541
574
  });
542
575
  return result;
@@ -561,17 +594,17 @@ const createLifecyclesService = ({ strapi: strapi2 }) => {
561
594
  }
562
595
  };
563
596
  };
564
- const services$1 = {
597
+ const services$2 = {
565
598
  history: createHistoryService,
566
599
  lifecycles: createLifecyclesService
567
600
  };
568
- const info = { pluginName: "content-manager", type: "admin" };
601
+ const info$1 = { pluginName: "content-manager", type: "admin" };
569
602
  const historyVersionRouter = {
570
603
  type: "admin",
571
604
  routes: [
572
605
  {
573
606
  method: "GET",
574
- info,
607
+ info: info$1,
575
608
  path: "/history-versions",
576
609
  handler: "history-version.findMany",
577
610
  config: {
@@ -580,7 +613,7 @@ const historyVersionRouter = {
580
613
  },
581
614
  {
582
615
  method: "PUT",
583
- info,
616
+ info: info$1,
584
617
  path: "/history-versions/:versionId/restore",
585
618
  handler: "history-version.restoreVersion",
586
619
  config: {
@@ -589,7 +622,7 @@ const historyVersionRouter = {
589
622
  }
590
623
  ]
591
624
  };
592
- const routes$1 = {
625
+ const routes$2 = {
593
626
  "history-version": historyVersionRouter
594
627
  };
595
628
  const historyVersion = {
@@ -636,7 +669,7 @@ const historyVersion = {
636
669
  }
637
670
  }
638
671
  };
639
- const getFeature = () => {
672
+ const getFeature$1 = () => {
640
673
  if (strapi.ee.features.isEnabled("cms-content-history")) {
641
674
  return {
642
675
  register({ strapi: strapi2 }) {
@@ -648,9 +681,9 @@ const getFeature = () => {
648
681
  destroy({ strapi: strapi2 }) {
649
682
  getService(strapi2, "lifecycles").destroy();
650
683
  },
651
- controllers: controllers$1,
652
- services: services$1,
653
- routes: routes$1
684
+ controllers: controllers$2,
685
+ services: services$2,
686
+ routes: routes$2
654
687
  };
655
688
  }
656
689
  return {
@@ -659,7 +692,7 @@ const getFeature = () => {
659
692
  }
660
693
  };
661
694
  };
662
- const history = getFeature();
695
+ const history = getFeature$1();
663
696
  const register = async ({ strapi: strapi2 }) => {
664
697
  await history.register?.({ strapi: strapi2 });
665
698
  };
@@ -667,6 +700,62 @@ const ALLOWED_WEBHOOK_EVENTS = {
667
700
  ENTRY_PUBLISH: "entry.publish",
668
701
  ENTRY_UNPUBLISH: "entry.unpublish"
669
702
  };
703
+ const FEATURE_ID = "preview";
704
+ const info = { pluginName: "content-manager", type: "admin" };
705
+ const previewRouter = {
706
+ type: "admin",
707
+ routes: [
708
+ {
709
+ method: "GET",
710
+ info,
711
+ path: "/preview/url/:contentType",
712
+ handler: "preview.getPreviewURL",
713
+ config: {
714
+ policies: ["admin::isAuthenticatedAdmin"]
715
+ }
716
+ }
717
+ ]
718
+ };
719
+ const routes$1 = {
720
+ preview: previewRouter
721
+ };
722
+ const createPreviewController = () => {
723
+ return {
724
+ async getPreviewURL(ctx) {
725
+ ctx.request;
726
+ return {
727
+ data: { url: "" }
728
+ };
729
+ }
730
+ };
731
+ };
732
+ const controllers$1 = {
733
+ preview: createPreviewController
734
+ /**
735
+ * Casting is needed because the types aren't aware that Strapi supports
736
+ * passing a controller factory as the value, instead of a controller object directly
737
+ */
738
+ };
739
+ const createPreviewService = () => {
740
+ };
741
+ const services$1 = {
742
+ preview: createPreviewService
743
+ };
744
+ const getFeature = () => {
745
+ if (!strapi.features.future.isEnabled(FEATURE_ID)) {
746
+ return {};
747
+ }
748
+ return {
749
+ bootstrap() {
750
+ console.log("Bootstrapping preview server");
751
+ strapi.config.get("admin.preview");
752
+ },
753
+ routes: routes$1,
754
+ controllers: controllers$1,
755
+ services: services$1
756
+ };
757
+ };
758
+ const preview = getFeature();
670
759
  const bootstrap = async () => {
671
760
  Object.entries(ALLOWED_WEBHOOK_EVENTS).forEach(([key, value]) => {
672
761
  strapi.get("webhookStore").addAllowedEvent(key, value);
@@ -676,6 +765,7 @@ const bootstrap = async () => {
676
765
  await getService$1("content-types").syncConfigurations();
677
766
  await getService$1("permission").registerPermissions();
678
767
  await history.bootstrap?.({ strapi });
768
+ await preview.bootstrap?.({ strapi });
679
769
  };
680
770
  const destroy = async ({ strapi: strapi2 }) => {
681
771
  await history.destroy?.({ strapi: strapi2 });
@@ -1165,7 +1255,8 @@ const admin = {
1165
1255
  };
1166
1256
  const routes = {
1167
1257
  admin,
1168
- ...history.routes ? history.routes : {}
1258
+ ...history.routes ? history.routes : {},
1259
+ ...preview.routes ? preview.routes : {}
1169
1260
  };
1170
1261
  const hasPermissionsSchema = yup$1.object({
1171
1262
  actions: yup$1.array().of(yup$1.string()),
@@ -1176,6 +1267,11 @@ const { createPolicy } = policy;
1176
1267
  const hasPermissions = createPolicy({
1177
1268
  name: "plugin::content-manager.hasPermissions",
1178
1269
  validator: validateHasPermissionsInput,
1270
+ /**
1271
+ * NOTE: Action aliases are currently not checked at this level (policy).
1272
+ * This is currently the intended behavior to avoid changing the behavior of API related permissions.
1273
+ * If you want to add support for it, please create a dedicated RFC with a list of potential side effect this could have.
1274
+ */
1179
1275
  handler(ctx, config = {}) {
1180
1276
  const { actions = [], hasAtLeastOne = false } = config;
1181
1277
  const { userAbility } = ctx.state;
@@ -1656,7 +1752,7 @@ const updateDocument = async (ctx, opts) => {
1656
1752
  throw new errors.ForbiddenError();
1657
1753
  }
1658
1754
  const pickPermittedFields = documentVersion ? permissionChecker2.sanitizeUpdateInput(documentVersion) : permissionChecker2.sanitizeCreateInput;
1659
- const setCreator = setCreatorFields({ user, isEdition: true });
1755
+ const setCreator = documentVersion ? setCreatorFields({ user, isEdition: true }) : setCreatorFields({ user });
1660
1756
  const sanitizeFn = async.pipe(pickPermittedFields, setCreator);
1661
1757
  const sanitizedBody = await sanitizeFn(body);
1662
1758
  return documentManager2.update(documentVersion?.documentId || id, model, {
@@ -1728,7 +1824,7 @@ const collectionTypes = {
1728
1824
  permissionChecker2,
1729
1825
  model,
1730
1826
  // @ts-expect-error TODO: fix
1731
- { id, locale, publishedAt: null },
1827
+ { documentId: id, locale, publishedAt: null },
1732
1828
  { availableLocales: true, availableStatus: false }
1733
1829
  );
1734
1830
  ctx.body = { data: {}, meta };
@@ -1854,11 +1950,34 @@ const collectionTypes = {
1854
1950
  const publishedDocument = await strapi.db.transaction(async () => {
1855
1951
  const permissionQuery = await permissionChecker2.sanitizedQuery.publish(ctx.query);
1856
1952
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
1857
- const document = id ? await updateDocument(ctx, { populate }) : await createDocument(ctx, { populate });
1953
+ let document;
1954
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
1955
+ const isCreate = isNil$1(id);
1956
+ if (isCreate) {
1957
+ if (permissionChecker2.cannot.create()) {
1958
+ throw new errors.ForbiddenError();
1959
+ }
1960
+ document = await createDocument(ctx, { populate });
1961
+ }
1962
+ const isUpdate = !isCreate;
1963
+ if (isUpdate) {
1964
+ const documentExists = documentManager2.exists(model, id);
1965
+ if (!documentExists) {
1966
+ throw new errors.NotFoundError("Document not found");
1967
+ }
1968
+ document = await documentManager2.findOne(id, model, { populate, locale });
1969
+ if (!document) {
1970
+ if (permissionChecker2.cannot.create({ locale }) || permissionChecker2.cannot.publish({ locale })) {
1971
+ throw new errors.ForbiddenError();
1972
+ }
1973
+ document = await updateDocument(ctx);
1974
+ } else if (permissionChecker2.can.update(document)) {
1975
+ await updateDocument(ctx);
1976
+ }
1977
+ }
1858
1978
  if (permissionChecker2.cannot.publish(document)) {
1859
1979
  throw new errors.ForbiddenError();
1860
1980
  }
1861
- const { locale } = await getDocumentLocaleAndStatus(body, model);
1862
1981
  const publishResult = await documentManager2.publish(document.documentId, model, {
1863
1982
  locale
1864
1983
  // TODO: Allow setting creator fields on publish
@@ -1914,7 +2033,9 @@ const collectionTypes = {
1914
2033
  if (permissionChecker2.cannot.unpublish()) {
1915
2034
  return ctx.forbidden();
1916
2035
  }
1917
- const { locale } = await getDocumentLocaleAndStatus(body, model);
2036
+ const { locale } = await getDocumentLocaleAndStatus(body, model, {
2037
+ allowMultipleLocales: true
2038
+ });
1918
2039
  const entityPromises = documentIds.map(
1919
2040
  (documentId) => documentManager2.findLocales(documentId, model, { locale, isPublished: true })
1920
2041
  );
@@ -2265,32 +2386,37 @@ const sanitizeMainField = (model, mainField, userAbility) => {
2265
2386
  userAbility,
2266
2387
  model: model.uid
2267
2388
  });
2268
- if (!isListable(model, mainField)) {
2389
+ const isMainFieldListable = isListable(model, mainField);
2390
+ const canReadMainField = permissionChecker2.can.read(null, mainField);
2391
+ if (!isMainFieldListable || !canReadMainField) {
2269
2392
  return "id";
2270
2393
  }
2271
- if (permissionChecker2.cannot.read(null, mainField)) {
2272
- if (model.uid === "plugin::users-permissions.role") {
2273
- const userPermissionChecker = getService$1("permission-checker").create({
2274
- userAbility,
2275
- model: "plugin::users-permissions.user"
2276
- });
2277
- if (userPermissionChecker.can.read()) {
2278
- return "name";
2279
- }
2280
- }
2281
- return "id";
2394
+ if (model.uid === "plugin::users-permissions.role") {
2395
+ return "name";
2282
2396
  }
2283
2397
  return mainField;
2284
2398
  };
2285
- const addStatusToRelations = async (uid2, relations2) => {
2286
- if (!contentTypes$1.hasDraftAndPublish(strapi.contentTypes[uid2])) {
2399
+ const addStatusToRelations = async (targetUid, relations2) => {
2400
+ if (!contentTypes$1.hasDraftAndPublish(strapi.getModel(targetUid))) {
2287
2401
  return relations2;
2288
2402
  }
2289
2403
  const documentMetadata2 = getService$1("document-metadata");
2290
- const documentsAvailableStatus = await documentMetadata2.getManyAvailableStatus(uid2, relations2);
2404
+ if (!relations2.length) {
2405
+ return relations2;
2406
+ }
2407
+ const firstRelation = relations2[0];
2408
+ const filters = {
2409
+ documentId: { $in: relations2.map((r) => r.documentId) },
2410
+ // NOTE: find the "opposite" status
2411
+ publishedAt: firstRelation.publishedAt !== null ? { $null: true } : { $notNull: true }
2412
+ };
2413
+ const availableStatus = await strapi.query(targetUid).findMany({
2414
+ select: ["id", "documentId", "locale", "updatedAt", "createdAt", "publishedAt"],
2415
+ filters
2416
+ });
2291
2417
  return relations2.map((relation) => {
2292
- const availableStatuses = documentsAvailableStatus.filter(
2293
- (availableDocument) => availableDocument.documentId === relation.documentId
2418
+ const availableStatuses = availableStatus.filter(
2419
+ (availableDocument) => availableDocument.documentId === relation.documentId && (relation.locale ? availableDocument.locale === relation.locale : true)
2294
2420
  );
2295
2421
  return {
2296
2422
  ...relation,
@@ -2311,11 +2437,8 @@ const validateLocale = (sourceUid, targetUid, locale) => {
2311
2437
  const isLocalized = strapi.plugin("i18n").service("content-types").isLocalizedContentType;
2312
2438
  const isSourceLocalized = isLocalized(sourceModel);
2313
2439
  const isTargetLocalized = isLocalized(targetModel);
2314
- let validatedLocale = locale;
2315
- if (!targetModel || !isTargetLocalized)
2316
- validatedLocale = void 0;
2317
2440
  return {
2318
- locale: validatedLocale,
2441
+ locale,
2319
2442
  isSourceLocalized,
2320
2443
  isTargetLocalized
2321
2444
  };
@@ -2418,7 +2541,7 @@ const relations = {
2418
2541
  attribute,
2419
2542
  fieldsToSelect,
2420
2543
  mainField,
2421
- source: { schema: sourceSchema },
2544
+ source: { schema: sourceSchema, isLocalized: isSourceLocalized },
2422
2545
  target: { schema: targetSchema, isLocalized: isTargetLocalized },
2423
2546
  sourceSchema,
2424
2547
  targetSchema,
@@ -2440,7 +2563,8 @@ const relations = {
2440
2563
  fieldsToSelect,
2441
2564
  mainField,
2442
2565
  source: {
2443
- schema: { uid: sourceUid, modelType: sourceModelType }
2566
+ schema: { uid: sourceUid, modelType: sourceModelType },
2567
+ isLocalized: isSourceLocalized
2444
2568
  },
2445
2569
  target: {
2446
2570
  schema: { uid: targetUid },
@@ -2478,12 +2602,16 @@ const relations = {
2478
2602
  } else {
2479
2603
  where.id = id;
2480
2604
  }
2481
- if (status) {
2482
- where[`${alias}.published_at`] = getPublishedAtClause(status, targetUid);
2605
+ const publishedAt = getPublishedAtClause(status, targetUid);
2606
+ if (!isEmpty(publishedAt)) {
2607
+ where[`${alias}.published_at`] = publishedAt;
2483
2608
  }
2484
- if (filterByLocale) {
2609
+ if (isTargetLocalized && locale) {
2485
2610
  where[`${alias}.locale`] = locale;
2486
2611
  }
2612
+ if (isSourceLocalized && locale) {
2613
+ where.locale = locale;
2614
+ }
2487
2615
  if ((idsToInclude?.length ?? 0) !== 0) {
2488
2616
  where[`${alias}.id`].$notIn = idsToInclude;
2489
2617
  }
@@ -2501,7 +2629,8 @@ const relations = {
2501
2629
  id: { $notIn: uniq(idsToOmit) }
2502
2630
  });
2503
2631
  }
2504
- const res = await strapi.db.query(targetUid).findPage(strapi.get("query-params").transform(targetUid, queryParams));
2632
+ const dbQuery = strapi.get("query-params").transform(targetUid, queryParams);
2633
+ const res = await strapi.db.query(targetUid).findPage(dbQuery);
2505
2634
  ctx.body = {
2506
2635
  ...res,
2507
2636
  results: await addStatusToRelations(targetUid, res.results)
@@ -2516,29 +2645,39 @@ const relations = {
2516
2645
  attribute,
2517
2646
  targetField,
2518
2647
  fieldsToSelect,
2519
- source: {
2520
- schema: { uid: sourceUid }
2521
- },
2522
- target: {
2523
- schema: { uid: targetUid }
2524
- }
2648
+ status,
2649
+ source: { schema: sourceSchema },
2650
+ target: { schema: targetSchema }
2525
2651
  } = await this.extractAndValidateRequestInfo(ctx, id);
2652
+ const { uid: sourceUid } = sourceSchema;
2653
+ const { uid: targetUid } = targetSchema;
2526
2654
  const permissionQuery = await getService$1("permission-checker").create({ userAbility, model: targetUid }).sanitizedQuery.read({ fields: fieldsToSelect });
2527
2655
  const dbQuery = strapi.db.query(sourceUid);
2528
2656
  const loadRelations = relations$1.isAnyToMany(attribute) ? (...args) => dbQuery.loadPages(...args) : (...args) => dbQuery.load(...args).then((res2) => ({ results: res2 ? [res2] : [] }));
2657
+ const filters = {};
2658
+ if (sourceSchema?.options?.draftAndPublish) {
2659
+ if (targetSchema?.options?.draftAndPublish) {
2660
+ if (status === "published") {
2661
+ filters.publishedAt = { $notNull: true };
2662
+ } else {
2663
+ filters.publishedAt = { $null: true };
2664
+ }
2665
+ }
2666
+ } else if (targetSchema?.options?.draftAndPublish) {
2667
+ filters.publishedAt = { $null: true };
2668
+ }
2529
2669
  const res = await loadRelations({ id: entryId }, targetField, {
2530
- select: ["id", "documentId", "locale", "publishedAt"],
2670
+ select: ["id", "documentId", "locale", "publishedAt", "updatedAt"],
2531
2671
  ordering: "desc",
2532
2672
  page: ctx.request.query.page,
2533
- pageSize: ctx.request.query.pageSize
2673
+ pageSize: ctx.request.query.pageSize,
2674
+ filters
2534
2675
  });
2535
2676
  const loadedIds = res.results.map((item) => item.id);
2536
2677
  addFiltersClause(permissionQuery, { id: { $in: loadedIds } });
2537
2678
  const sanitizedRes = await loadRelations({ id: entryId }, targetField, {
2538
2679
  ...strapi.get("query-params").transform(targetUid, permissionQuery),
2539
- ordering: "desc",
2540
- page: ctx.request.query.page,
2541
- pageSize: ctx.request.query.pageSize
2680
+ ordering: "desc"
2542
2681
  });
2543
2682
  const relationsUnion = uniqBy("id", concat(sanitizedRes.results, res.results));
2544
2683
  ctx.body = {
@@ -2625,7 +2764,7 @@ const singleTypes = {
2625
2764
  permissionChecker2,
2626
2765
  model,
2627
2766
  // @ts-expect-error - fix types
2628
- { id: document.documentId, locale, publishedAt: null },
2767
+ { documentId: document.documentId, locale, publishedAt: null },
2629
2768
  { availableLocales: true, availableStatus: false }
2630
2769
  );
2631
2770
  ctx.body = { data: {}, meta };
@@ -2824,7 +2963,8 @@ const controllers = {
2824
2963
  relations,
2825
2964
  "single-types": singleTypes,
2826
2965
  uid: uid$1,
2827
- ...history.controllers ? history.controllers : {}
2966
+ ...history.controllers ? history.controllers : {},
2967
+ ...preview.controllers ? preview.controllers : {}
2828
2968
  };
2829
2969
  const keys = {
2830
2970
  CONFIGURATION: "configuration"
@@ -3444,12 +3584,27 @@ const createPermissionChecker = (strapi2) => ({ userAbility, model }) => {
3444
3584
  ability: userAbility,
3445
3585
  model
3446
3586
  });
3447
- const toSubject = (entity) => entity ? permissionsManager.toSubject(entity, model) : model;
3587
+ const { actionProvider } = strapi2.service("admin::permission");
3588
+ const toSubject = (entity) => {
3589
+ return entity ? permissionsManager.toSubject(entity, model) : model;
3590
+ };
3448
3591
  const can = (action, entity, field) => {
3449
- return userAbility.can(action, toSubject(entity), field);
3592
+ const subject = toSubject(entity);
3593
+ const aliases = actionProvider.unstable_aliases(action, model);
3594
+ return (
3595
+ // Test the original action to see if it passes
3596
+ userAbility.can(action, subject, field) || // Else try every known alias if at least one of them succeed, then the user "can"
3597
+ aliases.some((alias) => userAbility.can(alias, subject, field))
3598
+ );
3450
3599
  };
3451
3600
  const cannot = (action, entity, field) => {
3452
- return userAbility.cannot(action, toSubject(entity), field);
3601
+ const subject = toSubject(entity);
3602
+ const aliases = actionProvider.unstable_aliases(action, model);
3603
+ return (
3604
+ // Test both the original action
3605
+ userAbility.cannot(action, subject, field) && // and every known alias, if all of them fail (cannot), then the user truly "cannot"
3606
+ aliases.every((alias) => userAbility.cannot(alias, subject, field))
3607
+ );
3453
3608
  };
3454
3609
  const sanitizeOutput = (data, { action = ACTIONS.read } = {}) => {
3455
3610
  return permissionsManager.sanitizeOutput(data, { subject: toSubject(data), action });
@@ -3981,7 +4136,9 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
3981
4136
  */
3982
4137
  async getAvailableLocales(uid2, version, allVersions, validatableFields = []) {
3983
4138
  const versionsByLocale = groupBy("locale", allVersions);
3984
- delete versionsByLocale[version.locale];
4139
+ if (version.locale) {
4140
+ delete versionsByLocale[version.locale];
4141
+ }
3985
4142
  const model = strapi2.getModel(uid2);
3986
4143
  const keysToKeep = [...AVAILABLE_LOCALES_FIELDS, ...validatableFields];
3987
4144
  const traversalFunction = async (localeVersion) => traverseEntity(
@@ -4107,7 +4264,13 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
4107
4264
  */
4108
4265
  async formatDocumentWithMetadata(uid2, document, opts = {}) {
4109
4266
  if (!document) {
4110
- return document;
4267
+ return {
4268
+ data: document,
4269
+ meta: {
4270
+ availableLocales: [],
4271
+ availableStatus: []
4272
+ }
4273
+ };
4111
4274
  }
4112
4275
  const hasDraftAndPublish = contentTypes$1.hasDraftAndPublish(strapi2.getModel(uid2));
4113
4276
  if (!hasDraftAndPublish) {
@@ -4331,7 +4494,8 @@ const services = {
4331
4494
  permission,
4332
4495
  "populate-builder": populateBuilder$1,
4333
4496
  uid,
4334
- ...history.services ? history.services : {}
4497
+ ...history.services ? history.services : {},
4498
+ ...preview.services ? preview.services : {}
4335
4499
  };
4336
4500
  const index = () => {
4337
4501
  return {