reaarange table
This commit is contained in:
parent
bd153b7a87
commit
63fa79b95e
|
|
@ -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)]",
|
||||||
|
|
|
||||||
|
|
@ -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}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue