import { Alert, Button, Col, Form, Image, Input, InputNumber, Modal, Popover, Result, Row, Space, Steps, Tag, notification, } from "antd"; import { useContext, useMemo, useRef, useState } from "react"; import { useNavigate, useParams } from "react-router-dom"; import { Constants, FormatDatetime, WebSocketContext, SentMessagesCommands, GetDuration, MyAvatar, getUserId, GroupTasksStepsLockedAndUserUpdateInputValueRememberId, hasXYPermission, } from "../../../utils"; import { CheckOutlined, FileImageOutlined, InfoCircleOutlined, LockOutlined, RetweetOutlined, UndoOutlined, } from "@ant-design/icons"; import { StlViewer } from "react-stl-viewer"; import TextArea from "antd/es/input/TextArea"; import { useTranslation } from "react-i18next"; export default function GroupTasksViewModal({ isOpen }) { const webSocketContext = useContext(WebSocketContext); const navigate = useNavigate(); const [notificationApi, notificationContextHolder] = notification.useNotification(); let { paramGroupTaskId } = useParams(); const { t } = useTranslation(); 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 or no permissions if ( !currentGroupTask || !hasXYPermission( webSocketContext.User.Permissions, Constants.PERMISSIONS.GROUP_TASKS.OVERVIEW.XYView, currentGroupTask.Category ) ) { return ( {t("common.button.close")} } > ); } const getAlertType = (status) => { switch (status) { case Constants.GROUP_TASKS_STATUS.FINISHED: return "success"; case Constants.GROUP_TASKS_STATUS.FAILED: return "error"; case Constants.GROUP_TASKS_STATUS.CANCELED: case Constants.GROUP_TASKS_STATUS.PAUSED: case Constants.GROUP_TASKS_STATUS.UNDO_ENDED: return "warning"; case Constants.GROUP_TASKS_STATUS.INPUT_REQUIRED: case Constants.GROUP_TASKS_STATUS.RUNNING: default: return "info"; } }; const getAlertMessage = (status) => { switch (status) { case Constants.GROUP_TASKS_STATUS.FINISHED: return t("groupTasks.groupTasksViewModal.alertMessage.successful"); case Constants.GROUP_TASKS_STATUS.RUNNING: return t("groupTasks.groupTasksViewModal.alertMessage.taskIsRunning"); case Constants.GROUP_TASKS_STATUS.CANCELED: return t("groupTasks.groupTasksViewModal.alertMessage.taskCanceled"); case Constants.GROUP_TASKS_STATUS.FAILED: return t("groupTasks.groupTasksViewModal.alertMessage.taskFailed"); case Constants.GROUP_TASKS_STATUS.INPUT_REQUIRED: return t( "groupTasks.groupTasksViewModal.alertMessage.taskInputRequired" ); case Constants.GROUP_TASKS_STATUS.PAUSED: return t("groupTasks.groupTasksViewModal.alertMessage.paused"); case Constants.GROUP_TASKS_STATUS.UNDO_ENDED: return t("groupTasks.groupTasksViewModal.alertMessage.undoEnded"); 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: case Constants.GROUP_TASKS_STATUS.PAUSED: case Constants.GROUP_TASKS_STATUS.UNDO_ENDED: 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, }); } } const specifiedTaskTextareas = groupTasksViewModalRequiredInputsForm.getElementsByTagName("textarea"); if (specifiedTaskTextareas.length > 0) { for (let i = 0; i < specifiedTaskTextareas.length; i++) { if (specifiedTaskTextareas[i].value === "") { canTaskContinued = false; break; } taskInputs.push({ parameterName: specifiedTaskTextareas[i].id.split( "-" )[6] /* Format: UUID-STEP-PARAMETER_NAME */, value: specifiedTaskTextareas[i].value, }); } } } if (!canTaskContinued) { notificationApi["error"]({ message: t( "groupTasks.groupTasksViewModal.notification.inputsCannotBeEmpty.message" ), description: t( "groupTasks.groupTasksViewModal.notification.inputsCannotBeEmpty.description" ), }); return; } webSocketContext.SendSocketMessage( SentMessagesCommands.TaskContinueTaskStep, { groupTaskId: currentGroupTask.Id, category: currentGroupTask.Category, groupId: currentGroupTask.GroupId, step: step, taskStepId: taskStepId, taskInputs: taskInputs, } ); }; const handleUserActionTaskStep = (action, taskStepId, step) => { webSocketContext.SendSocketMessage( SentMessagesCommands.HandleUserActionTaskStep, { action: action, groupTaskId: currentGroupTask.Id, category: currentGroupTask.Category, groupId: currentGroupTask.GroupId, step: step, taskStepId: taskStepId, } ); }; const ActionHandler = ({ status, taskStepId, index, taskLocked }) => { const currentStepTask = webSocketContext.CategoryGroups.find( (category) => category.category === currentGroupTask.Category ).groups.find((group) => group.id === currentGroupTask.GroupId).tasks[ index ]; switch (status) { case Constants.GROUP_TASKS_STATUS.FAILED: return ( ); case Constants.GROUP_TASKS_STATUS.INPUT_REQUIRED: return ( ); case Constants.GROUP_TASKS_STATUS.PAUSED: return ( {currentStepTask.repeatPossible && ( )} {currentStepTask.undoPossible && ( )} ); case Constants.GROUP_TASKS_STATUS.UNDO_ENDED: return ( ); default: return <>; } }; 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; } }); } }); const getStepItem = (groupTask, index) => { return { key: index, title: groupTaskSteps[index] !== undefined && groupTaskSteps[index].Inputs !== "" && groupTaskSteps[index].Status !== Constants.GROUP_TASKS_STATUS.INPUT_REQUIRED && groupTaskSteps[index].Status !== Constants.GROUP_TASKS_STATUS.UNDO_ENDED ? ( <> {groupTask.name}{" "} {t( "groupTasks.groupTasksViewModal.popover.specifiedTaskInputs" )} } content={ <> {groupTask.parameters.length > 0 && groupTask.parameters.map((task) => { return ( {task.displayName}:{" "} { JSON.parse(groupTaskSteps[index].Inputs).find( (input) => input.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}
{t("groupTasks.groupTasksViewModal.startedAt")}:{" "} {FormatDatetime(groupTaskSteps[index].StartedAt)}
{t("groupTasks.groupTasksViewModal.endedAt")}:{" "} {groupTaskSteps[index].EndedAt !== "0001-01-01T00:00:00Z" ? FormatDatetime(groupTaskSteps[index].EndedAt) : Constants.TEXT_EMPTY_PLACEHOLDER}
{t("groupTasks.groupTasksViewModal.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 ? (
) : ( groupTaskSteps[index].Log.length > 0 && (
) ) } type={getAlertType(groupTaskSteps[index].Status)} showIcon /> ) : ( "" ), }; }; let stepItems = []; groupTasks.forEach((groupTask, index) => stepItems.push(getStepItem(groupTask, index)) ); // occurs when tasks were taken from the group task config, but at a previous time the tasks existed if (currentGroupTask.NumberOfSteps > groupTasks.length) { for (let i = groupTasks.length; i < currentGroupTask.NumberOfSteps; i++) { let stepParams = []; if (groupTaskSteps[i].Inputs !== "") { let params = JSON.parse(groupTaskSteps[i].Inputs); for (let i2 = 0; i2 < params.length; i2++) { params[i2].displayName = params[i2].parameterName; } stepParams = params; } stepItems.push(getStepItem({ name: "???", parameters: stepParams }, i)); } } return stepItems; }; return ( {t("common.button.close")} } > {notificationContextHolder} {webSocketContext.GroupTasks.map((groupTask) => { if (groupTask.Id === paramGroupTaskId) { let currentGroupTask = groupTask; return (

{currentGroupTask.GroupName}{" "} {t("groupTasks.groupTasksViewModal.popover.details")}

} content={ <>

ID:{" "} {paramGroupTaskId}
{t("groupTasks.groupTasksViewModal.category")}: {" "} {currentGroupTask.Category}
{t("groupTasks.groupTasksViewModal.startedAt")}: {" "} {FormatDatetime(currentGroupTask.StartedAt)}
{t("groupTasks.groupTasksViewModal.endedAt")}: {" "} {FormatDatetime(currentGroupTask.EndedAt)}
{t("groupTasks.groupTasksViewModal.duration")}: {" "} {GetDuration( currentGroupTask.StartedAt, currentGroupTask.EndedAt )}

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

{t( "groupTasks.groupTasksViewModal.popover.specifiedGlobalInputs" )}

{JSON.parse(currentGroupTask.GlobalInputs).map( (globalInput) => { return ( { webSocketContext.CategoryGroups.find( (categoryGroup) => categoryGroup.category === currentGroupTask.Category ) .groups.find( (group) => group.id === currentGroupTask.GroupId ) .globalInputs.find( (gI) => gI.parameterName === globalInput.parameterName ).displayName } :{" "} {globalInput.value !== "" ? globalInput.value : Constants.TEXT_EMPTY_PLACEHOLDER}
); } )}
) : null} } > {" "}
{currentGroupTask.Description}
); } return ""; })}
); } function InputRequiredHandler({ webSocketContext, currentGroupTask, groupTaskParameters, groupTaskStepInputs, notificationApi, step, taskLockedByUserId, }) { const { t } = useTranslation(); const [inputFields, setInputFields] = useState({}); const globalInputs = JSON.parse(currentGroupTask.GlobalInputs); const stepInputs = JSON.parse(groupTaskStepInputs); const getDefaultValue = (groupTaskParameter) => { if (stepInputs !== false) { const stepInput = stepInputs.find( (stepInput) => stepInput.parameterName === groupTaskParameter.parameterName )?.value; if (stepInput) { return stepInput; } } if (globalInputs === undefined || !groupTaskParameter.global) return null; const globalInputValue = globalInputs.find( (globalInput) => globalInput.parameterName === groupTaskParameter.parameterName ); return globalInputValue !== undefined ? globalInputValue.value : ""; }; const getLabel = (displayName, groupTaskParameter) => { return groupTaskParameter.global ? ( <> {displayName} {t("groupTasks.tag.global")} ) : ( displayName ); }; let lastChange = useRef(); let typingTimer = useRef(); const sendTypingMessage = ( currentGroupTaskId, groupTaskParameterName, inputValue ) => { webSocketContext.SendSocketMessage(SentMessagesCommands.TaskLocking, { element: `${currentGroupTaskId}-${step}-${groupTaskParameterName}`, lockedByUserId: getUserId(), groupTaskId: currentGroupTaskId, parameterName: groupTaskParameterName, value: inputValue, step: step, rememberId: GroupTasksStepsLockedAndUserUpdateInputValueRememberId, }); }; const onInputChange = ( inputValue, currentGroupTaskId, groupTaskParameterName ) => { setInputFields((fields) => { return ({ ...fields }[groupTaskParameterName] = inputValue === null ? "" : inputValue); }); if (taskLockedByUserId !== "") return; if (Date.now() >= lastChange.current || lastChange.current === undefined) { lastChange.current = Date.now() + 1000; sendTypingMessage(currentGroupTaskId, groupTaskParameterName, inputValue); } else { clearTimeout(typingTimer.current); } typingTimer.current = setTimeout( () => sendTypingMessage( currentGroupTaskId, groupTaskParameterName, inputValue ), 1000 ); }; 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 ) } value={inputFields[groupTaskParameter.parameterName]} /> ); case "textarea": return (