96 lines
2.7 KiB
TypeScript
96 lines
2.7 KiB
TypeScript
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<TaskStatus, vscode.ThemeIcon> = {
|
|
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<vscode.TreeItem> {
|
|
#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<vscode.TreeItem[]> {
|
|
if (!element) {
|
|
return this.getRootChildren();
|
|
}
|
|
return this.getTaskChildren(element as TaskGroupTreeItem);
|
|
}
|
|
|
|
private async getRootChildren(): Promise<vscode.TreeItem[]> {
|
|
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;
|
|
});
|
|
}
|
|
}
|