fix(#338): Route all state-changing fetch() calls through API client

- Replace raw fetch() with apiPost/apiPatch/apiDelete in:
  - ImportExportActions.tsx: POST for file imports
  - KanbanBoard.tsx: PATCH for task status updates
  - ActiveProjectsWidget.tsx: POST for widget data fetches
  - useLayouts.ts: POST/PATCH/DELETE for layout management
- Add apiPostFormData() method to API client for FormData uploads
- Ensures CSRF token is included in all state-changing requests
- Update tests to mock CSRF token fetch for API client usage

Refs #338

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Jason Woltje
2026-02-05 17:06:23 -06:00
parent 5ae07f7a84
commit 344e5df3bb
7 changed files with 198 additions and 119 deletions

View File

@@ -2,6 +2,7 @@
import { useState, useRef } from "react";
import { Upload, Download, Loader2, CheckCircle2, XCircle } from "lucide-react";
import { apiPostFormData } from "@/lib/api/client";
interface ImportResult {
filename: string;
@@ -63,17 +64,8 @@ export function ImportExportActions({
const formData = new FormData();
formData.append("file", file);
const response = await fetch("/api/knowledge/import", {
method: "POST",
body: formData,
});
if (!response.ok) {
const error = (await response.json()) as { message?: string };
throw new Error(error.message ?? "Import failed");
}
const result = (await response.json()) as ImportResponse;
// Use API client to ensure CSRF token is included
const result = await apiPostFormData<ImportResponse>("/api/knowledge/import", formData);
setImportResult(result);
// Notify parent component