diff --git a/src/modules/manager/workflowTemplates/components/CapabilityEditors/AssigneesOfITaskAssigneeEditor.tsx b/src/modules/manager/workflowTemplates/components/CapabilityEditors/AssigneesOfITaskAssigneeEditor.tsx index e53d090..a426375 100644 --- a/src/modules/manager/workflowTemplates/components/CapabilityEditors/AssigneesOfITaskAssigneeEditor.tsx +++ b/src/modules/manager/workflowTemplates/components/CapabilityEditors/AssigneesOfITaskAssigneeEditor.tsx @@ -171,14 +171,14 @@ export const AssigneesOfITaskAssigneeEditor: React.FC = ( const runValidation = ( task: TaskDefinition, tasks: TaskDefinition[], -): Record => { +): Promise> => { const errors: Record = {}; const guid = task.config.guid as string; const assignees = task.config.assignees as ITaskAssignee[] | undefined; if (!assignees || assignees.length === 0) { errors[`${guid}.assignees`] = "At least one assignee is required."; - return errors; + return Promise.resolve(errors); } assignees.forEach((a, i) => { diff --git a/src/modules/manager/workflowTemplates/components/CapabilityEditors/BudgetEditorRegistryEntry.tsx b/src/modules/manager/workflowTemplates/components/CapabilityEditors/BudgetEditorRegistryEntry.tsx index c794614..16918b6 100644 --- a/src/modules/manager/workflowTemplates/components/CapabilityEditors/BudgetEditorRegistryEntry.tsx +++ b/src/modules/manager/workflowTemplates/components/CapabilityEditors/BudgetEditorRegistryEntry.tsx @@ -69,10 +69,10 @@ export const BudgetEditor: React.FC = (props) => { const runValidation = ( task: TaskDefinition, tasks: TaskDefinition[], -): Record => { +): Promise> => { const errors: Record = {}; - return errors; + return Promise.resolve(errors); }; export function defaultsAssignment( diff --git a/src/modules/manager/workflowTemplates/components/CapabilityEditors/BypassableEditor.tsx b/src/modules/manager/workflowTemplates/components/CapabilityEditors/BypassableEditor.tsx index a35741b..ea72fac 100644 --- a/src/modules/manager/workflowTemplates/components/CapabilityEditors/BypassableEditor.tsx +++ b/src/modules/manager/workflowTemplates/components/CapabilityEditors/BypassableEditor.tsx @@ -27,10 +27,10 @@ export const BypassableEditor: React.FC = (props) => { const runValidation = ( task: TaskDefinition, tasks: TaskDefinition[], -): Record => { +): Promise> => { const errors: Record = {}; - return errors; + return Promise.resolve(errors); }; export function defaultsAssignment( diff --git a/src/modules/manager/workflowTemplates/components/CapabilityEditors/OutcomeOfApprovalVerdictRegistryEntry.tsx b/src/modules/manager/workflowTemplates/components/CapabilityEditors/OutcomeOfApprovalVerdictRegistryEntry.tsx index 02639da..00afd7b 100644 --- a/src/modules/manager/workflowTemplates/components/CapabilityEditors/OutcomeOfApprovalVerdictRegistryEntry.tsx +++ b/src/modules/manager/workflowTemplates/components/CapabilityEditors/OutcomeOfApprovalVerdictRegistryEntry.tsx @@ -152,7 +152,7 @@ export const outcomeEditor: React.FC = (props) => { const runValidation = ( task: TaskDefinition, tasks: TaskDefinition[], -): Record => { +): Promise> => { const errors: Record = {}; const guid = task.config.guid as string; const outcomeActions = @@ -160,7 +160,7 @@ const runValidation = ( if (!outcomeActions) { // No outcome actions is valid, it just means there are no outcomes configured - return errors; + return Promise.resolve(errors); } // --- Rule 1: Task must be selected --- @@ -190,7 +190,7 @@ const runValidation = ( } }); - return errors; + return Promise.resolve(errors); }; export function defaultsAssignment( diff --git a/src/modules/manager/workflowTemplates/components/CapabilityEditors/StageOfGeneralTaskEditor.tsx b/src/modules/manager/workflowTemplates/components/CapabilityEditors/StageOfGeneralTaskEditor.tsx index c63439b..3623901 100644 --- a/src/modules/manager/workflowTemplates/components/CapabilityEditors/StageOfGeneralTaskEditor.tsx +++ b/src/modules/manager/workflowTemplates/components/CapabilityEditors/StageOfGeneralTaskEditor.tsx @@ -31,7 +31,7 @@ export const StageOfGeneralTaskEditor: React.FC = ( const runDefaults = useCapabilityDefaults(tasksMetadata); - const handleAddTask = (selectedType: TaskMetadata) => { + const handleAddTask = async (selectedType: TaskMetadata) => { const newTask: TaskDefinition = { type: selectedType.taskType, @@ -48,14 +48,12 @@ export const StageOfGeneralTaskEditor: React.FC = ( }); const updatedTasks = [...childTasks, newTask]; - const errors = validateTask(newTask, updatedTasks, tasksMetadata); + const errors = await validateTask(newTask, updatedTasks, tasksMetadata); const isValid = Object.keys(errors).length === 0; task.config.tasks = updatedTasks; - onValidate({ errors: errors, isValid: isValid } as TaskValidationResult); - onChange(task); }; @@ -66,12 +64,28 @@ export const StageOfGeneralTaskEditor: React.FC = ( ); }; -const runValidation = ( +const runValidation = async ( task: TaskDefinition, tasks: TaskDefinition[], -): Record => { +): Promise> => { const errors: Record = {}; + const meta = await templateVersionsService.getTaskMetadata("GeneralTask"); + + if (task.config.tasks) { + for (const childTask of task.config.tasks as TaskDefinition[]) { + const childErrors = await validateTask( + childTask, + task.config.tasks as TaskDefinition[], + meta, + ); + + if (childErrors && Object.keys(childErrors).length > 0) { + errors[`${task.config.guid}.tasks`] = + `One or more child tasks are invalid.`; + } + } + } return errors; }; diff --git a/src/modules/manager/workflowTemplates/components/CapabilityEditors/TagsEditor.tsx b/src/modules/manager/workflowTemplates/components/CapabilityEditors/TagsEditor.tsx index 3833d7c..2a9c626 100644 --- a/src/modules/manager/workflowTemplates/components/CapabilityEditors/TagsEditor.tsx +++ b/src/modules/manager/workflowTemplates/components/CapabilityEditors/TagsEditor.tsx @@ -27,10 +27,10 @@ export const TagsEditor: React.FC = (props) => { const runValidation = ( task: TaskDefinition, tasks: TaskDefinition[], -): Record => { +): Promise> => { const errors: Record = {}; - return errors; + return Promise.resolve(errors); }; export function defaultsAssignment( diff --git a/src/modules/manager/workflowTemplates/components/CapabilityEditors/TaskCoreEditor.tsx b/src/modules/manager/workflowTemplates/components/CapabilityEditors/TaskCoreEditor.tsx index dda1829..6c4d9c8 100644 --- a/src/modules/manager/workflowTemplates/components/CapabilityEditors/TaskCoreEditor.tsx +++ b/src/modules/manager/workflowTemplates/components/CapabilityEditors/TaskCoreEditor.tsx @@ -120,7 +120,7 @@ export const TaskCoreEditor: React.FC = (props) => { const runValidation = ( task: TaskDefinition, tasks: TaskDefinition[], -): Record => { +): Promise> => { const errors: Record = {}; if (!(task.config.name as string)?.trim()) { @@ -156,7 +156,7 @@ const runValidation = ( } } - return errors; + return Promise.resolve(errors); }; export function defaultsAssignment( diff --git a/src/modules/manager/workflowTemplates/components/TasksEditor.tsx b/src/modules/manager/workflowTemplates/components/TasksEditor.tsx index 214aafe..a63e9b7 100644 --- a/src/modules/manager/workflowTemplates/components/TasksEditor.tsx +++ b/src/modules/manager/workflowTemplates/components/TasksEditor.tsx @@ -41,12 +41,16 @@ const TaskEditorComponent: React.FC = ({ ); const runValidation = useCallback( - ( + async ( taskToValidate: TaskDefinition, tasksList: TaskDefinition[], tasksMetadataList: TaskMetadata[], ) => { - const errors = validateTask(taskToValidate, tasksList, tasksMetadataList); + const errors = await validateTask( + taskToValidate, + tasksList, + tasksMetadataList, + ); setFieldErrors(errors); onValidate( taskToValidate.config.guid as string, diff --git a/src/modules/manager/workflowTemplates/components/useCapabilityDefaults.tsx b/src/modules/manager/workflowTemplates/components/useCapabilityDefaults.tsx index 2eeb6eb..14ce243 100644 --- a/src/modules/manager/workflowTemplates/components/useCapabilityDefaults.tsx +++ b/src/modules/manager/workflowTemplates/components/useCapabilityDefaults.tsx @@ -36,14 +36,14 @@ export interface capabilityEditorRegistryEntry { task: TaskDefinition, tasks: TaskDefinition[], tasksMetadata: TaskMetadata[], - ) => Record; + ) => Promise>; } -export function validateTask( +export async function validateTask( task: TaskDefinition, tasks: TaskDefinition[], tasksMetadata: TaskMetadata[], -): Record { +): Promise> { const taskMeta = tasksMetadata.find((t) => t.taskType === task.type); const errors: Record = {}; @@ -55,7 +55,7 @@ export function validateTask( continue; } - const validationErrors = entry.ValidationRunner(task, tasks); + const validationErrors = await entry.ValidationRunner(task, tasks); Object.assign(errors, validationErrors); } return errors;