feat: add unknown status and priority, change todo status to open

This commit is contained in:
2026-07-18 07:48:11 +05:00
parent 526a001d06
commit 148ed75841
28 changed files with 162 additions and 111 deletions
+5 -4
View File
@@ -2,6 +2,7 @@ import { describe, expect, it } from "vitest";
import { err } from "neverthrow";
import { appError, AppErrorVariant } from "@/error";
import { Task } from "@/model/task";
import { TaskPriority } from "@/model/taskPriority";
import { TaskStatus } from "@/model/taskStatus";
import { serializeTask } from "@/utils/markdown";
import { applyRawTaskContent } from "./applyRawTaskContent";
@@ -10,8 +11,8 @@ const previous: Task = {
id: "keep-me",
title: "Old title",
description: "old body",
status: TaskStatus.TODO,
priority: "medium",
status: TaskStatus.OPEN,
priority: TaskPriority.MEDIUM,
tags: [],
assignee: "",
created: "2026-01-01T00:00:00.000Z",
@@ -26,7 +27,7 @@ describe("applyRawTaskContent", () => {
title: "New title",
description: "new body",
status: TaskStatus.DONE,
priority: "high",
priority: TaskPriority.HIGH,
tags: ["a"],
assignee: "bob",
created: "2099-01-01T00:00:00.000Z",
@@ -41,7 +42,7 @@ describe("applyRawTaskContent", () => {
expect(result.value.title).toBe("New title");
expect(result.value.description).toBe("new body");
expect(result.value.status).toBe(TaskStatus.DONE);
expect(result.value.priority).toBe("high");
expect(result.value.priority).toBe(TaskPriority.HIGH);
expect(result.value.tags).toEqual(["a"]);
expect(result.value.assignee).toBe("bob");
});
+13 -11
View File
@@ -1,13 +1,15 @@
import { describe, expect, it } from "vitest";
import { Task } from "@/model/task";
import { TaskPriority } from "@/model/taskPriority";
import { TaskStatus } from "@/model/taskStatus";
import { GroupBy } from "./groupBy";
import { buildDashboardView } from "./buildDashboardView";
function task(partial: Partial<Task> & Pick<Task, "id" | "title">): Task {
return {
description: "",
status: "todo",
priority: "medium",
status: TaskStatus.OPEN,
priority: TaskPriority.MEDIUM,
tags: [],
assignee: "",
created: "2026-01-01T00:00:00.000Z",
@@ -21,22 +23,22 @@ describe("buildDashboardView", () => {
task({
id: "1",
title: "Alpha",
status: "todo",
priority: "high",
status: TaskStatus.OPEN,
priority: TaskPriority.HIGH,
description: "first",
}),
task({
id: "2",
title: "Beta",
status: "in-progress",
priority: "low",
status: TaskStatus.IN_PROGRESS,
priority: TaskPriority.LOW,
description: "second",
}),
task({
id: "3",
title: "Gamma",
status: "todo",
priority: "medium",
status: TaskStatus.OPEN,
priority: TaskPriority.MEDIUM,
description: "third",
}),
];
@@ -52,12 +54,12 @@ describe("buildDashboardView", () => {
it("applies filter then groups", () => {
const view = buildDashboardView(tasks, {
filter: { statuses: ["todo"] },
filter: { statuses: [TaskStatus.OPEN] },
groupBy: GroupBy.PRIORITY,
});
expect(view.visibleTasks.map((t) => t.id)).toEqual(["1", "3"]);
expect(view.groups.map((g) => g.key)).toEqual(["high", "medium"]);
expect(view.groups.map((g) => g.key)).toEqual([TaskPriority.HIGH, TaskPriority.MEDIUM]);
});
it("resolves selected task by id from the full task list", () => {
@@ -68,7 +70,7 @@ describe("buildDashboardView", () => {
it("keeps selection even when the task is filtered out of the list", () => {
const view = buildDashboardView(tasks, {
filter: { statuses: ["todo"] },
filter: { statuses: [TaskStatus.OPEN] },
selectedId: "2",
});
+3 -2
View File
@@ -1,6 +1,7 @@
import { describe, expect, it } from "vitest";
import { Task } from "@/model/task";
import { LocatedTask, TaskScope } from "@/model/taskLocation";
import { TaskPriority } from "@/model/taskPriority";
import { TaskStatus } from "@/model/taskStatus";
import { filterLocatedByScope } from "./filterLocatedByScope";
@@ -13,8 +14,8 @@ function located(
id,
title: id,
description: "",
status: TaskStatus.TODO,
priority: "medium",
status: TaskStatus.OPEN,
priority: TaskPriority.MEDIUM,
tags: [],
assignee: "",
created: "2026-01-01T00:00:00.000Z",
+18 -16
View File
@@ -1,12 +1,14 @@
import { describe, expect, it } from "vitest";
import { Task } from "@/model/task";
import { TaskPriority } from "@/model/taskPriority";
import { TaskStatus } from "@/model/taskStatus";
import { filterTasks } from "./filterTasks";
function task(partial: Partial<Task> & Pick<Task, "id" | "title">): Task {
return {
description: "",
status: "todo",
priority: "medium",
status: TaskStatus.OPEN,
priority: TaskPriority.MEDIUM,
tags: [],
assignee: "",
created: "2026-01-01T00:00:00.000Z",
@@ -21,32 +23,32 @@ describe("filterTasks", () => {
id: "1",
title: "Fix login",
description: "Auth token expired",
status: "todo",
priority: "high",
status: TaskStatus.OPEN,
priority: TaskPriority.HIGH,
tags: ["bug", "frontend"],
}),
task({
id: "2",
title: "Add dark mode",
description: "Theme toggle",
status: "in-progress",
priority: "medium",
status: TaskStatus.IN_PROGRESS,
priority: TaskPriority.MEDIUM,
tags: ["feature", "frontend"],
}),
task({
id: "3",
title: "Write docs",
description: "API reference",
status: "done",
priority: "low",
status: TaskStatus.DONE,
priority: TaskPriority.LOW,
tags: ["docs"],
}),
task({
id: "4",
title: "Deploy hotfix",
description: "Production login outage",
status: "todo",
priority: "critical",
status: TaskStatus.OPEN,
priority: TaskPriority.CRITICAL,
tags: ["bug", "ops"],
}),
];
@@ -56,17 +58,17 @@ describe("filterTasks", () => {
});
it("filters by a single status", () => {
const result = filterTasks(tasks, { statuses: ["todo"] });
const result = filterTasks(tasks, { statuses: [TaskStatus.OPEN] });
expect(result.map((t) => t.id)).toEqual(["1", "4"]);
});
it("filters by multiple statuses", () => {
const result = filterTasks(tasks, { statuses: ["todo", "done"] });
const result = filterTasks(tasks, { statuses: [TaskStatus.OPEN, TaskStatus.DONE] });
expect(result.map((t) => t.id)).toEqual(["1", "3", "4"]);
});
it("filters by priority", () => {
const result = filterTasks(tasks, { priorities: ["high", "critical"] });
const result = filterTasks(tasks, { priorities: [TaskPriority.HIGH, TaskPriority.CRITICAL] });
expect(result.map((t) => t.id)).toEqual(["1", "4"]);
});
@@ -92,8 +94,8 @@ describe("filterTasks", () => {
it("combines status, priority and query with AND", () => {
const result = filterTasks(tasks, {
statuses: ["todo"],
priorities: ["critical"],
statuses: [TaskStatus.OPEN],
priorities: [TaskPriority.CRITICAL],
query: "login",
});
expect(result.map((t) => t.id)).toEqual(["4"]);
@@ -101,6 +103,6 @@ describe("filterTasks", () => {
it("returns empty array for empty input", () => {
expect(filterTasks([], {})).toEqual([]);
expect(filterTasks([], { statuses: ["todo"] })).toEqual([]);
expect(filterTasks([], { statuses: [TaskStatus.OPEN] })).toEqual([]);
});
});
+4 -4
View File
@@ -16,7 +16,7 @@ import { groupTasks } from "./groupTasks";
function task(partial: Partial<Task> & Pick<Task, "id" | "title">): Task {
return {
description: "",
status: TaskStatus.TODO,
status: TaskStatus.OPEN,
priority: TaskPriority.MEDIUM,
tags: [],
assignee: "",
@@ -37,13 +37,13 @@ describe("groupTasks", () => {
task({
id: "b",
title: "B",
status: TaskStatus.TODO,
status: TaskStatus.OPEN,
priority: TaskPriority.CRITICAL,
}),
task({
id: "c",
title: "C",
status: TaskStatus.TODO,
status: TaskStatus.OPEN,
priority: TaskPriority.HIGH,
}),
task({
@@ -97,7 +97,7 @@ describe("groupTasks", () => {
it("silently drops tasks with unknown status from groups", () => {
const tasks: Task[] = [
task({ id: "a", title: "A", status: "__garbage__" as TaskStatus }),
task({ id: "b", title: "B", status: TaskStatus.TODO }),
task({ id: "b", title: "B", status: TaskStatus.OPEN }),
];
const groups = groupTasks(tasks, GroupBy.STATUS);
const allGrouped = groups.flatMap((g) => g.tasks.map((t) => t.id));
+3 -2
View File
@@ -1,5 +1,6 @@
import { describe, expect, it } from "vitest";
import { Task } from "@/model/task";
import { TaskPriority } from "@/model/taskPriority";
import { TaskStatus } from "@/model/taskStatus";
import { sortTasks, TaskSortDirection } from "./sortTasks";
@@ -8,8 +9,8 @@ function task(
): Task {
return {
description: "",
status: TaskStatus.TODO,
priority: "medium",
status: TaskStatus.OPEN,
priority: TaskPriority.MEDIUM,
tags: [],
assignee: "",
updated: "2026-01-01T00:00:00.000Z",