{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "audit-log-table",
  "title": "Audit Log Table",
  "description": "A dense, pinned-header event log with actors, mono action names, IPs and severity levels.",
  "registryDependencies": [
    "@spectrumui/data-table"
  ],
  "files": [
    {
      "path": "components/spectrumui/blocks/tables/audit-log-table.tsx",
      "content": "'use client';\n\nimport * as React from 'react';\nimport { DataTable, type DataTableColumn } from '@/components/spectrumui/data-table';\n\ntype Level = 'info' | 'warn' | 'error';\n\ninterface AuditEvent {\n  id: string;\n  time: string;\n  actor: string;\n  avatar: string | null;\n  action: string;\n  target: string;\n  ip: string;\n  level: Level;\n}\n\nconst ACTORS: { name: string; avatar: string | null }[] = [\n  { name: 'Freya Lindgren', avatar: '/avatars/people/01.jpg' },\n  { name: 'ops-bot', avatar: null },\n  { name: 'Mateo Alvarez', avatar: '/avatars/people/03.jpg' },\n  { name: 'Aiko Watanabe', avatar: '/avatars/people/06.jpg' },\n  { name: 'ci-runner', avatar: null },\n  { name: 'Zara Osei', avatar: '/avatars/people/12.jpg' },\n];\n\nconst ACTIONS = [\n  'member.invited',\n  'key.rotated',\n  'billing.plan_changed',\n  'webhook.retried',\n  'sso.enforced',\n  'export.requested',\n  'session.revoked',\n  'role.granted',\n];\n\nconst TARGETS = ['workspace/driftlab', 'org/keelworks', 'project/atlas', 'team/platform'];\n\nconst EVENTS: AuditEvent[] = Array.from({ length: 28 }, (_, index) => {\n  const minute = 56 - index * 2;\n  const hour = 15 + Math.floor(minute / 60);\n  const actor = ACTORS[index % ACTORS.length];\n  return {\n    id: `ev_${7200 - index}`,\n    time: `${String(hour).padStart(2, '0')}:${String(((minute % 60) + 60) % 60).padStart(2, '0')}`,\n    actor: actor.name,\n    avatar: actor.avatar,\n    action: ACTIONS[index % ACTIONS.length],\n    target: TARGETS[index % TARGETS.length],\n    ip: `203.0.113.${(index * 13) % 255}`,\n    level: index % 13 === 4 ? 'error' : index % 6 === 2 ? 'warn' : 'info',\n  };\n});\n\nconst LEVEL_STYLE: Record<Level, string> = {\n  info: 'text-neutral-500 dark:text-neutral-400',\n  warn: 'text-amber-700 dark:text-amber-300',\n  error: 'text-rose-700 dark:text-rose-300',\n};\n\nconst columns: DataTableColumn<AuditEvent>[] = [\n  {\n    id: 'time',\n    header: 'Time',\n    sortable: true,\n    value: (row) => row.time,\n    cell: (row) => <span className=\"tabular-nums\">{row.time}</span>,\n  },\n  {\n    id: 'actor',\n    header: 'Actor',\n    sortable: true,\n    value: (row) => row.actor,\n    cell: (row) => (\n      <span className=\"flex items-center gap-2 font-normal\">\n        {row.avatar ? (\n          /* eslint-disable-next-line @next/next/no-img-element */\n          <img\n            src={row.avatar}\n            alt=\"\"\n            loading=\"lazy\"\n            width={20}\n            height={20}\n            className=\"size-5 shrink-0 rounded-full object-cover outline outline-1 -outline-offset-1 outline-black/10 dark:outline-white/10\"\n          />\n        ) : (\n          <span\n            aria-hidden=\"true\"\n            className=\"grid size-5 shrink-0 place-items-center rounded-full bg-neutral-100 font-mono text-[9px] text-neutral-500 dark:bg-neutral-800 dark:text-neutral-400\"\n          >\n            {'>_'}\n          </span>\n        )}\n        <span className=\"truncate\">{row.actor}</span>\n      </span>\n    ),\n  },\n  {\n    id: 'action',\n    header: 'Action',\n    sortable: true,\n    value: (row) => row.action,\n    cell: (row) => <span className=\"font-mono text-xs\">{row.action}</span>,\n  },\n  { id: 'target', header: 'Target', hideBelow: 'lg', value: (row) => row.target },\n  {\n    id: 'ip',\n    header: 'IP',\n    hideBelow: 'md',\n    value: (row) => row.ip,\n    cell: (row) => <span className=\"font-mono text-xs\">{row.ip}</span>,\n  },\n  {\n    id: 'level',\n    header: 'Level',\n    sortable: true,\n    value: (row) => row.level,\n    cell: (row) => (\n      <span className={`inline-flex items-center gap-1.5 font-medium ${LEVEL_STYLE[row.level]}`}>\n        <span aria-hidden=\"true\" className=\"size-1.5 rounded-full bg-current\" />\n        {row.level}\n      </span>\n    ),\n  },\n];\n\nexport function AuditLogTable({ variant = 'Pinned' }: { variant?: 'Pinned' | 'Paged' }) {\n  const pinned = variant === 'Pinned';\n\n  return (\n    <div className=\"mx-auto w-full max-w-4xl px-4 py-10 sm:px-6\">\n      <DataTable\n        data={EVENTS}\n        columns={columns}\n        rowId={(row) => row.id}\n        rowLabel={(row) => `${row.action} at ${row.time}`}\n        caption=\"Audit events for this workspace, newest first.\"\n        variant=\"bordered\"\n        density=\"compact\"\n        searchable\n        searchPlaceholder=\"Search events\"\n        quickFilter={{ columnId: 'level', label: 'Filter by level' }}\n        resizableColumns\n        pinFirstColumn\n        stickyHeader={pinned}\n        maxHeight={pinned ? 340 : undefined}\n        pageSize={pinned ? undefined : 8}\n        defaultSort={{ columnId: 'time', direction: 'desc' }}\n      />\n    </div>\n  );\n}\n",
      "type": "registry:block",
      "target": "components/spectrumui/blocks/tables/audit-log-table.tsx"
    }
  ],
  "type": "registry:block"
}
