feat: pass actor slug to all task updates (system messages show who did it)

This commit is contained in:
Markov 2026-02-24 13:26:40 +01:00
parent 44884d937c
commit 9a1b7a8d57
3 changed files with 19 additions and 7 deletions

View File

@ -1,7 +1,7 @@
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import type { Task } from "@/lib/api"; import type { Task } from "@/lib/api";
import { getTasks, updateTask } from "@/lib/api"; import { getTasks, updateTask, getCurrentSlug } 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"; import { wsClient } from "@/lib/ws";
@ -80,12 +80,12 @@ export default function KanbanBoard({ projectId, projectSlug }: Props) {
if (!task || task.status === status) return; if (!task || task.status === status) return;
setTasks((prev) => prev.map((t) => (t.id === draggedTask ? { ...t, status } : t))); setTasks((prev) => prev.map((t) => (t.id === draggedTask ? { ...t, status } : t)));
setDraggedTask(null); setDraggedTask(null);
try { await updateTask(draggedTask, { status }); } catch { loadTasks(); } try { await updateTask(draggedTask, { status }, getCurrentSlug()); } catch { loadTasks(); }
}; };
const handleMoveTask = async (taskId: string, newStatus: string) => { const handleMoveTask = async (taskId: string, newStatus: string) => {
setTasks((prev) => prev.map((t) => (t.id === taskId ? { ...t, status: newStatus } : t))); setTasks((prev) => prev.map((t) => (t.id === taskId ? { ...t, status: newStatus } : t)));
try { await updateTask(taskId, { status: newStatus }); } catch { loadTasks(); } try { await updateTask(taskId, { status: newStatus }, getCurrentSlug()); } catch { loadTasks(); }
}; };
if (loading) { if (loading) {

View File

@ -2,7 +2,7 @@
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import type { Task, Member, Step, Message } from "@/lib/api"; import type { Task, Member, Step, Message } from "@/lib/api";
import { import {
updateTask, deleteTask, getMembers, updateTask, deleteTask, getMembers, getCurrentSlug,
getSteps, createStep, updateStep, deleteStep as _deleteStepApi, getSteps, createStep, updateStep, deleteStep as _deleteStepApi,
getMessages, sendMessage, getMessages, sendMessage,
} from "@/lib/api"; } from "@/lib/api";
@ -62,7 +62,7 @@ export default function TaskModal({ task, projectId: _projectId, projectSlug: _p
const save = async (patch: Partial<Task>) => { const save = async (patch: Partial<Task>) => {
setSaving(true); setSaving(true);
try { try {
const updated = await updateTask(task.id, patch); const updated = await updateTask(task.id, patch, getCurrentSlug());
onUpdated(updated); onUpdated(updated);
} catch (e) { } catch (e) {
console.error(e); console.error(e);

View File

@ -9,6 +9,17 @@ function getToken(): string | null {
return localStorage.getItem("tb_token"); return localStorage.getItem("tb_token");
} }
export function getCurrentSlug(): string {
const token = getToken();
if (!token) return "unknown";
try {
const payload = JSON.parse(atob(token.split(".")[1]));
return payload.slug || payload.sub || "unknown";
} catch {
return "unknown";
}
}
async function request<T = any>(path: string, options: RequestInit = {}): Promise<T> { async function request<T = any>(path: string, options: RequestInit = {}): Promise<T> {
const token = getToken(); const token = getToken();
const headers: Record<string, string> = { const headers: Record<string, string> = {
@ -165,8 +176,9 @@ export async function createTask(projectSlug: string, data: Partial<Task>): Prom
}); });
} }
export async function updateTask(taskId: string, data: Partial<Task>): Promise<Task> { export async function updateTask(taskId: string, data: Partial<Task>, actor?: string): Promise<Task> {
return request(`/api/v1/tasks/${taskId}`, { method: "PATCH", body: JSON.stringify(data) }); const qs = actor ? `?actor=${encodeURIComponent(actor)}` : "";
return request(`/api/v1/tasks/${taskId}${qs}`, { method: "PATCH", body: JSON.stringify(data) });
} }
export async function deleteTask(taskId: string): Promise<void> { export async function deleteTask(taskId: string): Promise<void> {