Tidy up of compiler warnings, also make sure that the unique naming works better.
This commit is contained in:
parent
6f49add5f7
commit
291a391faf
@ -28,33 +28,63 @@ export const TaskCoreEditor: React.FC<TaskCoreEditorProps> = ({
|
|||||||
const [fieldErrors, setFieldErrors] = useState<Record<string, string>>({});
|
const [fieldErrors, setFieldErrors] = useState<Record<string, string>>({});
|
||||||
const prevErrorsRef = useRef<Record<string, string>>({});
|
const prevErrorsRef = useRef<Record<string, string>>({});
|
||||||
|
|
||||||
const formatNewTaskName = (
|
// Generate a unique default name
|
||||||
tasks: TaskDefinition<Record<string, unknown>>[],
|
const nameExists = (tasks: TaskDefinition[], candidate: string): boolean => {
|
||||||
) => {
|
const target = candidate.trim().toLowerCase();
|
||||||
|
|
||||||
|
return tasks.some(
|
||||||
|
(t) => (t.config.name as string)?.trim().toLowerCase() === target,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const formatNewTaskName = useCallback(
|
||||||
|
(tasks: TaskDefinition[]) => {
|
||||||
const displayName = allowedTasks.find(
|
const displayName = allowedTasks.find(
|
||||||
(t) => t.taskType === task.type,
|
(t) => t.taskType === task.type,
|
||||||
)?.displayName;
|
)?.displayName;
|
||||||
|
|
||||||
return `${tTaskType(displayName!)} ${tasks.length + 1}`;
|
if (!displayName) return "New Task";
|
||||||
};
|
|
||||||
|
const base = `${tTaskType(displayName)} `;
|
||||||
|
let index = 1;
|
||||||
|
|
||||||
|
while (nameExists(tasks, `${base}${index}`)) {
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return `${base}${index}`;
|
||||||
|
},
|
||||||
|
[allowedTasks, task.type, tTaskType],
|
||||||
|
);
|
||||||
|
|
||||||
const runValidation = useCallback(() => {
|
const runValidation = useCallback(() => {
|
||||||
const errors: Record<string, string> = {};
|
const errors: Record<string, string> = {};
|
||||||
|
|
||||||
//If the task doesn't have a name (can happen when adding a new task), generate a default one.
|
// If the task doesn't have a name, generate a default one via onChange
|
||||||
if (task.config.name === undefined) {
|
if (!task.config.name) {
|
||||||
task.config.name = formatNewTaskName(allTasks);
|
const newName = formatNewTaskName(allTasks);
|
||||||
|
|
||||||
|
onChange({
|
||||||
|
...task,
|
||||||
|
config: {
|
||||||
|
...task.config,
|
||||||
|
name: newName,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Stop here — next render will validate again
|
||||||
|
return { errors: {}, isValid: true };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!task.config.name || (task.config.name as string).trim() === "") {
|
// Name required
|
||||||
|
if (!(task.config.name as string).trim()) {
|
||||||
errors["name"] = "Name cannot be empty";
|
errors["name"] = "Name cannot be empty";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (task.config.name) {
|
// Name must be unique
|
||||||
// Name must be unique across all tasks
|
|
||||||
const duplicate = allTasks.find(
|
const duplicate = allTasks.find(
|
||||||
(t) =>
|
(t) =>
|
||||||
(t.config.guid as string) !== (task.config.guid as string) && // exclude self
|
t.config.guid !== task.config.guid &&
|
||||||
(t.config.name as string).trim().toLowerCase() ===
|
(t.config.name as string).trim().toLowerCase() ===
|
||||||
(task.config.name as string).trim().toLowerCase(),
|
(task.config.name as string).trim().toLowerCase(),
|
||||||
);
|
);
|
||||||
@ -62,12 +92,12 @@ export const TaskCoreEditor: React.FC<TaskCoreEditorProps> = ({
|
|||||||
if (duplicate) {
|
if (duplicate) {
|
||||||
errors["name"] = "Name must be unique.";
|
errors["name"] = "Name must be unique.";
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
// Description max length
|
||||||
const descriptionMaxLength = 5000;
|
const descriptionMaxLength = 5000;
|
||||||
if (
|
if (
|
||||||
task.config.description &&
|
(task.config.description && (task.config.description as string).length) ??
|
||||||
(task.config.description as string).length >= descriptionMaxLength
|
0 > descriptionMaxLength
|
||||||
) {
|
) {
|
||||||
errors["description"] =
|
errors["description"] =
|
||||||
`Description can be up to ${descriptionMaxLength} characters long.`;
|
`Description can be up to ${descriptionMaxLength} characters long.`;
|
||||||
@ -75,9 +105,9 @@ export const TaskCoreEditor: React.FC<TaskCoreEditorProps> = ({
|
|||||||
|
|
||||||
const isValid = Object.keys(errors).length === 0;
|
const isValid = Object.keys(errors).length === 0;
|
||||||
return { errors, isValid };
|
return { errors, isValid };
|
||||||
}, [allTasks, task.config.description, task.config.guid, task.config.name]);
|
}, [task, allTasks, formatNewTaskName, onChange]);
|
||||||
|
|
||||||
//Validate when task changes.
|
// Validate when task changes (new task selected / created)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const { errors, isValid } = runValidation();
|
const { errors, isValid } = runValidation();
|
||||||
|
|
||||||
@ -85,7 +115,7 @@ export const TaskCoreEditor: React.FC<TaskCoreEditorProps> = ({
|
|||||||
prevErrorsRef.current = errors;
|
prevErrorsRef.current = errors;
|
||||||
|
|
||||||
onValidate({ isValid, errors });
|
onValidate({ isValid, errors });
|
||||||
}, [onValidate, runValidation, task.config.guid]);
|
}, [task.config.guid, runValidation, onValidate]);
|
||||||
|
|
||||||
// Validate when fields change
|
// Validate when fields change
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -101,7 +131,7 @@ export const TaskCoreEditor: React.FC<TaskCoreEditorProps> = ({
|
|||||||
onValidate({ isValid, errors });
|
onValidate({ isValid, errors });
|
||||||
prevErrorsRef.current = errors;
|
prevErrorsRef.current = errors;
|
||||||
}
|
}
|
||||||
}, [task.config.description, task.config.name, onValidate, runValidation]);
|
}, [task.config.name, task.config.description, runValidation, onValidate]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@ -4,8 +4,6 @@ import {
|
|||||||
TaskMetadata,
|
TaskMetadata,
|
||||||
} from "../services/WorkflowTemplateService";
|
} from "../services/WorkflowTemplateService";
|
||||||
import AddTaskButton from "./AddTaskButton";
|
import AddTaskButton from "./AddTaskButton";
|
||||||
import { Namespaces } from "../../../../i18n/i18n";
|
|
||||||
import { useTranslation } from "react-i18next";
|
|
||||||
import { SelectableList } from "../../../../components/common/SelectableList";
|
import { SelectableList } from "../../../../components/common/SelectableList";
|
||||||
import { faExclamationCircle } from "@fortawesome/free-solid-svg-icons";
|
import { faExclamationCircle } from "@fortawesome/free-solid-svg-icons";
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
|
|||||||
@ -22,6 +22,7 @@ export const TaskEditor: React.FC<TaskEditorProps> = ({
|
|||||||
onChange,
|
onChange,
|
||||||
onValidate,
|
onValidate,
|
||||||
}) => {
|
}) => {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
const [validationMap, setValidationMap] = useState<
|
const [validationMap, setValidationMap] = useState<
|
||||||
Record<string, TaskValidationResult>
|
Record<string, TaskValidationResult>
|
||||||
>({});
|
>({});
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user