Files
HiveGrid-Wireframes/hivegrid-cloud/apps/web/app/modules/events/components/EventsTable.tsx
T

140 lines
5.4 KiB
TypeScript

import { Link, useParams } from "react-router";
import { Fragment, useState } from "react";
import { useTranslation } from "react-i18next";
import { PaginationDto } from "~/application/dtos/data/PaginationDto";
import { Colors } from "~/application/enums/shared/Colors";
import SimpleBadge from "~/components/ui/badges/SimpleBadge";
import ExternalLinkEmptyIcon from "~/components/ui/icons/ExternalLinkEmptyIcon";
import OpenModal from "~/components/ui/modals/OpenModal";
import TableSimple from "~/components/ui/tables/TableSimple";
import { EventWithAttempts } from "../db/events.db.server";
import MonacoEditor from "~/components/editors/MonacoEditor";
import { Badge } from "~/components/ui/badge";
import { useLocaleFormatters } from "~/locale/format";
import { appPath } from "~/utils/app/CanonicalUrlUtils";
import { redactDiagnosticJsonString } from "~/utils/redaction";
import EventUtils from "../utils/EventUtils";
interface Props {
items: EventWithAttempts[];
pagination: PaginationDto;
}
export default function EventsTable({ items, pagination }: Props) {
const { t } = useTranslation();
const formatters = useLocaleFormatters();
const params = useParams();
const [selectedData, setSelectedData] = useState<EventWithAttempts | undefined>(undefined);
const formattedData = (item: EventWithAttempts) => {
return redactDiagnosticJsonString(item.data);
};
return (
<>
<TableSimple
items={items}
actions={[
{
title: t("shared.details"),
onClickRoute: (_, i) => i.id,
},
]}
pagination={pagination}
headers={[
{
name: "event",
title: t("models.event.object"),
value: (i) => EventUtils.parseName(i.name, t),
formattedValue: (i) => (
<div>
<Badge variant="secondary">{EventUtils.parseName(i.name, t)}</Badge>
</div>
),
},
{
name: "data",
title: t("models.event.data"),
value: (i) => (
<button type="button" onClick={() => setSelectedData(i)} className="hover:text-theme-500 truncate underline">
{EventUtils.parseDescription(i, t, formatters)}
</button>
),
className: "w-full",
},
// {
// name: "attempts",
// title: t("models.event.attempts"),
// value: (i) => i.attempts.length,
// formattedValue: (i) => (
// <div className="flex space-x-1">
// {i.attempts.map((f, idx) => (
// <Link to={i.id + "?attempt=" + f.id} key={idx}>
// <StatusBadge startedAt={f.startedAt} finishedAt={f.finishedAt} endpoint={f.endpoint} status={f.status} />
// </Link>
// ))}
// </div>
// ),
// },
{
name: "tenant",
title: t("models.tenant.object"),
value: (i) => (
<div className="text-xs">
{!i.tenant ? (
<span className="text-muted-foreground italic">{t("shared.notSet")}</span>
) : (
<Fragment>
<div className="font-medium">{i.tenant?.name}</div>
<Link
to={appPath({ tenantSlug: i.tenant.slug, mode: "host-aware" })}
target="_blank"
className="text-muted-foreground focus:bg-secondary/90 hover:border-border rounded-md border-b border-dashed text-xs hover:border-dashed"
>
<span>/{i.tenant.slug}</span>
</Link>
</Fragment>
)}
</div>
),
hidden: !!params.tenant,
},
{
name: "createdAt",
title: t("shared.createdAt"),
value: (i) => (
<div className="text-xs">
<div>{i.user?.email ?? <span className="text-muted-foreground italic">{t("shared.notSet")}</span>}</div>
<div className="text-muted-foreground text-xs">{formatters.relativeDate(i.createdAt)}</div>
</div>
),
},
]}
/>
{selectedData && (
<OpenModal className="max-w-md" onClose={() => setSelectedData(undefined)}>
<div className="space-y-3 text-sm">
<div className="border-border flex justify-between border-b pb-3">
<h3>
<SimpleBadge className="text-lg" title={EventUtils.parseName(selectedData.name, t)} color={Colors.VIOLET} />
</h3>
<div className="flex items-center space-x-2">
<div className="text-muted-foreground text-sm">{formatters.dateTime(selectedData.createdAt)}</div>
<Link to={selectedData.id} className="text-muted-foreground hover:text-foreground/80">
<ExternalLinkEmptyIcon className="h-5 w-5" />
</Link>
</div>
</div>
<div className="space-y-2">
<p className="text-xs font-bold">{t("models.event.data")}</p>
<div className="h-96 overflow-auto p-2">
<MonacoEditor value={formattedData(selectedData)} onChange={() => {}} theme="vs-dark" language="json" />
</div>
</div>
</div>
</OpenModal>
)}
</>
);
}