Initial commit
This commit is contained in:
commit
78f8d225ee
21173 changed files with 2907774 additions and 0 deletions
135
app/files/page.tsx
Normal file
135
app/files/page.tsx
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
// /var/www/makearmy.io/app/app/files/page.tsx
|
||||
"use client";
|
||||
|
||||
import Link from "next/link";
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import { useSearchParams, useRouter } from "next/navigation";
|
||||
|
||||
type FileItem = {
|
||||
name: string;
|
||||
isDir: boolean;
|
||||
size: number;
|
||||
mtime: number;
|
||||
};
|
||||
|
||||
export default function FilesPage() {
|
||||
const search = useSearchParams();
|
||||
const router = useRouter();
|
||||
const path = useMemo(() => search.get("path") || "/", [search]);
|
||||
|
||||
const [items, setItems] = useState<FileItem[] | null>(null);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false;
|
||||
async function load() {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
try {
|
||||
const res = await fetch(
|
||||
`/api/files/list?path=${encodeURIComponent(path)}`
|
||||
);
|
||||
if (!res.ok) {
|
||||
if (!cancelled) setError(`HTTP ${res.status}`);
|
||||
return;
|
||||
}
|
||||
const json = await res.json();
|
||||
if (!cancelled) setItems(json.items || []);
|
||||
} catch (e: any) {
|
||||
if (!cancelled) setError(e?.message || String(e));
|
||||
} finally {
|
||||
if (!cancelled) setLoading(false);
|
||||
}
|
||||
}
|
||||
load();
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}, [path]);
|
||||
|
||||
const upPath = useMemo(() => {
|
||||
if (path === "/") return null;
|
||||
const parts = path.replace(/\/+$/, "").split("/").filter(Boolean);
|
||||
parts.pop();
|
||||
return "/" + parts.join("/");
|
||||
}, [path]);
|
||||
|
||||
return (
|
||||
<div className="p-6 text-sm">
|
||||
|
||||
<div className="mb-3">
|
||||
<span className="opacity-70 mr-1">Path:</span>
|
||||
<code>{path}</code>
|
||||
{upPath && (
|
||||
<>
|
||||
<span className="mx-2 opacity-50">•</span>
|
||||
<Link href={`/files?path=${encodeURIComponent(upPath)}`}>
|
||||
Up one level
|
||||
</Link>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{loading && <div>Loading…</div>}
|
||||
{error && (
|
||||
<div className="bg-red-900/60 text-red-200 p-3 rounded border border-red-800">
|
||||
Error loading files: {error}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{!loading && !error && items && (
|
||||
<table className="w-full text-left mt-3 border-collapse">
|
||||
<thead className="opacity-70">
|
||||
<tr>
|
||||
<th className="py-2 pr-4">Name</th>
|
||||
<th className="py-2 pr-4">Type</th>
|
||||
<th className="py-2 pr-4">Size</th>
|
||||
<th className="py-2 pr-4">Modified</th>
|
||||
<th className="py-2 pr-4"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{items.map((it) => {
|
||||
const href = it.isDir
|
||||
? `/files?path=${encodeURIComponent(
|
||||
(path.endsWith("/") ? path : path + "/") + it.name
|
||||
)}`
|
||||
: `/api/files/raw?path=${encodeURIComponent(
|
||||
(path.endsWith("/") ? path : path + "/") + it.name
|
||||
)}`;
|
||||
const dl = it.isDir
|
||||
? null
|
||||
: `/api/files/download?path=${encodeURIComponent(
|
||||
(path.endsWith("/") ? path : path + "/") + it.name
|
||||
)}`;
|
||||
|
||||
return (
|
||||
<tr key={it.name} className="border-t border-white/10">
|
||||
<td className="py-2 pr-4">
|
||||
<Link href={href}>{it.name}</Link>
|
||||
</td>
|
||||
<td className="py-2 pr-4">{it.isDir ? "Dir" : "File"}</td>
|
||||
<td className="py-2 pr-4">
|
||||
{it.isDir ? "-" : `${it.size.toLocaleString()} B`}
|
||||
</td>
|
||||
<td className="py-2 pr-4">
|
||||
{new Date(it.mtime).toLocaleString()}
|
||||
</td>
|
||||
<td className="py-2 pr-4">
|
||||
{!it.isDir && dl && (
|
||||
<a href={dl} className="underline">
|
||||
Download
|
||||
</a>
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue