metis-desk/packages/rdx-ui/src/components/entity-table-configuration.tsx
David 9fc7d3a2e0 feat: add entity list state management and UI components
- Implemented asset and resource list query state helpers to manage loading, error, and availability states.
- Created EntityListStatus component for displaying status messages and retry options based on entity list state.
- Added EntityTableSkeleton component for rendering loading placeholders in tables.
- Defined EntityListState type and entityListState function for consistent state management across components.
- Developed comprehensive UI tests for list states using Playwright, covering various scenarios including loading, error handling, and responsiveness.
2026-10-22 11:16:59 +02:00

96 lines
3.0 KiB
TypeScript

import { Button } from "@repo/shadcn-ui/components/button";
import type { Table as TableModel } from "@tanstack/react-table";
import { useId, useState } from "react";
import type { EntityColumnGroup, EntityColumnMetadata } from "../lib/entity-column-configuration";
import { entityListLabels } from "../lib/entity-list";
import { EntityTableColumnsDialog } from "./entity-table-columns-dialog";
import { SelectWithAction } from "./select-with-action";
export function EntityTableConfiguration<T>({
table,
locale,
onSort,
presentation = "full",
columnGroups,
columnMetadata,
onResetColumns,
columnsDisabled = false,
}: {
table: TableModel<T>;
locale: string;
onSort: () => void;
presentation?: "full" | "picker";
columnGroups?: readonly EntityColumnGroup[] | undefined;
columnMetadata?: readonly (EntityColumnMetadata & { id: string })[] | undefined;
onResetColumns?: (() => void) | undefined;
columnsDisabled?: boolean | undefined;
}) {
const id = useId();
const labels = entityListLabels(locale);
const [columnsOpen, setColumnsOpen] = useState(false);
const sorting = table.getState().sorting;
const columns = table.getAllLeafColumns().map((column) => ({
id: column.id,
label: String(column.columnDef.header),
value: column.getCanSort(),
}));
const setSorting = table.setSorting;
return (
<>
<div className="flex flex-wrap items-center gap-2">
<Button
disabled={columnsDisabled}
onClick={() => setColumnsOpen(true)}
size="sm"
variant="outline"
>
{labels.columns}
</Button>
<div
className={
presentation === "picker" ? "hidden @min-[32rem]/entity-table:block" : "contents"
}
>
<SelectWithAction
id={`${id}-sort`}
label={labels.sort}
onValueChange={(value) => {
const [column, direction] = value.split(":");
if (column && column !== "initial") {
setSorting([{ id: column, desc: direction === "desc" }]);
} else {
table.resetSorting();
}
onSort();
}}
options={[
{ value: "initial", label: labels.initial },
...columns
.filter((column) => column.value)
.flatMap((column) => [
{ value: `${column.id}:asc`, label: `${column.label} · ${labels.ascending}` },
{ value: `${column.id}:desc`, label: `${column.label} · ${labels.descending}` },
]),
]}
placeholder={labels.sort}
value={sorting[0] ? `${sorting[0].id}:${sorting[0].desc ? "desc" : "asc"}` : "initial"}
/>
</div>
</div>{" "}
<EntityTableColumnsDialog
columnGroups={columnGroups}
columnMetadata={columnMetadata}
locale={locale}
onOpenChange={setColumnsOpen}
onResetColumns={onResetColumns}
open={columnsOpen}
table={table}
/>
</>
);
}