feat: update kanban view, dashboard view, add backlog status

This commit is contained in:
2026-07-15 03:14:03 +05:00
parent 84f64af62d
commit e46437a512
16 changed files with 451 additions and 141 deletions
+18 -25
View File
@@ -9,25 +9,23 @@ import {
describe("parseDashboardInboundMessage", () => {
it("parses ready", () => {
expect(parseDashboardInboundMessage({ type: "ready" })).toEqual(
ok({ type: "ready" } satisfies DashboardInboundMessage),
expect(parseDashboardInboundMessage({ variant: "ready" })).toEqual(
ok({ variant: "ready" } satisfies DashboardInboundMessage),
);
});
it("parses selectTask", () => {
expect(
parseDashboardInboundMessage({ type: "selectTask", id: "abc" }),
).toEqual(ok({ type: "selectTask", id: "abc" }));
parseDashboardInboundMessage({ variant: "selectTask", id: "abc" }),
).toEqual(ok({ variant: "selectTask", id: "abc" }));
});
it("parses setFilter", () => {
const raw = {
type: "setFilter",
const raw = { variant: "setFilter",
filter: { statuses: ["todo"], query: "login" },
};
expect(parseDashboardInboundMessage(raw)).toEqual(
ok({
type: "setFilter",
ok({ variant: "setFilter",
filter: { statuses: ["todo"], query: "login" },
}),
);
@@ -35,23 +33,20 @@ describe("parseDashboardInboundMessage", () => {
it("parses setGroupBy", () => {
expect(
parseDashboardInboundMessage({
type: "setGroupBy",
parseDashboardInboundMessage({ variant: "setGroupBy",
groupBy: GroupBy.STATUS,
}),
).toEqual(ok({ type: "setGroupBy", groupBy: GroupBy.STATUS }));
).toEqual(ok({ variant: "setGroupBy", groupBy: GroupBy.STATUS }));
});
it("parses saveDescription", () => {
expect(
parseDashboardInboundMessage({
type: "saveDescription",
parseDashboardInboundMessage({ variant: "saveDescription",
id: "abc",
description: "updated body",
}),
).toEqual(
ok({
type: "saveDescription",
ok({ variant: "saveDescription",
id: "abc",
description: "updated body",
}),
@@ -59,14 +54,14 @@ describe("parseDashboardInboundMessage", () => {
});
it("parses refresh", () => {
expect(parseDashboardInboundMessage({ type: "refresh" })).toEqual(
ok({ type: "refresh" }),
expect(parseDashboardInboundMessage({ variant: "refresh" })).toEqual(
ok({ variant: "refresh" }),
);
});
it("parses createTask", () => {
expect(parseDashboardInboundMessage({ type: "createTask" })).toEqual(
ok({ type: "createTask" } satisfies DashboardInboundMessage),
expect(parseDashboardInboundMessage({ variant: "createTask" })).toEqual(
ok({ variant: "createTask" } satisfies DashboardInboundMessage),
);
});
@@ -78,22 +73,21 @@ describe("parseDashboardInboundMessage", () => {
});
it("rejects unknown type", () => {
const result = parseDashboardInboundMessage({ type: "explode" });
const result = parseDashboardInboundMessage({ variant: "explode" });
expect(result.isErr()).toBe(true);
if (result.isOk()) return;
expect(result.error.variant).toBe(AppErrorVariant.INVALID_MESSAGE);
});
it("rejects selectTask without id", () => {
const result = parseDashboardInboundMessage({ type: "selectTask" });
const result = parseDashboardInboundMessage({ variant: "selectTask" });
expect(result.isErr()).toBe(true);
if (result.isOk()) return;
expect(result.error.variant).toBe(AppErrorVariant.INVALID_MESSAGE);
});
it("rejects setGroupBy with invalid groupBy", () => {
const result = parseDashboardInboundMessage({
type: "setGroupBy",
const result = parseDashboardInboundMessage({ variant: "setGroupBy",
groupBy: "__not_a_group_by__",
});
expect(result.isErr()).toBe(true);
@@ -102,8 +96,7 @@ describe("parseDashboardInboundMessage", () => {
});
it("rejects saveDescription with non-string description", () => {
const result = parseDashboardInboundMessage({
type: "saveDescription",
const result = parseDashboardInboundMessage({ variant: "saveDescription",
id: "abc",
description: 42,
});
+21 -23
View File
@@ -4,13 +4,13 @@ import { TaskFilter } from "./filterTasks";
import { GroupBy, isGroupBy } from "./groupBy";
export type DashboardInboundMessage =
| { type: "ready" }
| { type: "selectTask"; id: string }
| { type: "setFilter"; filter: TaskFilter }
| { type: "setGroupBy"; groupBy: GroupBy }
| { type: "saveDescription"; id: string; description: string }
| { type: "refresh" }
| { type: "createTask" };
| { variant: "ready" }
| { variant: "selectTask"; id: string }
| { variant: "setFilter"; filter: TaskFilter }
| { variant: "setGroupBy"; groupBy: GroupBy }
| { variant: "saveDescription"; id: string; description: string }
| { variant: "refresh" }
| { variant: "createTask" };
function invalid(detail?: string): Result<DashboardInboundMessage, AppError> {
return err(
@@ -31,56 +31,54 @@ export function parseDashboardInboundMessage(
return invalid();
}
const type = raw.type;
if (typeof type !== "string") {
const variant = raw.variant;
if (typeof variant !== "string") {
return invalid();
}
switch (type) {
switch (variant) {
case "ready":
case "refresh":
case "createTask":
return ok({ type });
return ok({ variant });
case "selectTask": {
if (typeof raw.id !== "string" || raw.id.length === 0) {
return invalid(type);
return invalid(variant);
}
return ok({ type: "selectTask", id: raw.id });
return ok({ variant: "selectTask", id: raw.id });
}
case "setFilter": {
if (!isRecord(raw.filter)) {
return invalid(type);
return invalid(variant);
}
return ok({
type: "setFilter",
return ok({ variant: "setFilter",
filter: raw.filter as TaskFilter,
});
}
case "setGroupBy": {
if (!isGroupBy(raw.groupBy)) {
return invalid(type);
return invalid(variant);
}
return ok({ type: "setGroupBy", groupBy: raw.groupBy });
return ok({ variant: "setGroupBy", groupBy: raw.groupBy });
}
case "saveDescription": {
if (typeof raw.id !== "string" || raw.id.length === 0) {
return invalid(type);
return invalid(variant);
}
if (typeof raw.description !== "string") {
return invalid(type);
return invalid(variant);
}
return ok({
type: "saveDescription",
return ok({ variant: "saveDescription",
id: raw.id,
description: raw.description,
});
}
default:
return invalid(type);
return invalid(variant);
}
}
+3 -4
View File
@@ -5,13 +5,12 @@ import { GroupBy, TaskGroup } from "./groupTasks";
/** Host → webview messages (presentation payload only). */
export type DashboardOutboundMessage =
| {
type: "state";
| { variant: "state";
filter: TaskFilter;
groupBy: GroupBy;
selectedId: string | undefined;
groups: TaskGroup[];
selected: Task | null;
}
| { type: "error"; error: AppError }
| { type: "saved"; task: Task };
| { variant: "error"; error: AppError }
| { variant: "saved"; task: Task };