Improve ISO list route UI
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Pierre HUBERT 2025-05-21 20:45:48 +02:00
parent 8c27010396
commit 01f26c1a79
5 changed files with 80 additions and 51 deletions

View File

@ -1,5 +1,4 @@
import { import {
Avatar,
Button, Button,
Dialog, Dialog,
DialogActions, DialogActions,
@ -27,7 +26,7 @@ export function IsoCatalogDialog(p: {
return ( return (
<Dialog open={p.open} onClose={p.onClose}> <Dialog open={p.open} onClose={p.onClose}>
<DialogTitle>Iso catalog</DialogTitle> <DialogTitle>ISO catalog</DialogTitle>
<DialogContent> <DialogContent>
<AsyncWidget <AsyncWidget
loadKey={1} loadKey={1}
@ -52,12 +51,13 @@ export function IsoCatalogDialogInner(p: {
<List dense> <List dense>
{p.catalog.map((entry) => ( {p.catalog.map((entry) => (
<a <a
key={entry.name}
href={entry.url} href={entry.url}
target="_blank" target="_blank"
rel="noopener" rel="noopener"
style={{ color: "inherit", textDecoration: "none" }} style={{ color: "inherit", textDecoration: "none" }}
> >
<ListItem key={entry.name}> <ListItem>
<ListItemButton> <ListItemButton>
<ListItemAvatar> <ListItemAvatar>
<img <img

View File

@ -1,5 +1,7 @@
import DeleteIcon from "@mui/icons-material/Delete"; import DeleteIcon from "@mui/icons-material/Delete";
import DownloadIcon from "@mui/icons-material/Download"; import DownloadIcon from "@mui/icons-material/Download";
import MenuBookIcon from "@mui/icons-material/MenuBook";
import RefreshIcon from "@mui/icons-material/Refresh";
import { import {
Alert, Alert,
Button, Button,
@ -15,6 +17,7 @@ import { filesize } from "filesize";
import React from "react"; import React from "react";
import { IsoFile, IsoFilesApi } from "../api/IsoFilesApi"; import { IsoFile, IsoFilesApi } from "../api/IsoFilesApi";
import { ServerApi } from "../api/ServerApi"; import { ServerApi } from "../api/ServerApi";
import { IsoCatalogDialog } from "../dialogs/IsoCatalogDialog";
import { useAlert } from "../hooks/providers/AlertDialogProvider"; import { useAlert } from "../hooks/providers/AlertDialogProvider";
import { useConfirm } from "../hooks/providers/ConfirmDialogProvider"; import { useConfirm } from "../hooks/providers/ConfirmDialogProvider";
import { useLoadingMessage } from "../hooks/providers/LoadingMessageProvider"; import { useLoadingMessage } from "../hooks/providers/LoadingMessageProvider";
@ -24,8 +27,6 @@ import { AsyncWidget } from "../widgets/AsyncWidget";
import { FileInput } from "../widgets/forms/FileInput"; import { FileInput } from "../widgets/forms/FileInput";
import { VirtWebPaper } from "../widgets/VirtWebPaper"; import { VirtWebPaper } from "../widgets/VirtWebPaper";
import { VirtWebRouteContainer } from "../widgets/VirtWebRouteContainer"; import { VirtWebRouteContainer } from "../widgets/VirtWebRouteContainer";
import MenuBookIcon from "@mui/icons-material/MenuBook";
import { IsoCatalogDialog } from "../dialogs/IsoCatalogDialog";
export function IsoFilesRoute(): React.ReactElement { export function IsoFilesRoute(): React.ReactElement {
const [list, setList] = React.useState<IsoFile[] | undefined>(); const [list, setList] = React.useState<IsoFile[] | undefined>();
@ -53,11 +54,18 @@ export function IsoFilesRoute(): React.ReactElement {
<VirtWebRouteContainer <VirtWebRouteContainer
label="ISO files management" label="ISO files management"
actions={ actions={
<Tooltip title="Open the ISO catalog"> <span>
<IconButton onClick={() => setIsoCatalog(true)}> <Tooltip title="Open the ISO catalog">
<MenuBookIcon /> <IconButton onClick={() => { setIsoCatalog(true); }}>
</IconButton> <MenuBookIcon />
</Tooltip> </IconButton>
</Tooltip>
<Tooltip title="Refresh ISO list">
<IconButton onClick={reload}>
<RefreshIcon />
</IconButton>
</Tooltip>
</span>
} }
> >
<UploadIsoFileCard onFileUploaded={reload} /> <UploadIsoFileCard onFileUploaded={reload} />
@ -68,7 +76,7 @@ export function IsoFilesRoute(): React.ReactElement {
/> />
<IsoCatalogDialog <IsoCatalogDialog
open={isoCatalog} open={isoCatalog}
onClose={() => setIsoCatalog(false)} onClose={() => { setIsoCatalog(false); }}
/> />
</> </>
); );
@ -122,7 +130,7 @@ function UploadIsoFileCard(p: {
if (uploadProgress !== null) { if (uploadProgress !== null) {
return ( return (
<VirtWebPaper label="File upload"> <VirtWebPaper label="File upload" noHorizontalMargin>
<Typography variant="body1"> <Typography variant="body1">
Upload in progress ({Math.floor(uploadProgress * 100)}%)... Upload in progress ({Math.floor(uploadProgress * 100)}%)...
</Typography> </Typography>
@ -132,7 +140,7 @@ function UploadIsoFileCard(p: {
} }
return ( return (
<VirtWebPaper label="File upload"> <VirtWebPaper label="File upload" noHorizontalMargin>
<div style={{ display: "flex", alignItems: "center" }}> <div style={{ display: "flex", alignItems: "center" }}>
<FileInput <FileInput
value={value} value={value}
@ -180,7 +188,7 @@ function UploadIsoFileFromUrlCard(p: {
}; };
return ( return (
<VirtWebPaper label="File upload from URL"> <VirtWebPaper label="File upload from URL" noHorizontalMargin>
<div style={{ display: "flex", alignItems: "center" }}> <div style={{ display: "flex", alignItems: "center" }}>
<TextField <TextField
label="URL" label="URL"
@ -297,38 +305,31 @@ function IsoFilesList(p: {
return ( return (
<> <>
<VirtWebPaper label="Files list"> {/* Download notification */}
{/* Download notification */} {dlProgress !== undefined && (
{dlProgress !== undefined && ( <Alert severity="info">
<Alert severity="info"> <div
<div style={{
style={{ display: "flex",
display: "flex", flexDirection: "row",
flexDirection: "row", alignItems: "center",
alignItems: "center", overflow: "hidden",
overflow: "hidden", }}
}} >
> <Typography variant="body1">
<Typography variant="body1"> Downloading... {dlProgress}%
Downloading... {dlProgress}% </Typography>
</Typography> <CircularProgress
<CircularProgress variant="determinate"
variant="determinate" size={"1.5rem"}
size={"1.5rem"} style={{ marginLeft: "10px" }}
style={{ marginLeft: "10px" }} value={dlProgress}
value={dlProgress} />
/> </div>
</div> </Alert>
</Alert> )}
)} {/* ISO files list table */}
<DataGrid getRowId={(c) => c.filename} rows={p.list} columns={columns} />
{/* Files list table */}
<DataGrid
getRowId={(c) => c.filename}
rows={p.list}
columns={columns}
/>
</VirtWebPaper>
</> </>
); );
} }

View File

@ -13,7 +13,7 @@ import {
List, List,
ListItemButton, ListItemButton,
ListItemIcon, ListItemIcon,
ListItemText ListItemText,
} from "@mui/material"; } from "@mui/material";
import { Outlet, useLocation } from "react-router-dom"; import { Outlet, useLocation } from "react-router-dom";
import { RouterLink } from "./RouterLink"; import { RouterLink } from "./RouterLink";
@ -82,7 +82,15 @@ export function BaseAuthenticatedPage(): React.ReactElement {
icon={<Icon path={mdiInformation} size={1} />} icon={<Icon path={mdiInformation} size={1} />}
/> />
</List> </List>
<div style={{ flex: 1 }}> <div
style={{
flexGrow: 1,
flexShrink: 0,
flexBasis: 0,
minWidth: 0,
display: "flex",
}}
>
<Outlet /> <Outlet />
</div> </div>
</Box> </Box>

View File

@ -2,10 +2,19 @@ import { Paper, Typography } from "@mui/material";
import React, { PropsWithChildren } from "react"; import React, { PropsWithChildren } from "react";
export function VirtWebPaper( export function VirtWebPaper(
p: { label: string | React.ReactElement } & PropsWithChildren p: {
label: string | React.ReactElement;
noHorizontalMargin?: boolean;
} & PropsWithChildren
): React.ReactElement { ): React.ReactElement {
return ( return (
<Paper elevation={2} style={{ padding: "10px", margin: "20px" }}> <Paper
elevation={2}
style={{
padding: "10px",
margin: p.noHorizontalMargin ? "20px 0px" : "20px",
}}
>
<Typography <Typography
variant="subtitle1" variant="subtitle1"
style={{ marginBottom: "10px", fontWeight: "bold" }} style={{ marginBottom: "10px", fontWeight: "bold" }}

View File

@ -8,7 +8,18 @@ export function VirtWebRouteContainer(
} & PropsWithChildren } & PropsWithChildren
): React.ReactElement { ): React.ReactElement {
return ( return (
<div style={{ margin: "50px" }}> <div
style={{
margin: "50px",
flex: "1",
flexGrow: 1,
flexShrink: 0,
flexBasis: 0,
minWidth: 0,
display: "flex",
flexDirection: "column",
}}
>
<div <div
style={{ style={{
display: "flex", display: "flex",