Started working on the assignments editor
This commit is contained in:
parent
0130a578ea
commit
3cc7a42f57
@ -11,6 +11,7 @@ interface UserPickerProps {
|
||||
value: any;
|
||||
domain?: GeneralIdRef;
|
||||
onChange?: (name: string, value: GeneralIdRef) => void;
|
||||
includeLabel?: boolean;
|
||||
}
|
||||
|
||||
export default function UserPicker({
|
||||
@ -20,6 +21,7 @@ export default function UserPicker({
|
||||
value,
|
||||
domain,
|
||||
onChange,
|
||||
includeLabel = true,
|
||||
}: UserPickerProps) {
|
||||
const [options, setOptions] = useState<Option[] | undefined>(undefined);
|
||||
|
||||
@ -59,6 +61,7 @@ export default function UserPicker({
|
||||
options={options}
|
||||
includeBlankFirstEntry={true}
|
||||
onChange={handleChange}
|
||||
includeLabel={includeLabel}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@ -104,7 +104,11 @@ const WorkflowTemplateDetails: React.FC<{ editMode: boolean }> = ({
|
||||
// -----------------------------
|
||||
const doSubmit = async (buttonName: string) => {
|
||||
try {
|
||||
//const { name } = form.state.data;
|
||||
const { data } = form.state;
|
||||
|
||||
var json = JSON.stringify(data);
|
||||
|
||||
console.log("Submitting workflow template:", json);
|
||||
|
||||
if (editMode) {
|
||||
//await templateVersionsService.putTemplateVersion({ name });
|
||||
|
||||
@ -0,0 +1,214 @@
|
||||
import React from "react";
|
||||
import UserPicker from "../../../../../components/pickers/UserPicker";
|
||||
import { GeneralIdRef } from "../../../../../utils/GeneralIdRef";
|
||||
import { TaskDefinition } from "../../services/WorkflowTemplateService";
|
||||
import {
|
||||
CapabilityEditorProps,
|
||||
capabilityEditorRegistryEntry,
|
||||
defaultsContext,
|
||||
} from "../useCapabilityDefaults";
|
||||
import Button, { ButtonType } from "../../../../../components/common/Button";
|
||||
|
||||
// TODO: Replace with your real RolePicker and RaciPicker
|
||||
const RolePicker = (props: any) => (
|
||||
<div style={{ marginBottom: 8 }}>
|
||||
<input
|
||||
type="text"
|
||||
name={props.name}
|
||||
value={props.value?.id ?? ""}
|
||||
onChange={(e) =>
|
||||
props.onChange(props.name, { id: BigInt(e.target.value) })
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
const RaciPicker = (props: any) => (
|
||||
<div style={{ marginBottom: 8 }}>
|
||||
<select
|
||||
name={props.name}
|
||||
value={props.value}
|
||||
onChange={(e) => props.onChange(props.name, e.target.value)}
|
||||
>
|
||||
<option value="Responsible">Responsible</option>
|
||||
<option value="Accountable">Accountable</option>
|
||||
<option value="Consulted">Consulted</option>
|
||||
<option value="Informed">Informed</option>
|
||||
</select>
|
||||
</div>
|
||||
);
|
||||
|
||||
// ---------------------------
|
||||
// Domain Interfaces
|
||||
// ---------------------------
|
||||
|
||||
export interface ITaskAssignee {
|
||||
role?: GeneralIdRef | null;
|
||||
contact?: GeneralIdRef | null;
|
||||
raci: string; // Raci enum as string
|
||||
}
|
||||
|
||||
export interface IAssigneesCapability {
|
||||
assignees: ITaskAssignee[];
|
||||
}
|
||||
|
||||
// ---------------------------
|
||||
// Editor Component
|
||||
// ---------------------------
|
||||
|
||||
export const AssigneesOfITaskAssigneeEditor: React.FC<CapabilityEditorProps> = (
|
||||
props,
|
||||
) => {
|
||||
const { task, onChange, fieldErrors } = props;
|
||||
const assignees = (task.config.assignees ?? []) as ITaskAssignee[];
|
||||
|
||||
function updateAssignee(index: number, updated: ITaskAssignee) {
|
||||
const clone = structuredClone(task);
|
||||
const list = clone.config.assignees ?? [];
|
||||
list[index] = updated;
|
||||
clone.config.assignees = list;
|
||||
onChange(clone);
|
||||
}
|
||||
|
||||
function addAssignee() {
|
||||
const clone = structuredClone(task);
|
||||
const list = clone.config.assignees ?? [];
|
||||
list.push({
|
||||
role: null,
|
||||
contact: null,
|
||||
raci: "Responsible",
|
||||
});
|
||||
clone.config.assignees = list;
|
||||
onChange(clone);
|
||||
}
|
||||
|
||||
function removeAssignee(index: number) {
|
||||
const clone = structuredClone(task);
|
||||
const list = clone.config.assignees ?? [];
|
||||
clone.config.assignees = list.filter((_, i) => i !== index);
|
||||
onChange(clone);
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
Select assigness (you can select either a role or a contact)
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Role</th>
|
||||
<th>Contact</th>
|
||||
<th>RACI</th>
|
||||
<th>
|
||||
<Button onClick={addAssignee} buttonType={ButtonType.secondary}>
|
||||
Add Assignee
|
||||
</Button>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{assignees.map((assignee, index) => (
|
||||
<tr key={index}>
|
||||
<td>
|
||||
<RolePicker
|
||||
name="role"
|
||||
label="Role"
|
||||
value={assignee.role}
|
||||
error={fieldErrors?.[`assignees[${index}].role`]}
|
||||
onChange={(name: string, val: GeneralIdRef | null) =>
|
||||
updateAssignee(index, { ...assignee, role: val })
|
||||
}
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<UserPicker
|
||||
includeLabel={false}
|
||||
name="contact"
|
||||
label="Contact"
|
||||
value={assignee.contact}
|
||||
error={fieldErrors?.[`assignees[${index}].contact`]}
|
||||
onChange={(name: string, val: GeneralIdRef | null) =>
|
||||
updateAssignee(index, { ...assignee, contact: val })
|
||||
}
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<RaciPicker
|
||||
name="raci"
|
||||
label="RACI"
|
||||
value={assignee.raci}
|
||||
error={fieldErrors?.[`assignees[${index}].raci`]}
|
||||
onChange={(name: string, val: string) =>
|
||||
updateAssignee(index, { ...assignee, raci: val })
|
||||
}
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<Button
|
||||
onClick={() => removeAssignee(index)}
|
||||
buttonType={ButtonType.secondary}
|
||||
>
|
||||
Remove
|
||||
</Button>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
// ---------------------------
|
||||
// Validation
|
||||
// ---------------------------
|
||||
|
||||
const runValidation = (
|
||||
task: TaskDefinition,
|
||||
tasks: TaskDefinition[],
|
||||
): Record<string, string> => {
|
||||
const errors: Record<string, string> = {};
|
||||
const assignees = task.config.assignees as ITaskAssignee[] | undefined;
|
||||
|
||||
if (!assignees || assignees.length === 0) {
|
||||
errors["assignees"] = "At least one assignee is required.";
|
||||
return errors;
|
||||
}
|
||||
|
||||
assignees.forEach((a, i) => {
|
||||
if (!a.role && !a.contact) {
|
||||
//errors[`assignees[${i}]`] = "Either role or contact must be selected.";
|
||||
errors[`assignees`] = "Either role or contact must be selected.";
|
||||
}
|
||||
|
||||
if (!a.raci) {
|
||||
//errors[`assignees[${i}].raci`] = "RACI is required.";
|
||||
errors[`assignees`] = "RACI is required.";
|
||||
}
|
||||
});
|
||||
|
||||
return errors;
|
||||
};
|
||||
|
||||
// ---------------------------
|
||||
// Defaults Assignment
|
||||
// ---------------------------
|
||||
|
||||
export function defaultsAssignment(
|
||||
task: TaskDefinition,
|
||||
tasks: TaskDefinition[],
|
||||
ctx: defaultsContext,
|
||||
) {
|
||||
task.config.assignees = [{ raci: "Responsible" } as ITaskAssignee];
|
||||
//task.config.assignees = [];
|
||||
}
|
||||
|
||||
// ---------------------------
|
||||
// Registry Entry
|
||||
// ---------------------------
|
||||
|
||||
export const AssigneesOfITaskAssigneeRegistryEntry: capabilityEditorRegistryEntry =
|
||||
{
|
||||
Editor: AssigneesOfITaskAssigneeEditor,
|
||||
DefaultsAssignment: defaultsAssignment,
|
||||
ValidationRunner: runValidation,
|
||||
};
|
||||
@ -1,4 +1,5 @@
|
||||
import { tagsEditorRegistryEntry } from "./CapabilityEditors/TagsEditor";
|
||||
import { AssigneesOfITaskAssigneeRegistryEntry } from "./CapabilityEditors/AssigneesOfITaskAssigneeEditor";
|
||||
import { taskCoreEditorRegistryEntry } from "./CapabilityEditors/TaskCoreEditor";
|
||||
import { capabilityEditorRegistryEntry } from "./useCapabilityDefaults";
|
||||
|
||||
@ -8,4 +9,5 @@ export const capabilityEditorRegistry: Record<
|
||||
> = {
|
||||
ITask: taskCoreEditorRegistryEntry,
|
||||
ITags: tagsEditorRegistryEntry,
|
||||
"IAssignees<ITaskAssignee>": AssigneesOfITaskAssigneeRegistryEntry,
|
||||
};
|
||||
|
||||
Loading…
Reference in New Issue
Block a user