Altered the default assignment code so that it is scalable.

This commit is contained in:
Colin Dawson 2026-02-14 22:56:34 +00:00
parent f45f9f0b25
commit e7a084c301
2 changed files with 71 additions and 35 deletions

View File

@ -16,6 +16,7 @@ interface TaskCoreEditorProps {
allowedTasks: TaskMetadata[]; allowedTasks: TaskMetadata[];
onChange: (updated: TaskDefinition) => void; onChange: (updated: TaskDefinition) => void;
onValidate: (result: TaskValidationResult) => void; onValidate: (result: TaskValidationResult) => void;
shouldAssignDefaults: boolean;
} }
export const TaskCoreEditor: React.FC<TaskCoreEditorProps> = ({ export const TaskCoreEditor: React.FC<TaskCoreEditorProps> = ({
@ -24,11 +25,11 @@ export const TaskCoreEditor: React.FC<TaskCoreEditorProps> = ({
allowedTasks, allowedTasks,
onChange, onChange,
onValidate, onValidate,
shouldAssignDefaults,
}) => { }) => {
const { t: tTaskType } = useTranslation(Namespaces.TaskTypes); const { t: tTaskType } = useTranslation(Namespaces.TaskTypes);
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 hasAssignedDefaultName = useRef(false);
// Generate a unique default name // Generate a unique default name
const nameExists = (tasks: TaskDefinition[], candidate: string): boolean => { const nameExists = (tasks: TaskDefinition[], candidate: string): boolean => {
@ -59,42 +60,50 @@ export const TaskCoreEditor: React.FC<TaskCoreEditorProps> = ({
[allowedTasks, task.type, tTaskType], [allowedTasks, task.type, tTaskType],
); );
useEffect(() => { const assignDefaults = (
// Reset the guard when a new task is loaded newConfig: Record<string, unknown>,
hasAssignedDefaultName.current = false; task: TaskDefinition,
}, [task.config.guid]); allTasks: TaskDefinition[],
allowedTasks: TaskMetadata[],
useEffect(() => { formatNewTaskName: (tasks: TaskDefinition[]) => string,
if (!hasAssignedDefaultName.current && !task.config.name) { ) => {
hasAssignedDefaultName.current = true;
const displayName = allowedTasks.find( const displayName = allowedTasks.find(
(t) => t.taskType === task.type, (t) => t.taskType === task.type,
)?.displayName; )?.displayName;
const newConfig = { ...task.config };
// Assign default name // Assign default name
if (displayName) { if (displayName) {
newConfig.name = formatNewTaskName(allTasks); newConfig.name = formatNewTaskName(allTasks);
} }
// Assign default predecessor (the task immediately before this one) // Assign default predecessor (the task immediately before this one)
const index = allTasks.findIndex( const index = allTasks.findIndex((t) => t.config.guid === task.config.guid);
(t) => t.config.guid === task.config.guid,
);
if (index > 0) { if (index > 0) {
const previousTask = allTasks[index - 1]; const previousTask = allTasks[index - 1];
newConfig.predecessors = [previousTask.config.guid as string]; newConfig.predecessors = [previousTask.config.guid as string];
} }
};
useEffect(() => {
if (!shouldAssignDefaults) return;
const newConfig = { ...task.config };
assignDefaults(newConfig, task, allTasks, allowedTasks, formatNewTaskName);
onChange({ onChange({
...task, ...task,
config: newConfig, config: newConfig,
}); });
} }, [
}, [allTasks, allowedTasks, formatNewTaskName, onChange, task]); shouldAssignDefaults,
task,
allTasks,
allowedTasks,
formatNewTaskName,
onChange,
]);
const runValidation = useCallback(() => { const runValidation = useCallback(() => {
const errors: Record<string, string> = {}; const errors: Record<string, string> = {};

View File

@ -25,6 +25,30 @@ export const TaskEditor: React.FC<TaskEditorProps> = ({
onChange, onChange,
onValidate, onValidate,
}) => { }) => {
//region assign defaults
const hasAssignedDefaultsRef = useRef(false);
const [shouldAssignDefaults, setShouldAssignDefaults] = useState(false);
// Reset guard when a new task is loaded
useEffect(() => {
hasAssignedDefaultsRef.current = false;
setShouldAssignDefaults(false);
}, [task.config.guid]);
// Decide when to trigger initial defaults (current rule: no name yet)
useEffect(() => {
if (!hasAssignedDefaultsRef.current && !task.config.name) {
hasAssignedDefaultsRef.current = true;
setShouldAssignDefaults(true);
} else {
// ensure we only pulse true once
setShouldAssignDefaults(false);
}
}, [task.config.name]);
//end region assign defaults
//region Validation
// eslint-disable-next-line @typescript-eslint/no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
const [validationMap, setValidationMap] = useState< const [validationMap, setValidationMap] = useState<
Record<string, TaskValidationResult> Record<string, TaskValidationResult>
@ -52,6 +76,8 @@ export const TaskEditor: React.FC<TaskEditorProps> = ({
} }
}, [validationMap, task.config.guid, onValidate]); }, [validationMap, task.config.guid, onValidate]);
//End region validation
return ( return (
<> <>
<TaskCoreEditor <TaskCoreEditor
@ -60,6 +86,7 @@ export const TaskEditor: React.FC<TaskEditorProps> = ({
allTasks={allTasks} allTasks={allTasks}
onChange={onChange} onChange={onChange}
onValidate={(result) => onCapabilityValidate("core", result)} onValidate={(result) => onCapabilityValidate("core", result)}
shouldAssignDefaults={shouldAssignDefaults}
/> />
</> </>
); );