The task processor is now wired up and ready to complete an assignment.
This commit is contained in:
parent
ea95b0747d
commit
61465130a6
@ -11,11 +11,14 @@ import LoadingPanel from "../../../../components/common/LoadingPanel";
|
|||||||
import AssigneePanel from "../../tasks/components/AssigneePanel";
|
import AssigneePanel from "../../tasks/components/AssigneePanel";
|
||||||
import TaskTypeAndNameDisplayPanel from "../../workflowTemplates/components/TaskTypeAndNameDisplayPanel";
|
import TaskTypeAndNameDisplayPanel from "../../workflowTemplates/components/TaskTypeAndNameDisplayPanel";
|
||||||
import Button, { ButtonType } from "../../../../components/common/Button";
|
import Button, { ButtonType } from "../../../../components/common/Button";
|
||||||
|
import TaskProcessor from "./components/TaskProcessor";
|
||||||
import "../../../../Sass/_assignmentComplete.scss";
|
import "../../../../Sass/_assignmentComplete.scss";
|
||||||
|
|
||||||
const AssignmentComplete: React.FC = () => {
|
const AssignmentComplete: React.FC = () => {
|
||||||
const { assignmentId } = useParams<{ assignmentId: string }>();
|
const { assignmentId } = useParams<{ assignmentId: string }>();
|
||||||
const { t } = useTranslation(Namespaces.Common);
|
const { t } = useTranslation(Namespaces.Common);
|
||||||
|
const [isTaskValid, setIsTaskValid] = useState<boolean>(false);
|
||||||
|
const [taskData, setTaskData] = useState<Record<string, unknown>>({});
|
||||||
const [assignmentDetails, setAssignmentDetails] =
|
const [assignmentDetails, setAssignmentDetails] =
|
||||||
useState<GetAssignmentForCompletion>();
|
useState<GetAssignmentForCompletion>();
|
||||||
|
|
||||||
@ -31,6 +34,9 @@ const AssignmentComplete: React.FC = () => {
|
|||||||
);
|
);
|
||||||
if (assignmentDetails) {
|
if (assignmentDetails) {
|
||||||
setAssignmentDetails(assignmentDetails);
|
setAssignmentDetails(assignmentDetails);
|
||||||
|
setTaskData({
|
||||||
|
comments: assignmentDetails.assignment.comments ?? "",
|
||||||
|
});
|
||||||
}
|
}
|
||||||
} catch (ex: any) {
|
} catch (ex: any) {
|
||||||
toast.error(ex.message);
|
toast.error(ex.message);
|
||||||
@ -63,16 +69,28 @@ const AssignmentComplete: React.FC = () => {
|
|||||||
<h2>{assignmentDetails.activity.name}</h2>
|
<h2>{assignmentDetails.activity.name}</h2>
|
||||||
</div>
|
</div>
|
||||||
<div className="actions">
|
<div className="actions">
|
||||||
<Button buttonType={ButtonType.primary}>Complete</Button>
|
<Button
|
||||||
|
buttonType={ButtonType.primary}
|
||||||
|
disabled={!isTaskValid}
|
||||||
|
onClick={() => {
|
||||||
|
console.log("Task data to submit:", taskData);
|
||||||
|
toast.info("Complete action not implemented yet");
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Complete
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="mainContent">
|
<div className="mainContent">
|
||||||
<div className="workarea">
|
<div className="workarea">
|
||||||
<div className="workareaInner">
|
<div className="workareaInner">
|
||||||
<div>{taskDefinition.config.description}</div>
|
<TaskProcessor
|
||||||
|
assignmentDetails={assignmentDetails}
|
||||||
<div>Comments</div>
|
taskDefinition={taskDefinition}
|
||||||
<div>{assignmentDetails.assignment.comments}</div>
|
taskData={taskData}
|
||||||
|
onTaskDataChange={setTaskData}
|
||||||
|
onValidationChange={setIsTaskValid}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,51 @@
|
|||||||
|
import React, { useEffect } from "react";
|
||||||
|
import { TaskDefinition } from "../../../workflowTemplates/services/WorkflowTemplateService";
|
||||||
|
import { GetAssignmentForCompletion } from "../services/assignmentCompleteService";
|
||||||
|
import BasicTask from "./tasksProcessor/BasicTask";
|
||||||
|
|
||||||
|
type TaskProcessorProps = {
|
||||||
|
assignmentDetails: GetAssignmentForCompletion;
|
||||||
|
taskDefinition: TaskDefinition;
|
||||||
|
taskData: Record<string, unknown>;
|
||||||
|
onTaskDataChange?: (data: Record<string, unknown>) => void;
|
||||||
|
onValidationChange?: (isValid: boolean) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
type TaskProcessorComponent = React.ComponentType<TaskProcessorProps>;
|
||||||
|
|
||||||
|
const taskProcessorRegistry: Record<string, TaskProcessorComponent> = {
|
||||||
|
"e_suite.Workflow.Core.Tasks.BasicTask": BasicTask,
|
||||||
|
};
|
||||||
|
|
||||||
|
const TaskProcessor: React.FC<TaskProcessorProps> = ({
|
||||||
|
assignmentDetails,
|
||||||
|
taskDefinition,
|
||||||
|
taskData,
|
||||||
|
onTaskDataChange,
|
||||||
|
onValidationChange,
|
||||||
|
}) => {
|
||||||
|
const processorType = assignmentDetails.task.taskType;
|
||||||
|
const Processor = taskProcessorRegistry[processorType];
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!Processor) {
|
||||||
|
onValidationChange?.(false);
|
||||||
|
}
|
||||||
|
}, [Processor, onValidationChange]);
|
||||||
|
|
||||||
|
if (!Processor) {
|
||||||
|
return <div>Unsupported task type: {processorType}</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Processor
|
||||||
|
assignmentDetails={assignmentDetails}
|
||||||
|
taskDefinition={taskDefinition}
|
||||||
|
taskData={taskData}
|
||||||
|
onTaskDataChange={onTaskDataChange}
|
||||||
|
onValidationChange={onValidationChange}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TaskProcessor;
|
||||||
@ -0,0 +1,114 @@
|
|||||||
|
import React, { useCallback, useEffect, useState } from "react";
|
||||||
|
import Joi from "joi";
|
||||||
|
import { InputType } from "../../../../../../components/common/Input";
|
||||||
|
import { renderInput } from "../../../../../../components/common/formHelpers";
|
||||||
|
import {
|
||||||
|
FormData,
|
||||||
|
FormError,
|
||||||
|
} from "../../../../../../components/common/useForm";
|
||||||
|
import { TaskDefinition } from "../../../../workflowTemplates/services/WorkflowTemplateService";
|
||||||
|
import { GetAssignmentForCompletion } from "../../services/assignmentCompleteService";
|
||||||
|
|
||||||
|
type BasicTaskProps = {
|
||||||
|
assignmentDetails: GetAssignmentForCompletion;
|
||||||
|
taskDefinition: TaskDefinition;
|
||||||
|
taskData: Record<string, unknown>;
|
||||||
|
onTaskDataChange?: (data: Record<string, unknown>) => void;
|
||||||
|
onValidationChange?: (isValid: boolean) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
const BasicTask: React.FC<BasicTaskProps> = ({
|
||||||
|
assignmentDetails,
|
||||||
|
taskDefinition,
|
||||||
|
taskData,
|
||||||
|
onTaskDataChange,
|
||||||
|
onValidationChange,
|
||||||
|
}) => {
|
||||||
|
const [errors, setErrors] = useState<FormError>({});
|
||||||
|
|
||||||
|
const validateData = useCallback(
|
||||||
|
(data: Record<string, unknown>) => {
|
||||||
|
const result = Joi.object({
|
||||||
|
comments: Joi.string().required().allow("").label("Comments"),
|
||||||
|
}).validate(data, { abortEarly: false });
|
||||||
|
|
||||||
|
const nextErrors: FormError = {};
|
||||||
|
|
||||||
|
if (result.error) {
|
||||||
|
for (const detail of result.error.details) {
|
||||||
|
const key = String(detail.path[0] ?? "_general");
|
||||||
|
nextErrors[key] = detail.message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setErrors(nextErrors);
|
||||||
|
|
||||||
|
const hasValidationErrors = Object.keys(nextErrors).some(
|
||||||
|
(key) => !key.startsWith("_"),
|
||||||
|
);
|
||||||
|
|
||||||
|
onValidationChange?.(!hasValidationErrors);
|
||||||
|
},
|
||||||
|
[onValidationChange],
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
validateData(taskData);
|
||||||
|
}, [taskData, validateData]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (taskData.comments === undefined) {
|
||||||
|
onTaskDataChange?.({
|
||||||
|
...taskData,
|
||||||
|
comments: assignmentDetails.assignment.comments ?? "",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [assignmentDetails.assignment.comments, onTaskDataChange, taskData]);
|
||||||
|
|
||||||
|
const commentsValue = String(taskData.comments ?? "");
|
||||||
|
|
||||||
|
const description =
|
||||||
|
typeof taskDefinition.config === "object" &&
|
||||||
|
taskDefinition.config !== null &&
|
||||||
|
"description" in taskDefinition.config
|
||||||
|
? String(
|
||||||
|
(taskDefinition.config as Record<string, unknown>).description ?? "",
|
||||||
|
)
|
||||||
|
: "";
|
||||||
|
|
||||||
|
const handleCommentsChange = (
|
||||||
|
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
|
||||||
|
) => {
|
||||||
|
if (e.target instanceof HTMLTextAreaElement) {
|
||||||
|
onTaskDataChange?.({
|
||||||
|
...taskData,
|
||||||
|
comments: e.target.value,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="workareaInner">
|
||||||
|
<div>{description}</div>
|
||||||
|
|
||||||
|
{renderInput(
|
||||||
|
"comments",
|
||||||
|
"Comments",
|
||||||
|
{ comments: commentsValue } as FormData,
|
||||||
|
errors,
|
||||||
|
InputType.textarea,
|
||||||
|
false,
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
0,
|
||||||
|
true,
|
||||||
|
undefined,
|
||||||
|
handleCommentsChange as (
|
||||||
|
e: React.ChangeEvent<HTMLInputElement>,
|
||||||
|
) => void,
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default BasicTask;
|
||||||
Loading…
Reference in New Issue
Block a user