v3: allow users to edit dump thumbnail, fixed some linter errors in the frontend
All checks were successful
Build and Publish Docker Image / build-and-push (push) Successful in 41s

This commit is contained in:
khannurien
2026-06-21 15:41:40 +00:00
parent 57cf55cc48
commit cf988ae608
27 changed files with 431 additions and 121 deletions

View File

@@ -17,6 +17,7 @@ import RichContentCard from "../components/RichContentCard.tsx";
import FilePreview from "../components/FilePreview.tsx";
import { TextEditor } from "../components/TextEditor.tsx";
import { FileDropZone } from "../components/FileDropZone.tsx";
import { ImagePicker } from "../components/ImagePicker.tsx";
type DumpEditState =
| { status: "loading" }
@@ -36,13 +37,13 @@ export function DumpEdit() {
const [newFile, setNewFile] = useState<File | null>(null);
const [confirmDelete, setConfirmDelete] = useState(false);
const [refreshing, setRefreshing] = useState(false);
const [thumbUploading, setThumbUploading] = useState(false);
useEffect(() => {
if (!selectedDump) return;
setState({ status: "loading" });
(async () => {
setState({ status: "loading" });
try {
const res = await fetch(`${API_URL}/api/dumps/${selectedDump}`, {
cache: "no-store",
@@ -131,6 +132,42 @@ export function DumpEdit() {
}
};
const handleThumbnailChange = async (file: File) => {
if (state.status !== "loaded") return;
setThumbUploading(true);
try {
const formData = new FormData();
formData.append("file", file);
const res = await authFetch(
`${API_URL}/api/dumps/${state.dump.id}/thumbnail`,
{ method: "PUT", body: formData },
);
const apiResponse = parseAPIResponse<RawDump>(await res.json());
if (apiResponse.success) {
setState({ status: "loaded", dump: deserializeDump(apiResponse.data) });
}
} finally {
setThumbUploading(false);
}
};
const handleThumbnailReset = async () => {
if (state.status !== "loaded") return;
setThumbUploading(true);
try {
const res = await authFetch(
`${API_URL}/api/dumps/${state.dump.id}/thumbnail`,
{ method: "DELETE" },
);
const apiResponse = parseAPIResponse<RawDump>(await res.json());
if (apiResponse.success) {
setState({ status: "loaded", dump: deserializeDump(apiResponse.data) });
}
} finally {
setThumbUploading(false);
}
};
const handleDelete = async () => {
if (state.status !== "loaded") return;
@@ -184,6 +221,16 @@ export function DumpEdit() {
const { dump } = state;
const currentThumbnailSrc = dump.thumbnailMime
? `${API_URL}/api/thumbnails/${dump.id}`
: dump.kind === "file"
? (dump.fileMime?.startsWith("image/")
? `${API_URL}/api/files/${dump.id}?v=${dump.fileSize ?? 0}`
: dump.fileMime?.startsWith("video/")
? `${API_URL}/api/thumbnails/${dump.id}`
: null)
: dump.richContent?.thumbnailUrl ?? null;
return (
<PageShell>
<div className="form-page form-page--two-col">
@@ -230,6 +277,30 @@ export function DumpEdit() {
handleSave();
}}
>
<div className="form-group">
<label>
<Trans>Thumbnail</Trans>
</label>
<div className="dump-edit-thumbnail-row">
<ImagePicker
src={currentThumbnailSrc}
size={64}
onChange={handleThumbnailChange}
uploading={thumbUploading}
/>
{dump.thumbnailMime && (
<button
type="button"
className="btn-border"
onClick={handleThumbnailReset}
disabled={thumbUploading}
>
<Trans>Reset to default</Trans>
</button>
)}
</div>
</div>
<div className="form-group">
<label htmlFor="title">
<Trans>Title</Trans>