919 lines
30 KiB
JavaScript
919 lines
30 KiB
JavaScript
import {
|
|
Alert,
|
|
Button,
|
|
Form,
|
|
Input,
|
|
InputNumber,
|
|
Popover,
|
|
Space,
|
|
Steps,
|
|
Tag,
|
|
notification,
|
|
} from "antd";
|
|
import { useEffect, useRef, useState } from "react";
|
|
import { useNavigate, useParams } from "react-router-dom";
|
|
import {
|
|
Constants,
|
|
FormatDatetime,
|
|
GetDuration,
|
|
getUserId,
|
|
hasXYPermission,
|
|
myFetch,
|
|
} from "../../../utils";
|
|
import {
|
|
CheckOutlined,
|
|
InfoCircleOutlined,
|
|
LockOutlined,
|
|
RetweetOutlined,
|
|
UndoOutlined,
|
|
} from "@ant-design/icons";
|
|
|
|
import TextArea from "antd/es/input/TextArea";
|
|
import { useTranslation } from "react-i18next";
|
|
import { MyAvatar } from "../../../Components/MyAvatar";
|
|
import MyModal, { MyNotFoundModalContent } from "../../../Components/MyModal";
|
|
import MyAttachments from "../../../Components/MyAttachments";
|
|
import { useWebSocketContext } from "../../../Contexts/WebSocketContext";
|
|
import { useGroupTasksContext } from "../../../Contexts/GroupTasksContext";
|
|
import { useAppContext } from "../../../Contexts/AppContext";
|
|
import {
|
|
GroupTasksStepsLockedAndUserUpdateInputValueRememberId,
|
|
SentMessagesCommands,
|
|
} from "../../../Handlers/WebSocketMessageHandler";
|
|
|
|
export default function GroupTasksViewModal({ isOpen }) {
|
|
const webSocketContext = useWebSocketContext();
|
|
const appContext = useAppContext();
|
|
const groupTasksContext = useGroupTasksContext();
|
|
const navigate = useNavigate();
|
|
const [notificationApi, notificationContextHolder] =
|
|
notification.useNotification();
|
|
let { paramCategory, paramGroupTaskId } = useParams();
|
|
const { t } = useTranslation();
|
|
const currentGroupTask = useRef(null);
|
|
|
|
const handleCancel = () => {
|
|
currentGroupTask.current = null;
|
|
navigate(`${Constants.ROUTE_PATHS.GROUP_TASKS}${paramCategory}`);
|
|
};
|
|
|
|
useEffect(() => {
|
|
if (!isOpen) return;
|
|
|
|
myFetch(
|
|
`/grouptasks/${paramCategory}/steps/${paramGroupTaskId}`,
|
|
"GET"
|
|
).then((data) => {
|
|
currentGroupTask.current = data.GroupTask;
|
|
groupTasksContext.setGroupTasksSteps(data.GroupTaskSteps);
|
|
});
|
|
}, [isOpen, paramCategory]);
|
|
|
|
if (!isOpen) return <></>;
|
|
|
|
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.current.Id,
|
|
category: currentGroupTask.current.Category,
|
|
groupId: currentGroupTask.current.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.current.Id,
|
|
category: currentGroupTask.current.Category,
|
|
groupId: currentGroupTask.current.GroupId,
|
|
step: step,
|
|
taskStepId: taskStepId,
|
|
taskInputs: taskInputs,
|
|
}
|
|
);
|
|
};
|
|
|
|
const handleUserActionTaskStep = (action, taskStepId, step) => {
|
|
webSocketContext.SendSocketMessage(
|
|
SentMessagesCommands.HandleUserActionTaskStep,
|
|
{
|
|
action: action,
|
|
groupTaskId: currentGroupTask.current.Id,
|
|
category: currentGroupTask.current.Category,
|
|
groupId: currentGroupTask.current.GroupId,
|
|
step: step,
|
|
taskStepId: taskStepId,
|
|
}
|
|
);
|
|
};
|
|
|
|
const ActionHandler = ({ status, taskStepId, index, taskLocked }) => {
|
|
const currentStepTask = groupTasksContext.categoryGroup.groups.find(
|
|
(group) => group.id === currentGroupTask.current.GroupId
|
|
).tasks[index];
|
|
|
|
switch (status) {
|
|
case Constants.GROUP_TASKS_STATUS.FAILED:
|
|
return (
|
|
<Button
|
|
size="small"
|
|
danger
|
|
disabled={taskLocked}
|
|
onClick={() =>
|
|
handleTaskFailedTryAgainRunTaskStep(taskStepId, index + 1)
|
|
}
|
|
>
|
|
{t("common.button.tryAgain")}
|
|
</Button>
|
|
);
|
|
case Constants.GROUP_TASKS_STATUS.INPUT_REQUIRED:
|
|
return (
|
|
<Button
|
|
size="small"
|
|
disabled={taskLocked}
|
|
onClick={() => handleTaskContinueTaskStep(taskStepId, index + 1)}
|
|
>
|
|
{t("common.button.continue")}
|
|
</Button>
|
|
);
|
|
case Constants.GROUP_TASKS_STATUS.PAUSED:
|
|
return (
|
|
<Space>
|
|
{currentStepTask.repeatPossible && (
|
|
<Button
|
|
icon={<RetweetOutlined />}
|
|
size="small"
|
|
disabled={taskLocked}
|
|
onClick={() =>
|
|
handleUserActionTaskStep(2, taskStepId, index + 1)
|
|
}
|
|
>
|
|
{t("common.button.repeat")}
|
|
</Button>
|
|
)}
|
|
|
|
{currentStepTask.undoPossible && (
|
|
<Button
|
|
icon={<UndoOutlined />}
|
|
size="small"
|
|
disabled={taskLocked}
|
|
onClick={() =>
|
|
handleUserActionTaskStep(1, taskStepId, index + 1)
|
|
}
|
|
>
|
|
{t("common.button.undo")}
|
|
</Button>
|
|
)}
|
|
|
|
<Button
|
|
icon={<CheckOutlined />}
|
|
size="small"
|
|
type={
|
|
currentStepTask.repeatPossible && currentStepTask.undoPossible
|
|
? "primary"
|
|
: "default"
|
|
}
|
|
disabled={taskLocked}
|
|
onClick={() => handleUserActionTaskStep(0, taskStepId, index + 1)}
|
|
>
|
|
{t("common.button.resume")}
|
|
</Button>
|
|
</Space>
|
|
);
|
|
case Constants.GROUP_TASKS_STATUS.UNDO_ENDED:
|
|
return (
|
|
<Button
|
|
size="small"
|
|
disabled={taskLocked}
|
|
onClick={() => handleUserActionTaskStep(2, taskStepId, index + 1)}
|
|
>
|
|
{t("common.button.resume")}
|
|
</Button>
|
|
);
|
|
|
|
default:
|
|
return <></>;
|
|
}
|
|
};
|
|
|
|
const stepsItemHandler = () => {
|
|
let groupTaskSteps = [];
|
|
let groupTasks = [];
|
|
|
|
groupTasksContext.groupTasksSteps.forEach((step) => {
|
|
if (step.GroupTasksId === paramGroupTaskId) {
|
|
groupTaskSteps.push(step);
|
|
}
|
|
});
|
|
|
|
groupTaskSteps.sort((a, b) => a.Step - b.Step);
|
|
|
|
groupTasksContext.categoryGroup.groups.forEach((group) => {
|
|
if (currentGroupTask.current.GroupId === group.id) {
|
|
groupTasks = group.tasks;
|
|
return;
|
|
}
|
|
});
|
|
|
|
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}{" "}
|
|
<Popover
|
|
key={groupTaskSteps[index].Id + index}
|
|
trigger="click"
|
|
placement="bottomLeft"
|
|
title={
|
|
<h2
|
|
style={{
|
|
fontWeight: "bold",
|
|
color: Constants.COLORS.SECONDARY,
|
|
}}
|
|
>
|
|
{t(
|
|
"groupTasks.groupTasksViewModal.popover.specifiedTaskInputs"
|
|
)}
|
|
</h2>
|
|
}
|
|
content={
|
|
<>
|
|
{groupTask.parameters.length > 0 &&
|
|
groupTask.parameters.map((task) => {
|
|
return (
|
|
<span key={task.parameterName}>
|
|
<span style={{ fontWeight: "bold" }}>
|
|
{task.displayName}:{" "}
|
|
</span>
|
|
<span>
|
|
{
|
|
JSON.parse(groupTaskSteps[index].Inputs).find(
|
|
(input) =>
|
|
input.parameterName === task.parameterName
|
|
)?.value
|
|
}
|
|
</span>
|
|
<br />
|
|
</span>
|
|
);
|
|
})}
|
|
</>
|
|
}
|
|
>
|
|
<InfoCircleOutlined
|
|
style={{
|
|
fontSize: "18px",
|
|
color: Constants.COLORS.ICON_INFO,
|
|
marginBottom: "4px",
|
|
verticalAlign: "middle",
|
|
}}
|
|
/>
|
|
</Popover>{" "}
|
|
{groupTaskSteps[index]?.CreatorUserId !== undefined && (
|
|
<MyAvatar
|
|
tooltip
|
|
allUsers={appContext.users}
|
|
userId={groupTaskSteps[index].CreatorUserId}
|
|
/>
|
|
)}
|
|
</>
|
|
) : (
|
|
<>
|
|
{groupTask.name}{" "}
|
|
{groupTaskSteps[index]?.CreatorUserId !== undefined && (
|
|
<MyAvatar
|
|
tooltip
|
|
allUsers={appContext.users}
|
|
userId={groupTaskSteps[index].CreatorUserId}
|
|
/>
|
|
)}
|
|
</>
|
|
),
|
|
status:
|
|
groupTaskSteps[index] !== undefined
|
|
? getStepItemStatus(groupTaskSteps[index].Status)
|
|
: "wait",
|
|
description:
|
|
groupTaskSteps[index] !== undefined ? (
|
|
<>
|
|
<p style={{ color: "#000" }}>
|
|
<b>ID:</b> {groupTaskSteps[index].Id}
|
|
<br />
|
|
<b>{t("groupTasks.groupTasksViewModal.startedAt")}:</b>{" "}
|
|
{FormatDatetime(groupTaskSteps[index].StartedAt)}
|
|
<br />
|
|
<b>{t("groupTasks.groupTasksViewModal.endedAt")}:</b>{" "}
|
|
{groupTaskSteps[index].EndedAt !== "0001-01-01T00:00:00Z"
|
|
? FormatDatetime(groupTaskSteps[index].EndedAt)
|
|
: Constants.TEXT_EMPTY_PLACEHOLDER}
|
|
<br />
|
|
<b>{t("groupTasks.groupTasksViewModal.duration")}:</b>{" "}
|
|
{GetDuration(
|
|
groupTaskSteps[index].StartedAt,
|
|
groupTaskSteps[index].EndedAt
|
|
)}
|
|
</p>
|
|
|
|
<Alert
|
|
style={{ width: "100%" }}
|
|
message={
|
|
<div
|
|
style={{
|
|
display: "flex",
|
|
justifyContent: "space-between",
|
|
}}
|
|
>
|
|
<b>
|
|
{getAlertMessage(groupTaskSteps[index].Status)}{" "}
|
|
{groupTaskSteps[index].LockedByUserId !== "" && (
|
|
<>
|
|
<LockOutlined />{" "}
|
|
<MyAvatar
|
|
tooltip
|
|
allUsers={appContext.users}
|
|
userId={groupTaskSteps[index].LockedByUserId}
|
|
avatarWidth={24}
|
|
/>
|
|
</>
|
|
)}
|
|
</b>
|
|
<ActionHandler
|
|
status={groupTaskSteps[index].Status}
|
|
index={index}
|
|
taskLocked={groupTaskSteps[index].LockedByUserId}
|
|
taskStepId={groupTaskSteps[index].Id}
|
|
/>
|
|
</div>
|
|
}
|
|
description={
|
|
groupTaskSteps[index].Status ===
|
|
Constants.GROUP_TASKS_STATUS.INPUT_REQUIRED ? (
|
|
<div id={`${currentGroupTask.current.Id}-scroll-${index}`}>
|
|
<InputRequiredHandler
|
|
webSocketContext={webSocketContext}
|
|
currentGroupTask={currentGroupTask.current}
|
|
groupTaskParameters={groupTask.parameters}
|
|
groupTaskStepInputs={
|
|
groupTaskSteps[index] !== undefined &&
|
|
groupTaskSteps[index].Inputs !== "" &&
|
|
groupTaskSteps[index].Inputs
|
|
}
|
|
notificationApi={notificationApi}
|
|
step={index + 1}
|
|
taskLockedByUserId={
|
|
groupTaskSteps[index].LockedByUserId
|
|
}
|
|
/>
|
|
</div>
|
|
) : (
|
|
groupTaskSteps[index].Log.length > 0 && (
|
|
<div
|
|
id={`${currentGroupTask.current.Id}-scroll-${index}`}
|
|
style={{ width: "100%" }}
|
|
>
|
|
<GroupTaskStepLogHandler
|
|
currentGroupTaskId={currentGroupTask.current.Id}
|
|
log={groupTaskSteps[index].Log}
|
|
files={groupTaskSteps[index].Files}
|
|
/>
|
|
</div>
|
|
)
|
|
)
|
|
}
|
|
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.current.NumberOfSteps > groupTasks.length) {
|
|
for (
|
|
let i = groupTasks.length;
|
|
i < currentGroupTask.current.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 (
|
|
<MyModal isOpen={isOpen} onCancel={handleCancel}>
|
|
{notificationContextHolder}
|
|
|
|
{!currentGroupTask.current ||
|
|
!hasXYPermission(
|
|
appContext.userPermissions,
|
|
Constants.PERMISSIONS.GROUP_TASKS.OVERVIEW.XYView,
|
|
currentGroupTask.current.Category
|
|
) ? (
|
|
<MyNotFoundModalContent
|
|
resultTitle={t("groupTasks.groupTasksViewModal.groupTaskNotFound")}
|
|
/>
|
|
) : (
|
|
<div key={paramGroupTaskId}>
|
|
<h1
|
|
style={{
|
|
color: Constants.COLORS.PRIMARY,
|
|
fontWeight: "bold",
|
|
marginBottom: 0,
|
|
}}
|
|
>
|
|
{currentGroupTask.current.GroupName}{" "}
|
|
<Popover
|
|
trigger="click"
|
|
title={
|
|
<h2
|
|
style={{
|
|
fontWeight: "bold",
|
|
color: Constants.COLORS.SECONDARY,
|
|
}}
|
|
>
|
|
{t("groupTasks.groupTasksViewModal.popover.details")}
|
|
</h2>
|
|
}
|
|
content={
|
|
<>
|
|
<p>
|
|
<span style={{ fontWeight: "bold" }}>ID:</span>{" "}
|
|
{paramGroupTaskId} <br />
|
|
<span style={{ fontWeight: "bold" }}>
|
|
{t("groupTasks.groupTasksViewModal.category")}:
|
|
</span>{" "}
|
|
{currentGroupTask.current.Category}
|
|
<br />
|
|
<span style={{ fontWeight: "bold" }}>
|
|
{t("groupTasks.groupTasksViewModal.startedAt")}:
|
|
</span>{" "}
|
|
{FormatDatetime(currentGroupTask.current.StartedAt)}
|
|
<br />
|
|
<span style={{ fontWeight: "bold" }}>
|
|
{t("groupTasks.groupTasksViewModal.endedAt")}:
|
|
</span>{" "}
|
|
{FormatDatetime(currentGroupTask.current.EndedAt)}
|
|
<br />
|
|
<span style={{ fontWeight: "bold" }}>
|
|
{t("groupTasks.groupTasksViewModal.duration")}:
|
|
</span>{" "}
|
|
{GetDuration(
|
|
currentGroupTask.current.StartedAt,
|
|
currentGroupTask.current.EndedAt
|
|
)}
|
|
</p>
|
|
|
|
{currentGroupTask.current.GlobalInputs !== "[]" ? (
|
|
<>
|
|
<h2
|
|
style={{
|
|
fontWeight: "bold",
|
|
color: Constants.COLORS.SECONDARY,
|
|
}}
|
|
>
|
|
{t(
|
|
"groupTasks.groupTasksViewModal.popover.specifiedGlobalInputs"
|
|
)}
|
|
</h2>
|
|
|
|
<span>
|
|
{JSON.parse(currentGroupTask.current.GlobalInputs).map(
|
|
(globalInput) => {
|
|
return (
|
|
<span
|
|
key={
|
|
globalInput.parameterName + globalInput.value
|
|
}
|
|
>
|
|
<span style={{ fontWeight: "bold" }}>
|
|
{
|
|
groupTasksContext.categoryGroup.groups
|
|
.find(
|
|
(group) =>
|
|
group.id ===
|
|
currentGroupTask.current.GroupId
|
|
)
|
|
.globalInputs.find(
|
|
(gI) =>
|
|
gI.parameterName ===
|
|
globalInput.parameterName
|
|
).displayName
|
|
}
|
|
:{" "}
|
|
</span>
|
|
<span>
|
|
{globalInput.value !== ""
|
|
? globalInput.value
|
|
: Constants.TEXT_EMPTY_PLACEHOLDER}
|
|
</span>
|
|
<br />
|
|
</span>
|
|
);
|
|
}
|
|
)}
|
|
</span>
|
|
</>
|
|
) : null}
|
|
</>
|
|
}
|
|
>
|
|
<InfoCircleOutlined
|
|
style={{
|
|
fontSize: "18px",
|
|
color: Constants.COLORS.ICON_INFO,
|
|
marginBottom: "4px",
|
|
verticalAlign: "middle",
|
|
}}
|
|
/>
|
|
</Popover>{" "}
|
|
<MyAvatar
|
|
tooltip
|
|
allUsers={appContext.users}
|
|
userId={currentGroupTask.current.CreatorUserId}
|
|
/>
|
|
<br />
|
|
</h1>
|
|
<div style={{ marginBottom: 16 }}>
|
|
<span>{currentGroupTask.current.Description}</span>
|
|
</div>
|
|
|
|
<Steps direction="vertical" items={stepsItemHandler()} />
|
|
</div>
|
|
)}
|
|
</MyModal>
|
|
);
|
|
}
|
|
|
|
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}
|
|
<Tag style={{ marginLeft: 6 }} color="purple">
|
|
{t("groupTasks.tag.global")}
|
|
</Tag>
|
|
</>
|
|
) : (
|
|
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 (
|
|
<Form layout="vertical" id="groupTasksViewModalRequiredInputsForm">
|
|
{groupTaskParameters.map((groupTaskParameter) => {
|
|
switch (groupTaskParameter.type) {
|
|
case "text":
|
|
return (
|
|
<Form.Item
|
|
key={"fitem-" + groupTaskParameter.parameterName}
|
|
label={getLabel(
|
|
groupTaskParameter.displayName,
|
|
groupTaskParameter
|
|
)}
|
|
required
|
|
>
|
|
<Input
|
|
id={`${currentGroupTask.Id}-${step}-${groupTaskParameter.parameterName}`}
|
|
defaultValue={getDefaultValue(groupTaskParameter)}
|
|
disabled={taskLockedByUserId !== ""}
|
|
onChange={(e) =>
|
|
onInputChange(
|
|
e.target.value,
|
|
currentGroupTask.Id,
|
|
groupTaskParameter.parameterName
|
|
)
|
|
}
|
|
value={inputFields[groupTaskParameter.parameterName]}
|
|
/>
|
|
</Form.Item>
|
|
);
|
|
case "number":
|
|
return (
|
|
<Form.Item
|
|
key={"fitem-" + groupTaskParameter.parameterName}
|
|
label={getLabel(
|
|
groupTaskParameter.displayName,
|
|
groupTaskParameter
|
|
)}
|
|
required
|
|
>
|
|
<InputNumber
|
|
id={`${currentGroupTask.Id}-${step}-${groupTaskParameter.parameterName}`}
|
|
style={{ width: "100%" }}
|
|
defaultValue={getDefaultValue(groupTaskParameter)}
|
|
disabled={taskLockedByUserId !== ""}
|
|
max={Number.MAX_SAFE_INTEGER}
|
|
onChange={(e) =>
|
|
onInputChange(
|
|
e,
|
|
currentGroupTask.Id,
|
|
groupTaskParameter.parameterName
|
|
)
|
|
}
|
|
value={inputFields[groupTaskParameter.parameterName]}
|
|
/>
|
|
</Form.Item>
|
|
);
|
|
case "textarea":
|
|
return (
|
|
<Form.Item
|
|
key={"fitem-" + groupTaskParameter.parameterName}
|
|
label={getLabel(
|
|
groupTaskParameter.displayName,
|
|
groupTaskParameter
|
|
)}
|
|
required
|
|
>
|
|
<TextArea
|
|
id={`${currentGroupTask.Id}-${step}-${groupTaskParameter.parameterName}`}
|
|
defaultValue={getDefaultValue(groupTaskParameter)}
|
|
disabled={taskLockedByUserId !== ""}
|
|
onChange={(e) =>
|
|
onInputChange(
|
|
e.target.value,
|
|
currentGroupTask.Id,
|
|
groupTaskParameter.parameterName
|
|
)
|
|
}
|
|
value={inputFields[groupTaskParameter.parameterName]}
|
|
/>
|
|
</Form.Item>
|
|
);
|
|
default:
|
|
notificationApi["error"]({
|
|
message: t(
|
|
"groupTasks.groupTasksViewModal.notification.groupTaskParameterNotImplemented.message",
|
|
{ groupTaskParameterType: groupTaskParameter.type }
|
|
),
|
|
description: t(
|
|
"groupTasks.groupTasksViewModal.notification.groupTaskParameterNotImplemented.description",
|
|
{
|
|
groupTaskParameterDisplayName: groupTaskParameter.displayName,
|
|
}
|
|
),
|
|
});
|
|
return (
|
|
<p>
|
|
Type <b>{groupTaskParameter.type}</b> not implemented. Was
|
|
specified in: <b>{groupTaskParameter.displayName}</b>
|
|
</p>
|
|
);
|
|
}
|
|
})}
|
|
</Form>
|
|
);
|
|
}
|
|
|
|
function GroupTaskStepLogHandler({ currentGroupTaskId, log, files }) {
|
|
return (
|
|
<span style={{ whiteSpace: "pre-line" }}>
|
|
{log}
|
|
{files !== "" && files !== " " && (
|
|
<MyAttachments
|
|
attachments={JSON.parse(files)}
|
|
downloadUrl={`${Constants.STATIC_CONTENT_ADDRESS}grouptasks/${currentGroupTaskId}/`}
|
|
/>
|
|
)}
|
|
</span>
|
|
);
|
|
}
|