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 { Task, getTasks, updateTask } from "@/lib/api";
|
||||||
import TaskModal from "@/components/TaskModal";
|
import TaskModal from "@/components/TaskModal";
|
||||||
import CreateTaskModal from "@/components/CreateTaskModal";
|
import CreateTaskModal from "@/components/CreateTaskModal";
|
||||||
|
import { wsClient } from "@/lib/ws";
|
||||||
|
|
||||||
const COLUMNS = [
|
const COLUMNS = [
|
||||||
{ key: "backlog", label: "Backlog", color: "#737373" },
|
{ 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) => {
|
const handleDrop = async (status: string) => {
|
||||||
if (!draggedTask) return;
|
if (!draggedTask) return;
|
||||||
|
|||||||
@ -173,6 +173,32 @@ export async function deleteTask(taskId: string): Promise<void> {
|
|||||||
await request(`/api/v1/tasks/${taskId}`, { method: "DELETE" });
|
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 ---
|
// --- Steps ---
|
||||||
|
|
||||||
export async function getSteps(taskId: string): Promise<Step[]> {
|
export async function getSteps(taskId: string): Promise<Step[]> {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user