-
← Back
System check
Run this before your first session, or any time something isn't working.
diff --git a/frontend/src/pages/Files.tsx b/frontend/src/pages/Files.tsx
index e5ad6b4..194277b 100644
--- a/frontend/src/pages/Files.tsx
+++ b/frontend/src/pages/Files.tsx
@@ -1,6 +1,7 @@
import { useEffect, useState, useCallback } from "react";
import { Link } from "react-router-dom";
import { api } from "../api";
+import { useCampaign } from "../contexts/CampaignContext";
function formatSize(bytes: number): string {
if (bytes < 1024) return `${bytes} B`;
@@ -47,11 +48,11 @@ function isText(path: string) {
}
export default function Files() {
+ const { currentCampaign } = useCampaign();
const [entries, setEntries] = useState
([]);
const [currentPath, setCurrentPath] = useState("");
const [parentPath, setParentPath] = useState(null);
const [selectedPaths, setSelectedPaths] = useState>(new Set());
- const [copiedFile, setCopiedFile] = useState<{ path: string; name: string } | null>(null);
const [loading, setLoading] = useState(true);
const [toast, setToast] = useState(null);
const [uploading, setUploading] = useState(false);
@@ -59,20 +60,22 @@ export default function Files() {
const [expandedContent, setExpandedContent] = useState(null);
const [expanding, setExpanding] = useState(false);
+ const campaignId = currentCampaign?.id;
+
const load = useCallback(async (path: string) => {
setLoading(true);
setExpandedPath(null);
setExpandedContent(null);
try {
- const res = await api.browseFiles(path || undefined);
+ const res = await api.browseFiles(path || undefined, campaignId);
setEntries(res.entries);
setCurrentPath(res.current_path);
setParentPath(res.parent_path);
} catch { setEntries([]); }
setLoading(false);
- }, []);
+ }, [campaignId]);
- useEffect(() => { load(currentPath); }, []);
+ useEffect(() => { load(currentPath); }, [campaignId]);
const navigate = (path: string) => {
setSelectedPaths(new Set());
@@ -84,23 +87,11 @@ export default function Files() {
setTimeout(() => setToast(null), 2000);
};
- // Keyboard shortcuts
+ // Keyboard shortcuts (delete only)
useEffect(() => {
const handler = (e: KeyboardEvent) => {
const tag = (e.target as HTMLElement)?.tagName;
if (tag === "INPUT" || tag === "TEXTAREA") return;
-
- if ((e.ctrlKey || e.metaKey) && e.key === "c") {
- e.preventDefault();
- if (selectedPaths.size > 0) {
- const first = entries.find(f => selectedPaths.has(f.path));
- if (first) { setCopiedFile({ path: first.path, name: first.name }); showToast(`Copied: ${first.name}`); }
- }
- }
- if ((e.ctrlKey || e.metaKey) && e.key === "v") {
- e.preventDefault();
- if (copiedFile) handlePaste();
- }
if (e.key === "Delete" && selectedPaths.size > 0) handleDelete();
if ((e.ctrlKey || e.metaKey) && e.key === "a") {
e.preventDefault();
@@ -109,7 +100,7 @@ export default function Files() {
};
window.addEventListener("keydown", handler);
return () => window.removeEventListener("keydown", handler);
- }, [selectedPaths, copiedFile, entries]);
+ }, [selectedPaths, entries]);
const toggleSelect = (path: string) => {
setSelectedPaths(prev => {
@@ -125,7 +116,7 @@ export default function Files() {
if (paths.length === 0) return;
if (!confirm(`Delete ${paths.length} item(s)?`)) return;
try {
- const res = await api.deleteFiles(paths);
+ const res = await api.deleteFiles(paths, campaignId);
setSelectedPaths(new Set());
setExpandedPath(null);
setExpandedContent(null);
@@ -136,18 +127,6 @@ export default function Files() {
}
};
- const handlePaste = async () => {
- if (!copiedFile) return;
- try {
- const res = await api.copyFile(copiedFile.path, currentPath || undefined);
- setCopiedFile(null);
- showToast(`Pasted as: ${res.dest.split("/").pop()}`);
- load(currentPath);
- } catch (e: any) {
- showToast(e.message || "Paste failed");
- }
- };
-
const handleUpload = async () => {
const input = document.createElement("input");
input.type = "file";
@@ -156,7 +135,7 @@ export default function Files() {
if (!file) return;
setUploading(true);
try {
- await api.uploadFile(file, currentPath || undefined);
+ await api.uploadFile(file, currentPath || undefined, campaignId);
showToast("Uploaded");
load(currentPath);
} catch (e: any) {
@@ -173,16 +152,16 @@ export default function Files() {
setExpandedContent(null);
return;
}
- setExpandedPath(entry.path);
- if (isAudio(entry.name)) {
- setExpandedContent(null);
- } else if (isText(entry.path)) {
- setExpanding(true);
- try {
- const res = await fetch(api.viewFileUrl(entry.path));
- const text = await res.text();
- setExpandedContent(text);
- } catch {
+ setExpandedPath(entry.path);
+ if (isAudio(entry.name)) {
+ setExpandedContent(null);
+ } else if (isText(entry.path)) {
+ setExpanding(true);
+ try {
+ const res = await fetch(api.viewFileUrl(entry.path, campaignId));
+ const text = await res.text();
+ setExpandedContent(text);
+ } catch {
setExpandedContent("(failed to load)");
}
setExpanding(false);
@@ -200,7 +179,6 @@ export default function Files() {
{toast}
)}
-
-
- {copiedFile && (
-
- Clipboard: {copiedFile.name}
-
- )}
{uploading ? "Uploading..." : "Upload"}
- {
- if (selectedPaths.size > 0) {
- const first = entries.find(f => selectedPaths.has(f.path));
- if (first) { setCopiedFile({ path: first.path, name: first.name }); showToast(`Copied: ${first.name}`); }
- }
- }} disabled={selectedCount === 0}>Copy
- Paste
Delete
{
const first = entries.find(f => selectedPaths.has(f.path));
- if (first) window.open(api.downloadFileUrl(first.path), "_blank");
+ if (first) window.open(api.downloadFileUrl(first.path, campaignId), "_blank");
}} disabled={selectedCount !== 1}>Download
@@ -311,7 +277,7 @@ export default function Files() {
{isAudio(e.name) ? (
- |