add task planner & alert improvments
All checks were successful
Deploy Sokko G / deploy (push) Successful in 7s
All checks were successful
Deploy Sokko G / deploy (push) Successful in 7s
This commit is contained in:
parent
2e6d8a2c0c
commit
e306bfc5d6
15 changed files with 1547 additions and 4 deletions
|
|
@ -189,6 +189,39 @@ export function validateSiteContent(site) {
|
|||
"toolboxes.modules.timer.emptyCountdowns",
|
||||
"toolboxes.modules.timer.renameTitle",
|
||||
"toolboxes.modules.timer.deleteTitle",
|
||||
"toolboxes.modules.taskPlanner.settingsTitle",
|
||||
"toolboxes.modules.taskPlanner.settingsButtonLabel",
|
||||
"toolboxes.modules.taskPlanner.sortModeLabel",
|
||||
"toolboxes.modules.taskPlanner.globalWeeklyResetDayLabel",
|
||||
"toolboxes.modules.taskPlanner.resetTimeLabel",
|
||||
"toolboxes.modules.taskPlanner.titlePlaceholder",
|
||||
"toolboxes.modules.taskPlanner.titleLabel",
|
||||
"toolboxes.modules.taskPlanner.descriptionPlaceholder",
|
||||
"toolboxes.modules.taskPlanner.descriptionLabel",
|
||||
"toolboxes.modules.taskPlanner.typeLabel",
|
||||
"toolboxes.modules.taskPlanner.uniqueType",
|
||||
"toolboxes.modules.taskPlanner.dailyType",
|
||||
"toolboxes.modules.taskPlanner.weeklyType",
|
||||
"toolboxes.modules.taskPlanner.addButton",
|
||||
"toolboxes.modules.taskPlanner.reorderTitle",
|
||||
"toolboxes.modules.taskPlanner.reorderDisabledTitle",
|
||||
"toolboxes.modules.taskPlanner.checkTitle",
|
||||
"toolboxes.modules.taskPlanner.uncheckTitle",
|
||||
"toolboxes.modules.taskPlanner.deleteTitle",
|
||||
"toolboxes.modules.taskPlanner.showDescriptionTitle",
|
||||
"toolboxes.modules.taskPlanner.hideDescriptionTitle",
|
||||
"toolboxes.modules.taskPlanner.taskSettingsTitle",
|
||||
"toolboxes.modules.taskPlanner.missingDependencyTitle",
|
||||
"toolboxes.modules.taskPlanner.missingDependencyBadge",
|
||||
"toolboxes.modules.taskPlanner.missingDependencyNotice",
|
||||
"toolboxes.modules.taskPlanner.taskWeeklyResetDayLabel",
|
||||
"toolboxes.modules.taskPlanner.inheritWeeklyResetDay",
|
||||
"toolboxes.modules.taskPlanner.linksLabel",
|
||||
"toolboxes.modules.taskPlanner.emptyLinks",
|
||||
"toolboxes.modules.taskPlanner.addLinkLabel",
|
||||
"toolboxes.modules.taskPlanner.dependencyCheckboxLabel",
|
||||
"toolboxes.modules.taskPlanner.removeRelationTitle",
|
||||
"toolboxes.modules.taskPlanner.emptyTasks",
|
||||
"toolboxes.modules.imageAnnotation.addImage",
|
||||
"toolboxes.modules.imageAnnotation.replaceImage",
|
||||
"toolboxes.modules.imageAnnotation.pastePlaceholder",
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ test("toolbox storage, cards and pages are wired", async () => {
|
|||
assert.match(toolboxStorage, /export function normalizeCountersData/);
|
||||
assert.match(toolboxStorage, /export function normalizeCalculatorData/);
|
||||
assert.match(toolboxStorage, /export function normalizeTimerData/);
|
||||
assert.match(toolboxStorage, /export function normalizeTaskPlannerData/);
|
||||
assert.match(toolboxStorage, /export function normalizeImageAnnotationData/);
|
||||
assert.match(toolboxStorage, /export function compactModuleDataForStorage\(type, value\)/);
|
||||
assert.match(toolboxStorage, /scrollResults/);
|
||||
|
|
@ -77,6 +78,7 @@ test("toolbox module registry and modules expose expected behavior", async () =>
|
|||
const notepadModule = await readFile("website/src/features/toolboxes/modules/NotepadModule.jsx", "utf8");
|
||||
const calculatorModule = await readFile("website/src/features/toolboxes/modules/CalculatorModule.jsx", "utf8");
|
||||
const timerModule = await readFile("website/src/features/toolboxes/modules/TimerModule.jsx", "utf8");
|
||||
const taskPlannerModule = await readFile("website/src/features/toolboxes/modules/TaskPlannerModule.jsx", "utf8");
|
||||
const checklistModule = await readFile("website/src/features/toolboxes/modules/ChecklistModule.jsx", "utf8");
|
||||
const imagesModule = await readFile("website/src/features/toolboxes/modules/ImagesModule.jsx", "utf8");
|
||||
const imageAnnotationModule = await readFile("website/src/features/toolboxes/modules/ImageAnnotationModule.jsx", "utf8");
|
||||
|
|
@ -97,6 +99,7 @@ test("toolbox module registry and modules expose expected behavior", async () =>
|
|||
assert.match(moduleRegistry, /counters:/);
|
||||
assert.match(moduleRegistry, /calculator:/);
|
||||
assert.match(moduleRegistry, /timer:/);
|
||||
assert.match(moduleRegistry, /taskPlanner:/);
|
||||
assert.match(moduleRegistry, /imageAnnotation:/);
|
||||
assert.match(moduleRegistry, /Annotation d'images/);
|
||||
assert.match(moduleRegistry, /editable: false/);
|
||||
|
|
@ -134,6 +137,13 @@ test("toolbox module registry and modules expose expected behavior", async () =>
|
|||
assert.match(timerModule, /stopwatch/);
|
||||
assert.match(timerModule, /countdown/);
|
||||
assert.match(timerModule, /normalizeTimerData/);
|
||||
assert.match(taskPlannerModule, /export function TaskPlannerModule/);
|
||||
assert.match(taskPlannerModule, /normalizeTaskPlannerData/);
|
||||
assert.match(taskPlannerModule, /applyDueResets/);
|
||||
assert.match(taskPlannerModule, /relations/);
|
||||
assert.match(taskPlannerModule, /dependency/);
|
||||
assert.match(taskPlannerModule, /task-planner-warning/);
|
||||
assert.match(taskPlannerModule, /usePointerReorder/);
|
||||
assert.match(checklistModule, /export function ChecklistModule/);
|
||||
assert.match(checklistModule, /TextImportModal/);
|
||||
assert.match(checklistModule, /Icon name="import"/);
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import { test } from "node:test";
|
|||
import assert from "node:assert/strict";
|
||||
import { parseColonImportLines } from "../website/src/features/toolboxes/modules/textImport.js";
|
||||
import { getTimePatternRecurrenceMs, getTimePatternTargetMs } from "../website/src/features/toolboxes/modules/timerUtils.js";
|
||||
import { compactModuleDataForStorage, createToolboxExportPayload, normalizeTaskPlannerData } from "../website/src/features/toolboxes/storage/toolboxStorage.js";
|
||||
|
||||
test("colon text import keeps urls intact after the first separator", () => {
|
||||
assert.deepEqual(parseColonImportLines("Build:https://example.com/build?class=rogue\nPotion:10"), [
|
||||
|
|
@ -26,3 +27,82 @@ test("time pattern recurrence uses configured frequency instead of next remainin
|
|||
assert.equal(getTimePatternRecurrenceMs("X:24:X"), 60 * 60 * 1000);
|
||||
assert.equal(getTimePatternRecurrenceMs("X:X:30"), 60 * 1000);
|
||||
});
|
||||
|
||||
test("task planner data normalizes invalid settings and relations", () => {
|
||||
const normalized = normalizeTaskPlannerData({
|
||||
sortMode: "unknown",
|
||||
weeklyResetDay: 9,
|
||||
resetTime: "27:80",
|
||||
tasks: [
|
||||
{ id: "task1", title: "Daily", type: "daily", checked: true, checkedAt: 1000 },
|
||||
{ id: "task2", title: "Weekly", type: "weekly", weeklyResetDay: 4 },
|
||||
{ id: "task3", title: "Invalid type", type: "later" }
|
||||
],
|
||||
relations: [
|
||||
{ id: "link1", fromTaskId: "task1", toTaskId: "task2" },
|
||||
{ id: "dep1", fromTaskId: "task2", toTaskId: "task1", dependency: true },
|
||||
{ id: "bad", fromTaskId: "task1", toTaskId: "missing" },
|
||||
{ id: "self", fromTaskId: "task2", toTaskId: "task2" }
|
||||
]
|
||||
});
|
||||
|
||||
assert.equal(normalized.sortMode, "manual");
|
||||
assert.equal(normalized.weeklyResetDay, 1);
|
||||
assert.equal(normalized.resetTime, "00:00");
|
||||
assert.equal(normalized.tasks[1].weeklyResetDay, 4);
|
||||
assert.equal(normalized.tasks[2].type, "unique");
|
||||
assert.deepEqual(normalized.relations.map((relation) => relation.id), ["link1", "dep1"]);
|
||||
assert.equal(normalized.relations[0].dependency, false);
|
||||
assert.equal(normalized.relations[1].dependency, true);
|
||||
});
|
||||
|
||||
test("task planner accepts temporary split links data as combined relations", () => {
|
||||
const normalized = normalizeTaskPlannerData({
|
||||
tasks: [
|
||||
{ id: "task1", title: "Daily", type: "daily" },
|
||||
{ id: "task2", title: "Weekly", type: "weekly" }
|
||||
],
|
||||
links: [{ id: "link1", fromTaskId: "task1", toTaskId: "task2" }],
|
||||
dependencies: [{ id: "dep1", fromTaskId: "task2", toTaskId: "task1" }]
|
||||
});
|
||||
|
||||
assert.deepEqual(normalized.relations.map((relation) => relation.toTaskId), ["task2", "task1"]);
|
||||
assert.equal(normalized.relations[0].dependency, false);
|
||||
assert.equal(normalized.relations[1].dependency, true);
|
||||
});
|
||||
|
||||
|
||||
test("task planner storage compacts defaults and export remaps task relations", () => {
|
||||
const compact = compactModuleDataForStorage("taskPlanner", {
|
||||
sortMode: "type",
|
||||
weeklyResetDay: 1,
|
||||
resetTime: "00:00",
|
||||
tasks: [
|
||||
{ id: "task1", title: "Daily", description: "", type: "daily", checked: false },
|
||||
{ id: "task2", title: "Weekly", description: "Run", type: "weekly", checked: true, checkedAt: 2000, weeklyResetDay: 5 }
|
||||
],
|
||||
relations: [
|
||||
{ id: "link1", fromTaskId: "task1", toTaskId: "task2", dependency: false },
|
||||
{ id: "dep1", fromTaskId: "task2", toTaskId: "task1", dependency: true }
|
||||
]
|
||||
});
|
||||
|
||||
assert.equal(compact.sortMode, "type");
|
||||
assert.equal(compact.weeklyResetDay, undefined);
|
||||
assert.equal(compact.resetTime, undefined);
|
||||
assert.deepEqual(compact.tasks[0], { id: "task1", title: "Daily", type: "daily" });
|
||||
assert.equal(compact.tasks[1].weeklyResetDay, 5);
|
||||
|
||||
const exported = createToolboxExportPayload(
|
||||
{ id: "toolbox1", name: "Planner", modules: [{ id: "module1", type: "taskPlanner" }], updatedAt: "2026-01-01T00:00:00.000Z" },
|
||||
{ "toolbox1:module1": compact }
|
||||
);
|
||||
const exportedPlanner = exported.modules.m1;
|
||||
assert.deepEqual(exportedPlanner.tasks.map((task) => task.id), ["a1", "a2"]);
|
||||
assert.equal(exportedPlanner.relations[0].fromTaskId, "a1");
|
||||
assert.equal(exportedPlanner.relations[0].toTaskId, "a2");
|
||||
assert.equal(exportedPlanner.relations[0].dependency, undefined);
|
||||
assert.equal(exportedPlanner.relations[1].fromTaskId, "a2");
|
||||
assert.equal(exportedPlanner.relations[1].toTaskId, "a1");
|
||||
assert.equal(exportedPlanner.relations[1].dependency, true);
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue