@strapi/admin 4.9.0-exp.90df253ba90fd6879eb56a720a1f80d04ff745b8 → 4.10.0-beta.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 (167) hide show
  1. package/admin/src/content-manager/components/DynamicTable/CellContent/PublicationState/PublicationState.js +26 -0
  2. package/admin/src/content-manager/components/DynamicTable/CellContent/PublicationState/index.js +1 -0
  3. package/admin/src/content-manager/components/DynamicTable/CellContent/ReviewWorkflowsStage/ReviewWorkflowsStage.js +15 -0
  4. package/admin/src/content-manager/components/DynamicTable/CellContent/ReviewWorkflowsStage/index.js +1 -0
  5. package/admin/src/content-manager/components/DynamicTable/index.js +43 -49
  6. package/admin/src/content-manager/components/DynamicZone/components/DynamicComponent.js +2 -0
  7. package/admin/src/content-manager/components/DynamicZone/utils/select.js +1 -1
  8. package/admin/src/content-manager/components/FieldComponent/utils/select.js +2 -1
  9. package/admin/src/content-manager/components/Inputs/utils/getInputType.js +1 -1
  10. package/admin/src/content-manager/components/Inputs/utils/select.js +1 -1
  11. package/admin/src/content-manager/hooks/useContentTypeLayout/index.js +1 -2
  12. package/admin/src/content-manager/hooks/useFetchContentTypeLayout/utils/formatLayouts.js +4 -1
  13. package/admin/src/content-manager/pages/CollectionTypeRecursivePath/index.js +1 -2
  14. package/admin/src/content-manager/pages/EditSettingsView/init.js +3 -1
  15. package/admin/src/content-manager/pages/EditSettingsView/utils/createPossibleMainFieldsForModelsAndComponents.js +2 -4
  16. package/admin/src/content-manager/pages/EditView/DeleteLink/utils/select.js +1 -1
  17. package/admin/src/content-manager/pages/EditView/Information/index.js +77 -53
  18. package/admin/src/content-manager/pages/EditView/InformationBox/InformationBoxCE.js +13 -0
  19. package/admin/src/content-manager/pages/EditView/InformationBox/index.js +3 -0
  20. package/admin/src/content-manager/pages/EditView/index.js +3 -4
  21. package/admin/src/content-manager/pages/EditView/utils/createAttributesLayout.js +2 -1
  22. package/admin/src/content-manager/pages/EditView/utils/getFieldsActionMatchingPermissions.js +2 -1
  23. package/admin/src/content-manager/pages/ListView/index.js +6 -9
  24. package/admin/src/content-manager/utils/checkIfAttributeIsDisplayable.js +1 -1
  25. package/admin/src/content-manager/utils/createDefaultForm.js +2 -2
  26. package/admin/src/content-manager/utils/formatLayoutToApi.js +2 -1
  27. package/admin/src/content-manager/utils/getFieldName.js +1 -1
  28. package/admin/src/content-manager/utils/mergeMetasWithSchema.js +1 -1
  29. package/admin/src/content-manager/utils/paths.js +1 -1
  30. package/admin/src/content-manager/utils/removePasswordFieldsFromData.js +1 -1
  31. package/admin/src/hooks/useRegenerate/index.js +1 -1
  32. package/admin/src/hooks/useSettingsForm/index.js +3 -3
  33. package/admin/src/hooks/useSettingsForm/reducer.js +3 -1
  34. package/admin/src/hooks/useSettingsMenu/reducer.js +1 -1
  35. package/admin/src/index.js +1 -0
  36. package/admin/src/pages/AuthPage/reducer.js +1 -1
  37. package/admin/src/pages/SettingsPage/components/Tokens/TokenTypeSelect/index.js +5 -7
  38. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/CollapsableContentType/index.js +1 -1
  39. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/reducer.js +1 -1
  40. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/utils/transformPermissionsData.js +6 -8
  41. package/admin/src/pages/SettingsPage/pages/Roles/EditPage/components/ConditionsModal/utils/createDefaultConditionsForm.js +1 -1
  42. package/admin/src/pages/SettingsPage/pages/Roles/EditPage/components/ContentTypeCollapse/Collapse/utils/generateCheckboxesActions.js +2 -1
  43. package/admin/src/pages/SettingsPage/pages/Roles/EditPage/components/ContentTypeCollapse/CollapsePropertyMatrix/ActionRow/utils/getRowLabelCheckboxeState.js +2 -1
  44. package/admin/src/pages/SettingsPage/pages/Roles/EditPage/components/GlobalActions/utils/getRowLabelCheckboxesState.js +1 -1
  45. package/admin/src/pages/SettingsPage/pages/Roles/EditPage/components/Permissions/reducer.js +6 -1
  46. package/admin/src/pages/SettingsPage/pages/Roles/EditPage/components/Permissions/utils/createDefaultCTFormFromLayout.js +5 -1
  47. package/admin/src/pages/SettingsPage/pages/Roles/EditPage/components/Permissions/utils/createDefaultPluginsFormFromLayout.js +1 -2
  48. package/admin/src/pages/SettingsPage/pages/Roles/EditPage/components/Permissions/utils/formatContentTypesPermissionToAPI.js +2 -2
  49. package/admin/src/pages/SettingsPage/pages/Roles/EditPage/components/Permissions/utils/updateConditionsToFalse.js +4 -1
  50. package/admin/src/pages/SettingsPage/pages/Roles/EditPage/components/Permissions/utils/updateValues.js +1 -1
  51. package/admin/src/pages/SettingsPage/pages/Roles/EditPage/components/PluginsAndSettings/SubCategory/utils/formatActions.js +1 -1
  52. package/admin/src/pages/SettingsPage/pages/Roles/EditPage/components/utils/createArrayOfValues.js +2 -1
  53. package/admin/src/pages/SettingsPage/pages/Roles/ListPage/index.js +1 -1
  54. package/admin/src/pages/SettingsPage/pages/TransferTokens/EditView/components/FormTransferTokenContainer/index.js +0 -41
  55. package/admin/src/pages/SettingsPage/pages/TransferTokens/EditView/index.js +4 -6
  56. package/admin/src/pages/SettingsPage/pages/TransferTokens/EditView/utils/schema.js +0 -1
  57. package/admin/src/pages/SettingsPage/pages/Users/ProtectedEditPage/index.js +2 -2
  58. package/admin/src/pages/SettingsPage/pages/Webhooks/EditView/utils/formatData.js +1 -7
  59. package/admin/src/permissions/index.js +1 -1
  60. package/admin/src/translations/en.json +6 -0
  61. package/admin/src/utils/getAttributesToDisplay.js +2 -4
  62. package/admin/src/utils/getExistingActions.js +1 -3
  63. package/admin/src/utils/sortLinks.js +1 -1
  64. package/build/{8580.b0dcf37c.chunk.js → 2263.4c5916f9.chunk.js} +61 -61
  65. package/build/4649.213b8a3b.chunk.js +30 -0
  66. package/build/6985.66cca29c.chunk.js +1 -0
  67. package/build/7259.aefb51e8.chunk.js +1 -0
  68. package/build/{7112.2bf13da3.chunk.js → 9505.dbe702ab.chunk.js} +6 -6
  69. package/build/{Admin-authenticatedApp.5aa08bf5.chunk.js → Admin-authenticatedApp.f50ad423.chunk.js} +3 -3
  70. package/build/{Admin_marketplace.0f6c8ee2.chunk.js → Admin_marketplace.02608d56.chunk.js} +1 -1
  71. package/build/{Admin_profilePage.d2a8f9ab.chunk.js → Admin_profilePage.76afeca0.chunk.js} +1 -1
  72. package/build/Admin_settingsPage.147755cd.chunk.js +9 -0
  73. package/build/admin-app.55dd7921.chunk.js +112 -0
  74. package/build/admin-edit-roles-page.cf543488.chunk.js +216 -0
  75. package/build/admin-edit-users.31c20712.chunk.js +10 -0
  76. package/build/admin-roles-list.489c501f.chunk.js +2 -0
  77. package/build/{admin-users.af8c3123.chunk.js → admin-users.3e111a7d.chunk.js} +1 -1
  78. package/build/{api-tokens-create-page.2a6e22bd.chunk.js → api-tokens-create-page.4328b852.chunk.js} +1 -1
  79. package/build/{api-tokens-edit-page.fa38cd63.chunk.js → api-tokens-edit-page.bce5050f.chunk.js} +1 -1
  80. package/build/content-manager.4480ae88.chunk.js +1137 -0
  81. package/build/content-type-builder-translation-en-json.7961593e.chunk.js +1 -0
  82. package/build/content-type-builder.af9abf1e.chunk.js +126 -0
  83. package/build/en-json.697b4bcf.chunk.js +1 -0
  84. package/build/index.html +1 -1
  85. package/build/main.af8c0f31.js +3790 -0
  86. package/build/review-workflows-settings.7a7dc773.chunk.js +57 -0
  87. package/build/runtime~main.5a95bee6.js +2 -0
  88. package/build/sso-settings-page.272b87c8.chunk.js +1 -0
  89. package/build/{upload-settings.0200561d.chunk.js → upload-settings.0875e973.chunk.js} +1 -1
  90. package/build/upload-translation-fr-json.baab9911.chunk.js +1 -0
  91. package/build/users-advanced-settings-page.1d3c14c7.chunk.js +1 -0
  92. package/build/{users-email-settings-page.a3c80419.chunk.js → users-email-settings-page.e8db68c4.chunk.js} +1 -1
  93. package/build/users-providers-settings-page.14cac425.chunk.js +1 -0
  94. package/build/users-roles-settings-page.2ea4de84.chunk.js +30 -0
  95. package/build/{webhook-edit-page.a2a2b7bb.chunk.js → webhook-edit-page.329141a5.chunk.js} +3 -3
  96. package/ee/admin/content-manager/pages/EditView/InformationBox/InformationBoxEE.js +92 -0
  97. package/ee/admin/content-manager/pages/EditView/InformationBox/index.js +3 -0
  98. package/ee/admin/hooks/useSettingsMenu/utils/customAdminLinks.js +12 -12
  99. package/ee/admin/hooks/useSettingsMenu/utils/customGlobalLinks.js +21 -13
  100. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/ReviewWorkflows.js +195 -0
  101. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/actions/index.js +42 -0
  102. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/components/AddStage/AddStage.js +87 -0
  103. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/components/AddStage/index.js +1 -0
  104. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/components/Stages/Stage/Stage.js +90 -0
  105. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/components/Stages/Stage/index.js +1 -0
  106. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/components/Stages/Stages.js +92 -0
  107. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/components/Stages/index.js +1 -0
  108. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/constants.js +6 -0
  109. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/hooks/useReviewWorkflows.js +35 -0
  110. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/index.js +3 -0
  111. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/reducer/index.js +121 -0
  112. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/utils/getWorkflowValidationSchema.js +25 -0
  113. package/ee/admin/pages/SettingsPage/utils/customRoutes.js +16 -2
  114. package/ee/admin/permissions/customPermissions.js +3 -0
  115. package/ee/server/bootstrap.js +16 -0
  116. package/ee/server/config/admin-actions.js +10 -0
  117. package/ee/server/constants/default-stages.json +14 -0
  118. package/ee/server/constants/default-workflow.json +1 -0
  119. package/ee/server/constants/workflows.js +8 -0
  120. package/ee/server/content-types/index.js +9 -0
  121. package/ee/server/content-types/workflow/index.js +34 -0
  122. package/ee/server/content-types/workflow-stage/index.js +41 -0
  123. package/ee/server/controllers/index.js +2 -0
  124. package/ee/server/controllers/workflows/index.js +36 -0
  125. package/ee/server/controllers/workflows/stages/index.js +95 -0
  126. package/ee/server/index.js +1 -0
  127. package/ee/server/middlewares/review-workflows.js +40 -0
  128. package/ee/server/migrations/review-workflows.js +39 -0
  129. package/ee/server/register.js +7 -0
  130. package/ee/server/routes/index.js +104 -0
  131. package/ee/server/services/index.js +4 -0
  132. package/ee/server/services/review-workflows/entity-service-decorator.js +42 -0
  133. package/ee/server/services/review-workflows/review-workflows.js +175 -0
  134. package/ee/server/services/review-workflows/stages.js +148 -0
  135. package/ee/server/services/review-workflows/workflows.js +25 -0
  136. package/ee/server/utils/index.js +8 -0
  137. package/ee/server/utils/persisted-tables.js +49 -0
  138. package/ee/server/utils/review-workflows.js +25 -0
  139. package/ee/server/utils/test.js +11 -0
  140. package/ee/server/validation/review-workflows.js +24 -0
  141. package/package.json +13 -13
  142. package/server/controllers/transfer/runner.js +2 -4
  143. package/server/routes/transfer.js +4 -13
  144. package/server/services/constants.js +0 -4
  145. package/server/services/permission/permissions-manager/sanitize.js +2 -0
  146. package/server/services/transfer/permission.js +1 -1
  147. package/server/services/transfer/token.js +31 -33
  148. package/server/validation/transfer/token.js +2 -10
  149. package/build/2637.679b590b.chunk.js +0 -1
  150. package/build/5563.451e91ee.chunk.js +0 -30
  151. package/build/7259.7744297b.chunk.js +0 -1
  152. package/build/Admin_settingsPage.489ec4eb.chunk.js +0 -9
  153. package/build/admin-app.4b313104.chunk.js +0 -112
  154. package/build/admin-edit-roles-page.3b196317.chunk.js +0 -216
  155. package/build/admin-edit-users.af3b0f15.chunk.js +0 -10
  156. package/build/admin-roles-list.0ad504a7.chunk.js +0 -2
  157. package/build/content-manager.f530e141.chunk.js +0 -1139
  158. package/build/content-type-builder-translation-en-json.e577d595.chunk.js +0 -1
  159. package/build/content-type-builder.6ecd201d.chunk.js +0 -126
  160. package/build/en-json.01a88a30.chunk.js +0 -1
  161. package/build/main.43b93ff3.js +0 -3843
  162. package/build/runtime~main.a40b1b57.js +0 -2
  163. package/build/sso-settings-page.5a8588ef.chunk.js +0 -1
  164. package/build/upload-translation-fr-json.84429734.chunk.js +0 -1
  165. package/build/users-advanced-settings-page.c0cae03a.chunk.js +0 -1
  166. package/build/users-providers-settings-page.5f86e45c.chunk.js +0 -1
  167. package/build/users-roles-settings-page.b02986df.chunk.js +0 -30
@@ -0,0 +1,121 @@
1
+ import { current, produce } from 'immer';
2
+ import isEqual from 'lodash/isEqual';
3
+
4
+ import {
5
+ ACTION_SET_WORKFLOWS,
6
+ ACTION_DELETE_STAGE,
7
+ ACTION_ADD_STAGE,
8
+ ACTION_UPDATE_STAGE,
9
+ } from '../constants';
10
+
11
+ export const initialState = {
12
+ status: 'loading',
13
+ serverState: {
14
+ currentWorkflow: null,
15
+ workflows: [],
16
+ },
17
+ clientState: {
18
+ currentWorkflow: { data: null, isDirty: false, hasDeletedServerStages: false },
19
+ },
20
+ };
21
+
22
+ export function reducer(state = initialState, action) {
23
+ return produce(state, (draft) => {
24
+ const { payload } = action;
25
+
26
+ switch (action.type) {
27
+ case ACTION_SET_WORKFLOWS: {
28
+ const { status, workflows } = payload;
29
+
30
+ draft.status = status;
31
+
32
+ if (workflows) {
33
+ const defaultWorkflow = workflows[0];
34
+
35
+ draft.serverState.workflows = workflows;
36
+ draft.serverState.currentWorkflow = defaultWorkflow;
37
+ draft.clientState.currentWorkflow.data = defaultWorkflow;
38
+ }
39
+ break;
40
+ }
41
+
42
+ case ACTION_DELETE_STAGE: {
43
+ const { stageId } = payload;
44
+ const { currentWorkflow } = state.clientState;
45
+
46
+ draft.clientState.currentWorkflow.data.stages = currentWorkflow.data.stages.filter(
47
+ (stage) => (stage?.id ?? stage.__temp_key__) !== stageId
48
+ );
49
+
50
+ if (!currentWorkflow.hasDeletedServerStages) {
51
+ draft.clientState.currentWorkflow.hasDeletedServerStages =
52
+ !!state.serverState.currentWorkflow.stages.find((stage) => stage.id === stageId);
53
+ }
54
+
55
+ break;
56
+ }
57
+
58
+ case ACTION_ADD_STAGE: {
59
+ const { currentWorkflow } = state.clientState;
60
+
61
+ if (!currentWorkflow.data) {
62
+ draft.clientState.currentWorkflow.data = {
63
+ stages: [],
64
+ };
65
+ }
66
+
67
+ const newTempKey = getMaxTempKey(draft.clientState.currentWorkflow.data.stages);
68
+
69
+ draft.clientState.currentWorkflow.data.stages.push({
70
+ ...payload,
71
+ __temp_key__: newTempKey,
72
+ });
73
+
74
+ break;
75
+ }
76
+
77
+ case ACTION_UPDATE_STAGE: {
78
+ const { currentWorkflow } = state.clientState;
79
+ const { stageId, ...modified } = payload;
80
+
81
+ draft.clientState.currentWorkflow.data.stages = currentWorkflow.data.stages.map((stage) =>
82
+ (stage.id ?? stage.__temp_key__) === stageId
83
+ ? {
84
+ ...stage,
85
+ ...modified,
86
+ }
87
+ : stage
88
+ );
89
+
90
+ break;
91
+ }
92
+
93
+ default:
94
+ break;
95
+ }
96
+
97
+ if (state.clientState.currentWorkflow.data) {
98
+ draft.clientState.currentWorkflow.isDirty = !isEqual(
99
+ current(draft.clientState.currentWorkflow).data,
100
+ state.serverState.currentWorkflow
101
+ );
102
+ }
103
+ });
104
+ }
105
+
106
+ /**
107
+ * @type {(stages: Array<{id?: number; __temp_key__: number}>) => number}
108
+ */
109
+ const getMaxTempKey = (stages = []) => {
110
+ /**
111
+ * We check if there are ids or __temp_key__ because you may add a stage to a list of stages
112
+ * already in the DB, alternatively you might add multiple new stages at once.
113
+ */
114
+ const ids = stages.map((stage) => stage.id ?? stage.__temp_key__);
115
+
116
+ /**
117
+ * If there are no ids it will return 0 as the max value
118
+ * because the max value is -1.
119
+ */
120
+ return Math.max(...ids, -1) + 1;
121
+ };
@@ -0,0 +1,25 @@
1
+ import * as yup from 'yup';
2
+
3
+ export function getWorkflowValidationSchema({ formatMessage }) {
4
+ return yup.object({
5
+ stages: yup.array().of(
6
+ yup.object().shape({
7
+ name: yup
8
+ .string()
9
+ .required(
10
+ formatMessage({
11
+ id: 'Settings.review-workflows.validation.stage.name',
12
+ defaultMessage: 'Name is required',
13
+ })
14
+ )
15
+ .max(
16
+ 255,
17
+ formatMessage({
18
+ id: 'Settings.review-workflows.validation.stage.max-length',
19
+ defaultMessage: 'Name can not be longer than 255 characters',
20
+ })
21
+ ),
22
+ })
23
+ ),
24
+ });
25
+ }
@@ -1,6 +1,6 @@
1
1
  const routes = [];
2
2
 
3
- if (strapi.features.isEnabled(strapi.features.SSO)) {
3
+ if (window.strapi.features.isEnabled(window.strapi.features.SSO)) {
4
4
  routes.push({
5
5
  async Component() {
6
6
  const component = await import(
@@ -14,7 +14,21 @@ if (strapi.features.isEnabled(strapi.features.SSO)) {
14
14
  });
15
15
  }
16
16
 
17
- if (strapi.features.isEnabled(strapi.features.AUDIT_LOGS)) {
17
+ if (window.strapi.features.isEnabled(window.strapi.features.REVIEW_WORKFLOWS)) {
18
+ routes.push({
19
+ async Component() {
20
+ const component = await import(
21
+ /* webpackChunkName: "review-workflows-settings" */ '../pages/ReviewWorkflows'
22
+ );
23
+
24
+ return component;
25
+ },
26
+ to: '/settings/review-workflows',
27
+ exact: true,
28
+ });
29
+ }
30
+
31
+ if (window.strapi.features.isEnabled(window.strapi.features.AUDIT_LOGS)) {
18
32
  routes.push({
19
33
  async Component() {
20
34
  const component = await import(
@@ -4,6 +4,9 @@ const customPermissions = {
4
4
  main: [{ action: 'admin::audit-logs.read', subject: null }],
5
5
  read: [{ action: 'admin::audit-logs.read', subject: null }],
6
6
  },
7
+ 'review-workflows': {
8
+ main: [{ action: 'admin::review-workflows.read', subject: null }],
9
+ },
7
10
  sso: {
8
11
  main: [{ action: 'admin::provider-login.read', subject: null }],
9
12
  read: [{ action: 'admin::provider-login.read', subject: null }],
@@ -5,6 +5,7 @@ const { features } = require('@strapi/strapi/lib/utils/ee');
5
5
  const executeCEBootstrap = require('../../server/bootstrap');
6
6
  const { getService } = require('../../server/utils');
7
7
  const actions = require('./config/admin-actions');
8
+ const { persistTablesWithPrefix } = require('./utils/persisted-tables');
8
9
 
9
10
  module.exports = async () => {
10
11
  const { actionProvider } = getService('permission');
@@ -14,9 +15,24 @@ module.exports = async () => {
14
15
  }
15
16
 
16
17
  if (features.isEnabled('audit-logs')) {
18
+ await persistTablesWithPrefix('strapi_audit_logs');
19
+
17
20
  await actionProvider.registerMany(actions.auditLogs);
18
21
  }
19
22
 
23
+ if (features.isEnabled('review-workflows')) {
24
+ await persistTablesWithPrefix('strapi_workflows');
25
+
26
+ const { bootstrap: rwBootstrap } = getService('review-workflows');
27
+
28
+ await rwBootstrap();
29
+ await actionProvider.registerMany(actions.reviewWorkflows);
30
+
31
+ // Decorate the entity service with review workflow logic
32
+ const { decorator } = getService('review-workflows-decorator');
33
+ strapi.entityService.decorate(decorator);
34
+ }
35
+
20
36
  await getService('seat-enforcement').seatEnforcementWorkflow();
21
37
 
22
38
  await executeCEBootstrap();
@@ -29,4 +29,14 @@ module.exports = {
29
29
  subCategory: 'options',
30
30
  },
31
31
  ],
32
+ reviewWorkflows: [
33
+ {
34
+ uid: 'review-workflows.read',
35
+ displayName: 'Read',
36
+ pluginName: 'admin',
37
+ section: 'settings',
38
+ category: 'review workflows',
39
+ subCategory: 'options',
40
+ },
41
+ ],
32
42
  };
@@ -0,0 +1,14 @@
1
+ [
2
+ {
3
+ "name": "To do"
4
+ },
5
+ {
6
+ "name": "Ready to review"
7
+ },
8
+ {
9
+ "name": "In progress"
10
+ },
11
+ {
12
+ "name": "Reviewed"
13
+ }
14
+ ]
@@ -0,0 +1,8 @@
1
+ 'use strict';
2
+
3
+ // TODO concatenate admin + content type singular name
4
+ module.exports = {
5
+ WORKFLOW_MODEL_UID: 'admin::workflow',
6
+ STAGE_MODEL_UID: 'admin::workflow-stage',
7
+ ENTITY_STAGE_ATTRIBUTE: 'strapi_reviewWorkflows_stage',
8
+ };
@@ -0,0 +1,9 @@
1
+ 'use strict';
2
+
3
+ const workflow = require('./workflow');
4
+ const workflowStage = require('./workflow-stage');
5
+
6
+ module.exports = {
7
+ workflow,
8
+ 'workflow-stage': workflowStage,
9
+ };
@@ -0,0 +1,34 @@
1
+ 'use strict';
2
+
3
+ module.exports = {
4
+ schema: {
5
+ collectionName: 'strapi_workflows',
6
+ info: {
7
+ name: 'Workflow',
8
+ description: '',
9
+ singularName: 'workflow',
10
+ pluralName: 'workflows',
11
+ displayName: 'Workflow',
12
+ },
13
+ options: {},
14
+ pluginOptions: {
15
+ 'content-manager': {
16
+ visible: false,
17
+ },
18
+ 'content-type-builder': {
19
+ visible: false,
20
+ },
21
+ },
22
+ attributes: {
23
+ uid: {
24
+ type: 'string',
25
+ },
26
+ stages: {
27
+ type: 'relation',
28
+ target: 'admin::workflow-stage',
29
+ relation: 'oneToMany',
30
+ mappedBy: 'workflow',
31
+ },
32
+ },
33
+ },
34
+ };
@@ -0,0 +1,41 @@
1
+ 'use strict';
2
+
3
+ module.exports = {
4
+ schema: {
5
+ collectionName: 'strapi_workflows_stages',
6
+ info: {
7
+ name: 'Workflow Stage',
8
+ description: '',
9
+ singularName: 'workflow-stage',
10
+ pluralName: 'workflow-stages',
11
+ displayName: 'Stages',
12
+ },
13
+ options: {},
14
+ pluginOptions: {
15
+ 'content-manager': {
16
+ visible: false,
17
+ },
18
+ 'content-type-builder': {
19
+ visible: false,
20
+ },
21
+ },
22
+ attributes: {
23
+ name: {
24
+ type: 'string',
25
+ configurable: false,
26
+ },
27
+ workflow: {
28
+ type: 'relation',
29
+ target: 'admin::workflow',
30
+ relation: 'manyToOne',
31
+ inversedBy: 'stages',
32
+ configurable: false,
33
+ },
34
+ related: {
35
+ type: 'relation',
36
+ relation: 'morphToMany',
37
+ configurable: false,
38
+ },
39
+ },
40
+ },
41
+ };
@@ -6,4 +6,6 @@ module.exports = {
6
6
  user: require('./user'),
7
7
  auditLogs: require('./audit-logs'),
8
8
  admin: require('./admin'),
9
+ workflows: require('./workflows'),
10
+ stages: require('./workflows/stages'),
9
11
  };
@@ -0,0 +1,36 @@
1
+ 'use strict';
2
+
3
+ const { getService } = require('../../utils');
4
+
5
+ module.exports = {
6
+ /**
7
+ * List all workflows
8
+ * @param {import('koa').BaseContext} ctx - koa context
9
+ */
10
+ async find(ctx) {
11
+ const { populate } = ctx.query;
12
+ const workflowService = getService('workflows');
13
+ const data = await workflowService.find({
14
+ populate,
15
+ });
16
+
17
+ ctx.body = {
18
+ data,
19
+ };
20
+ },
21
+ /**
22
+ * Get one workflow based on its id contained in request parameters
23
+ * @param {import('koa').BaseContext} ctx - koa context
24
+ */
25
+ async findById(ctx) {
26
+ const { id } = ctx.params;
27
+ const { populate } = ctx.query;
28
+
29
+ const workflowService = getService('workflows');
30
+ const data = await workflowService.findById(id, { populate });
31
+
32
+ ctx.body = {
33
+ data,
34
+ };
35
+ },
36
+ };
@@ -0,0 +1,95 @@
1
+ 'use strict';
2
+
3
+ const { ApplicationError } = require('@strapi/utils/lib/errors');
4
+ const { getService } = require('../../../utils');
5
+ const { hasReviewWorkflow } = require('../../../utils/review-workflows');
6
+ const {
7
+ validateUpdateStages,
8
+ validateUpdateStageOnEntity,
9
+ } = require('../../../validation/review-workflows');
10
+
11
+ module.exports = {
12
+ /**
13
+ * List all stages
14
+ * @param {import('koa').BaseContext} ctx - koa context
15
+ */
16
+ async find(ctx) {
17
+ const { workflow_id: workflowId } = ctx.params;
18
+ const { populate } = ctx.query;
19
+ const stagesService = getService('stages');
20
+
21
+ const data = await stagesService.find({
22
+ workflowId,
23
+ populate,
24
+ });
25
+
26
+ ctx.body = {
27
+ data,
28
+ };
29
+ },
30
+ /**
31
+ * Get one stage
32
+ * @param {import('koa').BaseContext} ctx - koa context
33
+ */
34
+ async findById(ctx) {
35
+ const { id, workflow_id: workflowId } = ctx.params;
36
+ const { populate } = ctx.query;
37
+ const stagesService = getService('stages');
38
+
39
+ const data = await stagesService.findById(id, {
40
+ workflowId,
41
+ populate,
42
+ });
43
+
44
+ ctx.body = {
45
+ data,
46
+ };
47
+ },
48
+
49
+ async replace(ctx) {
50
+ const { workflow_id: workflowId } = ctx.params;
51
+ const stagesService = getService('stages');
52
+ const {
53
+ body: { data: stages },
54
+ } = ctx.request;
55
+
56
+ const stagesValidated = await validateUpdateStages(stages);
57
+
58
+ const data = await stagesService.replaceWorkflowStages(workflowId, stagesValidated);
59
+
60
+ ctx.body = { data };
61
+ },
62
+
63
+ /**
64
+ * Updates an entity's stage.
65
+ * @async
66
+ * @param {Object} ctx - The Koa context object.
67
+ * @param {Object} ctx.params - An object containing the parameters from the request URL.
68
+ * @param {string} ctx.params.model_uid - The model UID of the entity.
69
+ * @param {string} ctx.params.id - The ID of the entity to update.
70
+ * @param {Object} ctx.request.body.data - Optional data object containing the new stage ID for the entity.
71
+ * @param {string} ctx.request.body.data.id - The ID of the new stage for the entity.
72
+ * @throws {ApplicationError} If review workflows is not activated on the specified model UID.
73
+ * @throws {ValidationError} If the `data` object in the request body fails to pass validation.
74
+ * @returns {Promise<void>} A promise that resolves when the entity's stage has been updated.
75
+ */
76
+ async updateEntity(ctx) {
77
+ const stagesService = getService('stages');
78
+ const { model_uid: modelUID, id: entityIdString } = ctx.params;
79
+ const entityId = Number(entityIdString);
80
+
81
+ const { id: stageId } = await validateUpdateStageOnEntity(
82
+ ctx.request?.body?.data,
83
+ 'You should pass an id to the body of the put request.'
84
+ );
85
+
86
+ if (!hasReviewWorkflow({ strapi }, modelUID)) {
87
+ throw new ApplicationError(`Review workflows is not activated on ${modelUID}.`);
88
+ }
89
+
90
+ // TODO When multiple workflows are possible, check if the stage is part of the right one
91
+ // Didn't need this today as their can only be one workflow
92
+
93
+ ctx.body = await stagesService.updateEntity({ id: entityId, modelUID }, stageId);
94
+ },
95
+ };
@@ -2,6 +2,7 @@
2
2
 
3
3
  module.exports = {
4
4
  register: require('./register'),
5
+ contentTypes: require('./content-types'),
5
6
  bootstrap: require('./bootstrap'),
6
7
  destroy: require('./destroy'),
7
8
  routes: require('./routes'),
@@ -0,0 +1,40 @@
1
+ 'use strict';
2
+
3
+ const { set } = require('lodash/fp');
4
+
5
+ module.exports = {
6
+ contentTypeMiddleware,
7
+ };
8
+
9
+ /**
10
+ * A Strapi middleware function that adds support for review workflows.
11
+ *
12
+ * Why is it needed ?
13
+ * For now, the admin panel cannot have anything but top-level attributes in the content-type for options.
14
+ * But we need the CE part to be agnostics from Review Workflow (which is an EE feature).
15
+ * CE handle the `options` object, that's why we move the reviewWorkflows boolean to the options object.
16
+ *
17
+ * @param {object} strapi - The Strapi instance.
18
+ */
19
+ function contentTypeMiddleware(strapi) {
20
+ /**
21
+ * A middleware function that moves the `reviewWorkflows` attribute from the top level of
22
+ * the request body to the `options` object within the request body.
23
+ *
24
+ * @param {object} ctx - The Koa context object.
25
+ */
26
+ const moveReviewWorkflowOption = (ctx) => {
27
+ // Move reviewWorkflows to options.reviewWorkflows
28
+ const { reviewWorkflows, ...contentType } = ctx.request.body.contentType;
29
+
30
+ if (typeof reviewWorkflows === 'boolean') {
31
+ ctx.request.body.contentType = set('options.reviewWorkflows', reviewWorkflows, contentType);
32
+ }
33
+ };
34
+ strapi.server.router.use('/content-type-builder/content-types/:uid?', (ctx, next) => {
35
+ if (ctx.method === 'PUT' || ctx.method === 'POST') {
36
+ moveReviewWorkflowOption(ctx);
37
+ }
38
+ return next();
39
+ });
40
+ }
@@ -0,0 +1,39 @@
1
+ 'use strict';
2
+
3
+ const { hasReviewWorkflow } = require('../utils/review-workflows');
4
+
5
+ /**
6
+ * Remove all stage information for all content types that have had review workflows disabled
7
+ */
8
+ /* eslint-disable no-continue */
9
+ const disableOnContentTypes = async ({ oldContentTypes, contentTypes }) => {
10
+ const uidsToRemove = [];
11
+ for (const uid in contentTypes) {
12
+ if (!oldContentTypes || !oldContentTypes[uid]) {
13
+ continue;
14
+ }
15
+
16
+ const oldContentType = oldContentTypes[uid];
17
+ const contentType = contentTypes?.[uid];
18
+
19
+ if (
20
+ hasReviewWorkflow({ strapi }, oldContentType) &&
21
+ !hasReviewWorkflow({ strapi }, contentType)
22
+ ) {
23
+ // If review workflows has been turned off on a content type
24
+ // remove stage information from all entities within this CT
25
+ uidsToRemove.push(uid);
26
+ }
27
+ }
28
+
29
+ if (uidsToRemove.length === 0) {
30
+ return;
31
+ }
32
+
33
+ await strapi.db
34
+ .connection('strapi_workflows_stages_related_morphs')
35
+ .whereIn('related_type', uidsToRemove)
36
+ .del();
37
+ };
38
+
39
+ module.exports = { disableOnContentTypes };
@@ -4,6 +4,8 @@ const { features } = require('@strapi/strapi/lib/utils/ee');
4
4
  const executeCERegister = require('../../server/register');
5
5
  const migrateAuditLogsTable = require('./migrations/audit-logs-table');
6
6
  const createAuditLogsService = require('./services/audit-logs');
7
+ const reviewWorkflowsMiddlewares = require('./middlewares/review-workflows');
8
+ const { getService } = require('./utils');
7
9
 
8
10
  module.exports = async ({ strapi }) => {
9
11
  if (features.isEnabled('audit-logs')) {
@@ -12,6 +14,11 @@ module.exports = async ({ strapi }) => {
12
14
  strapi.container.register('audit-logs', auditLogsService);
13
15
  await auditLogsService.register();
14
16
  }
17
+ if (features.isEnabled('review-workflows')) {
18
+ const reviewWorkflowService = getService('review-workflows');
15
19
 
20
+ reviewWorkflowsMiddlewares.contentTypeMiddleware(strapi);
21
+ await reviewWorkflowService.register();
22
+ }
16
23
  await executeCERegister({ strapi });
17
24
  };