From d9bbf40fadd382e1b30d44229b3603017a219004 Mon Sep 17 00:00:00 2001 From: Shinuwa Date: Mon, 24 Aug 2026 22:07:22 +0200 Subject: [PATCH] Refactor goal tree editor form --- tests/static-toolboxes.test.mjs | 8 +- .../toolboxes/modules/GoalTreeEditor.jsx | 227 ++++++++++++++++++ .../toolboxes/modules/GoalTreeModule.jsx | 189 ++------------- 3 files changed, 255 insertions(+), 169 deletions(-) create mode 100644 website/src/features/toolboxes/modules/GoalTreeEditor.jsx diff --git a/tests/static-toolboxes.test.mjs b/tests/static-toolboxes.test.mjs index 8a04f1e..c6a6241 100644 --- a/tests/static-toolboxes.test.mjs +++ b/tests/static-toolboxes.test.mjs @@ -165,7 +165,9 @@ test("toolbox module registry and modules expose expected behavior", async () => 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 goalTreeEditor = await readFile("website/src/features/toolboxes/modules/GoalTreeEditor.jsx", "utf8"); const goalTreeParts = await readFile("website/src/features/toolboxes/modules/GoalTreeParts.jsx", "utf8"); + const goalTreeBundle = `${goalTreeModule}\n${goalTreeEditor}\n${goalTreeParts}`; const goalTreeDisplay = await readFile("website/src/features/toolboxes/modules/goalTreeDisplay.js", "utf8"); const goalTreeUtils = await readFile("website/src/features/toolboxes/modules/goalTreeUtils.js", "utf8"); const equipmentPlannerModule = await readFile("website/src/features/toolboxes/modules/EquipmentPlannerModule.jsx", "utf8"); @@ -381,11 +383,15 @@ test("toolbox module registry and modules expose expected behavior", async () => assert.match(goalTreeModule, /applyGoalTreeDueResets/); assert.match(goalTreeModule, /TextExchangeActions/); assert.match(goalTreeModule, /DiagramConnectors/); + assert.match(goalTreeEditor, /export function GoalTreeEditor/); + assert.match(goalTreeEditor, /Tabs/); + assert.match(goalTreeEditor, /GoalTreeFormulaInput/); + assert.match(goalTreeEditor, /GoalTreePrerequisitePicker/); assert.match(goalTreeParts, /Tooltip/); assert.match(goalTreeParts, /export function GoalTreeIconPicker/); assert.match(goalTreeParts, /export function GoalTreeContentEditor/); assert.match(goalTreeParts, /function GoalTreeNodeContentPreview/); - assert.doesNotMatch(`${goalTreeModule}\n${goalTreeParts}`, /\.slice\(0, 3\)/); + assert.doesNotMatch(goalTreeBundle, /\.slice\(0, 3\)/); assert.match(goalTreeParts, /GoalTreeChecklistInlineControl/); assert.match(goalTreeParts, /GoalTreeStepLeafControl/); assert.match(goalTreeParts, /export function GoalTreePrerequisitePicker/); diff --git a/website/src/features/toolboxes/modules/GoalTreeEditor.jsx b/website/src/features/toolboxes/modules/GoalTreeEditor.jsx new file mode 100644 index 0000000..e7c71be --- /dev/null +++ b/website/src/features/toolboxes/modules/GoalTreeEditor.jsx @@ -0,0 +1,227 @@ +// Rôle : rend le formulaire d'édition des noeuds de l'arbre d'objectifs. +import { Icon } from "../../../components/Icon.jsx"; +import { Tabs } from "../../../components/Tabs.jsx"; +import { + GoalTreeContentEditor, + GoalTreeFormulaInput, + GoalTreeIconPicker, + GoalTreePrerequisitePicker, + GoalTreeTitleInput +} from "./GoalTreeParts.jsx"; +import { + KIND_LABELS, + RESET_LABELS +} from "./goalTreeDisplay.js"; +import { + GOAL_TREE_COLORS, + GOAL_TREE_COLOR_VALUES, + GOAL_TREE_KINDS, + GOAL_TREE_RESET_TYPES, + GOAL_TREE_WEEK_DAYS +} from "./goalTreeUtils.js"; + +export function GoalTreeEditor({ + selectedNode, + selectedNodeIsStep, + selectedProgressMode, + formTabs, + activeFormTab, + evaluatedNodes, + textContent, + onTabChange, + onClose, + onDeleteNode, + onSetKind, + onUpdateNode, + onSetStepTarget, + onAddNodeItem, + onUpdateNodeItem, + onDeleteNodeItem, + onToggleLinkedParent +}) { + if (!selectedNode) { + return ( +
+

{textContent.emptySelection || "Sélectionnez ou créez un objectif."}

+
+ ); + } + + return ( +
+
+ + + {activeFormTab === "base" && ( + + )} + + {activeFormTab === "content" && !selectedNodeIsStep && ( +
+ onAddNodeItem(selectedNode.id)} + onUpdate={(itemId, updater) => onUpdateNodeItem(selectedNode.id, itemId, updater)} + onDelete={(itemId) => onDeleteNodeItem(selectedNode.id, itemId)} + /> +
+ )} + + {activeFormTab === "content" && selectedNodeIsStep && ( +
+

{textContent.stepContentUnavailable || "Les étapes n'ont pas de contenu interne."}

+
+ )} + + {activeFormTab === "advanced" && ( + + )} + +
+ + +
+
+
+ ); +} + +function GoalTreeBasePanel({ selectedNode, selectedNodeIsStep, textContent, onSetKind, onUpdateNode }) { + return ( +
+ + + {selectedNodeIsStep && ( + <> + onUpdateNode(selectedNode.id, (node) => ({ ...node, icon }))} + /> +
+ {textContent.iconColorLabel || "Couleur de l'icône"} +
+ {GOAL_TREE_COLORS.map((color) => ( +
+
+ + )} + {!selectedNodeIsStep && ( +

{textContent.contentTabHint || "Le contenu se modifie dans l'onglet Contenu."}

+ )} +
+ ); +} + +function GoalTreeAdvancedPanel({ selectedNode, selectedNodeIsStep, selectedProgressMode, evaluatedNodes, textContent, onUpdateNode, onSetStepTarget, onToggleLinkedParent }) { + return ( +
+ + {selectedNode.resetType !== "none" && ( + + )} + {selectedNode.resetType === "weekly" && ( + + )} + {selectedNodeIsStep && ( + <> +
{textContent.quantitySectionTitle || "Quantité"}
+ +
{textContent.progressSectionTitle || "Progression"}
+