reaarange table

This commit is contained in:
null 2026-05-25 14:30:16 -05:00
parent bd153b7a87
commit 63fa79b95e
2 changed files with 35 additions and 19 deletions

View File

@ -26,10 +26,11 @@ import {
GitBranch, GitBranch,
GitCommitHorizontal, GitCommitHorizontal,
GitFork, GitFork,
KeyRound,
Loader2, Loader2,
Pencil,
RefreshCw, RefreshCw,
ShieldCheck, ShieldCheck,
Trash2,
} from "lucide-react"; } from "lucide-react";
import { import {
DataTable, DataTable,
@ -45,6 +46,11 @@ import type {
const repositoryLabel = (repo: ForgejoRepository) => const repositoryLabel = (repo: ForgejoRepository) =>
repo.display_name || `${repo.owner}/${repo.repo}`; repo.display_name || `${repo.owner}/${repo.repo}`;
const formatConnectionUrl = (value?: string | null) => {
if (!value) return "No connection";
return value.replace(/^https?:\/\//i, "").replace(/\/$/, "");
};
const repositoryTone = (repo: ForgejoRepository) => { const repositoryTone = (repo: ForgejoRepository) => {
if (repo.last_sync_error) return "danger"; if (repo.last_sync_error) return "danger";
if (!repo.active || repo.is_archived) return "muted"; if (!repo.active || repo.is_archived) return "muted";
@ -143,19 +149,21 @@ export function ForgejoRepositoriesTable({
const rowActions: DataTableRowAction<ForgejoRepository>[] = [ const rowActions: DataTableRowAction<ForgejoRepository>[] = [
{ {
key: "edit", key: "edit",
label: "Edit", label: <Pencil className="h-4 w-4" />,
ariaLabel: "Edit repository",
href: (row) => `/git-projects/repositories/${row.id}/edit`, href: (row) => `/git-projects/repositories/${row.id}/edit`,
className: className:
"inline-flex h-8 items-center justify-center rounded-lg px-3 text-xs font-semibold text-muted transition hover:bg-[color:var(--surface-muted)] hover:text-strong focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[color:var(--accent)]", "inline-flex h-8 w-8 items-center justify-center rounded-lg text-muted transition hover:bg-[color:var(--surface-muted)] hover:text-strong focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[color:var(--accent)]",
}, },
...(onDelete ...(onDelete
? [ ? [
{ {
key: "delete", key: "delete",
label: "Delete", label: <Trash2 className="h-4 w-4" />,
ariaLabel: "Delete repository",
onClick: onDelete, onClick: onDelete,
className: className:
"h-8 rounded-lg px-3 text-xs font-semibold text-muted transition hover:bg-[color:rgba(248,113,113,0.1)] hover:text-[color:var(--danger)]", "h-8 w-8 rounded-lg p-0 text-muted transition hover:bg-[color:rgba(248,113,113,0.1)] hover:text-[color:var(--danger)]",
} satisfies DataTableRowAction<ForgejoRepository>, } satisfies DataTableRowAction<ForgejoRepository>,
] ]
: []), : []),
@ -240,6 +248,10 @@ const columns = (
<span className="truncate font-semibold text-strong"> <span className="truncate font-semibold text-strong">
{repositoryLabel(repo)} {repositoryLabel(repo)}
</span> </span>
<span className="inline-flex items-center gap-1 rounded-full border border-[color:rgba(96,165,250,0.26)] bg-[color:rgba(96,165,250,0.1)] px-2 py-0.5 font-mono text-[11px] text-[color:var(--accent-strong)]">
<GitBranch className="h-3 w-3" />
Git
</span>
{repo.default_branch ? ( {repo.default_branch ? (
<span className="inline-flex items-center gap-1 rounded-full border border-[color:rgba(96,165,250,0.26)] bg-[color:rgba(96,165,250,0.1)] px-2 py-0.5 font-mono text-[11px] text-[color:var(--accent-strong)]"> <span className="inline-flex items-center gap-1 rounded-full border border-[color:rgba(96,165,250,0.26)] bg-[color:rgba(96,165,250,0.1)] px-2 py-0.5 font-mono text-[11px] text-[color:var(--accent-strong)]">
<GitCommitHorizontal className="h-3 w-3" /> <GitCommitHorizontal className="h-3 w-3" />
@ -291,11 +303,8 @@ const columns = (
const connection = row.original.connection; const connection = row.original.connection;
return ( return (
<div className="min-w-[180px]"> <div className="min-w-[180px]">
<span className="block truncate font-medium text-sm text-strong">
{connection?.name}
</span>
<span className="mt-1 inline-flex max-w-[240px] items-center rounded-full border border-[color:var(--border)] bg-[color:var(--surface-muted)] px-2 py-0.5 font-mono text-[11px] text-muted"> <span className="mt-1 inline-flex max-w-[240px] items-center rounded-full border border-[color:var(--border)] bg-[color:var(--surface-muted)] px-2 py-0.5 font-mono text-[11px] text-muted">
{connection?.base_url} {formatConnectionUrl(connection?.base_url)}
</span> </span>
</div> </div>
); );
@ -328,15 +337,9 @@ const columns = (
) : null} ) : null}
{repo.has_webhook_secret ? ( {repo.has_webhook_secret ? (
<Badge variant="success" className="gap-1"> <Badge variant="success" className="gap-1">
<KeyRound className="h-3 w-3" />
Webhook Webhook
</Badge> </Badge>
) : ( ) : null}
<Badge variant="warning" className="gap-1">
<KeyRound className="h-3 w-3" />
No secret
</Badge>
)}
{repo.last_sync_error ? ( {repo.last_sync_error ? (
<Badge variant="danger" className="gap-1"> <Badge variant="danger" className="gap-1">
<AlertCircle className="h-3 w-3" /> <AlertCircle className="h-3 w-3" />
@ -359,11 +362,11 @@ const columns = (
}, },
{ {
accessorKey: "openIssues", accessorKey: "openIssues",
header: "Issues", header: () => <span className="block text-center">Issues</span>,
cell: ({ row }) => ( cell: ({ row }) => (
<div <div
className={cn( className={cn(
"inline-flex min-w-[94px] flex-col rounded-xl border px-3 py-2", "mx-auto inline-flex min-w-[94px] flex-col items-center rounded-xl border px-3 py-2 text-center",
row.original.open_issues_count > 0 row.original.open_issues_count > 0
? "border-[color:rgba(251,191,36,0.24)] bg-[color:rgba(251,191,36,0.08)]" ? "border-[color:rgba(251,191,36,0.24)] bg-[color:rgba(251,191,36,0.08)]"
: "border-[color:rgba(52,211,153,0.18)] bg-[color:rgba(52,211,153,0.055)]", : "border-[color:rgba(52,211,153,0.18)] bg-[color:rgba(52,211,153,0.055)]",

View File

@ -19,7 +19,8 @@ export type DataTableEmptyState = {
export type DataTableRowAction<TData> = { export type DataTableRowAction<TData> = {
key: string; key: string;
label: string; label: ReactNode;
ariaLabel?: string;
href?: (row: TData) => string | null; href?: (row: TData) => string | null;
onClick?: (row: TData) => void; onClick?: (row: TData) => void;
className?: string; className?: string;
@ -166,6 +167,12 @@ export function DataTable<TData>({
<Link <Link
key={action.key} key={action.key}
href={href} href={href}
aria-label={action.ariaLabel}
title={
typeof action.label === "string"
? action.label
: action.ariaLabel
}
className={ className={
action.className ?? action.className ??
buttonVariants({ variant: "ghost", size: "sm" }) buttonVariants({ variant: "ghost", size: "sm" })
@ -182,6 +189,12 @@ export function DataTable<TData>({
variant="ghost" variant="ghost"
size="sm" size="sm"
className={action.className} className={action.className}
aria-label={action.ariaLabel}
title={
typeof action.label === "string"
? action.label
: action.ariaLabel
}
onClick={() => action.onClick?.(row.original)} onClick={() => action.onClick?.(row.original)}
> >
{action.label} {action.label}