import { Alert, Button, Form, Input, InputNumber, Modal, Popover, Result, Steps, Tag, notification, } from "antd"; import { useContext, useRef, useState } from "react"; import { useNavigate, useParams } from "react-router-dom"; import { Constants, FormatDatetime, WebSocketContext, SentMessagesCommands, GetDuration, MyAvatar, getUserId, setNativeValue, } from "../../utils"; import { InfoCircleOutlined, LockOutlined } from "@ant-design/icons"; export default function GroupTasksViewModal({ isOpen }) { const webSocketContext = useContext(WebSocketContext); const navigate = useNavigate(); const [notificationApi, notificationContextHolder] = notification.useNotification(); let { paramGroupTaskId } = useParams(); const handleCancel = () => navigate(Constants.ROUTE_PATHS.GROUP_TASKS); let currentGroupTask; webSocketContext.GroupTasks.forEach((groupTask) => { if (groupTask.Id === paramGroupTaskId) { currentGroupTask = groupTask; } }); // invalid group task id in url specified if (!currentGroupTask) { return ( Close} > {" "} ); } const getAlertType = (status) => { switch (status) { case Constants.GROUP_TASKS_STATUS.FINISHED: return "success"; case Constants.GROUP_TASKS_STATUS.RUNNING: return "info"; case Constants.GROUP_TASKS_STATUS.CANCELED: return "warning"; case Constants.GROUP_TASKS_STATUS.FAILED: return "error"; case Constants.GROUP_TASKS_STATUS.INPUT_REQUIRED: return "info"; default: return "info"; } }; const getAlertMessage = (status) => { switch (status) { case Constants.GROUP_TASKS_STATUS.FINISHED: return "Success"; case Constants.GROUP_TASKS_STATUS.RUNNING: return "Task is running"; case Constants.GROUP_TASKS_STATUS.CANCELED: return "Task cancelled"; case Constants.GROUP_TASKS_STATUS.FAILED: return "Task failed"; case Constants.GROUP_TASKS_STATUS.INPUT_REQUIRED: return "Input required"; default: return "Alert message not found"; } }; const getStepItemStatus = (status) => { switch (status) { case Constants.GROUP_TASKS_STATUS.FINISHED: return "finish"; case Constants.GROUP_TASKS_STATUS.RUNNING: return "process"; case Constants.GROUP_TASKS_STATUS.CANCELED: case Constants.GROUP_TASKS_STATUS.FAILED: return "error"; case Constants.GROUP_TASKS_STATUS.INPUT_REQUIRED: return "wait"; default: return "wait"; } }; const handleTaskFailedTryAgainRunTaskStep = (taskStepId, step) => { webSocketContext.SendSocketMessage( SentMessagesCommands.TaskFailedTryAgainRunTaskStep, { groupTaskId: currentGroupTask.Id, category: currentGroupTask.Category, groupId: currentGroupTask.GroupId, step: step, taskStepId: taskStepId, } ); }; const handleTaskContinueTaskStep = (taskStepId, step) => { const groupTasksViewModalRequiredInputsForm = document.getElementById( "groupTasksViewModalRequiredInputsForm" ); let canTaskContinued = true; let taskInputs = []; if (groupTasksViewModalRequiredInputsForm !== null) { const specifiedTaskInputs = groupTasksViewModalRequiredInputsForm.getElementsByTagName("input"); if (specifiedTaskInputs.length > 0) { for (let i = 0; i < specifiedTaskInputs.length; i++) { if (specifiedTaskInputs[i].value === "") { canTaskContinued = false; break; } taskInputs.push({ parameterName: specifiedTaskInputs[i].id.split( "-" )[6] /* Format: UUID-STEP-PARAMETER_NAME */, value: specifiedTaskInputs[i].value, }); } } } if (!canTaskContinued) { notificationApi["error"]({ message: `Inputs cannot be empty`, description: `Please fill in all inputs`, }); return; } webSocketContext.SendSocketMessage( SentMessagesCommands.TaskContinueTaskStep, { groupTaskId: currentGroupTask.Id, category: currentGroupTask.Category, groupId: currentGroupTask.GroupId, step: step, taskStepId: taskStepId, taskInputs: taskInputs, } ); }; const alertActionHandler = (status, taskStepId, index, taskLocked) => { switch (status) { case Constants.GROUP_TASKS_STATUS.FAILED: return ( ); case Constants.GROUP_TASKS_STATUS.INPUT_REQUIRED: return ( ); default: return <>; } }; const getGroupTaskStepLog = (log) => { return log.length === 0 ? ( "" ) : ( {log} ); }; const stepsItemHandler = () => { let groupTaskSteps = []; let groupTasks = []; webSocketContext.GroupTasksSteps.forEach((step) => { if (step.GroupTasksId === paramGroupTaskId) { groupTaskSteps.push(step); } }); groupTaskSteps.sort((a, b) => a.Step - b.Step); webSocketContext.CategoryGroups.forEach((categoryGroup) => { if (categoryGroup.category === currentGroupTask.Category) { categoryGroup.groups.forEach((group) => { if (currentGroupTask.GroupId === group.id) { groupTasks = group.tasks; } }); } }); let stepItems = []; groupTasks.forEach((groupTask, index) => { stepItems.push({ key: index, title: groupTaskSteps[index] !== undefined && groupTaskSteps[index].Inputs !== "" ? ( <> {groupTask.name}{" "} Specified Task Inputs } content={ <> {groupTask.parameters.length > 0 && groupTask.parameters.map((task) => { return ( {task.displayName}:{" "} { JSON.parse(groupTaskSteps[index].Inputs).find( (step) => step.parameterName === task.parameterName ).value }
); })} } >
{" "} {groupTaskSteps[index]?.CreatorUserId !== undefined && ( )} ) : ( <> {groupTask.name}{" "} {groupTaskSteps[index]?.CreatorUserId !== undefined && ( )} ), status: groupTaskSteps[index] !== undefined ? getStepItemStatus(groupTaskSteps[index].Status) : "wait", description: groupTaskSteps[index] !== undefined ? ( <>

Id: {groupTaskSteps[index].Id}
Started at:{" "} {FormatDatetime(groupTaskSteps[index].StartedAt)}
Ended at:{" "} {groupTaskSteps[index].EndedAt !== "0001-01-01T00:00:00Z" ? FormatDatetime(groupTaskSteps[index].EndedAt) : Constants.TEXT_EMPTY_PLACEHOLDER}
Duration:{" "} {GetDuration( groupTaskSteps[index].StartedAt, groupTaskSteps[index].EndedAt )}

{getAlertMessage(groupTaskSteps[index].Status)}{" "} {groupTaskSteps[index].LockedByUserId !== "" && ( <> {" "} )} } description={ groupTaskSteps[index].Status === Constants.GROUP_TASKS_STATUS.INPUT_REQUIRED ? ( ) : ( getGroupTaskStepLog(groupTaskSteps[index].Log) ) } type={getAlertType(groupTaskSteps[index].Status)} showIcon action={alertActionHandler( groupTaskSteps[index].Status, groupTaskSteps[index].Id, index, groupTaskSteps[index].LockedByUserId )} /> ) : ( "" ), }); }); return stepItems; }; return ( Close} > {notificationContextHolder} {webSocketContext.GroupTasks.map((groupTask) => { if (groupTask.Id === paramGroupTaskId) { let currentGroupTask = groupTask; return (

{currentGroupTask.GroupName}{" "} Details

} content={ <>

ID:{" "} {paramGroupTaskId}
Category: {" "} {currentGroupTask.Category}
Started at: {" "} {FormatDatetime(currentGroupTask.StartedAt)}
Endet at: {" "} {FormatDatetime(currentGroupTask.EndedAt)}
Duration: {" "} {GetDuration( currentGroupTask.StartedAt, currentGroupTask.EndedAt )}

{currentGroupTask.GlobalInputs !== "[]" ? ( <>

Specified Global Inputs

{JSON.parse(currentGroupTask.GlobalInputs).map( (globalInput) => { return ( {globalInput.parameterName}:{" "} {globalInput.value !== "" ? globalInput.value : Constants.TEXT_EMPTY_PLACEHOLDER}
); } )}

) : null} } > {" "}
{currentGroupTask.Description}
); } return ""; })}
); } function InputRequiredHandler({ webSocketContext, currentGroupTask, groupTaskParameters, notificationApi, step, taskLockedByUserId, }) { const [inputFields, setInputFields] = useState({}); const globalInputs = JSON.parse(currentGroupTask.GlobalInputs); const getDefaultValue = (groupTaskParameter) => { if (globalInputs === undefined || !groupTaskParameter.global) return null; return globalInputs.find( (globalInput) => globalInput.parameterName === groupTaskParameter.parameterName ).value; }; const getLabel = (displayName, groupTaskParameter) => { return groupTaskParameter.global ? ( <> {displayName} Global ) : ( displayName ); }; let lastChanges = useRef([]); let typingTimer = useRef(); const onInputChange = ( inputValue, currentGroupTaskId, groupTaskParameterName ) => { setInputFields((fields) => { return ({ ...fields }[groupTaskParameterName] = inputValue); }); if (taskLockedByUserId !== "") return; lastChanges.current = lastChanges.current.filter( (lc) => Date.now() - new Date(lc.changeTime) < Constants.GROUP_TASK_LOCKED_TIME ); const lastChange = lastChanges.current.find((lC) => lC.step === step); if (lastChange === undefined) { lastChanges.current.push({ step: step, changeTime: Date.now(), }); webSocketContext.SendSocketMessage(SentMessagesCommands.TaskLocking, { lockedByUserId: getUserId(), groupTaskId: currentGroupTaskId, step: step, }); } // sync input value with other web clients clearTimeout(typingTimer.current); typingTimer.current = setTimeout(() => { webSocketContext.SendSocketMessage( SentMessagesCommands.UpdateGroupTaskStepUserInputValue, { element: `${currentGroupTaskId}-${step}-${groupTaskParameterName}`, value: inputValue, } ); }, 500); }; return (
{groupTaskParameters.map((groupTaskParameter) => { switch (groupTaskParameter.type) { case "text": return ( onInputChange( e.target.value, currentGroupTask.Id, groupTaskParameter.parameterName ) } value={inputFields[groupTaskParameter.parameterName]} /> ); case "number": return ( onInputChange( e, currentGroupTask.Id, groupTaskParameter.parameterName ) } /> ); default: notificationApi["error"]({ message: `Type ${groupTaskParameter.type} not implemented`, description: `Was specified in: ${groupTaskParameter.displayName}`, }); return (

Type ${groupTaskParameter.type} not implemented. Was specified in: ${groupTaskParameter.displayName}

); } })}
); }