@strapi/review-workflows 5.2.0 → 5.3.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 (59) hide show
  1. package/dist/_chunks/{Layout-C9m07iTY.mjs → Layout-BIIxkAtf.mjs} +3 -3
  2. package/dist/_chunks/Layout-BIIxkAtf.mjs.map +1 -0
  3. package/dist/_chunks/{Layout-8i0EXRRs.js → Layout-BWNbQOes.js} +3 -3
  4. package/dist/_chunks/Layout-BWNbQOes.js.map +1 -0
  5. package/dist/_chunks/{en-xcewH2pC.js → en-CYgjfSep.js} +5 -2
  6. package/dist/_chunks/en-CYgjfSep.js.map +1 -0
  7. package/dist/_chunks/{en-D9ZrQAV6.mjs → en-D9dxziEb.mjs} +5 -2
  8. package/dist/_chunks/en-D9dxziEb.mjs.map +1 -0
  9. package/dist/_chunks/{id-CmtaTf1x.js → id-CaHzMdxL.js} +72 -12
  10. package/dist/_chunks/id-CaHzMdxL.js.map +1 -0
  11. package/dist/_chunks/{id-DV0Ndeav.mjs → id-CtcCl3zh.mjs} +72 -12
  12. package/dist/_chunks/id-CtcCl3zh.mjs.map +1 -0
  13. package/dist/_chunks/{index-BCUO98DV.js → index-BX5MyocW.js} +3 -3
  14. package/dist/_chunks/{index-BCUO98DV.js.map → index-BX5MyocW.js.map} +1 -1
  15. package/dist/_chunks/{index-CqYVkW3E.mjs → index-ByTEmYbc.mjs} +3 -3
  16. package/dist/_chunks/{index-CqYVkW3E.mjs.map → index-ByTEmYbc.mjs.map} +1 -1
  17. package/dist/_chunks/{index-CA5Axcoc.mjs → index-CGmh3cED.mjs} +3 -3
  18. package/dist/_chunks/{index-CA5Axcoc.mjs.map → index-CGmh3cED.mjs.map} +1 -1
  19. package/dist/_chunks/{index-B8WmHbCU.js → index-DKLk-Z5E.js} +3 -3
  20. package/dist/_chunks/{index-B8WmHbCU.js.map → index-DKLk-Z5E.js.map} +1 -1
  21. package/dist/_chunks/{router-BOXlNnrU.js → router-Bt6JHY-e.js} +3 -3
  22. package/dist/_chunks/{router-BOXlNnrU.js.map → router-Bt6JHY-e.js.map} +1 -1
  23. package/dist/_chunks/{router-Jdt6SbIA.mjs → router-Cr3nulh9.mjs} +3 -3
  24. package/dist/_chunks/{router-Jdt6SbIA.mjs.map → router-Cr3nulh9.mjs.map} +1 -1
  25. package/dist/admin/index.js +1 -1
  26. package/dist/admin/index.mjs +1 -1
  27. package/dist/admin/src/services/settings.d.ts +7 -3
  28. package/dist/server/index.js +116 -16
  29. package/dist/server/index.js.map +1 -1
  30. package/dist/server/index.mjs +116 -16
  31. package/dist/server/index.mjs.map +1 -1
  32. package/dist/server/src/bootstrap.d.ts.map +1 -1
  33. package/dist/server/src/constants/workflows.d.ts +1 -0
  34. package/dist/server/src/constants/workflows.d.ts.map +1 -1
  35. package/dist/server/src/content-types/index.d.ts +6 -0
  36. package/dist/server/src/content-types/index.d.ts.map +1 -1
  37. package/dist/server/src/content-types/workflow/index.d.ts +6 -0
  38. package/dist/server/src/content-types/workflow/index.d.ts.map +1 -1
  39. package/dist/server/src/index.d.ts +15 -2
  40. package/dist/server/src/index.d.ts.map +1 -1
  41. package/dist/server/src/register.d.ts.map +1 -1
  42. package/dist/server/src/services/document-service-middleware.d.ts +1 -0
  43. package/dist/server/src/services/document-service-middleware.d.ts.map +1 -1
  44. package/dist/server/src/services/index.d.ts +3 -2
  45. package/dist/server/src/services/index.d.ts.map +1 -1
  46. package/dist/server/src/services/metrics/index.d.ts +4 -4
  47. package/dist/server/src/services/metrics/index.d.ts.map +1 -1
  48. package/dist/server/src/services/workflows.d.ts.map +1 -1
  49. package/dist/server/src/validation/review-workflows.d.ts +4 -0
  50. package/dist/server/src/validation/review-workflows.d.ts.map +1 -1
  51. package/dist/shared/contracts/review-workflows.d.ts +8 -3
  52. package/dist/shared/contracts/review-workflows.d.ts.map +1 -1
  53. package/package.json +8 -8
  54. package/dist/_chunks/Layout-8i0EXRRs.js.map +0 -1
  55. package/dist/_chunks/Layout-C9m07iTY.mjs.map +0 -1
  56. package/dist/_chunks/en-D9ZrQAV6.mjs.map +0 -1
  57. package/dist/_chunks/en-xcewH2pC.js.map +0 -1
  58. package/dist/_chunks/id-CmtaTf1x.js.map +0 -1
  59. package/dist/_chunks/id-DV0Ndeav.mjs.map +0 -1
@@ -6386,7 +6386,8 @@ const WORKFLOW_POPULATE = {
6386
6386
  }
6387
6387
  }
6388
6388
  }
6389
- }
6389
+ },
6390
+ stageRequiredToPublish: true
6390
6391
  };
6391
6392
  function checkVersionThreshold(startVersion, currentVersion, thresholdVersion) {
6392
6393
  return semver$1.gte(currentVersion, thresholdVersion) && semver$1.lt(startVersion, thresholdVersion);
@@ -6561,8 +6562,40 @@ function extendReviewWorkflowContentTypes({ strapi: strapi2 }) {
6561
6562
  });
6562
6563
  }
6563
6564
  }
6565
+ function persistRWOnDowngrade({ strapi: strapi2 }) {
6566
+ const { removePersistedTablesWithSuffix, persistTables } = getAdminService("persist-tables");
6567
+ return async ({ contentTypes: contentTypes2 }) => {
6568
+ const getStageTableToPersist = (contentTypeUID) => {
6569
+ const { attributes, tableName } = strapi2.db.metadata.get(contentTypeUID);
6570
+ const joinTableName = attributes[ENTITY_STAGE_ATTRIBUTE].joinTable.name;
6571
+ return {
6572
+ name: joinTableName,
6573
+ dependsOn: [{ name: tableName }]
6574
+ };
6575
+ };
6576
+ const getAssigneeTableToPersist = (contentTypeUID) => {
6577
+ const { attributes, tableName } = strapi2.db.metadata.get(contentTypeUID);
6578
+ const joinTableName = attributes[ENTITY_ASSIGNEE_ATTRIBUTE].joinTable.name;
6579
+ return {
6580
+ name: joinTableName,
6581
+ dependsOn: [{ name: tableName }]
6582
+ };
6583
+ };
6584
+ const enabledRWContentTypes = fp.pipe([
6585
+ getVisibleContentTypesUID,
6586
+ fp.filter((uid) => hasStageAttribute(contentTypes2[uid]))
6587
+ ])(contentTypes2);
6588
+ const stageJoinTablesToPersist = enabledRWContentTypes.map(getStageTableToPersist);
6589
+ await removePersistedTablesWithSuffix("_strapi_stage_lnk");
6590
+ await persistTables(stageJoinTablesToPersist);
6591
+ const assigneeJoinTablesToPersist = enabledRWContentTypes.map(getAssigneeTableToPersist);
6592
+ await removePersistedTablesWithSuffix("_strapi_assignee_lnk");
6593
+ await persistTables(assigneeJoinTablesToPersist);
6594
+ };
6595
+ }
6564
6596
  const register = async ({ strapi: strapi2 }) => {
6565
6597
  strapi2.hook("strapi::content-types.beforeSync").register(migrateStageAttribute);
6598
+ strapi2.hook("strapi::content-types.afterSync").register(persistRWOnDowngrade({ strapi: strapi2 }));
6566
6599
  strapi2.hook("strapi::content-types.afterSync").register(migrateReviewWorkflowStagesColor).register(migrateReviewWorkflowStagesRoles).register(migrateReviewWorkflowName).register(migrateWorkflowsContentTypes).register(migrateDeletedCTInWorkflows);
6567
6600
  reviewWorkflowsMiddlewares.contentTypeMiddleware(strapi2);
6568
6601
  extendReviewWorkflowContentTypes({ strapi: strapi2 });
@@ -6607,6 +6640,12 @@ const workflow = {
6607
6640
  relation: "oneToMany",
6608
6641
  mappedBy: "workflow"
6609
6642
  },
6643
+ stageRequiredToPublish: {
6644
+ type: "relation",
6645
+ target: "plugin::review-workflows.workflow-stage",
6646
+ relation: "oneToOne",
6647
+ required: false
6648
+ },
6610
6649
  contentTypes: {
6611
6650
  type: "json",
6612
6651
  required: true,
@@ -6756,6 +6795,7 @@ const bootstrap = async (args) => {
6756
6795
  const docsMiddlewares = getService("document-service-middlewares");
6757
6796
  strapi.documents.use(docsMiddlewares.assignStageOnCreate);
6758
6797
  strapi.documents.use(docsMiddlewares.handleStageOnUpdate);
6798
+ strapi.documents.use(docsMiddlewares.checkStageBeforePublish);
6759
6799
  };
6760
6800
  const destroy = async ({ strapi: strapi2 }) => {
6761
6801
  };
@@ -6988,9 +7028,9 @@ const processFilters = ({ strapi: strapi2 }, filters = {}) => {
6988
7028
  };
6989
7029
  const processPopulate = (populate) => {
6990
7030
  if (!populate) {
6991
- return populate;
7031
+ return WORKFLOW_POPULATE;
6992
7032
  }
6993
- return WORKFLOW_POPULATE;
7033
+ return populate;
6994
7034
  };
6995
7035
  const workflows$1 = ({ strapi: strapi2 }) => {
6996
7036
  const workflowsContentTypes = workflowsContentTypesFactory({ strapi: strapi2 });
@@ -7041,14 +7081,27 @@ const workflows$1 = ({ strapi: strapi2 }) => {
7041
7081
  const stages2 = await getService("stages", { strapi: strapi2 }).createMany(opts.data.stages);
7042
7082
  const mapIds = fp.map(fp.get("id"));
7043
7083
  createOpts = fp.set("data.stages", mapIds(stages2), createOpts);
7084
+ if (opts.data.stageRequiredToPublishName) {
7085
+ const stageRequiredToPublish = stages2.find(
7086
+ (stage) => stage.name === opts.data.stageRequiredToPublishName
7087
+ );
7088
+ if (!stageRequiredToPublish) {
7089
+ throw new errors.ApplicationError("Stage required to publish does not exist");
7090
+ }
7091
+ createOpts = fp.set("data.stageRequiredToPublish", stageRequiredToPublish.id, createOpts);
7092
+ }
7044
7093
  if (opts.data.contentTypes) {
7045
7094
  await workflowsContentTypes.migrate({
7046
7095
  destContentTypes: opts.data.contentTypes,
7047
7096
  stageId: stages2[0].id
7048
7097
  });
7049
7098
  }
7050
- metrics.sendDidCreateWorkflow();
7051
- return strapi2.db.query(WORKFLOW_MODEL_UID).create(strapi2.get("query-params").transform(WORKFLOW_MODEL_UID, createOpts));
7099
+ const createdWorkflow = await strapi2.db.query(WORKFLOW_MODEL_UID).create(strapi2.get("query-params").transform(WORKFLOW_MODEL_UID, createOpts));
7100
+ metrics.sendDidCreateWorkflow(createdWorkflow.id, !!opts.data.stageRequiredToPublishName);
7101
+ if (opts.data.stageRequiredToPublishName) {
7102
+ await strapi2.plugin("content-releases").service("release-action").validateActionsByContentTypes(opts.data.contentTypes);
7103
+ }
7104
+ return createdWorkflow;
7052
7105
  });
7053
7106
  },
7054
7107
  /**
@@ -7061,6 +7114,7 @@ const workflows$1 = ({ strapi: strapi2 }) => {
7061
7114
  async update(workflow2, opts) {
7062
7115
  const stageService = getService("stages", { strapi: strapi2 });
7063
7116
  let updateOpts = { ...opts, populate: { ...WORKFLOW_POPULATE } };
7117
+ let updatedStages = [];
7064
7118
  let updatedStageIds;
7065
7119
  await workflowValidator.validateWorkflowCount();
7066
7120
  return strapi2.db.transaction(async () => {
@@ -7069,9 +7123,28 @@ const workflows$1 = ({ strapi: strapi2 }) => {
7069
7123
  opts.data.stages.forEach(
7070
7124
  (stage) => this.assertStageBelongsToWorkflow(stage.id, workflow2)
7071
7125
  );
7072
- updatedStageIds = await stageService.replaceStages(workflow2.stages, opts.data.stages, workflow2.contentTypes).then((stages2) => stages2.map((stage) => stage.id));
7126
+ updatedStages = await stageService.replaceStages(
7127
+ workflow2.stages,
7128
+ opts.data.stages,
7129
+ workflow2.contentTypes
7130
+ );
7131
+ updatedStageIds = updatedStages.map((stage) => stage.id);
7073
7132
  updateOpts = fp.set("data.stages", updatedStageIds, updateOpts);
7074
7133
  }
7134
+ if (opts.data.stageRequiredToPublishName !== void 0) {
7135
+ const stages2 = updatedStages ?? workflow2.stages;
7136
+ if (opts.data.stageRequiredToPublishName === null) {
7137
+ updateOpts = fp.set("data.stageRequiredToPublish", null, updateOpts);
7138
+ } else {
7139
+ const stageRequiredToPublish = stages2.find(
7140
+ (stage) => stage.name === opts.data.stageRequiredToPublishName
7141
+ );
7142
+ if (!stageRequiredToPublish) {
7143
+ throw new errors.ApplicationError("Stage required to publish does not exist");
7144
+ }
7145
+ updateOpts = fp.set("data.stageRequiredToPublish", stageRequiredToPublish.id, updateOpts);
7146
+ }
7147
+ }
7075
7148
  if (opts.data.contentTypes) {
7076
7149
  await workflowsContentTypes.migrate({
7077
7150
  srcContentTypes: workflow2.contentTypes,
@@ -7079,12 +7152,17 @@ const workflows$1 = ({ strapi: strapi2 }) => {
7079
7152
  stageId: updatedStageIds ? updatedStageIds[0] : workflow2.stages[0].id
7080
7153
  });
7081
7154
  }
7082
- metrics.sendDidEditWorkflow();
7155
+ metrics.sendDidEditWorkflow(workflow2.id, !!opts.data.stageRequiredToPublishName);
7083
7156
  const query = strapi2.get("query-params").transform(WORKFLOW_MODEL_UID, updateOpts);
7084
- return strapi2.db.query(WORKFLOW_MODEL_UID).update({
7157
+ const updatedWorkflow = await strapi2.db.query(WORKFLOW_MODEL_UID).update({
7085
7158
  ...query,
7086
7159
  where: { id: workflow2.id }
7087
7160
  });
7161
+ await strapi2.plugin("content-releases").service("release-action").validateActionsByContentTypes([
7162
+ ...workflow2.contentTypes,
7163
+ ...opts.data.contentTypes || []
7164
+ ]);
7165
+ return updatedWorkflow;
7088
7166
  });
7089
7167
  },
7090
7168
  /**
@@ -7107,10 +7185,12 @@ const workflows$1 = ({ strapi: strapi2 }) => {
7107
7185
  destContentTypes: []
7108
7186
  });
7109
7187
  const query = strapi2.get("query-params").transform(WORKFLOW_MODEL_UID, opts);
7110
- return strapi2.db.query(WORKFLOW_MODEL_UID).delete({
7188
+ const deletedWorkflow = await strapi2.db.query(WORKFLOW_MODEL_UID).delete({
7111
7189
  ...query,
7112
7190
  where: { id: workflow2.id }
7113
7191
  });
7192
+ await strapi2.plugin("content-releases").service("release-action").validateActionsByContentTypes(workflow2.contentTypes);
7193
+ return deletedWorkflow;
7114
7194
  });
7115
7195
  },
7116
7196
  /**
@@ -7580,11 +7660,11 @@ const sendDidDeleteStage = async () => {
7580
7660
  const sendDidChangeEntryStage = async () => {
7581
7661
  strapi.telemetry.send("didChangeEntryStage", {});
7582
7662
  };
7583
- const sendDidCreateWorkflow = async () => {
7584
- strapi.telemetry.send("didCreateWorkflow", {});
7663
+ const sendDidCreateWorkflow = async (workflowId, hasRequiredStageToPublish) => {
7664
+ strapi.telemetry.send("didCreateWorkflow", { workflowId, hasRequiredStageToPublish });
7585
7665
  };
7586
- const sendDidEditWorkflow = async () => {
7587
- strapi.telemetry.send("didEditWorkflow", {});
7666
+ const sendDidEditWorkflow = async (workflowId, hasRequiredStageToPublish) => {
7667
+ strapi.telemetry.send("didEditWorkflow", { workflowId, hasRequiredStageToPublish });
7588
7668
  };
7589
7669
  const sendDidEditAssignee = async (fromId, toId) => {
7590
7670
  strapi.telemetry.send("didEditAssignee", { from: fromId, to: toId });
@@ -7837,9 +7917,27 @@ const handleStageOnUpdate = async (ctx, next) => {
7837
7917
  }
7838
7918
  return next();
7839
7919
  };
7920
+ const checkStageBeforePublish = async (ctx, next) => {
7921
+ if (ctx.action !== "publish") {
7922
+ return next();
7923
+ }
7924
+ const workflow2 = await getService("workflows").getAssignedWorkflow(ctx.contentType.uid, {
7925
+ populate: "stageRequiredToPublish"
7926
+ });
7927
+ if (!workflow2 || !workflow2.stageRequiredToPublish) {
7928
+ return next();
7929
+ }
7930
+ const { documentId } = ctx.params;
7931
+ const entryStage = await getEntityStage(ctx.contentType.uid, documentId, ctx.params);
7932
+ if (entryStage.id !== workflow2.stageRequiredToPublish.id) {
7933
+ throw new errors.ValidationError("Entry is not at the required stage to publish");
7934
+ }
7935
+ return next();
7936
+ };
7840
7937
  const documentServiceMiddleware = () => ({
7841
7938
  assignStageOnCreate,
7842
- handleStageOnUpdate
7939
+ handleStageOnUpdate,
7940
+ checkStageBeforePublish
7843
7941
  });
7844
7942
  const services = {
7845
7943
  workflows: workflows$1,
@@ -7889,12 +7987,14 @@ const validateContentTypes = yup.array().of(
7889
7987
  const validateWorkflowCreateSchema = yup.object().shape({
7890
7988
  name: yup.string().max(255).min(1, "Workflow name can not be empty").required(),
7891
7989
  stages: yup.array().of(stageObject).uniqueProperty("name", "Stage name must be unique").min(1, "Can not create a workflow without stages").max(200, "Can not have more than 200 stages").required("Can not create a workflow without stages"),
7892
- contentTypes: validateContentTypes
7990
+ contentTypes: validateContentTypes,
7991
+ stageRequiredToPublishName: yup.string().min(1).nullable()
7893
7992
  });
7894
7993
  const validateWorkflowUpdateSchema = yup.object().shape({
7895
7994
  name: yup.string().max(255).min(1, "Workflow name can not be empty"),
7896
7995
  stages: yup.array().of(stageObject).uniqueProperty("name", "Stage name must be unique").min(1, "Can not update a workflow without stages").max(200, "Can not have more than 200 stages"),
7897
- contentTypes: validateContentTypes
7996
+ contentTypes: validateContentTypes,
7997
+ stageRequiredToPublishName: yup.string().min(1).nullable()
7898
7998
  });
7899
7999
  const validateUpdateAssigneeOnEntitySchema = yup.object().shape({
7900
8000
  id: yup.number().integer().min(1).nullable()