mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-06-04 20:05:16 +02:00
feat(web): add download original action to editor header
This commit is contained in:
parent
637affecb8
commit
af192a8405
2 changed files with 86 additions and 0 deletions
|
|
@ -0,0 +1,79 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
import { Download } from "lucide-react";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import { toast } from "sonner";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { Spinner } from "@/components/ui/spinner";
|
||||||
|
import { documentsApiService } from "@/lib/apis/documents-api.service";
|
||||||
|
import { authenticatedFetch } from "@/lib/auth-utils";
|
||||||
|
import { BACKEND_URL } from "@/lib/env-config";
|
||||||
|
|
||||||
|
interface DownloadOriginalButtonProps {
|
||||||
|
documentId: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Renders only when the document has a stored ORIGINAL file; downloads it on click. */
|
||||||
|
export function DownloadOriginalButton({ documentId }: DownloadOriginalButtonProps) {
|
||||||
|
const [originalFilename, setOriginalFilename] = useState<string | null>(null);
|
||||||
|
const [downloading, setDownloading] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
let active = true;
|
||||||
|
documentsApiService
|
||||||
|
.getDocumentFiles(documentId)
|
||||||
|
.then((files) => {
|
||||||
|
if (!active) return;
|
||||||
|
const original = files.find((file) => file.kind === "ORIGINAL");
|
||||||
|
setOriginalFilename(original?.original_filename ?? null);
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
if (active) setOriginalFilename(null);
|
||||||
|
});
|
||||||
|
return () => {
|
||||||
|
active = false;
|
||||||
|
};
|
||||||
|
}, [documentId]);
|
||||||
|
|
||||||
|
if (!originalFilename) return null;
|
||||||
|
|
||||||
|
const handleDownload = async () => {
|
||||||
|
setDownloading(true);
|
||||||
|
try {
|
||||||
|
const response = await authenticatedFetch(
|
||||||
|
`${BACKEND_URL}/api/v1/documents/${documentId}/download-original`,
|
||||||
|
{ method: "GET" }
|
||||||
|
);
|
||||||
|
if (!response.ok) throw new Error("Download failed");
|
||||||
|
|
||||||
|
const blob = await response.blob();
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
const anchor = document.createElement("a");
|
||||||
|
anchor.href = url;
|
||||||
|
anchor.download = originalFilename;
|
||||||
|
document.body.appendChild(anchor);
|
||||||
|
anchor.click();
|
||||||
|
anchor.remove();
|
||||||
|
URL.revokeObjectURL(url);
|
||||||
|
toast.success("Download started");
|
||||||
|
} catch {
|
||||||
|
toast.error("Failed to download original file");
|
||||||
|
} finally {
|
||||||
|
setDownloading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="icon"
|
||||||
|
className="size-6"
|
||||||
|
onClick={handleDownload}
|
||||||
|
disabled={downloading}
|
||||||
|
title={`Download original (${originalFilename})`}
|
||||||
|
>
|
||||||
|
{downloading ? <Spinner size="xs" /> : <Download className="size-3.5" />}
|
||||||
|
<span className="sr-only">Download original file</span>
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -15,6 +15,7 @@ import dynamic from "next/dynamic";
|
||||||
import { useCallback, useEffect, useRef, useState } from "react";
|
import { useCallback, useEffect, useRef, useState } from "react";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { closeEditorPanelAtom, editorPanelAtom } from "@/atoms/editor/editor-panel.atom";
|
import { closeEditorPanelAtom, editorPanelAtom } from "@/atoms/editor/editor-panel.atom";
|
||||||
|
import { DownloadOriginalButton } from "@/components/documents/download-original-button";
|
||||||
import { VersionHistoryButton } from "@/components/documents/version-history";
|
import { VersionHistoryButton } from "@/components/documents/version-history";
|
||||||
import { SourceCodeEditor } from "@/components/editor/source-code-editor";
|
import { SourceCodeEditor } from "@/components/editor/source-code-editor";
|
||||||
import {
|
import {
|
||||||
|
|
@ -584,6 +585,9 @@ export function EditorPanelContent({
|
||||||
documentType={editorDoc.document_type}
|
documentType={editorDoc.document_type}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
{!isLocalFileMode && !isMemoryMode && documentId && (
|
||||||
|
<DownloadOriginalButton documentId={documentId} />
|
||||||
|
)}
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
size="icon"
|
size="icon"
|
||||||
|
|
@ -668,6 +672,9 @@ export function EditorPanelContent({
|
||||||
documentType={editorDoc.document_type}
|
documentType={editorDoc.document_type}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
{!isLocalFileMode && !isMemoryMode && documentId && (
|
||||||
|
<DownloadOriginalButton documentId={documentId} />
|
||||||
|
)}
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
size="icon"
|
size="icon"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue