@strapi/content-releases 0.0.0-experimental.e9122b401c96877b6707775c4f893660eab93ae3 → 0.0.0-experimental.eba25ec571b091c6bde1104eb6c753debdf15462

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 (51) hide show
  1. package/dist/_chunks/{App-JwN_xBnA.mjs → App-FQyYFBJT.mjs} +299 -114
  2. package/dist/_chunks/App-FQyYFBJT.mjs.map +1 -0
  3. package/dist/_chunks/{App-BFo3ibui.js → App-lx4Ucy9W.js} +338 -153
  4. package/dist/_chunks/App-lx4Ucy9W.js.map +1 -0
  5. package/dist/_chunks/{ReleasesSettingsPage-CNMXGcZC.mjs → ReleasesSettingsPage-DqBxvJ9i.mjs} +3 -3
  6. package/dist/_chunks/{ReleasesSettingsPage-CNMXGcZC.mjs.map → ReleasesSettingsPage-DqBxvJ9i.mjs.map} +1 -1
  7. package/dist/_chunks/{ReleasesSettingsPage-BanjZwEc.js → ReleasesSettingsPage-T5VEAV03.js} +3 -3
  8. package/dist/_chunks/{ReleasesSettingsPage-BanjZwEc.js.map → ReleasesSettingsPage-T5VEAV03.js.map} +1 -1
  9. package/dist/_chunks/{en-CmYoEnA7.js → en-BWPPsSH-.js} +11 -2
  10. package/dist/_chunks/en-BWPPsSH-.js.map +1 -0
  11. package/dist/_chunks/{en-D0yVZFqf.mjs → en-D9Q4YW03.mjs} +11 -2
  12. package/dist/_chunks/en-D9Q4YW03.mjs.map +1 -0
  13. package/dist/_chunks/{index-C_e6DQb0.mjs → index-CK9G80CL.mjs} +57 -19
  14. package/dist/_chunks/index-CK9G80CL.mjs.map +1 -0
  15. package/dist/_chunks/{index-Em3KctMx.js → index-Cl3tM1YW.js} +57 -19
  16. package/dist/_chunks/index-Cl3tM1YW.js.map +1 -0
  17. package/dist/_chunks/{schemas-z5zp-_Gd.js → schemas-BE1LxE9J.js} +2 -2
  18. package/dist/_chunks/schemas-BE1LxE9J.js.map +1 -0
  19. package/dist/_chunks/{schemas-63pFihNF.mjs → schemas-DdA2ic2U.mjs} +2 -2
  20. package/dist/_chunks/schemas-DdA2ic2U.mjs.map +1 -0
  21. package/dist/admin/index.js +1 -1
  22. package/dist/admin/index.mjs +1 -1
  23. package/dist/admin/src/components/EntryValidationPopover.d.ts +13 -0
  24. package/dist/admin/src/services/release.d.ts +28 -28
  25. package/dist/server/index.js +118 -15
  26. package/dist/server/index.js.map +1 -1
  27. package/dist/server/index.mjs +118 -15
  28. package/dist/server/index.mjs.map +1 -1
  29. package/dist/server/src/controllers/release-action.d.ts.map +1 -1
  30. package/dist/server/src/controllers/release.d.ts.map +1 -1
  31. package/dist/server/src/index.d.ts +4 -6
  32. package/dist/server/src/index.d.ts.map +1 -1
  33. package/dist/server/src/middlewares/documents.d.ts.map +1 -1
  34. package/dist/server/src/migrations/database/5.0.0-document-id-in-actions.d.ts.map +1 -1
  35. package/dist/server/src/services/index.d.ts +4 -6
  36. package/dist/server/src/services/index.d.ts.map +1 -1
  37. package/dist/server/src/services/release-action.d.ts +6 -8
  38. package/dist/server/src/services/release-action.d.ts.map +1 -1
  39. package/dist/server/src/utils/index.d.ts.map +1 -1
  40. package/dist/shared/contracts/release-actions.d.ts +8 -1
  41. package/dist/shared/contracts/release-actions.d.ts.map +1 -1
  42. package/package.json +15 -14
  43. package/dist/_chunks/App-BFo3ibui.js.map +0 -1
  44. package/dist/_chunks/App-JwN_xBnA.mjs.map +0 -1
  45. package/dist/_chunks/en-CmYoEnA7.js.map +0 -1
  46. package/dist/_chunks/en-D0yVZFqf.mjs.map +0 -1
  47. package/dist/_chunks/index-C_e6DQb0.mjs.map +0 -1
  48. package/dist/_chunks/index-Em3KctMx.js.map +0 -1
  49. package/dist/_chunks/schemas-63pFihNF.mjs.map +0 -1
  50. package/dist/_chunks/schemas-z5zp-_Gd.js.map +0 -1
  51. package/strapi-server.js +0 -3
@@ -111,6 +111,13 @@ const isEntryValid = async (contentTypeUid, entry, { strapi: strapi2 }) => {
111
111
  // @ts-expect-error - FIXME: entity here is unnecessary
112
112
  entry
113
113
  );
114
+ const workflowsService = strapi2.plugin("review-workflows").service("workflows");
115
+ const workflow = await workflowsService.getAssignedWorkflow(contentTypeUid, {
116
+ populate: "stageRequiredToPublish"
117
+ });
118
+ if (workflow?.stageRequiredToPublish) {
119
+ return entry.strapi_stage.id === workflow.stageRequiredToPublish.id;
120
+ }
114
121
  return true;
115
122
  } catch {
116
123
  return false;
@@ -124,7 +131,11 @@ const getEntry = async ({
124
131
  status = "draft"
125
132
  }, { strapi: strapi2 }) => {
126
133
  if (documentId) {
127
- return strapi2.documents(contentType).findOne({ documentId, locale, populate, status });
134
+ const entry = await strapi2.documents(contentType).findOne({ documentId, locale, populate, status });
135
+ if (status === "published" && !entry) {
136
+ return strapi2.documents(contentType).findOne({ documentId, locale, populate, status: "draft" });
137
+ }
138
+ return entry;
128
139
  }
129
140
  return strapi2.documents(contentType).findFirst({ locale, populate, status });
130
141
  };
@@ -329,6 +340,10 @@ async function enableContentTypeLocalized({ oldContentTypes, contentTypes: conte
329
340
  const addEntryDocumentToReleaseActions = {
330
341
  name: "content-releases::5.0.0-add-entry-document-id-to-release-actions",
331
342
  async up(trx, db) {
343
+ const hasTable = await trx.schema.hasTable("strapi_release_actions");
344
+ if (!hasTable) {
345
+ return;
346
+ }
332
347
  const hasPolymorphicColumn = await trx.schema.hasColumn("strapi_release_actions", "target_id");
333
348
  if (hasPolymorphicColumn) {
334
349
  const hasEntryDocumentIdColumn = await trx.schema.hasColumn(
@@ -370,6 +385,7 @@ const register = async ({ strapi: strapi2 }) => {
370
385
  const updateActionsStatusAndUpdateReleaseStatus = async (contentType, entry) => {
371
386
  const releases = await strapi.db.query(RELEASE_MODEL_UID).findMany({
372
387
  where: {
388
+ releasedAt: null,
373
389
  actions: {
374
390
  contentType,
375
391
  entryDocumentId: entry.documentId,
@@ -378,7 +394,7 @@ const updateActionsStatusAndUpdateReleaseStatus = async (contentType, entry) =>
378
394
  }
379
395
  });
380
396
  const entryStatus = await isEntryValid(contentType, entry, { strapi });
381
- await strapi.db.query(RELEASE_ACTION_MODEL_UID).update({
397
+ await strapi.db.query(RELEASE_ACTION_MODEL_UID).updateMany({
382
398
  where: {
383
399
  contentType,
384
400
  entryDocumentId: entry.documentId,
@@ -482,8 +498,8 @@ const bootstrap = async ({ strapi: strapi2 }) => {
482
498
  const { where } = event.params;
483
499
  deleteReleasesActionsAndUpdateReleaseStatus({
484
500
  contentType: model.uid,
485
- locale: where.locale ?? null,
486
- ...where.documentId && { entryDocumentId: where.documentId }
501
+ locale: where?.locale ?? null,
502
+ ...where?.documentId && { entryDocumentId: where.documentId }
487
503
  });
488
504
  }
489
505
  } catch (error) {
@@ -929,7 +945,7 @@ const createReleaseActionService = ({ strapi: strapi2 }) => {
929
945
  return contentTypesData;
930
946
  };
931
947
  return {
932
- async create(releaseId, action) {
948
+ async create(releaseId, action, { disableUpdateReleaseStatus = false } = {}) {
933
949
  const { validateEntryData, validateUniqueEntry } = getService("release-validation", {
934
950
  strapi: strapi2
935
951
  });
@@ -937,6 +953,14 @@ const createReleaseActionService = ({ strapi: strapi2 }) => {
937
953
  validateEntryData(action.contentType, action.entryDocumentId),
938
954
  validateUniqueEntry(releaseId, action)
939
955
  ]);
956
+ const model = strapi2.contentType(action.contentType);
957
+ if (model.kind === "singleType") {
958
+ const document = await strapi2.db.query(model.uid).findOne({ select: ["documentId"] });
959
+ if (!document) {
960
+ throw new utils.errors.NotFoundError(`No entry found for contentType ${action.contentType}`);
961
+ }
962
+ action.entryDocumentId = document.documentId;
963
+ }
940
964
  const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({ where: { id: releaseId } });
941
965
  if (!release2) {
942
966
  throw new utils.errors.NotFoundError(`No release found for id ${releaseId}`);
@@ -962,7 +986,9 @@ const createReleaseActionService = ({ strapi: strapi2 }) => {
962
986
  },
963
987
  populate: { release: { select: ["id"] } }
964
988
  });
965
- getService("release", { strapi: strapi2 }).updateReleaseStatus(release2.id);
989
+ if (!disableUpdateReleaseStatus) {
990
+ getService("release", { strapi: strapi2 }).updateReleaseStatus(release2.id);
991
+ }
966
992
  return releaseAction2;
967
993
  },
968
994
  async findPage(releaseId, query) {
@@ -1028,16 +1054,26 @@ const createReleaseActionService = ({ strapi: strapi2 }) => {
1028
1054
  const groupName = getGroupName(groupBy);
1029
1055
  return ___default.default.groupBy(groupName)(formattedData);
1030
1056
  },
1031
- getContentTypeModelsFromActions(actions) {
1057
+ async getContentTypeModelsFromActions(actions) {
1032
1058
  const contentTypeUids = actions.reduce((acc, action) => {
1033
1059
  if (!acc.includes(action.contentType)) {
1034
1060
  acc.push(action.contentType);
1035
1061
  }
1036
1062
  return acc;
1037
1063
  }, []);
1038
- const contentTypeModelsMap = contentTypeUids.reduce(
1039
- (acc, contentTypeUid) => {
1040
- acc[contentTypeUid] = strapi2.getModel(contentTypeUid);
1064
+ const workflowsService = strapi2.plugin("review-workflows").service("workflows");
1065
+ const contentTypeModelsMap = await utils.async.reduce(contentTypeUids)(
1066
+ async (accPromise, contentTypeUid) => {
1067
+ const acc = await accPromise;
1068
+ const contentTypeModel = strapi2.getModel(contentTypeUid);
1069
+ const workflow = await workflowsService.getAssignedWorkflow(contentTypeUid, {
1070
+ populate: "stageRequiredToPublish"
1071
+ });
1072
+ acc[contentTypeUid] = {
1073
+ ...contentTypeModel,
1074
+ hasReviewWorkflow: !!workflow,
1075
+ stageRequiredToPublish: workflow?.stageRequiredToPublish
1076
+ };
1041
1077
  return acc;
1042
1078
  },
1043
1079
  {}
@@ -1065,7 +1101,7 @@ const createReleaseActionService = ({ strapi: strapi2 }) => {
1065
1101
  `Action with id ${actionId} not found in release with id ${releaseId} or it is already published`
1066
1102
  );
1067
1103
  }
1068
- const actionStatus = update.type === "publish" ? getDraftEntryValidStatus(
1104
+ const actionStatus = update.type === "publish" ? await getDraftEntryValidStatus(
1069
1105
  {
1070
1106
  contentType: action.contentType,
1071
1107
  documentId: action.entryDocumentId,
@@ -1112,6 +1148,54 @@ const createReleaseActionService = ({ strapi: strapi2 }) => {
1112
1148
  }
1113
1149
  getService("release", { strapi: strapi2 }).updateReleaseStatus(releaseId);
1114
1150
  return deletedAction;
1151
+ },
1152
+ async validateActionsByContentTypes(contentTypeUids) {
1153
+ const actions = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).findMany({
1154
+ where: {
1155
+ contentType: {
1156
+ $in: contentTypeUids
1157
+ },
1158
+ // We only want to validate actions that are going to be published
1159
+ type: "publish",
1160
+ release: {
1161
+ releasedAt: {
1162
+ $null: true
1163
+ }
1164
+ }
1165
+ },
1166
+ populate: { release: true }
1167
+ });
1168
+ const releasesUpdated = [];
1169
+ await utils.async.map(actions, async (action) => {
1170
+ const isValid = await getDraftEntryValidStatus(
1171
+ {
1172
+ contentType: action.contentType,
1173
+ documentId: action.entryDocumentId,
1174
+ locale: action.locale
1175
+ },
1176
+ { strapi: strapi2 }
1177
+ );
1178
+ await strapi2.db.query(RELEASE_ACTION_MODEL_UID).update({
1179
+ where: {
1180
+ id: action.id
1181
+ },
1182
+ data: {
1183
+ isEntryValid: isValid
1184
+ }
1185
+ });
1186
+ if (!releasesUpdated.includes(action.release.id)) {
1187
+ releasesUpdated.push(action.release.id);
1188
+ }
1189
+ return {
1190
+ id: action.id,
1191
+ isEntryValid: isValid
1192
+ };
1193
+ });
1194
+ if (releasesUpdated.length > 0) {
1195
+ await utils.async.map(releasesUpdated, async (releaseId) => {
1196
+ await getService("release", { strapi: strapi2 }).updateReleaseStatus(releaseId);
1197
+ });
1198
+ }
1115
1199
  }
1116
1200
  };
1117
1201
  };
@@ -1306,7 +1390,15 @@ const releaseController = {
1306
1390
  const releaseService = getService("release", { strapi });
1307
1391
  const query = await permissionsManager.sanitizeQuery(ctx.query);
1308
1392
  await validatefindByDocumentAttachedParams(query);
1309
- const { contentType, entryDocumentId, hasEntryAttached, locale } = query;
1393
+ const model = strapi.getModel(query.contentType);
1394
+ if (model.kind && model.kind === "singleType") {
1395
+ const document = await strapi.db.query(model.uid).findOne({ select: ["documentId"] });
1396
+ if (!document) {
1397
+ throw new utils.errors.NotFoundError(`No entry found for contentType ${query.contentType}`);
1398
+ }
1399
+ query.entryDocumentId = document.documentId;
1400
+ }
1401
+ const { contentType, hasEntryAttached, entryDocumentId, locale } = query;
1310
1402
  const isEntryAttached = typeof hasEntryAttached === "string" ? Boolean(JSON.parse(hasEntryAttached)) : false;
1311
1403
  if (isEntryAttached) {
1312
1404
  const releases = await releaseService.findMany({
@@ -1320,7 +1412,12 @@ const releaseController = {
1320
1412
  },
1321
1413
  populate: {
1322
1414
  actions: {
1323
- fields: ["type"]
1415
+ fields: ["type"],
1416
+ filters: {
1417
+ contentType,
1418
+ entryDocumentId: entryDocumentId ?? null,
1419
+ locale: locale ?? null
1420
+ }
1324
1421
  }
1325
1422
  }
1326
1423
  });
@@ -1551,11 +1648,14 @@ const releaseActionController = {
1551
1648
  releaseActionsArgs.map((releaseActionArgs) => validateReleaseAction(releaseActionArgs))
1552
1649
  );
1553
1650
  const releaseActionService = getService("release-action", { strapi });
1651
+ const releaseService = getService("release", { strapi });
1554
1652
  const releaseActions = await strapi.db.transaction(async () => {
1555
1653
  const releaseActions2 = await Promise.all(
1556
1654
  releaseActionsArgs.map(async (releaseActionArgs) => {
1557
1655
  try {
1558
- const action = await releaseActionService.create(releaseId, releaseActionArgs);
1656
+ const action = await releaseActionService.create(releaseId, releaseActionArgs, {
1657
+ disableUpdateReleaseStatus: true
1658
+ });
1559
1659
  return action;
1560
1660
  } catch (error) {
1561
1661
  if (error instanceof AlreadyOnReleaseError) {
@@ -1568,6 +1668,9 @@ const releaseActionController = {
1568
1668
  return releaseActions2;
1569
1669
  });
1570
1670
  const newReleaseActions = releaseActions.filter((action) => action !== null);
1671
+ if (newReleaseActions.length > 0) {
1672
+ releaseService.updateReleaseStatus(releaseId);
1673
+ }
1571
1674
  ctx.created({
1572
1675
  data: newReleaseActions,
1573
1676
  meta: {
@@ -1611,7 +1714,7 @@ const releaseActionController = {
1611
1714
  entry: action.entry ? await contentTypeOutputSanitizers[action.contentType](action.entry) : {}
1612
1715
  }));
1613
1716
  const groupedData = await releaseActionService.groupActions(sanitizedResults, query.sort);
1614
- const contentTypes2 = releaseActionService.getContentTypeModelsFromActions(results);
1717
+ const contentTypes2 = await releaseActionService.getContentTypeModelsFromActions(results);
1615
1718
  const releaseService = getService("release", { strapi });
1616
1719
  const components = await releaseService.getAllComponents();
1617
1720
  ctx.body = {