Newer
Older
import {
TableContainer,
Paper,
Table,
TableHead,
TableRow,
TableCell,
TableBody,
CircularProgress,
Typography,

Fabien Amarger
committed
IconButton,
Tooltip,
Box,
Menu,
MenuItem,
} from "@mui/material";
import CheckIcon from "@mui/icons-material/Check";
import CloseIcon from "@mui/icons-material/Close";
import ScheduleIcon from "@mui/icons-material/Schedule";
import DownloadIcon from "@mui/icons-material/Download";
import FileDownloadOffIcon from "@mui/icons-material/FileDownloadOff";
import { ImportProcess } from "@/types";
import { useGetImportProcesses } from "@/hooks/useGetImportProcesses";
import { ErrorScreen } from "./ErrorScreen";
import { LoadingScreen } from "./LoadingScreen";

Fabien Amarger
committed
import { ButtonTooltip } from "./ButtonTooltip";
import { useState, useEffect } from "react";
import { getFileNameFromURL } from "@/utils";
export interface ImportProcessTableProps {
dataServiceEid?: number;
recipeEid?: number;
projectEid?: number;
const REFRESH_INTERVAL = 5000;
export function ImportProcessTable(props: ImportProcessTableProps) {
const {
data: importProcessList,
error,
loading,
} = useGetImportProcesses(props);
const showProjectColumn = props.showProjectColumn !== false;
useEffect(() => {
const interval = setInterval(refresh, REFRESH_INTERVAL);
return () => clearInterval(interval);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
if (error) {
return <ErrorScreen message={error} />;
}
if (loading && !importProcessList) {
return <LoadingScreen />;
}
if (!importProcessList) {
return <ErrorScreen />;
}
if (importProcessList.length === 0) {
return (
<Typography variant="subtitle1" color={"GrayText"}>
Aucun import process
</Typography>
);
}
return (
<TableContainer component={Paper}>
<Table sx={{ minWidth: 650 }} aria-label="simple table">
<TableHead>
<TableRow>
<TableCell>eid</TableCell>
<TableCell>Date</TableCell>
<TableCell>Recette</TableCell>
<TableCell>État</TableCell>
{showProjectColumn ? <TableCell>Projet</TableCell> : null}

Fabien Amarger
committed
<TableCell width={50}>Dataset</TableCell>
<TableCell width={50}>Log</TableCell>
<TableCell width={50}>SHACL</TableCell>
</TableRow>
</TableHead>
<TableBody>

Fabien Amarger
committed
{importProcessList.map((row, i) => (
<ImportProcessTableRow
key={i}
importProcess={row}
showProjectColumn={showProjectColumn}
/>
))}
</TableBody>
</Table>
</TableContainer>
);
}

Fabien Amarger
committed
function ImportProcessTableRow({
importProcess,

Fabien Amarger
committed
}: {
importProcess: ImportProcess;

Fabien Amarger
committed
}) {
const hasLog = importProcess.log_url != null;

Fabien Amarger
committed
return (
<TableRow key={importProcess.eid}>
<TableCell component="th" scope="row">
{importProcess.eid}
</TableCell>

Fabien Amarger
committed
<TableCell>{importProcess.recipe}</TableCell>
<TableCell>
<StateIcon state={importProcess.state} />
</TableCell>
{showProjectColumn ? (
<TableCell>{importProcess.project}</TableCell>
) : null}
<DatasetButton importProcess={importProcess} />

Fabien Amarger
committed
<TableCell>
<ButtonTooltip
title={hasLog ? "Voir le fichier de log" : "Aucun log disponible"}
>
<IconButton
color="primary"
disabled={!hasLog}
href={importProcess.log_url ?? ""}
download={getFileNameFromURL(importProcess.log_url)}

Fabien Amarger
committed
>
{hasLog ? <DownloadIcon /> : <FileDownloadOffIcon />}

Fabien Amarger
committed
</IconButton>
</ButtonTooltip>
</TableCell>
<ShaclButton importProcess={importProcess} />

Fabien Amarger
committed
</TableRow>
);
}
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
function DatasetButton({ importProcess }: { importProcess: ImportProcess }) {
const hasDataset =
importProcess.input_dataset_url != null ||
importProcess.output_dataset_url != null;
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
const open = Boolean(anchorEl);
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
return (
<TableCell>
<ButtonTooltip
title={
hasDataset ? "Voir le fichier de Dataset" : "Aucun Dataset disponible"
}
>
<IconButton
color="primary"
disabled={!hasDataset}
onClick={handleClick}
>
{hasDataset ? <DownloadIcon /> : <FileDownloadOffIcon />}
</IconButton>
</ButtonTooltip>
<Menu
id="dataset-menu"
anchorEl={anchorEl}
open={open}
onClose={handleClose}
MenuListProps={{
"aria-labelledby": "dataset-menu",
}}
>
<DatasetMenuItem
text="Entrée"
url={importProcess.input_dataset_url}
onClick={handleClose}
/>
<DatasetMenuItem
text="Sortie"
url={importProcess.output_dataset_url}
onClick={handleClose}
/>
</Menu>
</TableCell>
);
}
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
function DatasetMenuItem({
text,
url,
onClick,
}: {
text: string;
url?: string;
onClick: () => void;
}) {
if (!url) {
return (
<MenuItem onClick={onClick} disabled={true}>
{text}
</MenuItem>
);
}
// Putting href and download props directly on the MenuItem does not work
return (
<a
href={url}
download={getFileNameFromURL(url)}
style={{
color: "inherit",
textDecoration: "inherit",
}}
>
<MenuItem onClick={onClick} disabled={false}>
{text}
</MenuItem>
</a>
);
}
function ShaclButton({ importProcess }: { importProcess: ImportProcess }) {
if (importProcess.shacl_valid) {
return (
<TableCell>
<Tooltip title="La validation SHACL a réussi">
<Box
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
}}
>
<CheckIcon />
</Box>
</Tooltip>
</TableCell>
);
}
return (
<TableCell>
<ButtonTooltip title={"Voir le rapport d'erreur SHACL"}>
<IconButton
color="primary"
href={importProcess.shacl_report_url ?? ""}
download={getFileNameFromURL(importProcess.shacl_report_url)}
<DownloadIcon color="warning" />
</IconButton>
</ButtonTooltip>
</TableCell>
);
}
function StateIcon({ state }: { state: ImportProcess["state"] }) {
if (state === "successful") {
return <CheckIcon />;
}
if (state === "error") {
return <CloseIcon color="error" />;
}
if (state === "waiting") {
return <ScheduleIcon color="warning" />;
}
if (state === "ongoing") {
return <CircularProgress size={20} />;
}
}