frontend/src/component/Admin/Entity/EntityRow.tsx

211 lines
7.0 KiB
TypeScript

import { Box, Checkbox, IconButton, Link, Skeleton, TableCell, TableRow, Tooltip } from "@mui/material";
import { useState } from "react";
import { useTranslation } from "react-i18next";
import { Link as RouterLink } from "react-router-dom";
import { getEntityUrl } from "../../../api/api";
import { Entity } from "../../../api/dashboard";
import { EntityType } from "../../../api/explorer";
import { useAppDispatch } from "../../../redux/hooks";
import { sizeToString } from "../../../util";
import { NoWrapTableCell, NoWrapTypography, SquareChip } from "../../Common/StyledComponents";
import TimeBadge from "../../Common/TimeBadge";
import UserAvatar from "../../Common/User/UserAvatar";
import { EntityTypeText } from "../../FileManager/Sidebar/Data";
import Delete from "../../Icons/Delete";
import Download from "../../Icons/Download";
export interface EntityRowProps {
entity?: Entity;
loading?: boolean;
selected?: boolean;
onDelete?: (id: number) => void;
onSelect?: (id: number) => void;
openEntityDialog?: (id: number) => void;
openUserDialog?: (id: number) => void;
}
const EntityRow = ({
entity,
loading,
selected,
onDelete,
onSelect,
openUserDialog,
openEntityDialog,
}: EntityRowProps) => {
const { t } = useTranslation("dashboard");
const dispatch = useAppDispatch();
const [deleteLoading, setDeleteLoading] = useState(false);
const [openLoading, setOpenLoading] = useState(false);
const onSelectClick = (e: React.MouseEvent<HTMLElement>) => {
e.stopPropagation();
e.preventDefault();
onSelect?.(entity?.id ?? 0);
};
const onOpenClick = (e: React.MouseEvent<HTMLButtonElement>) => {
e.stopPropagation();
setOpenLoading(true);
dispatch(getEntityUrl(entity?.id ?? 0))
.then((url) => {
window.location.assign(url);
})
.finally(() => {
setOpenLoading(false);
})
.catch((error) => {
console.error('Failed to get entity URL:', error);
});
};
const userClicked = (e: React.MouseEvent<HTMLElement>) => {
e.stopPropagation();
e.preventDefault();
openUserDialog?.(entity?.edges?.user?.id ?? 0);
};
const onDeleteClick = (e: React.MouseEvent<HTMLButtonElement>) => {
e.stopPropagation();
e.preventDefault();
onDelete?.(entity?.id ?? 0);
};
if (loading) {
return (
<TableRow sx={{ height: "43px" }}>
<NoWrapTableCell>
<Skeleton variant="circular" width={24} height={24} />
</NoWrapTableCell>
<NoWrapTableCell>
<Skeleton variant="text" width={30} />
</NoWrapTableCell>
<NoWrapTableCell>
<Skeleton variant="text" width={80} />
</NoWrapTableCell>
<NoWrapTableCell>
<Skeleton variant="text" width={200} />
</NoWrapTableCell>
<NoWrapTableCell>
<Skeleton variant="text" width={50} />
</NoWrapTableCell>
<NoWrapTableCell>
<Skeleton variant="text" width={100} />
</NoWrapTableCell>
<NoWrapTableCell>
<Skeleton variant="text" width={30} />
</NoWrapTableCell>
<NoWrapTableCell>
<Skeleton variant="text" width={100} />
</NoWrapTableCell>
<NoWrapTableCell>
<Box sx={{ display: "flex", alignItems: "center", gap: 1 }}>
<Skeleton variant="circular" width={24} height={24} />
<Skeleton variant="text" width={100} />
</Box>
</NoWrapTableCell>
<NoWrapTableCell>
<Skeleton variant="circular" width={24} height={24} />
</NoWrapTableCell>
</TableRow>
);
}
return (
<TableRow
hover
key={entity?.id}
sx={{ cursor: "pointer" }}
onClick={() => openEntityDialog?.(entity?.id ?? 0)}
selected={selected}
>
<TableCell padding="checkbox">
<Checkbox size="small" disableRipple color="primary" onClick={onSelectClick} checked={selected} />
</TableCell>
<NoWrapTableCell>
<NoWrapTypography variant="inherit">{entity?.id}</NoWrapTypography>
</NoWrapTableCell>
<NoWrapTableCell>
<NoWrapTypography variant="inherit">{t(EntityTypeText[entity?.type ?? EntityType.version])}</NoWrapTypography>
</NoWrapTableCell>
<NoWrapTableCell>
<Box sx={{ display: "flex", alignItems: "center", gap: 1 }}>
<Tooltip title={entity?.source || ""}>
<NoWrapTypography variant="inherit">{entity?.source || "-"}</NoWrapTypography>
</Tooltip>
<Box sx={{ display: "flex", alignItems: "center", gap: 0.5 }}>
{!entity?.reference_count && <SquareChip size="small" label={t("entity.waitForRecycle")} />}
</Box>
</Box>
</NoWrapTableCell>
<NoWrapTableCell>
<NoWrapTypography variant="inherit">{sizeToString(entity?.size ?? 0)}</NoWrapTypography>
</NoWrapTableCell>
<NoWrapTableCell>
<NoWrapTypography variant="inherit">
<Link
sx={{
whiteSpace: "nowrap",
overflow: "hidden",
textOverflow: "ellipsis",
}}
component={RouterLink}
underline="hover"
to={`/admin/policy/${entity?.edges?.storage_policy?.id}`}
>
{entity?.edges?.storage_policy?.name || "-"}
</Link>
</NoWrapTypography>
</NoWrapTableCell>
<NoWrapTableCell>
<NoWrapTypography variant="inherit">{entity?.reference_count ?? 0}</NoWrapTypography>
</NoWrapTableCell>
<NoWrapTableCell>
<NoWrapTypography variant="inherit">
<TimeBadge datetime={entity?.created_at ?? ""} variant="inherit" timeAgoThreshold={0} />
</NoWrapTypography>
</NoWrapTableCell>
<NoWrapTableCell>
<Box sx={{ display: "flex", alignItems: "center", gap: 1 }}>
<UserAvatar
sx={{ width: 24, height: 24 }}
overwriteTextSize
user={{
id: entity?.user_hash_id ?? "",
nickname: entity?.edges?.user?.nick ?? "",
created_at: entity?.edges?.user?.created_at ?? "",
}}
/>
<NoWrapTypography variant="inherit">
<Link
sx={{
whiteSpace: "nowrap",
overflow: "hidden",
textOverflow: "ellipsis",
}}
onClick={userClicked}
underline="hover"
href="#/"
>
{entity?.edges?.user?.nick || "-"}
</Link>
</NoWrapTypography>
</Box>
</NoWrapTableCell>
<NoWrapTableCell>
<Box sx={{ display: "flex", alignItems: "center", gap: 1 }}>
<IconButton size="small" onClick={onOpenClick} disabled={openLoading}>
<Download fontSize="small" />
</IconButton>
<IconButton size="small" onClick={onDeleteClick} disabled={deleteLoading}>
<Delete fontSize="small" />
</IconButton>
</Box>
</NoWrapTableCell>
</TableRow>
);
};
export default EntityRow;