Display info of uploaded files

This commit is contained in:
2025-04-28 21:38:27 +02:00
parent 3ae229a275
commit c6851bb50d
7 changed files with 78 additions and 3 deletions

View File

@ -39,6 +39,11 @@ pub async fn upload(auth: AuthExtractor, file: FileExtractor) -> HttpResult {
Ok(HttpResponse::Ok().json(file))
}
/// Get information about a file
pub async fn get_info(file_extractor: FileIdExtractor) -> HttpResult {
Ok(HttpResponse::Ok().json(file_extractor.as_ref()))
}
/// Download an uploaded file
pub async fn download(req: HttpRequest, file_extractor: FileIdExtractor) -> HttpResult {
serve_file(req, file_extractor.as_ref()).await

View File

@ -123,6 +123,10 @@ async fn main() -> std::io::Result<()> {
.route("/api/file", web::post().to(files_controller::upload))
.route(
"/api/file/{file_id}",
web::get().to(files_controller::get_info),
)
.route(
"/api/file/{file_id}/download",
web::get().to(files_controller::download),
)
.route(

View File

@ -20,6 +20,7 @@
"@mui/x-date-pickers": "^8.0.0-beta.3",
"date-and-time": "^3.6.0",
"dayjs": "^1.11.13",
"filesize": "^10.1.6",
"qrcode.react": "^4.2.0",
"react": "^19.1.0",
"react-dom": "^19.1.0",
@ -3148,6 +3149,15 @@
"node": ">=16.0.0"
}
},
"node_modules/filesize": {
"version": "10.1.6",
"resolved": "https://registry.npmjs.org/filesize/-/filesize-10.1.6.tgz",
"integrity": "sha512-sJslQKU2uM33qH5nqewAwVB2QgR6w1aMNsYUp3aN5rMRyXEwJGmZvaWzeJFNTOXWlHQyBFCWrdj3fV/fsTOX8w==",
"license": "BSD-3-Clause",
"engines": {
"node": ">= 10.4.0"
}
},
"node_modules/fill-range": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",

View File

@ -22,6 +22,7 @@
"@mui/x-date-pickers": "^8.0.0-beta.3",
"date-and-time": "^3.6.0",
"dayjs": "^1.11.13",
"filesize": "^10.1.6",
"qrcode.react": "^4.2.0",
"react": "^19.1.0",
"react-dom": "^19.1.0",

View File

@ -25,4 +25,16 @@ export class FileApi {
})
).data;
}
/**
* Get a file information
*/
static async GetFile(id: number): Promise<UploadedFile> {
return (
await APIClient.exec({
method: "GET",
uri: `/file/${id}`,
})
).data;
}
}

View File

@ -25,6 +25,7 @@ import { NewMovementWidget } from "../widgets/NewMovementWidget";
import { NotFoundRoute } from "./NotFound";
import { UploadFileButton } from "../widgets/forms/UploadFileButton";
import { UploadedFile } from "../api/FileApi";
import { UploadedFileWidget } from "../widgets/UploadedFileWidget";
export function AccountRoute(): React.ReactElement {
const loadingMessage = useLoadingMessage();
@ -281,7 +282,7 @@ function MovementsTable(p: {
{
field: "label",
headerName: "Label",
flex: 1,
flex: 3,
editable: true,
type: "string",
},
@ -301,7 +302,7 @@ function MovementsTable(p: {
field: "file",
headerName: "File",
editable: false,
width: 150,
flex: 1,
renderCell: (params) => {
if (!params.row.file_id)
return (
@ -311,7 +312,7 @@ function MovementsTable(p: {
onUploaded={(f) => setUploadedFile(params.row, f)}
/>
);
else return <>got file</>;
else return <UploadedFileWidget file_id={params.row.file_id} />;
},
},
{

View File

@ -0,0 +1,42 @@
import ImageIcon from "@mui/icons-material/Image";
import PictureAsPdfIcon from "@mui/icons-material/PictureAsPdf";
import { Button } from "@mui/material";
import { filesize } from "filesize";
import React from "react";
import { FileApi, UploadedFile } from "../api/FileApi";
import { AsyncWidget } from "./AsyncWidget";
export function UploadedFileWidget(p: { file_id: number }): React.ReactElement {
const [file, setFile] = React.useState<UploadedFile | null>(null);
const load = async () => {
setFile(await FileApi.GetFile(p.file_id));
};
return (
<AsyncWidget
errMsg="Failed"
build={() => <UploadedFileWidgetInner file={file!} />}
loadKey={p.file_id}
load={load}
/>
);
}
function UploadedFileWidgetInner(p: {
file: UploadedFile;
}): React.ReactElement {
return (
<Button
startIcon={
p.file.mime_type === "application/pdf" ? (
<PictureAsPdfIcon />
) : (
<ImageIcon />
)
}
>
{p.file.file_name} ({filesize(p.file.file_size)})
</Button>
);
}