OutcomeOfApprovalVerdict should now be working
This commit is contained in:
parent
a3430d221d
commit
fb09052476
@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"Approved": "Схвалено",
|
"Approved": "Схвалено",
|
||||||
"ApprovedWithComments": "Схвалено з коментарями",
|
"ApprovedWithComments": "Схвалено з коментарями",
|
||||||
|
"None": "Ніхто.",
|
||||||
"Pending": "У підготовці.",
|
"Pending": "У підготовці.",
|
||||||
"Rejected": "Відхилено",
|
"Rejected": "Відхилено",
|
||||||
"Reviewed": "Оглянуто."
|
"Reviewed": "Оглянуто."
|
||||||
|
|||||||
@ -42,7 +42,7 @@ export interface InputProps {
|
|||||||
placeHolder?: string;
|
placeHolder?: string;
|
||||||
readOnly?: boolean;
|
readOnly?: boolean;
|
||||||
type: InputType;
|
type: InputType;
|
||||||
value?: string | number | readonly string[] | undefined;
|
value?: string | number | readonly string[] | boolean | undefined;
|
||||||
defaultValue?: string | number | readonly string[] | undefined;
|
defaultValue?: string | number | readonly string[] | undefined;
|
||||||
min?: number;
|
min?: number;
|
||||||
max?: number;
|
max?: number;
|
||||||
@ -56,6 +56,7 @@ export interface InputProps {
|
|||||||
) => void;
|
) => void;
|
||||||
maxLength?: number;
|
maxLength?: number;
|
||||||
options?: { value: string; label: string }[];
|
options?: { value: string; label: string }[];
|
||||||
|
title: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
function Input(props: InputProps) {
|
function Input(props: InputProps) {
|
||||||
@ -74,6 +75,7 @@ function Input(props: InputProps) {
|
|||||||
autoComplete,
|
autoComplete,
|
||||||
onChange,
|
onChange,
|
||||||
options,
|
options,
|
||||||
|
title,
|
||||||
...rest
|
...rest
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
@ -88,7 +90,7 @@ function Input(props: InputProps) {
|
|||||||
const [showPasswordIcon, setShowPasswordIcon] = useState(faEyeSlash);
|
const [showPasswordIcon, setShowPasswordIcon] = useState(faEyeSlash);
|
||||||
|
|
||||||
if (type === InputType.checkbox) {
|
if (type === InputType.checkbox) {
|
||||||
checked = value === String(true);
|
checked = value === true || value === "true";
|
||||||
showValue = undefined;
|
showValue = undefined;
|
||||||
divClassName = "form-check allignedCheckBox";
|
divClassName = "form-check allignedCheckBox";
|
||||||
className = "form-check-input";
|
className = "form-check-input";
|
||||||
@ -154,7 +156,12 @@ function Input(props: InputProps) {
|
|||||||
return (
|
return (
|
||||||
<div className={divClassName} hidden={hidden}>
|
<div className={divClassName} hidden={hidden}>
|
||||||
{(includeLabel === true || includeLabel === undefined) && (
|
{(includeLabel === true || includeLabel === undefined) && (
|
||||||
<label className={labelClassName} htmlFor={name} hidden={hidden}>
|
<label
|
||||||
|
className={labelClassName}
|
||||||
|
htmlFor={name}
|
||||||
|
hidden={hidden}
|
||||||
|
title={title}
|
||||||
|
>
|
||||||
{label}
|
{label}
|
||||||
</label>
|
</label>
|
||||||
)}
|
)}
|
||||||
@ -178,6 +185,7 @@ function Input(props: InputProps) {
|
|||||||
defaultValue={defaultValue}
|
defaultValue={defaultValue}
|
||||||
maxLength={maxLength! > 0 ? maxLength : undefined}
|
maxLength={maxLength! > 0 ? maxLength : undefined}
|
||||||
autoComplete={autoComplete}
|
autoComplete={autoComplete}
|
||||||
|
title={title}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|||||||
@ -1,8 +1,10 @@
|
|||||||
import Button, { ButtonType } from "../../../../../components/common/Button";
|
import Button, { ButtonType } from "../../../../../components/common/Button";
|
||||||
import ErrorBlock from "../../../../../components/common/ErrorBlock";
|
import ErrorBlock from "../../../../../components/common/ErrorBlock";
|
||||||
|
import { InputType } from "../../../../../components/common/Input";
|
||||||
import VerdictPicker from "../../../../../components/pickers/VerdictPicker";
|
import VerdictPicker from "../../../../../components/pickers/VerdictPicker";
|
||||||
import ValidationErrorIcon from "../../../../../components/validationErrorIcon";
|
import ValidationErrorIcon from "../../../../../components/validationErrorIcon";
|
||||||
import { TaskDefinition } from "../../services/WorkflowTemplateService";
|
import { TaskDefinition } from "../../services/WorkflowTemplateService";
|
||||||
|
import { renderTaskField } from "../taskEditorHelpers";
|
||||||
import TaskPicker from "../TaskPicker";
|
import TaskPicker from "../TaskPicker";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@ -27,6 +29,7 @@ export const outcomeEditor: React.FC<CapabilityEditorProps> = (props) => {
|
|||||||
task: null,
|
task: null,
|
||||||
});
|
});
|
||||||
clone.config.outcomeActions = list;
|
clone.config.outcomeActions = list;
|
||||||
|
clone.config.overrideDefaultTaskProgression = false;
|
||||||
onChange(clone);
|
onChange(clone);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,82 +54,98 @@ export const outcomeEditor: React.FC<CapabilityEditorProps> = (props) => {
|
|||||||
const otherTasks = tasks.filter((t) => (t.config.guid as string) !== guid);
|
const otherTasks = tasks.filter((t) => (t.config.guid as string) !== guid);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<>
|
||||||
<table>
|
<div>
|
||||||
<thead>
|
<table>
|
||||||
<tr>
|
<thead>
|
||||||
<th></th>
|
<tr>
|
||||||
<th>Verdict</th>
|
<th></th>
|
||||||
<th>Task</th>
|
<th>Verdict</th>
|
||||||
<th>
|
<th>Task</th>
|
||||||
<Button onClick={addOutcome} buttonType={ButtonType.secondary}>
|
<th>
|
||||||
Add Outcome
|
<Button onClick={addOutcome} buttonType={ButtonType.secondary}>
|
||||||
</Button>
|
Add Outcome
|
||||||
</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{outcomeActions.map((outcomeAction, index) => (
|
|
||||||
<tr key={index} className="align-top">
|
|
||||||
<td className="form-group">
|
|
||||||
<ValidationErrorIcon
|
|
||||||
visible={
|
|
||||||
!!fieldErrors?.[
|
|
||||||
`${guid}.outcomeActions[${index}].verdict`
|
|
||||||
] ||
|
|
||||||
!!fieldErrors?.[`${guid}.outcomeActions[${index}].task`]
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<VerdictPicker
|
|
||||||
includeLabel={false}
|
|
||||||
name="verdict"
|
|
||||||
label="Verdict"
|
|
||||||
value={outcomeAction.verdict}
|
|
||||||
error={
|
|
||||||
fieldErrors?.[`${guid}.outcomeActions[${index}].verdict`]
|
|
||||||
}
|
|
||||||
onChange={(name: string, val: string) =>
|
|
||||||
updateOutcome(index, { ...outcomeAction, verdict: val })
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<TaskPicker
|
|
||||||
includeLabel={false}
|
|
||||||
name="task"
|
|
||||||
label="Task"
|
|
||||||
value={(outcomeAction.task as string) ?? null}
|
|
||||||
tasks={otherTasks}
|
|
||||||
error={fieldErrors?.[`${guid}.outcomeActions[${index}].task`]}
|
|
||||||
onChange={(name, val) =>
|
|
||||||
updateOutcome(index, { ...outcomeAction, task: val })
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</td>
|
|
||||||
<td className="form-group">
|
|
||||||
<Button
|
|
||||||
onClick={() => removeOutcome(index)}
|
|
||||||
buttonType={ButtonType.secondary}
|
|
||||||
>
|
|
||||||
Remove
|
|
||||||
</Button>
|
</Button>
|
||||||
</td>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
))}
|
</thead>
|
||||||
</tbody>
|
<tbody>
|
||||||
</table>
|
{outcomeActions.map((outcomeAction, index) => (
|
||||||
<ErrorBlock
|
<tr key={index} className="align-top">
|
||||||
error={Object.values(fieldErrors ?? {})
|
<td className="form-group">
|
||||||
.filter((_, i) =>
|
<ValidationErrorIcon
|
||||||
Object.keys(fieldErrors ?? {}).some(
|
visible={
|
||||||
(key) => key === `${guid}.outcomeActions[${i}]`,
|
!!fieldErrors?.[
|
||||||
),
|
`${guid}.outcomeActions[${index}].verdict`
|
||||||
)
|
] ||
|
||||||
.join("; ")}
|
!!fieldErrors?.[`${guid}.outcomeActions[${index}].task`]
|
||||||
/>
|
}
|
||||||
</div>
|
/>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<VerdictPicker
|
||||||
|
includeLabel={false}
|
||||||
|
name="verdict"
|
||||||
|
label="Verdict"
|
||||||
|
value={outcomeAction.verdict}
|
||||||
|
error={
|
||||||
|
fieldErrors?.[`${guid}.outcomeActions[${index}].verdict`]
|
||||||
|
}
|
||||||
|
onChange={(name: string, val: string) =>
|
||||||
|
updateOutcome(index, { ...outcomeAction, verdict: val })
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<TaskPicker
|
||||||
|
includeLabel={false}
|
||||||
|
name="task"
|
||||||
|
label="Task"
|
||||||
|
value={(outcomeAction.task as string) ?? null}
|
||||||
|
tasks={otherTasks}
|
||||||
|
error={
|
||||||
|
fieldErrors?.[`${guid}.outcomeActions[${index}].task`]
|
||||||
|
}
|
||||||
|
onChange={(name, val) =>
|
||||||
|
updateOutcome(index, { ...outcomeAction, task: val })
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</td>
|
||||||
|
<td className="form-group">
|
||||||
|
<Button
|
||||||
|
onClick={() => removeOutcome(index)}
|
||||||
|
buttonType={ButtonType.secondary}
|
||||||
|
>
|
||||||
|
Remove
|
||||||
|
</Button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<ErrorBlock
|
||||||
|
error={Object.values(fieldErrors ?? {})
|
||||||
|
.filter((_, i) =>
|
||||||
|
Object.keys(fieldErrors ?? {}).some(
|
||||||
|
(key) => key === `${guid}.outcomeActions[${i}]`,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.join("; ")}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{renderTaskField(
|
||||||
|
task,
|
||||||
|
onChange,
|
||||||
|
"overrideDefaultTaskProgression",
|
||||||
|
"Override Default Task Progression",
|
||||||
|
InputType.checkbox,
|
||||||
|
fieldErrors,
|
||||||
|
undefined, //placeholder
|
||||||
|
undefined, //maxLength
|
||||||
|
undefined, //extraProps
|
||||||
|
"Checking this will override the default task progression, allowing manual control over task flow. If unchecked, the default task progression will be followed if no outcome actions are triggered.", //title
|
||||||
|
)}
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -178,7 +197,9 @@ export function defaultsAssignment(
|
|||||||
task: TaskDefinition,
|
task: TaskDefinition,
|
||||||
tasks: TaskDefinition[],
|
tasks: TaskDefinition[],
|
||||||
ctx: defaultsContext,
|
ctx: defaultsContext,
|
||||||
) {}
|
) {
|
||||||
|
task.config.overrideDefaultTaskProgression = true;
|
||||||
|
}
|
||||||
|
|
||||||
export const outcomeOfApprovalVerdictRegistryEntry: capabilityEditorRegistryEntry =
|
export const outcomeOfApprovalVerdictRegistryEntry: capabilityEditorRegistryEntry =
|
||||||
{
|
{
|
||||||
|
|||||||
@ -13,21 +13,31 @@ export const renderTaskField = (
|
|||||||
extraProps?: {
|
extraProps?: {
|
||||||
options?: { value: string; label: string }[];
|
options?: { value: string; label: string }[];
|
||||||
},
|
},
|
||||||
|
title?: string,
|
||||||
) => {
|
) => {
|
||||||
const handleChange = (
|
const handleChange = (
|
||||||
e: React.ChangeEvent<
|
e: React.ChangeEvent<
|
||||||
HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement
|
HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement
|
||||||
>,
|
>,
|
||||||
) => {
|
) => {
|
||||||
const newValue = e.target.value;
|
let newValue: string | boolean;
|
||||||
|
|
||||||
onChange({
|
if (type === InputType.checkbox) {
|
||||||
...task,
|
newValue = (e.target as HTMLInputElement).checked;
|
||||||
|
} else {
|
||||||
|
newValue = e.target.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
const clone = structuredClone(task);
|
||||||
|
const updated = {
|
||||||
|
...clone,
|
||||||
config: {
|
config: {
|
||||||
...task.config,
|
...clone.config,
|
||||||
[field]: newValue,
|
[field]: newValue,
|
||||||
},
|
},
|
||||||
});
|
};
|
||||||
|
|
||||||
|
onChange(updated);
|
||||||
};
|
};
|
||||||
|
|
||||||
return renderTaskInput(
|
return renderTaskInput(
|
||||||
@ -41,13 +51,14 @@ export const renderTaskField = (
|
|||||||
placeholder ?? "",
|
placeholder ?? "",
|
||||||
maxLength ?? 0,
|
maxLength ?? 0,
|
||||||
extraProps,
|
extraProps,
|
||||||
|
title,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const renderTaskInput = (
|
export const renderTaskInput = (
|
||||||
name: string,
|
name: string,
|
||||||
label: string,
|
label: string,
|
||||||
value: string | number | readonly string[] | undefined,
|
value: string | number | readonly string[] | boolean | undefined,
|
||||||
error: string | undefined,
|
error: string | undefined,
|
||||||
type: InputType = InputType.text,
|
type: InputType = InputType.text,
|
||||||
onChange: (
|
onChange: (
|
||||||
@ -59,6 +70,7 @@ export const renderTaskInput = (
|
|||||||
extraProps?: {
|
extraProps?: {
|
||||||
options?: { value: string; label: string }[];
|
options?: { value: string; label: string }[];
|
||||||
},
|
},
|
||||||
|
title?: string,
|
||||||
) => {
|
) => {
|
||||||
const normalisedValue =
|
const normalisedValue =
|
||||||
type === InputType.multiselect
|
type === InputType.multiselect
|
||||||
@ -77,6 +89,7 @@ export const renderTaskInput = (
|
|||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
readOnly={readOnly}
|
readOnly={readOnly}
|
||||||
placeHolder={placeholder}
|
placeHolder={placeholder}
|
||||||
|
title={title}
|
||||||
{...extraProps}
|
{...extraProps}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user