metis-desk/packages/rdx-ui/src/components/compact-table.tsx
David fa9d95fa9e feat: add workstation equipment and organizational assignment functionalities
- Implemented `workstationEquipment` to manage workstation asset assignments, including principal and secondary assets.
- Created tests for `workstationEquipment` to ensure correct behavior with various scenarios.
- Developed `workstationOrganizationalAssignments` to retrieve current assignments for a responsible person in a company.
- Added tests for `workstationOrganizationalAssignments` to validate assignment retrieval logic.
- Introduced UI components for displaying workstation profile configurations and responsible person details.
- Created compact UI components for displaying lists and tables, enhancing the user interface for asset management.
- Added utility functions for handling cell content in tables, ensuring proper rendering of data.
2026-10-24 04:13:30 +02:00

115 lines
3.3 KiB
TypeScript

import { Skeleton } from "@repo/shadcn-ui/components/skeleton";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@repo/shadcn-ui/components/table";
import type { ReactNode } from "react";
import { useRef } from "react";
import { hasCellContent } from "../lib/collection-cell-content";
import type { EntityListState } from "../lib/entity-list-state";
import { EntityListStatus } from "./entity-list-status";
export type CompactColumn<T> = {
id: string;
label: string;
render: (item: T) => ReactNode;
align?: "start" | "end";
};
/** Comparación contextual sin herramientas de exploración ni estado remoto propio. */
export function CompactTable<T extends { id: string }>({
title,
className,
items,
columns,
emptyMessage,
state,
onRetry,
retryLabel,
}: {
title: string;
className?: string;
items: readonly T[];
columns: readonly CompactColumn<T>[];
emptyMessage: string;
state?: EntityListState;
onRetry?: () => Promise<unknown>;
retryLabel?: string;
}) {
const ref = useRef<HTMLDivElement>(null);
const available = state?.status !== "loading" && state?.status !== "unavailable";
return (
<div className="min-w-0" data-slot="compact-table" ref={ref} tabIndex={-1}>
{state && (
<EntityListStatus
onRetry={retryLabel ? onRetry : undefined}
retryFocus={() => ref.current}
retryLabel={retryLabel ?? ""}
state={state}
/>
)}
<Table
aria-busy={state?.status === "loading" || state?.status === "refreshing" || undefined}
aria-label={title}
className={className}
>
<TableHeader>
<TableRow>
{columns.map((column) => (
<TableHead
className={`px-2 font-medium ${column.align === "end" ? "text-right" : "text-left"}`}
key={column.id}
scope="col"
>
{column.label}
</TableHead>
))}
</TableRow>
</TableHeader>
<TableBody>
{state?.status === "loading" && (
<TableRow aria-hidden="true">
{columns.map((column) => (
<TableCell className="p-2" key={column.id}>
<Skeleton className="h-5 w-full" />
</TableCell>
))}
</TableRow>
)}
{available &&
items.map((item) => (
<TableRow data-entity-id={item.id} key={item.id}>
{columns.map((column) => (
<TableCell
className={`px-2 py-1.5 whitespace-normal break-words ${column.align === "end" ? "text-right tabular-nums" : "text-left"}`}
key={column.id}
>
{cellContent(column.render(item))}
</TableCell>
))}
</TableRow>
))}
{available && items.length === 0 && (
<TableRow>
<TableCell className="p-2 text-muted-foreground" colSpan={columns.length}>
{emptyMessage}
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
</div>
);
}
function cellContent(content: ReactNode) {
return hasCellContent(content) ? content : "—";
}