import { Task, TaskStatus } from "@/model/task"; import { IConfigProvider, ITaskRepository } from "@/ports"; import * as vscode from "vscode"; const STATUS_ORDER: TaskStatus[] = ["todo", "in-progress", "done", "cancelled"]; const STATUS_ICONS: Record = { todo: new vscode.ThemeIcon("circle-outline"), "in-progress": new vscode.ThemeIcon("sync"), done: new vscode.ThemeIcon("check"), cancelled: new vscode.ThemeIcon("close"), }; class TaskGroupTreeItem extends vscode.TreeItem { readonly tasks: Task[]; constructor(label: string, tasks: Task[], icon: vscode.ThemeIcon) { super(label, vscode.TreeItemCollapsibleState.Collapsed); this.iconPath = icon; this.tasks = tasks; this.description = `(${tasks.length})`; } } export class TaskTreeProvider implements vscode.TreeDataProvider { #onDidChangeTreeData = new vscode.EventEmitter< vscode.TreeItem | undefined | null | void >(); readonly onDidChangeTreeData = this.#onDidChangeTreeData.event; #taskStore: ITaskRepository; #configStore: IConfigProvider; constructor(taskStore: ITaskRepository, configStore: IConfigProvider) { this.#taskStore = taskStore; this.#configStore = configStore; } refresh(): void { this.#onDidChangeTreeData.fire(); } getTreeItem(element: vscode.TreeItem): vscode.TreeItem { return element; } async getChildren(element?: vscode.TreeItem): Promise { if (!element) { return this.getRootChildren(); } return this.getTaskChildren(element as TaskGroupTreeItem); } private async getRootChildren(): Promise { const projectPath = this.#configStore.getProjectTaskPath(); if (!projectPath) { return [new vscode.TreeItem("Open a workspace folder to start")]; } const tasks = await this.#taskStore.list(projectPath); return STATUS_ORDER.map((status) => { const groupTasks = tasks.filter((t) => t.status === status); const label = status === "todo" ? "To Do" : status === "in-progress" ? "In Progress" : status === "done" ? "Done" : "Cancelled"; const item = new TaskGroupTreeItem( label, groupTasks, STATUS_ICONS[status], ); item.id = `group-${status}`; item.contextValue = "taskGroup"; return item; }); } private getTaskChildren(group: TaskGroupTreeItem): vscode.TreeItem[] { return group.tasks.map((task) => { const item = new vscode.TreeItem(task.title); item.id = task.id; item.description = task.priority; item.tooltip = new vscode.MarkdownString( `**${task.title}**\n\nPriority: ${task.priority}\nStatus: ${task.status}${task.assignee ? `\nAssignee: ${task.assignee}` : ""}`, ); item.contextValue = "task"; return item; }); } }