Started adding support for stages
This commit is contained in:
parent
70e4258071
commit
4706b78d88
@ -1,4 +1,5 @@
|
||||
{
|
||||
"High": "Élevé",
|
||||
"Low": "Faible"
|
||||
"Low": "Faible",
|
||||
"Normal": "Normalement"
|
||||
}
|
||||
@ -1,4 +1,5 @@
|
||||
{
|
||||
"High": "높은",
|
||||
"Low": "로우",
|
||||
"Normal": "정상"
|
||||
}
|
||||
@ -5,12 +5,34 @@ export interface SelectableListProps<T> {
|
||||
selectedValue?: T | null;
|
||||
renderLabel: (item: T) => React.ReactNode;
|
||||
onSelect: (item: T) => void;
|
||||
getChildren?: (item: T) => T[] | undefined;
|
||||
}
|
||||
|
||||
export const SelectableList = <T,>(
|
||||
props: SelectableListProps<T>,
|
||||
): JSX.Element => {
|
||||
const { items, selectedValue, renderLabel, onSelect } = props;
|
||||
const { items, selectedValue, renderLabel, onSelect, getChildren } = props;
|
||||
|
||||
const flattenedItems = React.useMemo(() => {
|
||||
const flattened: { item: T; depth: number }[] = [];
|
||||
|
||||
const walk = (source: T[], depth: number) => {
|
||||
source.forEach((item) => {
|
||||
flattened.push({ item, depth });
|
||||
|
||||
const children = getChildren?.(item) ?? [];
|
||||
if (children.length > 0) {
|
||||
walk(children, depth + 1);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
walk(items, 0);
|
||||
|
||||
return flattened;
|
||||
}, [items, getChildren]);
|
||||
|
||||
const flatItems = flattenedItems.map((entry) => entry.item);
|
||||
|
||||
const listRef = useRef<HTMLUListElement | null>(null);
|
||||
const isFocusedRef = useRef(false);
|
||||
@ -21,39 +43,41 @@ export const SelectableList = <T,>(
|
||||
const handleKeyDown = useCallback(
|
||||
(e: React.KeyboardEvent<HTMLUListElement>) => {
|
||||
if (!isFocusedRef.current) return;
|
||||
if (!items.length) return;
|
||||
if (!flatItems.length) return;
|
||||
|
||||
const currentIndex = selectedValue ? items.indexOf(selectedValue) : -1;
|
||||
const currentIndex = selectedValue
|
||||
? flatItems.indexOf(selectedValue)
|
||||
: -1;
|
||||
|
||||
if (e.key === "ArrowDown") {
|
||||
e.preventDefault();
|
||||
const nextIndex =
|
||||
currentIndex < items.length - 1 ? currentIndex + 1 : 0;
|
||||
onSelect(items[nextIndex]);
|
||||
currentIndex < flatItems.length - 1 ? currentIndex + 1 : 0;
|
||||
onSelect(flatItems[nextIndex]);
|
||||
}
|
||||
|
||||
if (e.key === "ArrowUp") {
|
||||
e.preventDefault();
|
||||
const prevIndex =
|
||||
currentIndex > 0 ? currentIndex - 1 : items.length - 1;
|
||||
onSelect(items[prevIndex]);
|
||||
currentIndex > 0 ? currentIndex - 1 : flatItems.length - 1;
|
||||
onSelect(flatItems[prevIndex]);
|
||||
}
|
||||
},
|
||||
[items, selectedValue, onSelect],
|
||||
[flatItems, selectedValue, onSelect],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isFocusedRef.current) return;
|
||||
if (!selectedValue) return;
|
||||
|
||||
const index = items.indexOf(selectedValue);
|
||||
const index = flatItems.indexOf(selectedValue);
|
||||
if (index < 0) return;
|
||||
|
||||
const el = itemRefs.current[index];
|
||||
if (el) {
|
||||
el.focus({ preventScroll: false });
|
||||
}
|
||||
}, [items, selectedValue]);
|
||||
}, [flatItems, selectedValue]);
|
||||
|
||||
// Separate effect for scrolling - only when selection changes
|
||||
useEffect(() => {
|
||||
@ -64,14 +88,14 @@ export const SelectableList = <T,>(
|
||||
|
||||
if (!selectedValue) return;
|
||||
|
||||
const index = items.indexOf(selectedValue);
|
||||
const index = flatItems.indexOf(selectedValue);
|
||||
if (index < 0) return;
|
||||
|
||||
const el = itemRefs.current[index];
|
||||
if (el) {
|
||||
el.scrollIntoView({ block: "nearest", behavior: "smooth" });
|
||||
}
|
||||
}, [selectedValue, items]);
|
||||
}, [selectedValue, flatItems]);
|
||||
|
||||
return (
|
||||
<ul
|
||||
@ -80,13 +104,13 @@ export const SelectableList = <T,>(
|
||||
tabIndex={0}
|
||||
role="listbox"
|
||||
aria-activedescendant={
|
||||
selectedValue ? `option-${items.indexOf(selectedValue)}` : undefined
|
||||
selectedValue ? `option-${flatItems.indexOf(selectedValue)}` : undefined
|
||||
}
|
||||
onFocus={() => (isFocusedRef.current = true)}
|
||||
onBlur={() => (isFocusedRef.current = false)}
|
||||
onKeyDown={handleKeyDown}
|
||||
>
|
||||
{items.map((item, index) => {
|
||||
{flattenedItems.map(({ item, depth }, index) => {
|
||||
const isSelected = selectedValue === item;
|
||||
const className = isSelected ? "selected" : "";
|
||||
|
||||
@ -100,6 +124,7 @@ export const SelectableList = <T,>(
|
||||
aria-selected={isSelected}
|
||||
onClick={() => onSelect(item)}
|
||||
className={className}
|
||||
style={{ paddingLeft: `${depth * 16}px` }}
|
||||
>
|
||||
{renderLabel(item)}
|
||||
</li>
|
||||
|
||||
@ -0,0 +1,91 @@
|
||||
import React, { useEffect } from "react";
|
||||
import templateVersionsService, {
|
||||
TaskDefinition,
|
||||
TaskMetadata,
|
||||
} from "../../services/WorkflowTemplateService";
|
||||
import AddTaskButton from "../AddTaskButton";
|
||||
import {
|
||||
CapabilityEditorProps,
|
||||
capabilityEditorRegistryEntry,
|
||||
defaultsContext,
|
||||
TaskValidationResult,
|
||||
useCapabilityDefaults,
|
||||
validateTask,
|
||||
} from "../useCapabilityDefaults";
|
||||
|
||||
export const StageOfGeneralTaskEditor: React.FC<CapabilityEditorProps> = (
|
||||
props,
|
||||
) => {
|
||||
const { task, onChange, onValidate, fieldErrors } = props;
|
||||
|
||||
const [tasksMetadata, setTasksMetadata] = React.useState<TaskMetadata[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
const fetchTaskMetadata = async () => {
|
||||
const meta = await templateVersionsService.getTaskMetadata("GeneralTask");
|
||||
setTasksMetadata(meta);
|
||||
};
|
||||
|
||||
fetchTaskMetadata();
|
||||
}, []);
|
||||
|
||||
const runDefaults = useCapabilityDefaults(tasksMetadata);
|
||||
|
||||
const handleAddTask = (selectedType: TaskMetadata) => {
|
||||
const newTask: TaskDefinition = {
|
||||
type: selectedType.taskType,
|
||||
|
||||
config: {
|
||||
guid: crypto.randomUUID(),
|
||||
},
|
||||
};
|
||||
|
||||
var childTasks = task.config.tasks as TaskDefinition[]; //Type assertion to satisfy the compiler, we know this will be the correct type.
|
||||
|
||||
//Assign the default values for the task here.
|
||||
selectedType.capabilities.forEach((capability) => {
|
||||
runDefaults(capability, newTask, childTasks);
|
||||
});
|
||||
|
||||
const updatedTasks = [...childTasks, newTask];
|
||||
const errors = validateTask(newTask, updatedTasks, tasksMetadata);
|
||||
|
||||
const isValid = Object.keys(errors).length === 0;
|
||||
|
||||
task.config.tasks = updatedTasks;
|
||||
|
||||
onValidate({ errors: errors, isValid: isValid } as TaskValidationResult);
|
||||
|
||||
onChange(task);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<AddTaskButton tasksMetadata={tasksMetadata} onAdd={handleAddTask} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const runValidation = (
|
||||
task: TaskDefinition,
|
||||
tasks: TaskDefinition[],
|
||||
): Record<string, string> => {
|
||||
const errors: Record<string, string> = {};
|
||||
|
||||
return errors;
|
||||
};
|
||||
|
||||
export function defaultsAssignment(
|
||||
task: TaskDefinition,
|
||||
tasks: TaskDefinition[],
|
||||
ctx: defaultsContext,
|
||||
) {
|
||||
task.config.tasks = [] as TaskDefinition[];
|
||||
}
|
||||
|
||||
export const stageOfGeneralTaskEditorRegistryEntry: capabilityEditorRegistryEntry =
|
||||
{
|
||||
Editor: StageOfGeneralTaskEditor,
|
||||
DefaultsAssignment: defaultsAssignment,
|
||||
ValidationRunner: runValidation,
|
||||
};
|
||||
@ -1,5 +1,5 @@
|
||||
import React from "react";
|
||||
import {
|
||||
import React, { useEffect } from "react";
|
||||
import templateVersionsService, {
|
||||
TaskDefinition,
|
||||
TaskMetadata,
|
||||
} from "../services/WorkflowTemplateService";
|
||||
@ -12,7 +12,6 @@ import ValidationErrorIcon from "../../../../components/validationErrorIcon";
|
||||
interface TaskListProps {
|
||||
tasks: TaskDefinition[];
|
||||
validTasksList: Record<string, boolean>;
|
||||
tasksMetadata: TaskMetadata[];
|
||||
onChange: (tasks: TaskDefinition[]) => void;
|
||||
selectedTask: TaskDefinition | null;
|
||||
onSelectTask: (task: TaskDefinition | null) => void;
|
||||
@ -22,14 +21,50 @@ interface TaskListProps {
|
||||
const TaskList: React.FC<TaskListProps> = ({
|
||||
tasks,
|
||||
validTasksList,
|
||||
tasksMetadata,
|
||||
onChange,
|
||||
selectedTask,
|
||||
onSelectTask,
|
||||
onValidate,
|
||||
}) => {
|
||||
const [tasksMetadata, setTasksMetadata] = React.useState<TaskMetadata[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
const fetchTaskMetadata = async () => {
|
||||
const meta = await templateVersionsService.getTaskMetadata("GeneralTask");
|
||||
setTasksMetadata(meta);
|
||||
};
|
||||
|
||||
fetchTaskMetadata();
|
||||
}, []);
|
||||
|
||||
const runDefaults = useCapabilityDefaults(tasksMetadata);
|
||||
|
||||
const taskMetadataByType = React.useMemo(() => {
|
||||
const map = new Map<string, TaskMetadata>();
|
||||
tasksMetadata.forEach((meta) => {
|
||||
map.set(meta.taskType, meta);
|
||||
});
|
||||
return map;
|
||||
}, [tasksMetadata]);
|
||||
|
||||
const getChildTasks = React.useCallback(
|
||||
(task: TaskDefinition) => {
|
||||
const meta = taskMetadataByType.get(task.type);
|
||||
const isStageTask =
|
||||
meta?.capabilities?.some((capability) =>
|
||||
capability.startsWith("IStage<"),
|
||||
) ?? false;
|
||||
|
||||
if (!isStageTask) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const childTasks = (task.config.tasks as TaskDefinition[]) ?? [];
|
||||
return sortTasksTopologically(childTasks);
|
||||
},
|
||||
[taskMetadataByType],
|
||||
);
|
||||
|
||||
const handleAddTask = (selectedType: TaskMetadata) => {
|
||||
const newTask: TaskDefinition = {
|
||||
type: selectedType.taskType,
|
||||
@ -64,6 +99,7 @@ const TaskList: React.FC<TaskListProps> = ({
|
||||
<div className="task-list-content">
|
||||
<SelectableList
|
||||
items={sortedTasks}
|
||||
getChildren={getChildTasks}
|
||||
selectedValue={selectedTask}
|
||||
renderLabel={(x) => {
|
||||
if (x) {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import React, { useCallback, useMemo } from "react";
|
||||
import {
|
||||
import React, { useCallback, useEffect, useMemo } from "react";
|
||||
import templateVersionsService, {
|
||||
TaskDefinition,
|
||||
TaskMetadata,
|
||||
} from "../services/WorkflowTemplateService";
|
||||
@ -11,7 +11,7 @@ import ConfirmButton from "../../../../components/common/ConfirmButton";
|
||||
interface TaskEditorProps {
|
||||
task: TaskDefinition;
|
||||
tasks: TaskDefinition[];
|
||||
tasksMetadata: TaskMetadata[];
|
||||
siblingTasks: TaskDefinition[];
|
||||
onChange: (updatedTask: TaskDefinition) => void;
|
||||
onValidate: (taskId: string, isValid: boolean) => void;
|
||||
onDelete: (taskId: string) => void;
|
||||
@ -20,11 +20,22 @@ interface TaskEditorProps {
|
||||
const TaskEditorComponent: React.FC<TaskEditorProps> = ({
|
||||
task,
|
||||
tasks,
|
||||
tasksMetadata,
|
||||
siblingTasks,
|
||||
onChange,
|
||||
onValidate,
|
||||
onDelete,
|
||||
}) => {
|
||||
const [tasksMetadata, setTasksMetadata] = React.useState<TaskMetadata[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
const fetchTaskMetadata = async () => {
|
||||
const meta = await templateVersionsService.getTaskMetadata("GeneralTask");
|
||||
setTasksMetadata(meta);
|
||||
};
|
||||
|
||||
fetchTaskMetadata();
|
||||
}, []);
|
||||
|
||||
const [fieldErrors, setFieldErrors] = React.useState<Record<string, string>>(
|
||||
{},
|
||||
);
|
||||
@ -56,17 +67,17 @@ const TaskEditorComponent: React.FC<TaskEditorProps> = ({
|
||||
|
||||
const handleTaskChange = useCallback(
|
||||
(updatedTask: TaskDefinition) => {
|
||||
// Update the task list
|
||||
const updatedTasks = tasks.map((t) =>
|
||||
// Update the sibling task list (validation runs on siblings only)
|
||||
const updatedSiblings = siblingTasks.map((t) =>
|
||||
t.config.guid === updatedTask.config.guid ? updatedTask : t,
|
||||
);
|
||||
|
||||
runValidation(updatedTask, updatedTasks, tasksMetadata);
|
||||
runValidation(updatedTask, updatedSiblings, tasksMetadata);
|
||||
|
||||
// Bubble updated task up
|
||||
onChange(updatedTask);
|
||||
},
|
||||
[tasks, tasksMetadata, runValidation, onChange],
|
||||
[siblingTasks, tasksMetadata, runValidation, onChange],
|
||||
);
|
||||
|
||||
const taskMeta = useMemo(
|
||||
|
||||
@ -26,16 +26,6 @@ const TasksTab: React.FC<TasksTabProps> = ({
|
||||
}) => {
|
||||
const tasks = data.tasks;
|
||||
const [selectedTask, setSelectedTask] = useState<TaskDefinition | null>(null);
|
||||
const [tasksMetadata, setTasksMetadata] = React.useState<TaskMetadata[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
const fetchTaskMetadata = async () => {
|
||||
const meta = await templateVersionsService.getTaskMetadata("GeneralTask");
|
||||
setTasksMetadata(meta);
|
||||
};
|
||||
|
||||
fetchTaskMetadata();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
// Don't override user selection
|
||||
@ -68,37 +58,165 @@ const TasksTab: React.FC<TasksTabProps> = ({
|
||||
[onTasksChange],
|
||||
);
|
||||
|
||||
const findTaskAndSiblings = (
|
||||
targetGuid: string,
|
||||
source: TaskDefinition[],
|
||||
): { task: TaskDefinition | null; siblings: TaskDefinition[] } => {
|
||||
for (const task of source) {
|
||||
if (task.config.guid === targetGuid) {
|
||||
return { task, siblings: source };
|
||||
}
|
||||
|
||||
const childTasks = (task.config.tasks as TaskDefinition[]) ?? [];
|
||||
if (childTasks.length === 0) continue;
|
||||
|
||||
const result = findTaskAndSiblings(targetGuid, childTasks);
|
||||
if (result.task) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return { task: null, siblings: [] };
|
||||
};
|
||||
|
||||
const handleTaskEditorChange = React.useCallback(
|
||||
(updatedTask: TaskDefinition) => {
|
||||
const newTasks = tasks.map((t) =>
|
||||
t.config.guid === updatedTask.config.guid ? updatedTask : t,
|
||||
const { siblings } = findTaskAndSiblings(
|
||||
updatedTask.config.guid as string,
|
||||
tasks,
|
||||
);
|
||||
|
||||
if (siblings.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const updateTaskRecursive = (
|
||||
source: TaskDefinition[],
|
||||
): TaskDefinition[] => {
|
||||
return source.map((t) => {
|
||||
if (t.config.guid === updatedTask.config.guid) {
|
||||
return updatedTask;
|
||||
}
|
||||
|
||||
const childTasks = (t.config.tasks as TaskDefinition[]) ?? [];
|
||||
if (childTasks.length === 0) {
|
||||
return t;
|
||||
}
|
||||
|
||||
const updatedChildren = updateTaskRecursive(childTasks);
|
||||
if (updatedChildren === childTasks) {
|
||||
return t;
|
||||
}
|
||||
|
||||
return {
|
||||
...t,
|
||||
config: {
|
||||
...t.config,
|
||||
tasks: updatedChildren,
|
||||
},
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
const newTasks = updateTaskRecursive(tasks);
|
||||
handleTasksChange(newTasks);
|
||||
|
||||
// Use the updated object from the array, not the raw updatedTask
|
||||
const updatedFromArray = newTasks.find(
|
||||
(t) => t.config.guid === updatedTask.config.guid,
|
||||
const { task: updatedFromArray } = findTaskAndSiblings(
|
||||
updatedTask.config.guid as string,
|
||||
newTasks,
|
||||
);
|
||||
|
||||
setSelectedTask(updatedFromArray!);
|
||||
if (updatedFromArray) {
|
||||
setSelectedTask(updatedFromArray);
|
||||
}
|
||||
},
|
||||
[tasks, handleTasksChange],
|
||||
);
|
||||
|
||||
const handleTaskDelete = React.useCallback(
|
||||
(taskId: string) => {
|
||||
const newTasks = tasks.filter((t) => t.config.guid !== taskId);
|
||||
const removeTaskRecursive = (
|
||||
source: TaskDefinition[],
|
||||
): { tasks: TaskDefinition[]; removed: boolean } => {
|
||||
let removed = false;
|
||||
|
||||
for (const t of newTasks) {
|
||||
// If any task has a dependency on the deleted task, remove that dependency
|
||||
if (t.config.predecessors) {
|
||||
t.config.predecessors = (t.config.predecessors as string[]).filter(
|
||||
(d) => d !== taskId,
|
||||
);
|
||||
}
|
||||
const updated = source.flatMap((task) => {
|
||||
if (task.config.guid === taskId) {
|
||||
removed = true;
|
||||
return [];
|
||||
}
|
||||
|
||||
const childTasks = (task.config.tasks as TaskDefinition[]) ?? [];
|
||||
if (childTasks.length === 0) {
|
||||
return [task];
|
||||
}
|
||||
|
||||
const childResult = removeTaskRecursive(childTasks);
|
||||
if (!childResult.removed) {
|
||||
return [task];
|
||||
}
|
||||
|
||||
removed = true;
|
||||
|
||||
return [
|
||||
{
|
||||
...task,
|
||||
config: {
|
||||
...task.config,
|
||||
tasks: childResult.tasks,
|
||||
},
|
||||
},
|
||||
];
|
||||
});
|
||||
|
||||
return { tasks: updated, removed };
|
||||
};
|
||||
|
||||
const removePredecessorRecursive = (
|
||||
source: TaskDefinition[],
|
||||
): TaskDefinition[] => {
|
||||
return source.map((task) => {
|
||||
const childTasks = (task.config.tasks as TaskDefinition[]) ?? [];
|
||||
const updatedChildren =
|
||||
childTasks.length > 0
|
||||
? removePredecessorRecursive(childTasks)
|
||||
: childTasks;
|
||||
|
||||
const predecessors = task.config.predecessors as string[] | undefined;
|
||||
const updatedPredecessors = predecessors
|
||||
? predecessors.filter((d) => d !== taskId)
|
||||
: predecessors;
|
||||
|
||||
const childrenChanged = updatedChildren !== childTasks;
|
||||
const predecessorsChanged = updatedPredecessors !== predecessors;
|
||||
|
||||
if (!childrenChanged && !predecessorsChanged) {
|
||||
return task;
|
||||
}
|
||||
|
||||
const updatedConfig = { ...task.config } as Record<string, unknown>;
|
||||
if (childrenChanged) {
|
||||
updatedConfig.tasks = updatedChildren;
|
||||
}
|
||||
if (predecessorsChanged) {
|
||||
updatedConfig.predecessors = updatedPredecessors;
|
||||
}
|
||||
|
||||
return {
|
||||
...task,
|
||||
config: updatedConfig,
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
const deleteResult = removeTaskRecursive(tasks);
|
||||
if (!deleteResult.removed) {
|
||||
return;
|
||||
}
|
||||
|
||||
const newTasks = removePredecessorRecursive(deleteResult.tasks);
|
||||
|
||||
onValidate(taskId, true); // Clear validation state for deleted task
|
||||
setSelectedTask(null);
|
||||
handleTasksChange(newTasks);
|
||||
@ -112,7 +230,6 @@ const TasksTab: React.FC<TasksTabProps> = ({
|
||||
<TaskList
|
||||
tasks={tasks}
|
||||
validTasksList={taskValidation}
|
||||
tasksMetadata={tasksMetadata}
|
||||
onChange={handleTasksChange}
|
||||
selectedTask={selectedTask}
|
||||
onSelectTask={setSelectedTask}
|
||||
@ -122,9 +239,12 @@ const TasksTab: React.FC<TasksTabProps> = ({
|
||||
{selectedTask && (
|
||||
<div>
|
||||
<TaskEditor
|
||||
tasksMetadata={tasksMetadata}
|
||||
task={selectedTask}
|
||||
tasks={tasks}
|
||||
siblingTasks={
|
||||
findTaskAndSiblings(selectedTask.config.guid as string, tasks)
|
||||
.siblings
|
||||
}
|
||||
onChange={handleTaskEditorChange}
|
||||
onValidate={onValidate}
|
||||
onDelete={handleTaskDelete}
|
||||
|
||||
@ -5,6 +5,7 @@ import { capabilityEditorRegistryEntry } from "./useCapabilityDefaults";
|
||||
import { outcomeOfApprovalVerdictRegistryEntry } from "./CapabilityEditors/OutcomeOfApprovalVerdictRegistryEntry";
|
||||
import { budgetEditorRegistryEntry } from "./CapabilityEditors/BudgetEditorRegistryEntry";
|
||||
import { bypassableEditorRegistryEntry } from "./CapabilityEditors/BypassableEditor";
|
||||
import { stageOfGeneralTaskEditorRegistryEntry } from "./CapabilityEditors/StageOfGeneralTaskEditor";
|
||||
|
||||
export const capabilityEditorRegistry: Record<
|
||||
string,
|
||||
@ -17,6 +18,6 @@ export const capabilityEditorRegistry: Record<
|
||||
"IOutcome<ApprovalVerdict>": outcomeOfApprovalVerdictRegistryEntry,
|
||||
// IFormTemplate: null, //ToDo implement this
|
||||
IBypassable: bypassableEditorRegistryEntry,
|
||||
// "IStage<GeneralTaskAttribute>": null, //ToDo implement this
|
||||
"IStage<GeneralTaskAttribute>": stageOfGeneralTaskEditorRegistryEntry,
|
||||
// "IStage<ApprovalTaskAttribute>": null, //ToDo implement this
|
||||
};
|
||||
|
||||
@ -6,7 +6,6 @@ import {
|
||||
MakeGeneralIdRefParams,
|
||||
} from "../../../../utils/GeneralIdRef";
|
||||
import MapToJson from "../../../../utils/MapToJson";
|
||||
import { CustomFieldValue } from "../../glossary/services/glossaryService";
|
||||
|
||||
const apiEndpoint = "/WorkflowTemplate";
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user