Task validation now returns it's state when navigating away from the tab.

This commit is contained in:
Colin Dawson 2026-02-14 13:36:41 +00:00
parent 319d5165a5
commit f30120d448
3 changed files with 54 additions and 29 deletions

View File

@ -30,6 +30,10 @@ const WorkflowTemplateDetails: React.FC<{ editMode: boolean }> = ({
const { userId } = useParams<{ userId: string }>(); const { userId } = useParams<{ userId: string }>();
const [activeTab, setActiveTab] = React.useState("general"); const [activeTab, setActiveTab] = React.useState("general");
const [taskValidation, setTaskValidation] = useState<Record<string, boolean>>(
{},
);
// useForm promoted to the parent // useForm promoted to the parent
const form = useFormWithGuard({ const form = useFormWithGuard({
loaded: false, loaded: false,
@ -124,11 +128,21 @@ const WorkflowTemplateDetails: React.FC<{ editMode: boolean }> = ({
form.handleSubmit(e, doSubmit); form.handleSubmit(e, doSubmit);
}; };
const [tasksValid, setTasksValid] = useState(true); //const [tasksValid, setTasksValid] = useState(true);
const handleTasksValidate = (isValid: boolean) => { const handleTaskValidate = (taskId: string, isValid: boolean) => {
console.log("Test", isValid); setTaskValidation((prev) => {
setTasksValid(isValid); const updated = { ...prev, [taskId]: isValid };
// Compute overall validity
//const allValid = Object.values(updated).every((v) => v === true);
// Bubble up to parent
//setTasksValid(allValid);
//setTaskValidation(updated);
return updated;
});
}; };
const { loaded, redirect, errors: formErrors, data } = form.state; const { loaded, redirect, errors: formErrors, data } = form.state;
@ -136,10 +150,6 @@ const WorkflowTemplateDetails: React.FC<{ editMode: boolean }> = ({
let errors = { ...formErrors }; let errors = { ...formErrors };
if (!tasksValid) {
errors["tasks"] = t("TasksValidationError");
}
const generalTabValid = !( const generalTabValid = !(
errors["domainId"] || errors["domainId"] ||
errors["name"] || errors["name"] ||
@ -147,6 +157,12 @@ const WorkflowTemplateDetails: React.FC<{ editMode: boolean }> = ({
errors["description"] errors["description"]
); );
const tasksValid = Object.values(taskValidation).every((v) => v === true);
if (!tasksValid) {
errors["tasks"] = t("TasksValidationError");
}
// ----------------------------- // -----------------------------
// Tabs // Tabs
// ----------------------------- // -----------------------------
@ -172,7 +188,8 @@ const WorkflowTemplateDetails: React.FC<{ editMode: boolean }> = ({
errors={errors} errors={errors}
isEditMode={editMode} isEditMode={editMode}
onTasksChange={form.handleTasksChange} onTasksChange={form.handleTasksChange}
onValidate={handleTasksValidate} onValidate={handleTaskValidate}
taskValidation={taskValidation}
/> />
</Tab>, </Tab>,

View File

@ -1,4 +1,4 @@
import { useEffect, useState } from "react"; import { useState } from "react";
import { TaskDefinition } from "../services/WorkflowTemplateService"; import { TaskDefinition } from "../services/WorkflowTemplateService";
import { TaskCoreEditor } from "./CapabilityEditors/TaskCoreEditor"; import { TaskCoreEditor } from "./CapabilityEditors/TaskCoreEditor";

View File

@ -11,7 +11,8 @@ interface TasksTabProps {
errors: Record<string, string>; errors: Record<string, string>;
isEditMode: boolean; isEditMode: boolean;
onTasksChange: (name: string, value: TaskDefinition[]) => void; onTasksChange: (name: string, value: TaskDefinition[]) => void;
onValidate: (isValid: boolean) => void; onValidate: (taskId: string, isValid: boolean) => void;
taskValidation: Record<string, boolean>;
} }
const TasksTab: React.FC<TasksTabProps> = ({ const TasksTab: React.FC<TasksTabProps> = ({
@ -20,26 +21,10 @@ const TasksTab: React.FC<TasksTabProps> = ({
isEditMode, isEditMode,
onTasksChange, onTasksChange,
onValidate, onValidate,
taskValidation,
}) => { }) => {
const tasks = data.tasks; const tasks = data.tasks;
const [selectedTask, setSelectedTask] = useState<TaskDefinition | null>(null); const [selectedTask, setSelectedTask] = useState<TaskDefinition | null>(null);
const [taskValidation, setTaskValidation] = useState<Record<string, boolean>>(
{},
);
const handleTaskValidate = (taskId: string, isValid: boolean) => {
setTaskValidation((prev) => {
const updated = { ...prev, [taskId]: isValid };
// Compute overall validity
const allValid = Object.values(updated).every((v) => v === true);
// Bubble up to parent
onValidate(allValid);
return updated;
});
};
useEffect(() => { useEffect(() => {
if (tasks.length === 0) { if (tasks.length === 0) {
@ -72,6 +57,29 @@ const TasksTab: React.FC<TasksTabProps> = ({
} }
}, [tasks, selectedTask]); }, [tasks, selectedTask]);
useEffect(() => {
// Don't override user selection
if (selectedTask) return;
if (tasks.length === 0) {
setSelectedTask(null);
return;
}
// Find first invalid task
const firstInvalid = tasks.find(
(t) => taskValidation[t.config.guid as string] === false,
);
if (firstInvalid) {
setSelectedTask(firstInvalid);
return;
}
// Otherwise select first task
setSelectedTask(tasks[0]);
}, [tasks, taskValidation, selectedTask]);
const handleTasksChange = (newTasks: TaskDefinition[]) => { const handleTasksChange = (newTasks: TaskDefinition[]) => {
// Update the parent form state // Update the parent form state
onTasksChange("tasks", newTasks); onTasksChange("tasks", newTasks);
@ -102,7 +110,7 @@ const TasksTab: React.FC<TasksTabProps> = ({
handleTasksChange(newTasks); handleTasksChange(newTasks);
setSelectedTask(updatedTask); setSelectedTask(updatedTask);
}} }}
onValidate={handleTaskValidate} onValidate={onValidate}
/> />
)} )}
</div> </div>