Add planner-aware memos and unified tool configuration panels
All checks were successful
Deploy Sokko G / deploy (push) Successful in 18s

This commit is contained in:
Shinuwa 2026-10-03 15:58:33 +02:00
parent acd9b2fe11
commit 808610dcf2
53 changed files with 842 additions and 329 deletions

View file

@ -4,6 +4,7 @@ import { test } from "node:test";
import assert from "node:assert/strict";
import { SOCKET_SHAPES, formatValue, getSocketItemName, setItemCategory } from "../website/src/features/toolboxes/modules/equipmentPlannerOptions.js";
import { applyDueResets, getTaskParentMap, getTaskTreeIds, isTaskResetSoon, moveTask } from "../website/src/features/toolboxes/modules/taskPlannerUtils.js";
import { getMemosDataAfterPlannerRemoval, getPlannerTaskTickerItems, resolveMemosPlannerLink } from "../website/src/features/toolboxes/modules/memosPlannerUtils.js";
import { createInput, getInputLabel, normalizeCustomKey, parseHoldSeconds } from "../website/src/features/toolboxes/modules/combosUtils.js";
import { getBoundsFromStartAndSize, getSelectionBounds, moveSelectionCells, parseTsvBlock, pasteCellBlock } from "../website/src/features/toolboxes/modules/tableUtils.js";
import { canToggleAutoRefresh, getCountdownValidationError, isAlertGuarded } from "../website/src/features/toolboxes/modules/timerOptions.js";
@ -97,7 +98,8 @@ test("toolbox module registry and modules expose expected behavior", async () =>
const toolboxPages = await readFile("website/src/features/toolboxes/ToolboxPages.jsx", "utf8");
const toolboxModules = await readFile("website/src/features/toolboxes/modules/ToolboxModules.jsx", "utf8");
const moduleShell = await readFile("website/src/features/toolboxes/modules/ModuleShell.jsx", "utf8");
const moduleRegistryBundle = `${moduleRegistry}\n${moduleComponents}\n${addToolControls}\n${toolboxModules}\n${moduleShell}`;
const moduleConfiguration = await readFile("website/src/features/toolboxes/modules/ModuleConfiguration.jsx", "utf8");
const moduleRegistryBundle = `${moduleRegistry}\n${moduleComponents}\n${addToolControls}\n${toolboxModules}\n${moduleShell}\n${moduleConfiguration}`;
const moduleMetadataRegistry = await readFile("website/src/features/toolboxes/toolboxModuleRegistry.js", "utf8");
const notepadModule = await readFile("website/src/features/toolboxes/modules/NotepadModule.jsx", "utf8");
const notepadToolbar = await readFile("website/src/features/toolboxes/modules/NotepadToolbar.jsx", "utf8");
@ -139,7 +141,7 @@ test("toolbox module registry and modules expose expected behavior", async () =>
const taskPlannerReorder = await readFile("website/src/features/toolboxes/modules/useTaskPlannerReorder.js", "utf8");
const taskPlannerTopbar = await readFile("website/src/features/toolboxes/modules/TaskPlannerTopbar.jsx", "utf8");
const taskPlannerSettings = await readFile("website/src/features/toolboxes/modules/TaskPlannerSettings.jsx", "utf8");
const taskPlannerBundle = `${taskPlannerBranch}\n${taskPlannerItem}\n${taskPlannerItemPanels}\n${taskPlannerReorder}\n${taskPlannerTopbar}\n${taskPlannerSettings}`;
const taskPlannerBundle = `${taskPlannerModule}\n${taskPlannerBranch}\n${taskPlannerItem}\n${taskPlannerItemPanels}\n${taskPlannerReorder}\n${taskPlannerTopbar}\n${taskPlannerSettings}`;
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");
@ -240,12 +242,18 @@ test("toolbox module registry and modules expose expected behavior", async () =>
assert.match(moduleShell, /module-scroll-button/);
assert.match(moduleShell, /module-collapse-button/);
assert.match(moduleShell, /aria-expanded=\{!collapsed\}/);
assert.match(moduleShell, /!collapsed &&/);
assert.match(moduleShell, /!collapsed \|\| configurationOpen/);
assert.match(moduleShell, /module-configuration-button/);
assert.match(moduleShell, /aria-controls=\{configurationId\}/);
assert.match(moduleShell, /module-configuration-panel/);
assert.match(moduleShell, /hidden=\{collapsed\}/);
assert.match(moduleConfiguration, /createPortal/);
assert.doesNotMatch(moduleShell, /module-exchange-button/);
assert.match(addToolControls, /Icon name="dropdown"/);
assert.match(addToolControls, /CompactDropdown/);
assert.doesNotMatch(source, /<select value="" onChange=\{\(event\) => addModule/);
assert.match(notepadModule, /export function NotepadModule/);
assert.match(notepadModule, /TextExchangeActions/);
assert.match(notepadModule, /ModuleTextExchangeConfiguration/);
assert.match(notepadModule, /type="notepad"/);
assert.match(notepadToolbar, /export function NotepadToolbar/);
assert.match(notepadToolbar, /FormattingColorDropdown/);
@ -300,7 +308,7 @@ test("toolbox module registry and modules expose expected behavior", async () =>
assert.match(timerBundle, /useInlineEdit/);
assert.match(timerModule, /useDraftForm/);
assert.match(timerModule, /normalizeTimerData/);
assert.match(timerModule, /TextExchangeActions/);
assert.match(timerModule, /ModuleTextExchangeConfiguration/);
assert.match(calendarModule, /export function CalendarModule/);
assert.match(calendarModule, /normalizeCalendarData/);
assert.match(calendarBundle, /calendar-mode-choice/);
@ -322,7 +330,7 @@ test("toolbox module registry and modules expose expected behavior", async () =>
assert.match(calendarBundle, /data-size=\{eventSurfaceSize\}/);
assert.match(calendarBundle, /is-compact/);
assert.match(calendarController, /handleKeyDown/);
assert.match(calendarContent, /TextExchangeActions/);
assert.match(calendarContent, /ModuleTextExchangeConfiguration/);
assert.match(calendarContent, /type="calendar"/);
assert.match(calendarBundle, /repeatLabel/);
assert.match(calendarBundle, /CalendarAlertModeSwitch/);
@ -342,7 +350,7 @@ test("toolbox module registry and modules expose expected behavior", async () =>
assert.match(goalTreeModule, /export function GoalTreeModule/);
assert.match(goalTreeBundle, /normalizeGoalTreeData/);
assert.match(goalTreeBundle, /applyGoalTreeDueResets/);
assert.match(goalTreeModule, /TextExchangeActions/);
assert.match(goalTreeModule, /ModuleTextExchangeConfiguration/);
assert.match(goalTreeBundle, /DiagramConnectors/);
assert.match(goalTreeEditor, /export function GoalTreeEditor/);
assert.match(goalTreeEditor, /Tabs/);
@ -388,14 +396,14 @@ test("toolbox module registry and modules expose expected behavior", async () =>
assert.match(equipmentPlannerEditors, /export \{ CharacteristicsEditor \}/);
assert.match(equipmentPlannerEditors, /export \{ MaterialsEditor \}/);
assert.match(equipmentPlannerEditors, /export \{ SocketItemsEditor \}/);
assert.match(equipmentPlannerModule, /TextExchangeActions/);
assert.match(equipmentPlannerModule, /ModuleTextExchangeConfiguration/);
assert.match(equipmentPlannerItem, /export function EquipmentItem/);
assert.match(equipmentPlannerPickers, /export function IconChoiceDropdown/);
assert.match(equipmentPlannerSummary, /export function EquipmentPlannerSummary/);
assert.match(equipmentPlannerOptions, /export const EQUIPMENT_ICONS/);
assert.match(equipmentPlannerOptions, /export function formatValue/);
assert.match(checklistModule, /export function ChecklistModule/);
assert.match(checklistModule, /TextExchangeActions/);
assert.match(checklistModule, /ModuleTextExchangeConfiguration/);
assert.match(checklistModule, /editing &&/);
assert.match(checklistParts, /ChecklistItem/);
assert.match(checklistParts, /export function ChecklistSection/);
@ -420,7 +428,7 @@ test("toolbox module registry and modules expose expected behavior", async () =>
assert.match(imagesModule, /editing &&/);
assert.match(imagesModule, /clipboardData/);
assert.match(imagesModule, /createImageAnnotationModule/);
assert.match(imagesModule, /TextExchangeActions/);
assert.match(imagesModule, /ModuleTextExchangeConfiguration/);
assert.match(imagesModule, /image-annotate-button/);
assert.match(imagesModule, /kind: "collection"/);
assert.match(imagesModule, /galleryButton/);
@ -432,15 +440,15 @@ test("toolbox module registry and modules expose expected behavior", async () =>
assert.match(imageAnnotationModule, /context\.setImage/);
assert.match(imageAnnotationModule, /createMarkerId/);
assert.match(imageAnnotationModule, /<Icon name="zoom"/);
assert.match(imageAnnotationModule, /TextExchangeActions/);
assert.match(linksModule, /TextExchangeActions/);
assert.match(imageAnnotationModule, /ModuleTextExchangeConfiguration/);
assert.match(linksModule, /ModuleTextExchangeConfiguration/);
assert.match(linksModule, /normalizeUrl/);
assert.match(linksModule, /useGroupedReorder/);
assert.match(linksModule, /link-drag-handle/);
assert.match(countersModule, /useGroupedReorder/);
assert.match(countersModule, /orientation: "horizontal"/);
assert.match(countersModule, /counter-drag-handle/);
assert.match(countersModule, /TextExchangeActions/);
assert.match(countersModule, /ModuleTextExchangeConfiguration/);
assert.match(timerModule, /useGroupedReorder/);
assert.match(timerModule, /reorderEnabled={!data\.sortResults}/);
assert.match(timerModule, /parentId=\{moduleId\}/);
@ -510,6 +518,41 @@ test("task planner helpers keep hierarchy, reorder and reset behavior stable", (
assert.equal(isTaskResetSoon({ id: "h", title: "H", type: "unique", checked: false }, resetData, new Date(2026, 0, 6, 7, 0).getTime()), false);
});
test("memos planner links select reset alerts and clear removed targets", () => {
const modules = [
{ id: "planner-a", type: "taskPlanner", title: "Raids" },
{ id: "planner-b", type: "taskPlanner", title: "Farm" },
{ id: "notes", type: "memos" }
];
const plannerData = {
"planner-a": {
resetTime: "06:00",
weeklyResetDay: 1,
tasks: [
{ id: "parent", title: "Parent", type: "unique", category: "Raid" },
{ id: "soon", title: "Donjon", type: "daily" },
{ id: "done", title: "Déjà faite", type: "daily", checked: true, checkedAt: Date.UTC(2026, 0, 2, 0) }
],
relations: [{ id: "relation", fromTaskId: "soon", toTaskId: "parent" }]
},
"planner-b": { resetTime: "18:00", tasks: [{ id: "later", title: "Récolte", type: "daily" }] }
};
const alerts = getPlannerTaskTickerItems({
plannerLink: "all",
modules,
getPlannerData: (plannerId) => plannerData[plannerId],
nowMs: Date.UTC(2026, 0, 2, 1),
alertTemplate: "Tâche : {category}{title} expire bientôt"
});
assert.deepEqual(alerts.map((item) => item.text), ["Tâche : Raid Donjon expire bientôt"]);
assert.equal(alerts[0].kind, "task-warning");
assert.equal(resolveMemosPlannerLink("missing", modules), "");
assert.equal(getMemosDataAfterPlannerRemoval({ plannerLink: "planner-a" }, "planner-a", modules.slice(1)).plannerLink, "");
assert.equal(getMemosDataAfterPlannerRemoval({ plannerLink: "all" }, "planner-a", modules.slice(1)).plannerLink, "all");
assert.equal(getMemosDataAfterPlannerRemoval({ plannerLink: "all" }, "planner-b", [{ id: "notes", type: "memos" }]).plannerLink, "");
});
test("equipment planner options expose stable formatting and socket helpers", () => {
assert.deepEqual(SOCKET_SHAPES, ["ball", "jewel"]);
assert.equal(formatValue(1.23456), "1.235");