{
  "$schema": "https://shadcn-vue.com/schema/registry-item.json",
  "name": "access-request-workflow",
  "title": "Access Request Workflow",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-vue/blocks/access-request-workflow/AccessRequestWorkflow.vue",
      "content": "<script setup lang=\"ts\">\nimport { computed, onMounted, onUnmounted, ref } from 'vue'\nimport type { HTMLAttributes } from 'vue'\nimport {\n  Check,\n  Clock,\n  Copy,\n  FileText,\n  History,\n  Hourglass,\n  KeyRound,\n  Lock,\n  MoreHorizontal,\n  Plus,\n  Search,\n  Send,\n  ShieldAlert,\n  X,\n} from 'lucide-vue-next'\nimport { cn } from '@/lib/utils'\nimport { Avatar, AvatarFallback } from '@/components/ui/avatar'\nimport { Badge, type BadgeVariants } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'\nimport {\n  Dialog,\n  DialogContent,\n  DialogDescription,\n  DialogFooter,\n  DialogHeader,\n  DialogTitle,\n  DialogTrigger,\n} from '@/components/ui/dialog'\nimport {\n  DropdownMenu,\n  DropdownMenuContent,\n  DropdownMenuItem,\n  DropdownMenuLabel,\n  DropdownMenuSeparator,\n  DropdownMenuTrigger,\n} from '@/components/ui/dropdown-menu'\nimport { Input } from '@/components/ui/input'\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'\nimport { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'\nimport { Textarea } from '@/components/ui/textarea'\n\ninterface Props {\n  title?: string\n  subtitle?: string\n  class?: HTMLAttributes['class']\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n  title: 'Access Requests & Privilege Elevation',\n  subtitle: 'Request temporary Just-In-Time production access with audit approval.',\n})\n\nexport interface AccessRequest {\n  id: string\n  requester: {\n    name: string\n    email: string\n    team: string\n    avatar: string\n  }\n  targetRole: string\n  system: string\n  duration: string\n  timeLeftLabel: string\n  secondsLeft: number\n  justification: string\n  ticketId: string\n  approver: string\n  status: 'active' | 'pending' | 'expired' | 'rejected'\n  createdAt: string\n  expiresAt: string\n}\n\nconst requests = ref<AccessRequest[]>([\n  {\n    id: 'req-1',\n    requester: {\n      name: 'Elena Rostova',\n      email: 'elena.rostova@acme.corp',\n      team: 'SecOps Team',\n      avatar: 'ER',\n    },\n    targetRole: 'AWS Production Admin',\n    system: 'AWS Cloud IAM (us-east-1)',\n    duration: '4 Hours',\n    timeLeftLabel: '2h 45m left',\n    secondsLeft: 9918,\n    justification: 'Investigating latency spike on payment gateway for incident #SEC-849',\n    ticketId: 'SEC-849',\n    approver: 'Marcus Vance',\n    status: 'active',\n    createdAt: '1h 15m ago',\n    expiresAt: 'Today at 16:30',\n  },\n  {\n    id: 'req-2',\n    requester: {\n      name: 'Marcus Vance',\n      email: 'marcus.vance@acme.corp',\n      team: 'DevOps & Infra',\n      avatar: 'MV',\n    },\n    targetRole: 'Production DB Read-Only',\n    system: 'PostgreSQL Aurora Primary',\n    duration: '1 Hour (Emergency)',\n    timeLeftLabel: '48m left',\n    secondsLeft: 2892,\n    justification: 'Emergency replica query check during PostgreSQL failover testing',\n    ticketId: 'INC-2044',\n    approver: 'Sarah Chen',\n    status: 'active',\n    createdAt: '12m ago',\n    expiresAt: 'Today at 14:15',\n  },\n  {\n    id: 'req-3',\n    requester: {\n      name: 'Sarah Chen',\n      email: 'sarah.chen@acme.corp',\n      team: 'Core Platform',\n      avatar: 'SC',\n    },\n    targetRole: 'Customer PII Decryption',\n    system: 'Customer Data Vault (KMS)',\n    duration: '8 Hours (1 Shift)',\n    timeLeftLabel: 'Pending Approval',\n    secondsLeft: 28800,\n    justification: 'GDPR user deletion verification request #COMP-1102',\n    ticketId: 'COMP-1102',\n    approver: 'Marcus Vance',\n    status: 'pending',\n    createdAt: '10m ago',\n    expiresAt: 'Awaiting approval',\n  },\n  {\n    id: 'req-4',\n    requester: {\n      name: 'David Kim',\n      email: 'david.kim@acme.corp',\n      team: 'Fintech Systems',\n      avatar: 'DK',\n    },\n    targetRole: 'Stripe Dashboard Full Access',\n    system: 'Stripe Merchant Gateway',\n    duration: '1 Hour (Emergency)',\n    timeLeftLabel: 'Pending Approval',\n    secondsLeft: 3600,\n    justification: 'Refunding disputed charges for compromised merchant accounts',\n    ticketId: 'FIN-582',\n    approver: 'Marcus Vance',\n    status: 'pending',\n    createdAt: '25m ago',\n    expiresAt: 'Awaiting approval',\n  },\n  {\n    id: 'req-5',\n    requester: {\n      name: 'Alex Morgan',\n      email: 'alex.m@acme.corp',\n      team: 'Data Platform',\n      avatar: 'AM',\n    },\n    targetRole: 'Production DB Read-Only',\n    system: 'Snowflake Core Analytics',\n    duration: '4 Hours',\n    timeLeftLabel: 'Expired',\n    secondsLeft: 0,\n    justification: 'Quarterly compliance metrics export and audit schema migration verification',\n    ticketId: 'AUD-309',\n    approver: 'Elena Rostova',\n    status: 'expired',\n    createdAt: 'Yesterday',\n    expiresAt: 'Expired at 18:00',\n  },\n])\n\n// Timer ticker for active sessions\nlet timerInterval: ReturnType<typeof setInterval> | null = null\n\nonMounted(() => {\n  timerInterval = setInterval(() => {\n    requests.value.forEach((req) => {\n      if (req.status === 'active' && req.secondsLeft > 0) {\n        req.secondsLeft -= 1\n        if (req.secondsLeft <= 0) {\n          req.status = 'expired'\n          req.timeLeftLabel = 'Expired'\n        } else {\n          const h = Math.floor(req.secondsLeft / 3600)\n          const m = Math.floor((req.secondsLeft % 3600) / 60)\n          req.timeLeftLabel = h > 0 ? `${h}h ${m}m left` : `${m}m left`\n        }\n      }\n    })\n  }, 1000)\n})\n\nonUnmounted(() => {\n  if (timerInterval) clearInterval(timerInterval)\n})\n\nfunction formatSeconds(seconds: number): string {\n  if (seconds <= 0) return '00:00:00'\n  const h = Math.floor(seconds / 3600)\n  const m = Math.floor((seconds % 3600) / 60)\n  const s = seconds % 60\n  return `${h.toString().padStart(2, '0')}:${m.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}`\n}\n\n// Governance KPI Counts\nconst activeCount = computed(() => requests.value.filter((r) => r.status === 'active').length)\nconst pendingCount = computed(() => requests.value.filter((r) => r.status === 'pending').length)\nconst expiringCount = computed(\n  () => requests.value.filter((r) => r.status === 'active' && r.secondsLeft <= 3600 * 4).length,\n)\nconst total30Day = computed(() => 42 + requests.value.filter((r) => r.id.startsWith('req-custom')).length)\n\n// Modal Form State\nconst isDialogOpen = ref(false)\nconst formRole = ref('AWS Production Admin')\nconst formDuration = ref('4 Hours')\nconst formApprover = ref('Security Lead: Marcus Vance')\nconst formJustification = ref('Investigating latency spike on payment gateway for incident #SEC-849')\n\nfunction handleCreateRequest() {\n  if (!formJustification.value.trim()) return\n\n  let seconds = 3600 * 4\n  if (formDuration.value.includes('1 Hour')) seconds = 3600\n  else if (formDuration.value.includes('8 Hours')) seconds = 3600 * 8\n  else if (formDuration.value.includes('24 Hours')) seconds = 3600 * 24\n\n  let system = 'AWS Cloud IAM (us-east-1)'\n  if (formRole.value.includes('DB')) system = 'PostgreSQL Aurora Primary'\n  else if (formRole.value.includes('Stripe')) system = 'Stripe Merchant Gateway'\n  else if (formRole.value.includes('PII')) system = 'Customer Data Vault (KMS)'\n\n  const newReq: AccessRequest = {\n    id: `req-custom-${Date.now()}`,\n    requester: {\n      name: 'Current Operator (You)',\n      email: 'operator@acme.corp',\n      team: 'Platform Engineering',\n      avatar: 'OP',\n    },\n    targetRole: formRole.value,\n    system,\n    duration: formDuration.value,\n    timeLeftLabel: 'Pending Approval',\n    secondsLeft: seconds,\n    justification: formJustification.value,\n    ticketId: `SEC-${Math.floor(100 + Math.random() * 900)}`,\n    approver: formApprover.value,\n    status: 'pending',\n    createdAt: 'Just now',\n    expiresAt: 'Awaiting approval',\n  }\n\n  requests.value.unshift(newReq)\n  isDialogOpen.value = false\n}\n\n// Table Filters\nconst selectedTab = ref<'all' | 'pending' | 'active' | 'expired'>('all')\nconst searchQuery = ref('')\n\nconst filteredRequests = computed(() => {\n  return requests.value.filter((req) => {\n    if (selectedTab.value !== 'all' && req.status !== selectedTab.value) {\n      return false\n    }\n    if (searchQuery.value.trim()) {\n      const q = searchQuery.value.toLowerCase()\n      const matchName = req.requester.name.toLowerCase().includes(q)\n      const matchRole = req.targetRole.toLowerCase().includes(q)\n      const matchTicket = req.ticketId.toLowerCase().includes(q)\n      const matchJust = req.justification.toLowerCase().includes(q)\n      const matchSys = req.system.toLowerCase().includes(q)\n      if (!matchName && !matchRole && !matchTicket && !matchJust && !matchSys) {\n        return false\n      }\n    }\n    return true\n  })\n})\n\n// Manager Actions\nfunction handleApprove(id: string) {\n  const req = requests.value.find((r) => r.id === id)\n  if (req) {\n    req.status = 'active'\n    const h = Math.floor(req.secondsLeft / 3600)\n    const m = Math.floor((req.secondsLeft % 3600) / 60)\n    req.timeLeftLabel = h > 0 ? `${h}h ${m}m left` : `${m}m left`\n  }\n}\n\nfunction handleReject(id: string) {\n  const req = requests.value.find((r) => r.id === id)\n  if (req) {\n    req.status = 'rejected'\n    req.timeLeftLabel = 'Rejected'\n  }\n}\n\nfunction handleRevoke(id: string) {\n  const req = requests.value.find((r) => r.id === id)\n  if (req) {\n    req.status = 'expired'\n    req.secondsLeft = 0\n    req.timeLeftLabel = 'Revoked'\n  }\n}\n\nfunction handleExtend(id: string) {\n  const req = requests.value.find((r) => r.id === id)\n  if (req && req.status === 'active') {\n    req.secondsLeft += 1800\n    const h = Math.floor(req.secondsLeft / 3600)\n    const m = Math.floor((req.secondsLeft % 3600) / 60)\n    req.timeLeftLabel = h > 0 ? `${h}h ${m}m left` : `${m}m left`\n  }\n}\n\nfunction handleReRequest(id: string) {\n  const req = requests.value.find((r) => r.id === id)\n  if (req) {\n    req.status = 'pending'\n    req.timeLeftLabel = 'Pending Approval'\n    req.secondsLeft = 3600 * 4\n  }\n}\n\nconst copiedId = ref<string | null>(null)\nfunction handleCopyToken(id: string) {\n  copiedId.value = id\n  setTimeout(() => {\n    if (copiedId.value === id) copiedId.value = null\n  }, 2000)\n}\n\nfunction getRoleBadgeVariant(role: string): BadgeVariants['variant'] {\n  if (role.includes('AWS') || role.includes('Admin')) return 'destructive'\n  if (role.includes('PII') || role.includes('Decryption')) return 'warning'\n  if (role.includes('DB') || role.includes('Read-Only')) return 'info'\n  if (role.includes('Stripe')) return 'secondary'\n  return 'default'\n}\n</script>\n\n<template>\n  <div data-slot=\"access-request-workflow\" :class=\"cn('flex flex-col gap-6', props.class)\">\n    <!-- Header -->\n    <div class=\"flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between\">\n      <div>\n        <div class=\"flex items-center gap-2\">\n          <div class=\"bg-primary/10 text-primary flex size-9 items-center justify-center rounded-lg\">\n            <KeyRound class=\"size-5\" />\n          </div>\n          <h1 class=\"text-foreground text-xl font-bold tracking-tight sm:text-2xl\">\n            {{ title }}\n          </h1>\n        </div>\n        <p class=\"text-muted-foreground mt-1 text-sm\">\n          {{ subtitle }}\n        </p>\n      </div>\n\n      <!-- Request New Access Modal Dialog -->\n      <Dialog v-model:open=\"isDialogOpen\">\n        <DialogTrigger as-child>\n          <Button class=\"shrink-0 gap-2 shadow-xs\">\n            <Plus class=\"size-4\" />\n            Request New Access\n          </Button>\n        </DialogTrigger>\n        <DialogContent class=\"sm:max-w-lg\">\n          <DialogHeader>\n            <DialogTitle class=\"flex items-center gap-2\">\n              <ShieldAlert class=\"text-primary size-5\" />\n              Request Temporary Access\n            </DialogTitle>\n            <DialogDescription>\n              Submit a Just-In-Time (JIT) access request with duration and business justification.\n            </DialogDescription>\n          </DialogHeader>\n\n          <form class=\"space-y-4 py-2\" @submit.prevent=\"handleCreateRequest\">\n            <div class=\"space-y-1.5\">\n              <label class=\"text-foreground text-xs font-medium\">Target System / Role</label>\n              <Select v-model=\"formRole\">\n                <SelectTrigger class=\"w-full\">\n                  <SelectValue placeholder=\"Select target role\" />\n                </SelectTrigger>\n                <SelectContent>\n                  <SelectItem value=\"Production DB Read-Only\">Production DB Read-Only</SelectItem>\n                  <SelectItem value=\"AWS Production Admin\">AWS Production Admin</SelectItem>\n                  <SelectItem value=\"Stripe Dashboard Full Access\">Stripe Dashboard Full Access</SelectItem>\n                  <SelectItem value=\"Customer PII Decryption\">Customer PII Decryption</SelectItem>\n                </SelectContent>\n              </Select>\n            </div>\n\n            <div class=\"grid grid-cols-1 gap-3 sm:grid-cols-2\">\n              <div class=\"space-y-1.5\">\n                <label class=\"text-foreground text-xs font-medium\">Access Duration</label>\n                <Select v-model=\"formDuration\">\n                  <SelectTrigger class=\"w-full\">\n                    <SelectValue placeholder=\"Select duration\" />\n                  </SelectTrigger>\n                  <SelectContent>\n                    <SelectItem value=\"1 Hour (Emergency)\">1 Hour (Emergency)</SelectItem>\n                    <SelectItem value=\"4 Hours\">4 Hours</SelectItem>\n                    <SelectItem value=\"8 Hours (1 Shift)\">8 Hours (1 Shift)</SelectItem>\n                    <SelectItem value=\"24 Hours max\">24 Hours max</SelectItem>\n                  </SelectContent>\n                </Select>\n              </div>\n\n              <div class=\"space-y-1.5\">\n                <label class=\"text-foreground text-xs font-medium\">Approver / Team</label>\n                <Select v-model=\"formApprover\">\n                  <SelectTrigger class=\"w-full\">\n                    <SelectValue placeholder=\"Select approver\" />\n                  </SelectTrigger>\n                  <SelectContent>\n                    <SelectItem value=\"Security Lead: Marcus Vance\">Security Lead: Marcus Vance</SelectItem>\n                    <SelectItem value=\"Infrastructure Team: Sarah Chen\">Infrastructure Team: Sarah Chen</SelectItem>\n                    <SelectItem value=\"Compliance Officer: Elena Rostova\">Compliance Officer: Elena Rostova</SelectItem>\n                    <SelectItem value=\"On-Call Lead: David Kim\">On-Call Lead: David Kim</SelectItem>\n                  </SelectContent>\n                </Select>\n              </div>\n            </div>\n\n            <div class=\"space-y-1.5\">\n              <label class=\"text-foreground text-xs font-medium\">Business Justification</label>\n              <Textarea\n                v-model=\"formJustification\"\n                placeholder=\"Investigating latency spike on payment gateway for incident #SEC-849\"\n                rows=\"3\"\n                class=\"resize-none text-xs\"\n              />\n              <p class=\"text-muted-foreground text-xs\">\n                All elevated actions are recorded and signed in the immutable IAM audit stream.\n              </p>\n            </div>\n\n            <DialogFooter class=\"pt-2\">\n              <Button type=\"button\" variant=\"outline\" @click=\"isDialogOpen = false\"> Cancel </Button>\n              <Button type=\"submit\" class=\"gap-2\">\n                <Send class=\"size-4\" />\n                Submit Request\n              </Button>\n            </DialogFooter>\n          </form>\n        </DialogContent>\n      </Dialog>\n    </div>\n\n    <!-- 4 Access Governance KPI Cards -->\n    <div class=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n      <Card class=\"border-border/80 relative overflow-hidden shadow-xs\">\n        <CardHeader class=\"flex flex-row items-center justify-between pb-2\">\n          <CardTitle class=\"text-muted-foreground text-xs font-medium\">Active Elevated Sessions</CardTitle>\n          <div class=\"bg-success/10 text-success rounded-md p-1.5\">\n            <ShieldAlert class=\"size-4\" />\n          </div>\n        </CardHeader>\n        <CardContent>\n          <div class=\"text-foreground text-2xl font-bold tracking-tight tabular-nums\">{{ activeCount }}</div>\n          <p class=\"text-muted-foreground mt-1 text-xs\">Expiring within 8h</p>\n        </CardContent>\n      </Card>\n\n      <Card class=\"border-border/80 relative overflow-hidden shadow-xs\">\n        <CardHeader class=\"flex flex-row items-center justify-between pb-2\">\n          <CardTitle class=\"text-muted-foreground text-xs font-medium\">Pending Approvals</CardTitle>\n          <div class=\"bg-warning/10 text-warning rounded-md p-1.5\">\n            <Clock class=\"size-4\" />\n          </div>\n        </CardHeader>\n        <CardContent>\n          <div class=\"text-foreground text-2xl font-bold tracking-tight tabular-nums\">{{ pendingCount }}</div>\n          <p class=\"text-muted-foreground mt-1 text-xs\">Requires security lead review</p>\n        </CardContent>\n      </Card>\n\n      <Card class=\"border-border/80 relative overflow-hidden shadow-xs\">\n        <CardHeader class=\"flex flex-row items-center justify-between pb-2\">\n          <CardTitle class=\"text-muted-foreground text-xs font-medium\">Requests Expiring Today</CardTitle>\n          <div class=\"bg-chart-1/10 text-chart-1 rounded-md p-1.5\">\n            <Hourglass class=\"size-4\" />\n          </div>\n        </CardHeader>\n        <CardContent>\n          <div class=\"text-foreground text-2xl font-bold tracking-tight tabular-nums\">{{ expiringCount }}</div>\n          <p class=\"text-muted-foreground mt-1 text-xs\">Auto-revocation armed</p>\n        </CardContent>\n      </Card>\n\n      <Card class=\"border-border/80 relative overflow-hidden shadow-xs\">\n        <CardHeader class=\"flex flex-row items-center justify-between pb-2\">\n          <CardTitle class=\"text-muted-foreground text-xs font-medium\">30-Day Total Requests</CardTitle>\n          <div class=\"bg-primary/10 text-primary rounded-md p-1.5\">\n            <History class=\"size-4\" />\n          </div>\n        </CardHeader>\n        <CardContent>\n          <div class=\"text-foreground text-2xl font-bold tracking-tight tabular-nums\">{{ total30Day }}</div>\n          <p class=\"text-muted-foreground mt-1 text-xs\">98.2% compliance audit pass</p>\n        </CardContent>\n      </Card>\n    </div>\n\n    <!-- Pending & Active Requests Table Card -->\n    <Card class=\"border-border/80 shadow-xs\">\n      <CardHeader class=\"border-border/60 border-b pb-4\">\n        <div class=\"flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between\">\n          <div>\n            <CardTitle class=\"text-foreground text-base font-semibold\">Privilege Escalation Queue</CardTitle>\n            <CardDescription class=\"text-muted-foreground mt-0.5 text-xs\">\n              Review, approve, or reject active and pending privilege requests.\n            </CardDescription>\n          </div>\n\n          <div class=\"flex flex-col gap-2 sm:flex-row sm:items-center\">\n            <!-- Search -->\n            <div class=\"relative w-full sm:w-60\">\n              <Search class=\"text-muted-foreground absolute top-1/2 left-2.5 size-3.5 -translate-y-1/2\" />\n              <Input v-model=\"searchQuery\" placeholder=\"Search requester, role, ticket...\" class=\"h-8 pl-8 text-xs\" />\n            </div>\n\n            <!-- Filter Tabs -->\n            <div class=\"border-border bg-muted/40 flex items-center rounded-lg border p-0.5\">\n              <button\n                type=\"button\"\n                :class=\"\n                  cn(\n                    'rounded-md px-2.5 py-1 text-xs font-medium transition-colors',\n                    selectedTab === 'all'\n                      ? 'bg-background text-foreground shadow-xs'\n                      : 'text-muted-foreground hover:text-foreground',\n                  )\n                \"\n                @click=\"selectedTab = 'all'\"\n              >\n                All ({{ requests.length }})\n              </button>\n              <button\n                type=\"button\"\n                :class=\"\n                  cn(\n                    'rounded-md px-2.5 py-1 text-xs font-medium transition-colors',\n                    selectedTab === 'pending'\n                      ? 'bg-background text-foreground shadow-xs'\n                      : 'text-muted-foreground hover:text-foreground',\n                  )\n                \"\n                @click=\"selectedTab = 'pending'\"\n              >\n                Pending ({{ pendingCount }})\n              </button>\n              <button\n                type=\"button\"\n                :class=\"\n                  cn(\n                    'rounded-md px-2.5 py-1 text-xs font-medium transition-colors',\n                    selectedTab === 'active'\n                      ? 'bg-background text-foreground shadow-xs'\n                      : 'text-muted-foreground hover:text-foreground',\n                  )\n                \"\n                @click=\"selectedTab = 'active'\"\n              >\n                Active ({{ activeCount }})\n              </button>\n              <button\n                type=\"button\"\n                :class=\"\n                  cn(\n                    'rounded-md px-2.5 py-1 text-xs font-medium transition-colors',\n                    selectedTab === 'expired'\n                      ? 'bg-background text-foreground shadow-xs'\n                      : 'text-muted-foreground hover:text-foreground',\n                  )\n                \"\n                @click=\"selectedTab = 'expired'\"\n              >\n                Expired ({{ requests.filter((r) => r.status === 'expired' || r.status === 'rejected').length }})\n              </button>\n            </div>\n          </div>\n        </div>\n      </CardHeader>\n\n      <CardContent class=\"p-0\">\n        <div class=\"overflow-x-auto\">\n          <Table>\n            <TableHeader>\n              <TableRow class=\"hover:bg-transparent\">\n                <TableHead class=\"w-[220px] text-xs font-medium\">Requester</TableHead>\n                <TableHead class=\"w-[200px] text-xs font-medium\">Target Role & System</TableHead>\n                <TableHead class=\"w-[170px] text-xs font-medium\">Duration & Timer</TableHead>\n                <TableHead class=\"min-w-[260px] text-xs font-medium\">Business Justification</TableHead>\n                <TableHead class=\"w-[180px] text-xs font-medium\">Status</TableHead>\n                <TableHead class=\"w-[160px] text-right text-xs font-medium\">Actions</TableHead>\n              </TableRow>\n            </TableHeader>\n            <TableBody>\n              <TableRow v-if=\"filteredRequests.length === 0\">\n                <TableCell colspan=\"6\" class=\"text-muted-foreground h-32 text-center text-xs\">\n                  No access requests match your filter.\n                </TableCell>\n              </TableRow>\n\n              <TableRow v-for=\"req in filteredRequests\" :key=\"req.id\" class=\"hover:bg-muted/30 transition-colors\">\n                <!-- Requester -->\n                <TableCell>\n                  <div class=\"flex items-center gap-3\">\n                    <Avatar class=\"border-border/60 size-8 border\">\n                      <AvatarFallback class=\"bg-muted text-foreground text-xs font-semibold\">\n                        {{ req.requester.avatar }}\n                      </AvatarFallback>\n                    </Avatar>\n                    <div class=\"min-w-0\">\n                      <div class=\"text-foreground truncate text-xs font-medium\">\n                        {{ req.requester.name }}\n                      </div>\n                      <div class=\"text-muted-foreground truncate text-xs\">\n                        {{ req.requester.email }}\n                      </div>\n                    </div>\n                  </div>\n                </TableCell>\n\n                <!-- Target Role & System -->\n                <TableCell>\n                  <div class=\"flex flex-col gap-1\">\n                    <Badge :variant=\"getRoleBadgeVariant(req.targetRole)\" class=\"w-fit text-xs font-medium\">\n                      {{ req.targetRole }}\n                    </Badge>\n                    <span class=\"text-muted-foreground truncate text-xs\">\n                      {{ req.system }}\n                    </span>\n                  </div>\n                </TableCell>\n\n                <!-- Duration & Timer -->\n                <TableCell>\n                  <div class=\"flex flex-col gap-1\">\n                    <span class=\"text-foreground text-xs font-medium\">\n                      {{ req.duration }}\n                    </span>\n                    <div\n                      v-if=\"req.status === 'active'\"\n                      class=\"text-success text-success flex items-center gap-1.5 font-mono text-xs tabular-nums\"\n                    >\n                      <Clock class=\"size-3 shrink-0\" />\n                      <span>{{ formatSeconds(req.secondsLeft) }}</span>\n                    </div>\n                    <div\n                      v-else-if=\"req.status === 'pending'\"\n                      class=\"text-muted-foreground flex items-center gap-1.5 font-mono text-xs tabular-nums\"\n                    >\n                      <Clock class=\"size-3 shrink-0\" />\n                      <span>Awaiting start</span>\n                    </div>\n                    <div v-else class=\"text-muted-foreground flex items-center gap-1.5 font-mono text-xs tabular-nums\">\n                      <Clock class=\"size-3 shrink-0\" />\n                      <span>Session ended</span>\n                    </div>\n                  </div>\n                </TableCell>\n\n                <!-- Business Justification -->\n                <TableCell>\n                  <div class=\"flex flex-col gap-1\">\n                    <div class=\"flex items-center gap-1.5\">\n                      <span\n                        class=\"border-border bg-muted/60 text-foreground inline-flex items-center rounded border px-1.5 py-0.5 font-mono text-xs font-medium\"\n                      >\n                        #{{ req.ticketId }}\n                      </span>\n                      <span class=\"text-muted-foreground text-xs\">\n                        Approver:\n                        {{\n                          req.approver\n                            .replace('Security Lead: ', '')\n                            .replace('Infrastructure Team: ', '')\n                            .replace('Compliance Officer: ', '')\n                            .replace('On-Call Lead: ', '')\n                        }}\n                      </span>\n                    </div>\n                    <p class=\"text-muted-foreground line-clamp-2 text-xs\" :title=\"req.justification\">\n                      {{ req.justification }}\n                    </p>\n                  </div>\n                </TableCell>\n\n                <!-- Status Badge -->\n                <TableCell>\n                  <div class=\"flex items-center\">\n                    <Badge v-if=\"req.status === 'active'\" variant=\"success\" class=\"gap-1.5 text-xs font-medium\">\n                      <span class=\"relative flex size-2\">\n                        <span class=\"bg-success absolute inline-flex h-full w-full rounded-full opacity-75\"></span>\n                        <span class=\"bg-success relative inline-flex size-2 rounded-full\"></span>\n                      </span>\n                      <span>Active - {{ req.timeLeftLabel }}</span>\n                    </Badge>\n\n                    <Badge v-else-if=\"req.status === 'pending'\" variant=\"warning\" class=\"gap-1.5 text-xs font-medium\">\n                      <span class=\"bg-warning size-2 animate-pulse rounded-full\"></span>\n                      <span>Pending Approval</span>\n                    </Badge>\n\n                    <Badge\n                      v-else-if=\"req.status === 'expired'\"\n                      variant=\"secondary\"\n                      class=\"text-muted-foreground gap-1.5 text-xs font-normal\"\n                    >\n                      <span class=\"bg-muted-foreground/50 size-2 rounded-full\"></span>\n                      <span>Expired</span>\n                    </Badge>\n\n                    <Badge\n                      v-else-if=\"req.status === 'rejected'\"\n                      variant=\"destructive\"\n                      class=\"gap-1.5 text-xs font-normal\"\n                    >\n                      <span class=\"bg-destructive size-2 rounded-full\"></span>\n                      <span>Rejected</span>\n                    </Badge>\n                  </div>\n                </TableCell>\n\n                <!-- Actions -->\n                <TableCell class=\"text-right\">\n                  <div class=\"flex items-center justify-end gap-1.5\">\n                    <!-- Pending Actions -->\n                    <template v-if=\"req.status === 'pending'\">\n                      <Button size=\"sm\" class=\"h-7 gap-1 px-2.5 text-xs shadow-xs\" @click=\"handleApprove(req.id)\">\n                        <Check class=\"size-3.5\" />\n                        Approve\n                      </Button>\n                      <Button\n                        size=\"sm\"\n                        variant=\"outline\"\n                        class=\"text-destructive hover:bg-destructive/10 hover:text-destructive h-7 gap-1 px-2 text-xs\"\n                        @click=\"handleReject(req.id)\"\n                      >\n                        <X class=\"size-3.5\" />\n                        Reject\n                      </Button>\n                    </template>\n\n                    <!-- Active Actions -->\n                    <template v-else-if=\"req.status === 'active'\">\n                      <Button\n                        size=\"sm\"\n                        variant=\"outline\"\n                        class=\"text-destructive border-destructive/30 hover:bg-destructive/10 hover:text-destructive h-7 gap-1 px-2 text-xs\"\n                        @click=\"handleRevoke(req.id)\"\n                      >\n                        <Lock class=\"size-3.5\" />\n                        Revoke\n                      </Button>\n\n                      <DropdownMenu>\n                        <DropdownMenuTrigger as-child>\n                          <Button variant=\"ghost\" size=\"icon\" class=\"size-7\">\n                            <MoreHorizontal class=\"size-3.5\" />\n                            <span class=\"sr-only\">More actions</span>\n                          </Button>\n                        </DropdownMenuTrigger>\n                        <DropdownMenuContent align=\"end\" class=\"w-48\">\n                          <DropdownMenuLabel class=\"text-xs\">Elevated Session</DropdownMenuLabel>\n                          <DropdownMenuSeparator />\n                          <DropdownMenuItem @click=\"handleExtend(req.id)\">\n                            <Clock class=\"mr-2 size-3.5\" />\n                            Extend 30 Minutes\n                          </DropdownMenuItem>\n                          <DropdownMenuItem @click=\"handleCopyToken(req.id)\">\n                            <Copy class=\"mr-2 size-3.5\" />\n                            {{ copiedId === req.id ? 'Copied Token!' : 'Copy Token' }}\n                          </DropdownMenuItem>\n                          <DropdownMenuSeparator />\n                          <DropdownMenuItem\n                            class=\"text-destructive focus:text-destructive\"\n                            @click=\"handleRevoke(req.id)\"\n                          >\n                            <ShieldAlert class=\"mr-2 size-3.5\" />\n                            Revoke Immediately\n                          </DropdownMenuItem>\n                        </DropdownMenuContent>\n                      </DropdownMenu>\n                    </template>\n\n                    <!-- Expired / Rejected Actions -->\n                    <template v-else>\n                      <Button\n                        size=\"sm\"\n                        variant=\"ghost\"\n                        class=\"text-muted-foreground hover:text-foreground h-7 px-2 text-xs\"\n                        @click=\"handleReRequest(req.id)\"\n                      >\n                        Re-request\n                      </Button>\n\n                      <DropdownMenu>\n                        <DropdownMenuTrigger as-child>\n                          <Button variant=\"ghost\" size=\"icon\" class=\"size-7\">\n                            <MoreHorizontal class=\"size-3.5\" />\n                            <span class=\"sr-only\">More actions</span>\n                          </Button>\n                        </DropdownMenuTrigger>\n                        <DropdownMenuContent align=\"end\" class=\"w-44\">\n                          <DropdownMenuItem @click=\"handleReRequest(req.id)\">\n                            <History class=\"mr-2 size-3.5\" />\n                            Request Again\n                          </DropdownMenuItem>\n                          <DropdownMenuItem>\n                            <FileText class=\"mr-2 size-3.5\" />\n                            View Audit Log\n                          </DropdownMenuItem>\n                        </DropdownMenuContent>\n                      </DropdownMenu>\n                    </template>\n                  </div>\n                </TableCell>\n              </TableRow>\n            </TableBody>\n          </Table>\n        </div>\n      </CardContent>\n    </Card>\n  </div>\n</template>\n",
      "type": "registry:block",
      "target": "~/app/components/blocks/AccessRequestWorkflow.vue"
    }
  ],
  "dependencies": [
    "lucide-vue-next"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/vue/avatar.json",
    "https://uipkge.dev/r/vue/badge.json",
    "https://uipkge.dev/r/vue/button.json",
    "https://uipkge.dev/r/vue/card.json",
    "https://uipkge.dev/r/vue/dialog.json",
    "https://uipkge.dev/r/vue/dropdown-menu.json",
    "https://uipkge.dev/r/vue/input.json",
    "https://uipkge.dev/r/vue/select.json",
    "https://uipkge.dev/r/vue/table.json",
    "https://uipkge.dev/r/vue/textarea.json"
  ],
  "description": "Just-In-Time (JIT) IAM temporary privilege escalation request modal and approval queue: governance metrics cards, elevated session countdown timers, approval form dialog, and active session manager with instant revoke and audit logging.",
  "categories": [
    "security",
    "iam",
    "dashboard"
  ]
}