Skip to content
Snippets Groups Projects
ImportProcessTable.tsx 6.7 KiB
Newer Older
import {
  TableContainer,
  Paper,
  Table,
  TableHead,
  TableRow,
  TableCell,
  TableBody,
  CircularProgress,
  Typography,
} 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 Visibility from "@mui/icons-material/Visibility";
import VisibilityOff from "@mui/icons-material/VisibilityOff";
import { ImportProcess } from "@/types";
import { useGetImportProcesses } from "@/hooks/useGetImportProcesses";
import { ErrorScreen } from "./ErrorScreen";
import { LoadingScreen } from "./LoadingScreen";
import { downloadFile, openFile } from "@/utils";
import { ButtonTooltip } from "./ButtonTooltip";
import { useState, useEffect } from "react";
export interface ImportProcessTableProps {
  dataServiceEid?: number;
  recipeEid?: number;
  projectEid?: number;
  showProjectColumn?: boolean;
async function showFile(url?: string) {
  if (url) {
    const fileToOpen = await downloadFile(url);
    openFile(fileToOpen);
  } else {
    console.error("No file to open");
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}
            <TableCell width={50}>Dataset</TableCell>
            <TableCell width={50}>Log</TableCell>
            <TableCell width={50}>SHACL</TableCell>
          </TableRow>
        </TableHead>
        <TableBody>
            <ImportProcessTableRow
              key={i}
              importProcess={row}
              showProjectColumn={showProjectColumn}
            />
          ))}
        </TableBody>
      </Table>
    </TableContainer>
  );
}
function ImportProcessTableRow({
  importProcess,
  showProjectColumn,
  showProjectColumn: boolean;
Arnaud Vergnet's avatar
Arnaud Vergnet committed
  const dateObj = new Date(importProcess.date);

  return (
    <TableRow key={importProcess.eid}>
      <TableCell component="th" scope="row">
        {importProcess.eid}
      </TableCell>
Arnaud Vergnet's avatar
Arnaud Vergnet committed
      <TableCell>{dateObj.toLocaleString()}</TableCell>
      <TableCell>{importProcess.recipe}</TableCell>
      <TableCell>
        <StateIcon state={importProcess.state} />
      </TableCell>
      {showProjectColumn ? (
        <TableCell>{importProcess.project}</TableCell>
      ) : null}
      <DatasetButton importProcess={importProcess} />
      <TableCell>
        <ButtonTooltip
          title={hasLog ? "Voir le fichier de log" : "Aucun log disponible"}
        >
          <IconButton
            color="primary"
            disabled={!hasLog}
            onClick={() => showFile(importProcess.log_url)}
          >
            {hasLog ? <Visibility /> : <VisibilityOff />}
          </IconButton>
        </ButtonTooltip>
      </TableCell>
      <ShaclButton importProcess={importProcess} />
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 ? <Visibility /> : <VisibilityOff />}
        </IconButton>
      </ButtonTooltip>
      <Menu
        id="dataset-menu"
        anchorEl={anchorEl}
        open={open}
        onClose={handleClose}
        MenuListProps={{
          "aria-labelledby": "dataset-menu",
        }}
      >
        <MenuItem
          onClick={() => {
            showFile(importProcess.input_dataset_url);
            handleClose();
          }}
          disabled={importProcess.input_dataset_url == null}
        >
          Entrée
        </MenuItem>
        <MenuItem
          onClick={() => {
            showFile(importProcess.output_dataset_url);
            handleClose();
          }}
          disabled={importProcess.output_dataset_url == null}
        >
          Sortie
        </MenuItem>
      </Menu>
    </TableCell>
  );
}

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"
          onClick={() => showFile(importProcess.shacl_report_url)}
        >
          <Visibility 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} />;
  }
}