feat: add sidebar panel

This commit is contained in:
2026-07-12 21:02:51 +05:00
parent 66ddc3762f
commit 4704a1d5a0
2 changed files with 106 additions and 0 deletions
+18
View File
@@ -1,10 +1,28 @@
import * as path from "path";
import * as vscode from "vscode";
import { ConfigStore } from "./storage/configStore";
import { TaskStore } from "./storage/taskStore";
import { TaskTreeProvider } from "./views/taskTreeProvider";
export function activate(context: vscode.ExtensionContext) {
const taskStore = new TaskStore();
const configStore = new ConfigStore();
const taskTreeProvider = new TaskTreeProvider();
vscode.window.registerTreeDataProvider(
"projectTasks.tasks",
taskTreeProvider,
);
const projectPath = configStore.getProjectTaskPath();
if (projectPath) {
const taskPattern = path.join(projectPath, "*.task.md").replace(/\\/g, "/");
const watcher = vscode.workspace.createFileSystemWatcher(taskPattern);
watcher.onDidCreate(() => taskTreeProvider.refresh());
watcher.onDidChange(() => taskTreeProvider.refresh());
watcher.onDidDelete(() => taskTreeProvider.refresh());
context.subscriptions.push(watcher);
}
const statusBarItem = vscode.window.createStatusBarItem(
vscode.StatusBarAlignment.Left,
+88
View File
@@ -0,0 +1,88 @@
import * as vscode from "vscode";
import { Task, TaskStatus } from "../model/task";
import { TaskStore } from "../storage/taskStore";
import { ConfigStore } from "../storage/configStore";
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 {
constructor(
label: string,
public readonly tasks: Task[],
icon: vscode.ThemeIcon,
) {
super(label, vscode.TreeItemCollapsibleState.Collapsed);
this.iconPath = icon;
this.description = `(${tasks.length})`;
}
}
export class TaskTreeProvider implements vscode.TreeDataProvider<vscode.TreeItem> {
private _onDidChangeTreeData = new vscode.EventEmitter<
vscode.TreeItem | undefined | null | void
>();
readonly onDidChangeTreeData = this._onDidChangeTreeData.event;
private taskStore = new TaskStore();
private configStore = new 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.listTasks(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;
});
}
}