- remove eslint - refactor code into common design patterns where needed - refactor taskMasterApi from 1.5k lines to smaller chunks and different files - removed taskFileReader (not used anywhere) - added support for tag selection (wip) - added configuration page where a user can see his config.json more visually
139 lines
3.1 KiB
TypeScript
139 lines
3.1 KiB
TypeScript
/**
|
|
* Task Repository - Simplified version
|
|
* Handles data access with caching
|
|
*/
|
|
|
|
import { EventEmitter } from '../utils/event-emitter';
|
|
import type { ExtensionLogger } from '../utils/logger';
|
|
import type { TaskMasterApi, TaskMasterTask } from '../utils/task-master-api';
|
|
|
|
// Use the TaskMasterTask type directly to ensure compatibility
|
|
export type Task = TaskMasterTask;
|
|
|
|
export class TaskRepository extends EventEmitter {
|
|
private cache: Task[] | null = null;
|
|
private cacheTimestamp = 0;
|
|
private readonly CACHE_DURATION = 30000; // 30 seconds
|
|
|
|
constructor(
|
|
private api: TaskMasterApi,
|
|
private logger: ExtensionLogger
|
|
) {
|
|
super();
|
|
}
|
|
|
|
async getAll(): Promise<Task[]> {
|
|
// Return from cache if valid
|
|
if (this.cache && Date.now() - this.cacheTimestamp < this.CACHE_DURATION) {
|
|
return this.cache;
|
|
}
|
|
|
|
try {
|
|
const result = await this.api.getTasks({ withSubtasks: true });
|
|
|
|
if (result.success && result.data) {
|
|
this.cache = result.data;
|
|
this.cacheTimestamp = Date.now();
|
|
this.emit('tasks:updated', result.data);
|
|
return result.data;
|
|
}
|
|
|
|
throw new Error(result.error || 'Failed to fetch tasks');
|
|
} catch (error) {
|
|
this.logger.error('Failed to get tasks', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async getById(taskId: string): Promise<Task | null> {
|
|
// First check cache
|
|
if (this.cache) {
|
|
// Handle both main tasks and subtasks
|
|
for (const task of this.cache) {
|
|
if (task.id === taskId) {
|
|
return task;
|
|
}
|
|
// Check subtasks
|
|
if (task.subtasks) {
|
|
for (const subtask of task.subtasks) {
|
|
if (
|
|
subtask.id === taskId ||
|
|
`${task.id}.${subtask.id}` === taskId
|
|
) {
|
|
return subtask;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// If not in cache, fetch all and search
|
|
const tasks = await this.getAll();
|
|
for (const task of tasks) {
|
|
if (task.id === taskId) {
|
|
return task;
|
|
}
|
|
// Check subtasks
|
|
if (task.subtasks) {
|
|
for (const subtask of task.subtasks) {
|
|
if (subtask.id === taskId || `${task.id}.${subtask.id}` === taskId) {
|
|
return subtask;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
async updateStatus(taskId: string, status: Task['status']): Promise<void> {
|
|
try {
|
|
const result = await this.api.updateTaskStatus(taskId, status);
|
|
|
|
if (!result.success) {
|
|
throw new Error(result.error || 'Failed to update status');
|
|
}
|
|
|
|
// Invalidate cache
|
|
this.cache = null;
|
|
|
|
// Fetch updated tasks
|
|
await this.getAll();
|
|
} catch (error) {
|
|
this.logger.error('Failed to update task status', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async updateContent(taskId: string, updates: any): Promise<void> {
|
|
try {
|
|
const result = await this.api.updateTask(taskId, updates, {
|
|
append: false,
|
|
research: false
|
|
});
|
|
|
|
if (!result.success) {
|
|
throw new Error(result.error || 'Failed to update task');
|
|
}
|
|
|
|
// Invalidate cache
|
|
this.cache = null;
|
|
|
|
// Fetch updated tasks
|
|
await this.getAll();
|
|
} catch (error) {
|
|
this.logger.error('Failed to update task content', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async refresh(): Promise<void> {
|
|
this.cache = null;
|
|
await this.getAll();
|
|
}
|
|
|
|
isConnected(): boolean {
|
|
return this.api.getConnectionStatus().isConnected;
|
|
}
|
|
}
|