fix: align web-client and BFF with TRACKER-PROTOCOL.md
All checks were successful
Deploy Web Client / deploy (push) Successful in 37s
All checks were successful
Deploy Web Client / deploy (push) Successful in 37s
- Add missing API functions: takeTask, rejectTask, assignTask, watchTask, unwatchTask - Add WebSocket event handlers for task.created, task.updated, task.assigned in KanbanBoard - Ensure real-time updates for task operations - All components now fully compatible with TRACKER-PROTOCOL.md specification
This commit is contained in:
parent
f99713195f
commit
c37d9aed15
@ -4,6 +4,7 @@ import { useEffect, useState } from "react";
|
||||
import { Task, getTasks, updateTask } from "@/lib/api";
|
||||
import TaskModal from "@/components/TaskModal";
|
||||
import CreateTaskModal from "@/components/CreateTaskModal";
|
||||
import { wsClient } from "@/lib/ws";
|
||||
|
||||
const COLUMNS = [
|
||||
{ key: "backlog", label: "Backlog", color: "#737373" },
|
||||
@ -44,7 +45,34 @@ export default function KanbanBoard({ projectId, projectSlug }: Props) {
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => { loadTasks(); }, [projectId]);
|
||||
useEffect(() => {
|
||||
loadTasks();
|
||||
|
||||
// Subscribe to WebSocket events for real-time updates
|
||||
const unsubscribeCreated = wsClient.on("task.created", (data: any) => {
|
||||
if (data.project_id === projectId) {
|
||||
setTasks((prev) => [...prev, data as Task]);
|
||||
}
|
||||
});
|
||||
|
||||
const unsubscribeUpdated = wsClient.on("task.updated", (data: any) => {
|
||||
if (data.project_id === projectId) {
|
||||
setTasks((prev) => prev.map((t) => t.id === data.id ? { ...t, ...data } : t));
|
||||
}
|
||||
});
|
||||
|
||||
const unsubscribeAssigned = wsClient.on("task.assigned", (data: any) => {
|
||||
if (data.project_id === projectId) {
|
||||
setTasks((prev) => prev.map((t) => t.id === data.id ? { ...t, assignee_slug: data.assignee_slug, assigned_at: data.assigned_at } : t));
|
||||
}
|
||||
});
|
||||
|
||||
return () => {
|
||||
unsubscribeCreated?.();
|
||||
unsubscribeUpdated?.();
|
||||
unsubscribeAssigned?.();
|
||||
};
|
||||
}, [projectId]);
|
||||
|
||||
const handleDrop = async (status: string) => {
|
||||
if (!draggedTask) return;
|
||||
|
||||
@ -173,6 +173,32 @@ export async function deleteTask(taskId: string): Promise<void> {
|
||||
await request(`/api/v1/tasks/${taskId}`, { method: "DELETE" });
|
||||
}
|
||||
|
||||
export async function takeTask(taskId: string, slug: string): Promise<Task> {
|
||||
return request(`/api/v1/tasks/${taskId}/take?slug=${slug}`, { method: "POST" });
|
||||
}
|
||||
|
||||
export async function rejectTask(taskId: string, reason: string): Promise<{ok: boolean; reason: string; old_assignee: string}> {
|
||||
return request(`/api/v1/tasks/${taskId}/reject`, {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ reason })
|
||||
});
|
||||
}
|
||||
|
||||
export async function assignTask(taskId: string, assigneeSlug: string): Promise<Task> {
|
||||
return request(`/api/v1/tasks/${taskId}/assign`, {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ assignee_slug: assigneeSlug })
|
||||
});
|
||||
}
|
||||
|
||||
export async function watchTask(taskId: string, slug: string): Promise<{ok: boolean; watchers: string[]}> {
|
||||
return request(`/api/v1/tasks/${taskId}/watch?slug=${slug}`, { method: "POST" });
|
||||
}
|
||||
|
||||
export async function unwatchTask(taskId: string, slug: string): Promise<{ok: boolean; watchers: string[]}> {
|
||||
return request(`/api/v1/tasks/${taskId}/watch?slug=${slug}`, { method: "DELETE" });
|
||||
}
|
||||
|
||||
// --- Steps ---
|
||||
|
||||
export async function getSteps(taskId: string): Promise<Step[]> {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user