mirror of
				https://github.com/strapi/strapi.git
				synced 2025-11-03 19:36:20 +00:00 
			
		
		
		
	fix(ee): logic for finding an entities target stage
This commit is contained in:
		
							parent
							
								
									f5279be28c
								
							
						
					
					
						commit
						d8da5b5214
					
				@ -156,7 +156,7 @@ describe('Review workflows - Stages service', () => {
 | 
				
			|||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    test('Should move entities in a deleted stage to the previous stage', async () => {
 | 
					    test('Should move entities in a deleted stage to the previous stage', async () => {
 | 
				
			||||||
      await stagesService.replaceWorkflowStages(1, workflowMock.stages.slice(0, 1));
 | 
					      await stagesService.replaceWorkflowStages(1, workflowMock.stages.slice(0, 2));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      expect(servicesMock['admin::workflows'].findById).toBeCalled();
 | 
					      expect(servicesMock['admin::workflows'].findById).toBeCalled();
 | 
				
			||||||
      expect(entityServiceMock.create).not.toBeCalled();
 | 
					      expect(entityServiceMock.create).not.toBeCalled();
 | 
				
			||||||
@ -173,7 +173,7 @@ describe('Review workflows - Stages service', () => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      expect(servicesMock['admin::workflows'].update).toBeCalled();
 | 
					      expect(servicesMock['admin::workflows'].update).toBeCalled();
 | 
				
			||||||
      expect(servicesMock['admin::workflows'].update).toBeCalledWith(workflowMock.id, {
 | 
					      expect(servicesMock['admin::workflows'].update).toBeCalledWith(workflowMock.id, {
 | 
				
			||||||
        stages: [workflowMock.stages[0].id],
 | 
					        stages: [workflowMock.stages[0].id, workflowMock.stages[1].id],
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -65,6 +65,8 @@ module.exports = ({ strapi }) => {
 | 
				
			|||||||
        const defaultWorkflow = await getDefaultWorkflow({ strapi });
 | 
					        const defaultWorkflow = await getDefaultWorkflow({ strapi });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        await mapAsync(updated, (stage) => this.update(stage.id, stage));
 | 
					        await mapAsync(updated, (stage) => this.update(stage.id, stage));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const entitiesToMove = [];
 | 
				
			||||||
        await mapAsync(deleted, async (stage) => {
 | 
					        await mapAsync(deleted, async (stage) => {
 | 
				
			||||||
          // Find any entities related to this stage
 | 
					          // Find any entities related to this stage
 | 
				
			||||||
          const stageInfo = await this.findById(stage.id, {
 | 
					          const stageInfo = await this.findById(stage.id, {
 | 
				
			||||||
@ -73,25 +75,39 @@ module.exports = ({ strapi }) => {
 | 
				
			|||||||
          });
 | 
					          });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          if ((stageInfo?.related?.length ?? 0) === 0) {
 | 
					          if ((stageInfo?.related?.length ?? 0) === 0) {
 | 
				
			||||||
 | 
					            // If there are no related entities, just delete the stage
 | 
				
			||||||
            return this.delete(stage.id);
 | 
					            return this.delete(stage.id);
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          // This stage has related entities that we need to move to the
 | 
					          // This stage has related entities that need to be moved to their
 | 
				
			||||||
          // previous stage
 | 
					          // target stage
 | 
				
			||||||
          const previousStage =
 | 
					          // Find the nearest stage in the workflow that is not deleted,
 | 
				
			||||||
            defaultWorkflow.stages[defaultWorkflow.stages.findIndex((s) => s.id === stage.id) - 1];
 | 
					          // prioritizing the previous stages
 | 
				
			||||||
 | 
					          const targetStageId = findNearestMatchingStageID(
 | 
				
			||||||
 | 
					            defaultWorkflow.stages,
 | 
				
			||||||
 | 
					            defaultWorkflow.stages.findIndex((s) => s.id === stage.id),
 | 
				
			||||||
 | 
					            (targetStage) => {
 | 
				
			||||||
 | 
					              return !deleted.find((s) => s.id === targetStage.id);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          // Keep track of the entities to move and their target stages
 | 
				
			||||||
 | 
					          entitiesToMove.push(...stageInfo.related.map((entity) => ({ ...entity, targetStageId })));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          mapAsync(stageInfo.related, (entity) => {
 | 
					 | 
				
			||||||
            return this.updateEntity(
 | 
					 | 
				
			||||||
              {
 | 
					 | 
				
			||||||
                id: entity.id,
 | 
					 | 
				
			||||||
                modelUID: entity.__type,
 | 
					 | 
				
			||||||
              },
 | 
					 | 
				
			||||||
              previousStage.id
 | 
					 | 
				
			||||||
            );
 | 
					 | 
				
			||||||
          });
 | 
					 | 
				
			||||||
          return this.delete(stage.id);
 | 
					          return this.delete(stage.id);
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Move all the entities whose stage was deleted to their target stage
 | 
				
			||||||
 | 
					        mapAsync(entitiesToMove, (entity) => {
 | 
				
			||||||
 | 
					          return this.updateEntity(
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					              id: entity.id,
 | 
				
			||||||
 | 
					              modelUID: entity.__type,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            entity.targetStageId
 | 
				
			||||||
 | 
					          );
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return workflowsService.update(workflowId, {
 | 
					        return workflowsService.update(workflowId, {
 | 
				
			||||||
          stages: stagesIds,
 | 
					          stages: stagesIds,
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
@ -174,3 +190,27 @@ function assertAtLeastOneStageRemain(workflowStages, diffStages) {
 | 
				
			|||||||
    throw new ApplicationError('At least one stage must remain in the workflow.');
 | 
					    throw new ApplicationError('At least one stage must remain in the workflow.');
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Find the nearest object in an array that matches a condition.
 | 
				
			||||||
 | 
					 * Starts by searching the elements before the index, then the remaining elements in the array.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param {Array} array of stages
 | 
				
			||||||
 | 
					 * @param {Number} index the index to start searching from
 | 
				
			||||||
 | 
					 * @param {Function} condition must evaluate to true for the object to be considered a match
 | 
				
			||||||
 | 
					 * @returns {Object}
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					function findNearestMatchingStageID(array, index, condition) {
 | 
				
			||||||
 | 
					  // Start by searching the elements before the index
 | 
				
			||||||
 | 
					  for (let i = index; i >= 0; i -= 1) {
 | 
				
			||||||
 | 
					    if (condition(array[i])) {
 | 
				
			||||||
 | 
					      return array[i].id;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // If no matching element is found before the index,
 | 
				
			||||||
 | 
					  // search the remaining elements in the array
 | 
				
			||||||
 | 
					  const remainingArray = array.slice(index + 1);
 | 
				
			||||||
 | 
					  const nearestObject = remainingArray.filter(condition)[0];
 | 
				
			||||||
 | 
					  return nearestObject.id;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user