diff --git a/tests/static-toolboxes.test.mjs b/tests/static-toolboxes.test.mjs index c776e46..8a04f1e 100644 --- a/tests/static-toolboxes.test.mjs +++ b/tests/static-toolboxes.test.mjs @@ -161,6 +161,8 @@ test("toolbox module registry and modules expose expected behavior", async () => const calendarUtils = await readFile("website/src/features/toolboxes/modules/calendarUtils.js", "utf8"); const taskPlannerModule = await readFile("website/src/features/toolboxes/modules/TaskPlannerModule.jsx", "utf8"); const taskPlannerItems = await readFile("website/src/features/toolboxes/modules/TaskPlannerItems.jsx", "utf8"); + const taskPlannerItemPanels = await readFile("website/src/features/toolboxes/modules/TaskPlannerItemPanels.jsx", "utf8"); + const taskPlannerBundle = `${taskPlannerItems}\n${taskPlannerItemPanels}`; const taskPlannerUtils = await readFile("website/src/features/toolboxes/modules/taskPlannerUtils.js", "utf8"); const goalTreeModule = await readFile("website/src/features/toolboxes/modules/GoalTreeModule.jsx", "utf8"); const goalTreeParts = await readFile("website/src/features/toolboxes/modules/GoalTreeParts.jsx", "utf8"); @@ -365,11 +367,11 @@ test("toolbox module registry and modules expose expected behavior", async () => assert.match(taskPlannerModule, /reorderFeatures/); assert.match(taskPlannerItems, /export function TaskPlannerBranch/); assert.match(taskPlannerItems, /function TaskPlannerItem/); - assert.match(taskPlannerItems, /task-planner-warning/); - assert.match(taskPlannerItems, /useInlineEdit/); - assert.match(taskPlannerItems, /commitOnEnter: false/); - assert.match(taskPlannerItems, /categoryLabel/); - assert.match(taskPlannerItems, /prerequisite/); + assert.match(taskPlannerBundle, /task-planner-warning/); + assert.match(taskPlannerBundle, /useInlineEdit/); + assert.match(taskPlannerBundle, /commitOnEnter: false/); + assert.match(taskPlannerBundle, /categoryLabel/); + assert.match(taskPlannerBundle, /prerequisite/); assert.match(taskPlannerUtils, /export function getTaskParentMap/); assert.match(taskPlannerUtils, /export function applyDueResets/); assert.doesNotMatch(taskPlannerModule, /canMoveItem:/); diff --git a/website/src/features/toolboxes/modules/TaskPlannerItemPanels.jsx b/website/src/features/toolboxes/modules/TaskPlannerItemPanels.jsx new file mode 100644 index 0000000..cbe63cb --- /dev/null +++ b/website/src/features/toolboxes/modules/TaskPlannerItemPanels.jsx @@ -0,0 +1,246 @@ +// Rôle : regroupe les panneaux secondaires d'une tâche du task planner. +import { Icon } from "../../../components/Icon.jsx"; +import { InlineNotice } from "../../../components/AppOverlays.jsx"; +import { Tooltip } from "../../../components/Tooltip.jsx"; +import { useInlineEdit } from "../../../hooks/useInlineEdit.js"; +import { + WEEK_DAYS, + getEffectiveTaskCategory, + getTaskById, + getTaskTitle +} from "./taskPlannerUtils.js"; + +export function MissingPrerequisitesTooltip({ missingPrerequisites, tasks, textContent }) { + return ( + + {textContent.missingPrerequisiteTitle || "Pré requis non effectué"} + + {missingPrerequisites.map((relation) => ( + {getTaskTitle(tasks, relation.toTaskId)} + ))} + + + )} + position="top-start" + > + {textContent.missingPrerequisiteBadge || "Pré requis"} + + ); +} + +export function TaskPlannerItemDetails({ + task, + tasks, + data, + parentMap, + parentId, + textContent, + descriptionOpen, + settingsOpen, + noticeMessage, + relations, + relationTargets, + onUpdateTask, + onAddLinkTarget, + onRemoveLinkTarget, + onSetPrerequisite, + onSetTaskCategory +}) { + return ( + <> + + {descriptionOpen && ( + + )} + {settingsOpen && ( +
+ + +
+ )} + + ); +} + +function TaskDescriptionPanel({ task, tasks, parentMap, parentId, textContent, onUpdateTask, onSetTaskCategory }) { + const parentTask = parentId ? getTaskById(tasks, parentId) : null; + const inheritedCategory = parentTask ? getEffectiveTaskCategory(parentTask, tasks, parentMap) : ""; + const categoryValue = parentTask ? inheritedCategory : task.category || ""; + const categoryEditable = !parentTask; + const categoryEdit = useInlineEdit({ + value: categoryValue, + onCommit: (category) => { + if (categoryEditable) onSetTaskCategory(task.id, category); + } + }); + const descriptionEdit = useInlineEdit({ + value: task.description, + onCommit: (description) => onUpdateTask(task.id, (current) => ({ ...current, description })), + commitOnEnter: false + }); + + return ( +
+ +