{
  "$schema": "https://uipkge.dev/schema/registry-item.json",
  "name": "lakehouse-table-optimizer",
  "title": "Lakehouse Table Optimizer",
  "type": "registry:page",
  "files": [
    {
      "path": "packages/registry-angular/blocks/lakehouse-table-optimizer/lakehouse-table-optimizer.component.ts",
      "content": "// Apache Iceberg and Delta Lake table maintenance manager, compaction optimizer, snapshot\n// history visualizer, and time-travel SQL query helper. Port of the React block 1:1.\nimport { ChangeDetectionStrategy, Component, Input, computed, signal } from '@angular/core'\nimport {\n  ArrowDownRight,\n  Check,\n  CheckCircle2,\n  Clock,\n  Copy,\n  Database,\n  FileCode2,\n  FileText,\n  FolderArchive,\n  HardDrive,\n  History,\n  Layers,\n  LucideAngularModule,\n  RefreshCw,\n  Search,\n  Server,\n  Terminal,\n  Trash2,\n  Workflow,\n  Zap,\n} from 'lucide-angular'\nimport { cn } from '@/lib/utils'\nimport { UiBadgeComponent } from '@/ui/badge/badge.component'\nimport { UiButtonComponent } from '@/ui/button/button.component'\nimport {\n  UiCardComponent,\n  UiCardContentComponent,\n  UiCardDescriptionComponent,\n  UiCardHeaderComponent,\n  UiCardTitleComponent,\n} from '@/ui/card/card.component'\nimport { UiProgressComponent } from '@/ui/progress/progress.component'\nimport { UiSeparatorComponent } from '@/ui/separator/separator.component'\nimport {\n  UiTableBodyComponent,\n  UiTableCellComponent,\n  UiTableComponent,\n  UiTableHeadComponent,\n  UiTableHeaderComponent,\n  UiTableRowComponent,\n} from '@/ui/table/table.component'\nimport { UiTabsComponent, UiTabsListComponent, UiTabsTriggerComponent } from '@/ui/tabs/tabs.component'\n\nexport type SnapshotOperation = 'MERGE' | 'APPEND' | 'OPTIMIZE' | 'REPLACE_PARTITION'\nexport type SqlSyntaxMode = 'system_time' | 'system_version' | 'pyspark' | 'trino'\n\nexport interface TableSnapshot {\n  id: string\n  numericId: string\n  timestamp: string\n  relativeTime: string\n  operation: SnapshotOperation\n  rowsAdded: string\n  rowsDeleted: string\n  author: string\n  summary: string\n  manifestFile: string\n  filesAdded: number\n  filesRemoved: number\n  byteDelta: string\n}\n\nexport interface PartitionRecord {\n  partitionKey: string\n  fileCount: number\n  avgFileSize: string\n  totalSize: string\n  skippedPercentage: number\n  zOrderScore: string\n  status: 'Optimized' | 'Compacting' | 'Needs Z-Order'\n  lastClustered: string\n}\n\nexport interface TableDetails {\n  name: string\n  format: string\n  totalSize: string\n  rowCount: string\n  statusText: string\n  catalog: string\n  storageLocation: string\n  lastCompacted: string\n  compressionCodec: string\n}\n\nconst defaultTable: TableDetails = {\n  name: 'lakehouse.silver_customer_events',\n  format: 'Apache Iceberg v2 · Parquet',\n  totalSize: '4.2 TB',\n  rowCount: '1.48B Rows',\n  statusText: 'Table Optimized · 0 Small Files',\n  catalog: 'AWS Glue Data Catalog (us-east-1)',\n  storageLocation: 's3://lakehouse-data-prod/silver/customer_events/',\n  lastCompacted: '28 mins ago',\n  compressionCodec: 'ZSTD (Level 7)',\n}\n\nconst defaultSnapshots: TableSnapshot[] = [\n  {\n    id: 'snap_84920194821',\n    numericId: '84920194821',\n    timestamp: '2026-08-21 09:30:00 UTC',\n    relativeTime: '12 mins ago',\n    operation: 'MERGE',\n    rowsAdded: '+142,500',\n    rowsDeleted: '-18,200',\n    author: 'spark-streaming-pipeline',\n    summary: \"Upserted late-arriving customer clickstream events from Kafka topic 'customer.events.prod'\",\n    manifestFile: 'snap-84920194821-1-m0.avro',\n    filesAdded: 4,\n    filesRemoved: 3,\n    byteDelta: '+128 MB',\n  },\n  {\n    id: 'snap_84920183104',\n    numericId: '84920183104',\n    timestamp: '2026-08-21 08:00:00 UTC',\n    relativeTime: '1 hour ago',\n    operation: 'OPTIMIZE',\n    rowsAdded: '+0',\n    rowsDeleted: '-0',\n    author: 'iceberg-compactor-daemon',\n    summary: 'Bin-pack compaction rewrote 4,210 small files into 42 optimal 128MB Parquet data files',\n    manifestFile: 'snap-84920183104-1-m0.avro',\n    filesAdded: 42,\n    filesRemoved: 4210,\n    byteDelta: '-4.1 GB (compaction gain)',\n  },\n  {\n    id: 'snap_84920152918',\n    numericId: '84920152918',\n    timestamp: '2026-08-21 06:15:00 UTC',\n    relativeTime: '3 hours ago',\n    operation: 'APPEND',\n    rowsAdded: '+890,200',\n    rowsDeleted: '-0',\n    author: 'batch-ingest-hourly',\n    summary: 'Micro-batch append for EMEA checkout and cart telemetry session events',\n    manifestFile: 'snap-84920152918-1-m0.avro',\n    filesAdded: 18,\n    filesRemoved: 0,\n    byteDelta: '+2.2 GB',\n  },\n  {\n    id: 'snap_84920120195',\n    numericId: '84920120195',\n    timestamp: '2026-08-20 23:45:00 UTC',\n    relativeTime: '9 hours ago',\n    operation: 'REPLACE_PARTITION',\n    rowsAdded: '+3,410,000',\n    rowsDeleted: '-3,398,000',\n    author: 'dbt-backfill-runner',\n    summary: \"Replaced partition 'event_date=2026-08-20' following upstream IP geolocation schema enrichment\",\n    manifestFile: 'snap-84920120195-1-m0.avro',\n    filesAdded: 28,\n    filesRemoved: 28,\n    byteDelta: '+140 MB',\n  },\n  {\n    id: 'snap_84919984120',\n    numericId: '84919984120',\n    timestamp: '2026-08-20 18:30:00 UTC',\n    relativeTime: '15 hours ago',\n    operation: 'APPEND',\n    rowsAdded: '+1,205,400',\n    rowsDeleted: '-0',\n    author: 'batch-ingest-hourly',\n    summary: 'Hourly ingestion run for US-East customer checkout telemetry records',\n    manifestFile: 'snap-84919984120-1-m0.avro',\n    filesAdded: 24,\n    filesRemoved: 0,\n    byteDelta: '+3.1 GB',\n  },\n]\n\nconst defaultPartitions: PartitionRecord[] = [\n  {\n    partitionKey: 'event_date=2026-08-21',\n    fileCount: 42,\n    avgFileSize: '128.2 MB',\n    totalSize: '5.38 GB',\n    skippedPercentage: 98.4,\n    zOrderScore: '98.4%',\n    status: 'Optimized',\n    lastClustered: '28m ago',\n  },\n  {\n    partitionKey: 'event_date=2026-08-20',\n    fileCount: 40,\n    avgFileSize: '127.9 MB',\n    totalSize: '5.12 GB',\n    skippedPercentage: 97.8,\n    zOrderScore: '97.8%',\n    status: 'Optimized',\n    lastClustered: '9h ago',\n  },\n  {\n    partitionKey: 'event_date=2026-08-19',\n    fileCount: 38,\n    avgFileSize: '128.0 MB',\n    totalSize: '4.86 GB',\n    skippedPercentage: 96.9,\n    zOrderScore: '96.9%',\n    status: 'Optimized',\n    lastClustered: '1d ago',\n  },\n  {\n    partitionKey: 'event_date=2026-08-18',\n    fileCount: 44,\n    avgFileSize: '126.8 MB',\n    totalSize: '5.58 GB',\n    skippedPercentage: 95.8,\n    zOrderScore: '95.8%',\n    status: 'Optimized',\n    lastClustered: '2d ago',\n  },\n  {\n    partitionKey: 'event_date=2026-08-17',\n    fileCount: 36,\n    avgFileSize: '128.5 MB',\n    totalSize: '4.62 GB',\n    skippedPercentage: 97.1,\n    zOrderScore: '97.1%',\n    status: 'Optimized',\n    lastClustered: '3d ago',\n  },\n  {\n    partitionKey: 'event_date=2026-08-16',\n    fileCount: 39,\n    avgFileSize: '127.4 MB',\n    totalSize: '4.97 GB',\n    skippedPercentage: 96.5,\n    zOrderScore: '96.5%',\n    status: 'Optimized',\n    lastClustered: '4d ago',\n  },\n]\n\nconst snapshotOps = ['ALL', 'MERGE', 'OPTIMIZE', 'APPEND', 'REPLACE_PARTITION'] as const\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.Eager,\n  selector: 'ui-lakehouse-table-optimizer, [ui-lakehouse-table-optimizer]',\n  standalone: true,\n  // React renders the root <div> itself: the host stays out of layout and `class` goes to the root.\n  host: { '[attr.class]': '\"contents\"' },\n  imports: [\n    LucideAngularModule,\n    UiBadgeComponent,\n    UiButtonComponent,\n    UiCardComponent,\n    UiCardContentComponent,\n    UiCardDescriptionComponent,\n    UiCardHeaderComponent,\n    UiCardTitleComponent,\n    UiProgressComponent,\n    UiSeparatorComponent,\n    UiTableComponent,\n    UiTableBodyComponent,\n    UiTableCellComponent,\n    UiTableHeadComponent,\n    UiTableHeaderComponent,\n    UiTableRowComponent,\n    UiTabsComponent,\n    UiTabsListComponent,\n    UiTabsTriggerComponent,\n  ],\n  template: `\n    <div data-slot=\"lakehouse-table-optimizer\" [class]=\"rootClass\">\n      <!-- Header Section -->\n      <div class=\"border-border bg-card rounded-xl border p-5 shadow-xs sm:p-6\">\n        <div class=\"flex flex-col gap-5 lg:flex-row lg:items-center lg:justify-between\">\n          <div class=\"flex items-start gap-4\">\n            <div\n              class=\"border-primary/20 bg-primary/10 text-primary flex size-11 shrink-0 items-center justify-center rounded-lg border shadow-xs\"\n            >\n              <lucide-icon [img]=\"Database\" class=\"size-6\" />\n            </div>\n            <div class=\"space-y-2\">\n              <div class=\"flex flex-wrap items-center gap-2\">\n                <h1 class=\"text-foreground font-mono text-lg font-bold tracking-tight break-all sm:text-xl\">\n                  {{ table().name }}\n                </h1>\n                <span ui-badge variant=\"success\" class=\"gap-1.5 font-medium\">\n                  <span class=\"bg-success size-1.5 animate-pulse rounded-full\"></span>\n                  {{ table().statusText }}\n                </span>\n              </div>\n              <div class=\"text-muted-foreground flex flex-wrap items-center gap-2 text-xs\">\n                <span ui-badge variant=\"outline\" class=\"gap-1 font-mono\">\n                  <lucide-icon [img]=\"Layers\" class=\"text-muted-foreground size-3\" />\n                  {{ table().format }}\n                </span>\n                <span ui-badge variant=\"secondary\" class=\"gap-1 font-mono font-medium\">\n                  <lucide-icon [img]=\"HardDrive\" class=\"text-muted-foreground size-3\" />\n                  {{ table().totalSize }} · {{ table().rowCount }}\n                </span>\n                <span class=\"hidden items-center gap-1 sm:inline-flex\">\n                  <lucide-icon [img]=\"Server\" class=\"size-3\" />\n                  {{ table().catalog }}\n                </span>\n              </div>\n            </div>\n          </div>\n\n          <div class=\"flex flex-wrap items-center gap-2.5\">\n            <button\n              ui-button\n              variant=\"outline\"\n              size=\"sm\"\n              class=\"h-9 gap-1.5 shadow-xs\"\n              [disabled]=\"isExpiring()\"\n              (click)=\"expireSnapshots()\"\n            >\n              @if (!isExpiring()) {\n                <lucide-icon [img]=\"Clock\" class=\"text-muted-foreground size-3.5\" />\n              } @else {\n                <lucide-icon [img]=\"RefreshCw\" class=\"text-muted-foreground size-3.5 animate-spin\" />\n              }\n              <span>{{ isExpiring() ? 'Expiring Stale...' : 'Expire Snapshots' }}</span>\n            </button>\n            <button\n              ui-button\n              variant=\"default\"\n              size=\"sm\"\n              class=\"h-9 gap-1.5 shadow-xs\"\n              [disabled]=\"isCompacting()\"\n              (click)=\"runCompaction()\"\n            >\n              @if (!isCompacting()) {\n                <lucide-icon [img]=\"Zap\" class=\"size-3.5\" />\n              } @else {\n                <lucide-icon [img]=\"RefreshCw\" class=\"size-3.5 animate-spin\" />\n              }\n              <span>{{ isCompacting() ? 'Compacting Table...' : 'Run Compaction & Vacuum' }}</span>\n            </button>\n          </div>\n        </div>\n\n        @if (actionNotification()) {\n          <div\n            class=\"border-success/20 bg-success/10 text-success mt-4 flex items-center justify-between rounded-lg border p-3 text-xs\"\n          >\n            <div class=\"flex items-center gap-2\">\n              <lucide-icon [img]=\"CheckCircle2\" class=\"text-success size-4 shrink-0\" />\n              <span>{{ actionNotification() }}</span>\n            </div>\n            <button\n              type=\"button\"\n              class=\"text-success/70 hover:bg-success/20 hover:text-success rounded p-1\"\n              (click)=\"actionNotification.set(null)\"\n            >\n              <span class=\"sr-only\">Dismiss</span>\n              &times;\n            </button>\n          </div>\n        }\n      </div>\n\n      <!-- 4 Table Health & Storage Telemetry Cards -->\n      <div class=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n        <div ui-card class=\"border-border bg-card shadow-xs\">\n          <div ui-card-header class=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n            <h3 ui-card-title class=\"text-muted-foreground text-xs font-semibold tracking-wider uppercase\">\n              Total Partitions\n            </h3>\n            <div\n              class=\"border-border bg-muted/50 text-muted-foreground flex size-7 items-center justify-center rounded-md border\"\n            >\n              <lucide-icon [img]=\"FolderArchive\" class=\"size-3.5\" />\n            </div>\n          </div>\n          <div ui-card-content class=\"space-y-2\">\n            <div class=\"flex flex-wrap items-baseline justify-between gap-2\">\n              <div class=\"text-foreground font-mono text-2xl font-bold tracking-tight tabular-nums\">1,420</div>\n              <span ui-badge variant=\"success\" class=\"text-xs\">100% Healthy</span>\n            </div>\n            <p class=\"text-muted-foreground text-xs\">1,420 Partitions · Date Partitioned</p>\n            <div class=\"space-y-1 pt-1\">\n              <ui-progress [value]=\"100\" class=\"bg-muted h-1.5\" />\n              <div class=\"text-muted-foreground flex justify-between text-xs\">\n                <span>event_date (YYYY-MM-DD)</span>\n                <span class=\"font-mono tabular-nums\">0 unpartitioned</span>\n              </div>\n            </div>\n          </div>\n        </div>\n\n        <div ui-card class=\"border-border bg-card shadow-xs\">\n          <div ui-card-header class=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n            <h3 ui-card-title class=\"text-muted-foreground text-xs font-semibold tracking-wider uppercase\">\n              Small Files Neutralized\n            </h3>\n            <div\n              class=\"border-border bg-muted/50 text-muted-foreground flex size-7 items-center justify-center rounded-md border\"\n            >\n              <lucide-icon [img]=\"HardDrive\" class=\"size-3.5\" />\n            </div>\n          </div>\n          <div ui-card-content class=\"space-y-2\">\n            <div class=\"flex flex-wrap items-baseline justify-between gap-2\">\n              <div class=\"text-foreground font-mono text-2xl font-bold tracking-tight tabular-nums\">14,280</div>\n              <span ui-badge variant=\"success\" class=\"font-mono text-xs\">99.0% Reduction</span>\n            </div>\n            <p class=\"text-muted-foreground text-xs\">14,280 small files compacted -> 142 optimal 128MB files</p>\n            <div class=\"space-y-1 pt-1\">\n              <ui-progress [value]=\"99\" class=\"bg-muted h-1.5\" />\n              <div class=\"text-muted-foreground flex justify-between text-xs\">\n                <span>Target: 128 MB</span>\n                <span class=\"font-mono tabular-nums\">0 files &lt;32MB</span>\n              </div>\n            </div>\n          </div>\n        </div>\n\n        <div ui-card class=\"border-border bg-card shadow-xs\">\n          <div ui-card-header class=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n            <h3 ui-card-title class=\"text-muted-foreground text-xs font-semibold tracking-wider uppercase\">\n              Snapshot History\n            </h3>\n            <div\n              class=\"border-border bg-muted/50 text-muted-foreground flex size-7 items-center justify-center rounded-md border\"\n            >\n              <lucide-icon [img]=\"History\" class=\"size-3.5\" />\n            </div>\n          </div>\n          <div ui-card-content class=\"space-y-2\">\n            <div class=\"flex flex-wrap items-baseline justify-between gap-2\">\n              <div class=\"text-foreground font-mono text-2xl font-bold tracking-tight tabular-nums\">48</div>\n              <span ui-badge variant=\"info\" class=\"font-mono text-xs\">30-Day Window</span>\n            </div>\n            <p class=\"text-muted-foreground text-xs\">48 Active Snapshots · 30-Day Time Travel</p>\n            <div class=\"space-y-1 pt-1\">\n              <ui-progress [value]=\"64\" class=\"bg-muted h-1.5\" />\n              <div class=\"text-muted-foreground flex justify-between text-xs\">\n                <span>Oldest: Jul 22, 2026</span>\n                <span class=\"font-mono tabular-nums\">4.8 MB metadata</span>\n              </div>\n            </div>\n          </div>\n        </div>\n\n        <div ui-card class=\"border-border bg-card shadow-xs\">\n          <div ui-card-header class=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n            <h3 ui-card-title class=\"text-muted-foreground text-xs font-semibold tracking-wider uppercase\">\n              Storage Optimization\n            </h3>\n            <div\n              class=\"border-border bg-muted/50 text-muted-foreground flex size-7 items-center justify-center rounded-md border\"\n            >\n              <lucide-icon [img]=\"Zap\" class=\"size-3.5\" />\n            </div>\n          </div>\n          <div ui-card-content class=\"space-y-2\">\n            <div class=\"flex flex-wrap items-baseline justify-between gap-2\">\n              <div class=\"text-foreground font-mono text-2xl font-bold tracking-tight tabular-nums\">1.2 TB</div>\n              <span ui-badge variant=\"success\" class=\"font-mono text-xs\">$240/mo Saved</span>\n            </div>\n            <p class=\"text-muted-foreground text-xs\">1.2 TB freed via Vacuum · $240/mo saved</p>\n            <div class=\"space-y-1 pt-1\">\n              <ui-progress [value]=\"85\" class=\"bg-muted h-1.5\" />\n              <div class=\"text-muted-foreground flex justify-between text-xs\">\n                <span>872 GB stale · 328 GB orphan</span>\n                <span class=\"font-mono tabular-nums\">-28.5% S3 Cost</span>\n              </div>\n            </div>\n          </div>\n        </div>\n      </div>\n\n      <!-- Main Lakehouse Inspection & Control Tabs -->\n      <ui-tabs [value]=\"activeTab()\" (valueChange)=\"setActiveTab($event)\" class=\"w-full space-y-5\">\n        <ui-tabs-list class=\"grid w-full grid-cols-2 md:grid-cols-4\">\n          <button ui-tabs-trigger value=\"snapshots\" class=\"gap-1.5 text-xs font-medium\">\n            <lucide-icon [img]=\"History\" class=\"size-3.5\" />\n            <span>Snapshots & Time-Travel</span>\n          </button>\n          <button ui-tabs-trigger value=\"partitions\" class=\"gap-1.5 text-xs font-medium\">\n            <lucide-icon [img]=\"Layers\" class=\"size-3.5\" />\n            <span>Partitions & Z-Ordering</span>\n          </button>\n          <button ui-tabs-trigger value=\"maintenance\" class=\"gap-1.5 text-xs font-medium\">\n            <lucide-icon [img]=\"Zap\" class=\"size-3.5\" />\n            <span>Compaction & Vacuum</span>\n          </button>\n          <button ui-tabs-trigger value=\"files\" class=\"gap-1.5 text-xs font-medium\">\n            <lucide-icon [img]=\"HardDrive\" class=\"size-3.5\" />\n            <span>File Sizing & Distribution</span>\n          </button>\n        </ui-tabs-list>\n\n        @if (activeTab() === 'snapshots') {\n          <div class=\"space-y-5\">\n            <div class=\"grid grid-cols-1 gap-6 lg:grid-cols-12\">\n              <div class=\"space-y-4 lg:col-span-7\">\n                <div ui-card class=\"border-border bg-card shadow-xs\">\n                  <div ui-card-header class=\"p-4 pb-3 sm:p-5 sm:pb-3\">\n                    <div class=\"flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n                      <div>\n                        <h3 ui-card-title class=\"text-sm font-semibold sm:text-base\">Snapshot Commit History</h3>\n                        <p ui-card-description class=\"text-xs\">\n                          Select any snapshot to generate reproducible time-travel queries\n                        </p>\n                      </div>\n                      <div class=\"flex flex-wrap items-center gap-1\">\n                        @for (op of snapshotOps; track op) {\n                          <button type=\"button\" [class]=\"opPillClass(op)\" (click)=\"snapshotFilter.set(op)\">\n                            {{ op }}\n                          </button>\n                        }\n                      </div>\n                    </div>\n                    <div class=\"relative pt-2\">\n                      <lucide-icon [img]=\"Search\" class=\"text-muted-foreground absolute top-5 left-2.5 size-3.5\" />\n                      <input\n                        [value]=\"snapshotSearch()\"\n                        (input)=\"snapshotSearch.set($any($event.target).value)\"\n                        type=\"text\"\n                        placeholder=\"Search snapshot ID, author, summary...\"\n                        class=\"border-border bg-background text-foreground placeholder:text-muted-foreground focus-visible:ring-ring w-full rounded-md border py-1.5 pr-3 pl-8 text-xs focus-visible:ring-2 focus-visible:outline-none\"\n                      />\n                    </div>\n                  </div>\n\n                  <ui-separator />\n\n                  <div ui-card-content class=\"p-4 sm:p-5\">\n                    <div\n                      class=\"before:bg-border relative space-y-4 before:absolute before:top-3 before:bottom-3 before:left-[17px] before:w-0.5\"\n                    >\n                      @for (snap of filteredSnapshots(); track snap.id) {\n                        <div\n                          role=\"button\"\n                          tabindex=\"0\"\n                          [class]=\"snapshotCardClass(snap.id)\"\n                          (click)=\"selectSnapshot(snap.id)\"\n                          (keydown.enter)=\"selectSnapshot(snap.id)\"\n                          (keydown.space)=\"selectSnapshotKey($event, snap.id)\"\n                        >\n                          <div\n                            class=\"border-border bg-card text-foreground group-hover:border-primary/50 relative z-10 flex size-9 shrink-0 items-center justify-center rounded-full border shadow-xs\"\n                          >\n                            @switch (snap.operation) {\n                              @case ('MERGE') {\n                                <lucide-icon [img]=\"History\" class=\"text-info size-4\" />\n                              }\n                              @case ('OPTIMIZE') {\n                                <lucide-icon [img]=\"Zap\" class=\"text-success size-4\" />\n                              }\n                              @case ('APPEND') {\n                                <lucide-icon [img]=\"ArrowDownRight\" class=\"text-chart-1 size-4\" />\n                              }\n                              @default {\n                                <lucide-icon [img]=\"RefreshCw\" class=\"text-warning size-4\" />\n                              }\n                            }\n                          </div>\n                          <div class=\"min-w-0 flex-1 space-y-2\">\n                            <div class=\"flex flex-wrap items-center justify-between gap-2\">\n                              <div class=\"flex flex-wrap items-center gap-2\">\n                                <span class=\"text-foreground font-mono text-xs font-bold\">{{ snap.id }}</span>\n                                <span\n                                  ui-badge\n                                  [variant]=\"operationBadgeVariant(snap.operation)\"\n                                  class=\"font-mono text-xs\"\n                                >\n                                  {{ snap.operation }}\n                                </span>\n                                @if (selectedSnapshotId() === snap.id) {\n                                  <span ui-badge variant=\"default\" class=\"text-xs\">Active Time-Travel Target</span>\n                                }\n                              </div>\n                              <span class=\"text-muted-foreground font-mono text-xs tabular-nums\">{{\n                                snap.relativeTime\n                              }}</span>\n                            </div>\n                            <p class=\"text-muted-foreground text-xs\">{{ snap.summary }}</p>\n                            <div class=\"flex flex-wrap items-center gap-3 pt-1 text-xs\">\n                              <div class=\"text-muted-foreground flex items-center gap-1 font-mono\">\n                                <span class=\"text-success font-semibold\">{{ snap.rowsAdded }}</span>\n                                <span>/</span>\n                                <span class=\"text-destructive font-semibold\">{{ snap.rowsDeleted }} rows</span>\n                              </div>\n                              <div class=\"text-muted-foreground flex items-center gap-1 font-mono\">\n                                <lucide-icon [img]=\"FileCode2\" class=\"text-muted-foreground size-3\" />\n                                <span>{{ snap.byteDelta }}</span>\n                              </div>\n                              <div class=\"text-muted-foreground flex items-center gap-1 font-mono\">\n                                <span>Author:</span>\n                                <span class=\"text-foreground font-medium\">{{ snap.author }}</span>\n                              </div>\n                            </div>\n                          </div>\n                        </div>\n                      }\n                    </div>\n                  </div>\n                </div>\n              </div>\n\n              <div class=\"space-y-4 lg:col-span-5\">\n                <div ui-card class=\"border-border bg-card shadow-xs\">\n                  <div ui-card-header class=\"p-4 pb-3 sm:p-5 sm:pb-3\">\n                    <div class=\"flex items-center justify-between\">\n                      <div class=\"space-y-1\">\n                        <h3 ui-card-title class=\"text-sm font-semibold sm:text-base\">Time-Travel Query Picker</h3>\n                        <p ui-card-description class=\"text-xs\">\n                          Instant query generator for snapshot audit & reconciliation\n                        </p>\n                      </div>\n                      <span ui-badge variant=\"outline\" class=\"font-mono text-xs\">{{\n                        selectedSnapshot().numericId\n                      }}</span>\n                    </div>\n                    <div class=\"grid grid-cols-2 gap-1 pt-3 sm:grid-cols-4\">\n                      <button\n                        type=\"button\"\n                        [class]=\"syntaxClass('system_time')\"\n                        (click)=\"sqlSyntaxMode.set('system_time')\"\n                      >\n                        SYSTEM_TIME\n                      </button>\n                      <button\n                        type=\"button\"\n                        [class]=\"syntaxClass('system_version')\"\n                        (click)=\"sqlSyntaxMode.set('system_version')\"\n                      >\n                        VERSION\n                      </button>\n                      <button type=\"button\" [class]=\"syntaxClass('pyspark')\" (click)=\"sqlSyntaxMode.set('pyspark')\">\n                        PySpark\n                      </button>\n                      <button type=\"button\" [class]=\"syntaxClass('trino')\" (click)=\"sqlSyntaxMode.set('trino')\">\n                        Trino SQL\n                      </button>\n                    </div>\n                  </div>\n\n                  <ui-separator />\n\n                  <div ui-card-content class=\"space-y-4 p-4 sm:p-5\">\n                    <div class=\"border-border bg-muted/40 space-y-1.5 rounded-lg border p-3 text-xs\">\n                      <div class=\"text-muted-foreground flex items-center justify-between\">\n                        <span>Target Snapshot:</span>\n                        <span class=\"text-foreground font-mono font-semibold\">{{ selectedSnapshot().id }}</span>\n                      </div>\n                      <div class=\"text-muted-foreground flex items-center justify-between\">\n                        <span>Point-in-Time:</span>\n                        <span class=\"text-foreground font-mono\">{{ selectedSnapshot().timestamp }}</span>\n                      </div>\n                      <div class=\"text-muted-foreground flex items-center justify-between\">\n                        <span>Commit Operation:</span>\n                        <span\n                          ui-badge\n                          [variant]=\"operationBadgeVariant(selectedSnapshot().operation)\"\n                          class=\"font-mono text-xs\"\n                        >\n                          {{ selectedSnapshot().operation }}\n                        </span>\n                      </div>\n                    </div>\n\n                    <div class=\"border-border bg-muted/70 relative overflow-hidden rounded-lg border font-mono\">\n                      <div\n                        class=\"border-border bg-muted/90 text-muted-foreground flex items-center justify-between border-b px-3 py-2 text-xs\"\n                      >\n                        <span class=\"text-foreground flex items-center gap-1.5 font-semibold\">\n                          <lucide-icon [img]=\"Terminal\" class=\"text-primary size-3.5\" />\n                          Query table as of snapshot:\n                        </span>\n                        <button\n                          ui-button\n                          variant=\"ghost\"\n                          size=\"sm\"\n                          class=\"hover:bg-background hover:text-foreground h-7 gap-1 px-2 text-xs\"\n                          (click)=\"handleCopyQuery()\"\n                        >\n                          @if (copiedQuery()) {\n                            <lucide-icon [img]=\"Check\" class=\"text-success size-3.5\" />\n                          } @else {\n                            <lucide-icon [img]=\"Copy\" class=\"text-muted-foreground size-3.5\" />\n                          }\n                          <span>{{ copiedQuery() ? 'Copied' : 'Copy' }}</span>\n                        </button>\n                      </div>\n                      <pre\n                        class=\"text-foreground overflow-x-auto p-3 text-xs leading-relaxed\"\n                      ><code>{{ generatedQuery() }}</code></pre>\n                    </div>\n\n                    <div class=\"border-border bg-card space-y-2 rounded-lg border p-3 text-xs\">\n                      <div class=\"text-muted-foreground flex items-center justify-between\">\n                        <span>Estimated Scan Overhead:</span>\n                        <span class=\"text-success font-mono font-semibold\">42ms · 96.4% skipped</span>\n                      </div>\n                      <div class=\"text-muted-foreground flex items-center justify-between\">\n                        <span>Manifest Avro File:</span>\n                        <span class=\"text-foreground font-mono text-xs\">{{ selectedSnapshot().manifestFile }}</span>\n                      </div>\n                      <div class=\"text-muted-foreground flex items-center justify-between\">\n                        <span>Storage Engine:</span>\n                        <span class=\"text-foreground\">Apache Iceberg Native Parquet Reader</span>\n                      </div>\n                    </div>\n                  </div>\n                </div>\n              </div>\n            </div>\n          </div>\n        }\n\n        @if (activeTab() === 'partitions') {\n          <div class=\"space-y-5\">\n            <div ui-card class=\"border-border bg-card shadow-xs\">\n              <div ui-card-header class=\"p-5 pb-4\">\n                <div class=\"flex flex-col gap-3 md:flex-row md:items-center md:justify-between\">\n                  <div>\n                    <h3 ui-card-title class=\"flex items-center gap-2 text-base font-semibold\">\n                      <lucide-icon [img]=\"Workflow\" class=\"text-primary size-4\" />\n                      Partition Health & Multidimensional Z-Order Clustering\n                    </h3>\n                    <p ui-card-description class=\"text-xs\">\n                      Z-Order clustered by customer_id, event_type to maximize Parquet min/max statistics pruning.\n                    </p>\n                  </div>\n                  <div class=\"relative w-full md:w-64\">\n                    <lucide-icon [img]=\"Search\" class=\"text-muted-foreground absolute top-2.5 left-2.5 size-3.5\" />\n                    <input\n                      [value]=\"partitionSearch()\"\n                      (input)=\"partitionSearch.set($any($event.target).value)\"\n                      type=\"text\"\n                      placeholder=\"Filter partitions...\"\n                      class=\"border-border bg-background text-foreground placeholder:text-muted-foreground focus-visible:ring-ring w-full rounded-md border py-1.5 pr-3 pl-8 text-xs focus-visible:ring-2 focus-visible:outline-none\"\n                    />\n                  </div>\n                </div>\n                <div\n                  class=\"border-border bg-muted/30 mt-4 grid grid-cols-1 gap-3 rounded-lg border p-3 text-xs sm:grid-cols-2 lg:grid-cols-4\"\n                >\n                  <div>\n                    <span class=\"text-muted-foreground\">Clustered Columns:</span>\n                    <div class=\"text-foreground font-mono font-semibold\">customer_id, event_type</div>\n                  </div>\n                  <div>\n                    <span class=\"text-muted-foreground\">Data Skipping Efficiency:</span>\n                    <div class=\"text-success font-mono font-semibold\">96.4% Row-Groups Skipped</div>\n                  </div>\n                  <div>\n                    <span class=\"text-muted-foreground\">Clustering Curve Algorithm:</span>\n                    <div class=\"text-foreground font-mono font-semibold\">Hilbert Space-Filling (Depth 16)</div>\n                  </div>\n                  <div>\n                    <span class=\"text-muted-foreground\">Compression Codec:</span>\n                    <div class=\"text-foreground font-mono font-semibold\">ZSTD Level 7 · Parquet v2</div>\n                  </div>\n                </div>\n              </div>\n\n              <ui-separator />\n\n              <div ui-card-content class=\"p-0\">\n                <div class=\"overflow-x-auto\">\n                  <table ui-table>\n                    <thead ui-table-header>\n                      <tr ui-table-row class=\"hover:bg-transparent\">\n                        <th ui-table-head class=\"text-xs\">Partition Key</th>\n                        <th ui-table-head class=\"text-xs\">File Count</th>\n                        <th ui-table-head class=\"text-xs\">Avg File Size</th>\n                        <th ui-table-head class=\"text-xs\">Total Data Size</th>\n                        <th ui-table-head class=\"text-xs\">Data Skipping</th>\n                        <th ui-table-head class=\"text-xs\">Z-Order Status</th>\n                        <th ui-table-head class=\"text-right text-xs\">Action</th>\n                      </tr>\n                    </thead>\n                    <tbody ui-table-body>\n                      @for (partition of filteredPartitions(); track partition.partitionKey) {\n                        <tr ui-table-row class=\"hover:bg-muted/50\">\n                          <td ui-table-cell class=\"text-foreground font-mono text-xs font-semibold\">\n                            {{ partition.partitionKey }}\n                          </td>\n                          <td ui-table-cell class=\"font-mono text-xs tabular-nums\">{{ partition.fileCount }} files</td>\n                          <td ui-table-cell class=\"font-mono text-xs tabular-nums\">{{ partition.avgFileSize }}</td>\n                          <td ui-table-cell class=\"font-mono text-xs tabular-nums\">{{ partition.totalSize }}</td>\n                          <td ui-table-cell>\n                            <div class=\"w-32 space-y-1\">\n                              <div class=\"text-muted-foreground flex justify-between font-mono text-xs tabular-nums\">\n                                <span>{{ partition.skippedPercentage }}%</span>\n                              </div>\n                              <ui-progress [value]=\"partition.skippedPercentage\" class=\"bg-muted h-1.5\" />\n                            </div>\n                          </td>\n                          <td ui-table-cell>\n                            <span ui-badge variant=\"success\" class=\"gap-1 font-mono text-xs\">\n                              <lucide-icon [img]=\"CheckCircle2\" class=\"size-3\" />\n                              {{ partition.status }}\n                            </span>\n                          </td>\n                          <td ui-table-cell class=\"text-right\">\n                            <button ui-button variant=\"ghost\" size=\"sm\" class=\"h-7 text-xs font-medium\">\n                              Re-cluster\n                            </button>\n                          </td>\n                        </tr>\n                      }\n                    </tbody>\n                  </table>\n                </div>\n              </div>\n            </div>\n          </div>\n        }\n\n        @if (activeTab() === 'maintenance') {\n          <div class=\"space-y-5\">\n            <div class=\"grid grid-cols-1 gap-4 md:grid-cols-2\">\n              <div ui-card class=\"border-border bg-card shadow-xs\">\n                <div ui-card-header class=\"p-4 pb-2 sm:p-5 sm:pb-2\">\n                  <div class=\"flex items-center justify-between\">\n                    <h3 ui-card-title class=\"flex items-center gap-2 text-sm font-semibold\">\n                      <lucide-icon [img]=\"Database\" class=\"text-success size-4\" />\n                      Bin-Pack Data File Compaction\n                    </h3>\n                    <span ui-badge variant=\"success\" class=\"text-xs\">Enabled · Auto</span>\n                  </div>\n                  <p ui-card-description class=\"text-xs\">\n                    Merges small files into optimized 128MB Parquet chunks to prevent small file bottleneck\n                  </p>\n                </div>\n                <div ui-card-content class=\"space-y-3 p-4 pt-3 text-xs sm:p-5\">\n                  <div class=\"border-border bg-muted/40 space-y-2 rounded-lg border p-3\">\n                    <div class=\"text-muted-foreground flex justify-between\">\n                      <span>Target File Size:</span>\n                      <span class=\"text-foreground font-mono font-semibold\">128 MB</span>\n                    </div>\n                    <div class=\"text-muted-foreground flex justify-between\">\n                      <span>Small File Threshold:</span>\n                      <span class=\"text-foreground font-mono font-semibold\">&lt; 32 MB</span>\n                    </div>\n                    <div class=\"text-muted-foreground flex justify-between\">\n                      <span>Execution Schedule:</span>\n                      <span class=\"text-foreground font-mono\">Every 2 Hours (cron: 0 */2 * * *)</span>\n                    </div>\n                    <div class=\"text-muted-foreground flex justify-between\">\n                      <span>Engine:</span>\n                      <span class=\"text-foreground\">Apache Spark Iceberg RewriteDataFiles Action</span>\n                    </div>\n                  </div>\n                </div>\n              </div>\n\n              <div ui-card class=\"border-border bg-card shadow-xs\">\n                <div ui-card-header class=\"p-4 pb-2 sm:p-5 sm:pb-2\">\n                  <div class=\"flex items-center justify-between\">\n                    <h3 ui-card-title class=\"flex items-center gap-2 text-sm font-semibold\">\n                      <lucide-icon [img]=\"Trash2\" class=\"text-destructive size-4\" />\n                      Vacuum & Orphan File Purger\n                    </h3>\n                    <span ui-badge variant=\"success\" class=\"text-xs\">Enabled · Daily</span>\n                  </div>\n                  <p ui-card-description class=\"text-xs\">\n                    Hard-deletes unreferenced data files and uncommitted multi-part upload orphans in S3\n                  </p>\n                </div>\n                <div ui-card-content class=\"space-y-3 p-4 pt-3 text-xs sm:p-5\">\n                  <div class=\"border-border bg-muted/40 space-y-2 rounded-lg border p-3\">\n                    <div class=\"text-muted-foreground flex justify-between\">\n                      <span>Retention Grace Period:</span>\n                      <span class=\"text-foreground font-mono font-semibold\">7 Days (168 Hours)</span>\n                    </div>\n                    <div class=\"text-muted-foreground flex justify-between\">\n                      <span>Storage Reclaimed (30d):</span>\n                      <span class=\"text-success font-mono font-semibold\">1.2 TB freed</span>\n                    </div>\n                    <div class=\"text-muted-foreground flex justify-between\">\n                      <span>Execution Schedule:</span>\n                      <span class=\"text-foreground font-mono\">Daily at 02:00 UTC</span>\n                    </div>\n                    <div class=\"text-muted-foreground flex justify-between\">\n                      <span>Safety Guard:</span>\n                      <span class=\"text-foreground\">Explicit dry-run verification check</span>\n                    </div>\n                  </div>\n                </div>\n              </div>\n\n              <div ui-card class=\"border-border bg-card shadow-xs\">\n                <div ui-card-header class=\"p-4 pb-2 sm:p-5 sm:pb-2\">\n                  <div class=\"flex items-center justify-between\">\n                    <h3 ui-card-title class=\"flex items-center gap-2 text-sm font-semibold\">\n                      <lucide-icon [img]=\"Clock\" class=\"text-info size-4\" />\n                      Snapshot Expiration Policy\n                    </h3>\n                    <span ui-badge variant=\"info\" class=\"text-xs\">30-Day Window</span>\n                  </div>\n                  <p ui-card-description class=\"text-xs\">\n                    Controls metadata table history retention for time-travel queries and rollback safety\n                  </p>\n                </div>\n                <div ui-card-content class=\"space-y-3 p-4 pt-3 text-xs sm:p-5\">\n                  <div class=\"border-border bg-muted/40 space-y-2 rounded-lg border p-3\">\n                    <div class=\"text-muted-foreground flex justify-between\">\n                      <span>Retention Window:</span>\n                      <span class=\"text-foreground font-mono font-semibold\">30 Days</span>\n                    </div>\n                    <div class=\"text-muted-foreground flex justify-between\">\n                      <span>Min Snapshots Retained:</span>\n                      <span class=\"text-foreground font-mono font-semibold\">20 Snapshots</span>\n                    </div>\n                    <div class=\"text-muted-foreground flex justify-between\">\n                      <span>Clean Expired Metadata:</span>\n                      <span class=\"text-foreground font-mono\">Yes (Purge orphan Avro manifests)</span>\n                    </div>\n                  </div>\n                </div>\n              </div>\n\n              <div ui-card class=\"border-border bg-card shadow-xs\">\n                <div ui-card-header class=\"p-4 pb-2 sm:p-5 sm:pb-2\">\n                  <div class=\"flex items-center justify-between\">\n                    <h3 ui-card-title class=\"flex items-center gap-2 text-sm font-semibold\">\n                      <lucide-icon [img]=\"FileText\" class=\"text-chart-1 size-4\" />\n                      Manifest File Consolidation\n                    </h3>\n                    <span ui-badge variant=\"success\" class=\"text-xs\">Optimized</span>\n                  </div>\n                  <p ui-card-description class=\"text-xs\">\n                    Rewrites small manifest files to accelerate query planning and metadata scanning\n                  </p>\n                </div>\n                <div ui-card-content class=\"space-y-3 p-4 pt-3 text-xs sm:p-5\">\n                  <div class=\"border-border bg-muted/40 space-y-2 rounded-lg border p-3\">\n                    <div class=\"text-muted-foreground flex justify-between\">\n                      <span>Active Manifest Count:</span>\n                      <span class=\"text-foreground font-mono font-semibold\">6 Manifests</span>\n                    </div>\n                    <div class=\"text-muted-foreground flex justify-between\">\n                      <span>Rewrite Trigger Threshold:</span>\n                      <span class=\"text-foreground font-mono\">&gt; 50 Small Manifests</span>\n                    </div>\n                    <div class=\"text-muted-foreground flex justify-between\">\n                      <span>Query Planning Overhead:</span>\n                      <span class=\"text-success font-mono font-semibold\">&lt; 15ms</span>\n                    </div>\n                  </div>\n                </div>\n              </div>\n            </div>\n          </div>\n        }\n\n        @if (activeTab() === 'files') {\n          <div class=\"space-y-5\">\n            <div ui-card class=\"border-border bg-card shadow-xs\">\n              <div ui-card-header class=\"p-5 pb-3\">\n                <h3 ui-card-title class=\"text-base font-semibold\">\n                  File Size Distribution & I/O Amplification Analysis\n                </h3>\n                <p ui-card-description class=\"text-xs\">\n                  Comparison of storage layout before vs. after Iceberg automatic compaction\n                </p>\n              </div>\n              <ui-separator />\n              <div ui-card-content class=\"space-y-6 p-5\">\n                <div class=\"grid grid-cols-1 gap-6 md:grid-cols-2\">\n                  <div class=\"border-border bg-muted/20 space-y-3 rounded-xl border p-4\">\n                    <div class=\"flex items-center justify-between\">\n                      <span class=\"text-destructive text-xs font-semibold\">Before Compaction (Small File Problem)</span>\n                      <span ui-badge variant=\"destructive\" class=\"font-mono text-xs\">18.4x I/O Amplification</span>\n                    </div>\n                    <div class=\"space-y-2 text-xs\">\n                      <div class=\"text-muted-foreground flex justify-between\">\n                        <span>Total Small Files (&lt;4MB):</span>\n                        <span class=\"text-foreground font-mono font-bold\">14,280 Files</span>\n                      </div>\n                      <div class=\"text-muted-foreground flex justify-between\">\n                        <span>Average File Size:</span>\n                        <span class=\"text-foreground font-mono\">2.4 MB</span>\n                      </div>\n                      <div class=\"text-muted-foreground flex justify-between\">\n                        <span>Query Scan Latency (P95):</span>\n                        <span class=\"text-destructive font-mono font-semibold\">8.4 seconds</span>\n                      </div>\n                      <div class=\"text-muted-foreground flex justify-between\">\n                        <span>S3 GET Request Cost:</span>\n                        <span class=\"text-foreground font-mono\">$380 / month</span>\n                      </div>\n                    </div>\n                  </div>\n                  <div class=\"border-success/30 bg-success/[0.03] space-y-3 rounded-xl border p-4\">\n                    <div class=\"flex items-center justify-between\">\n                      <span class=\"text-success text-xs font-semibold\">After Compaction (Optimal Bin-Pack)</span>\n                      <span ui-badge variant=\"success\" class=\"font-mono text-xs\">1.02x Near-Ideal</span>\n                    </div>\n                    <div class=\"space-y-2 text-xs\">\n                      <div class=\"text-muted-foreground flex justify-between\">\n                        <span>Total Target Files (128MB):</span>\n                        <span class=\"text-foreground font-mono font-bold\">142 Files</span>\n                      </div>\n                      <div class=\"text-muted-foreground flex justify-between\">\n                        <span>Average File Size:</span>\n                        <span class=\"text-foreground font-mono\">128.2 MB</span>\n                      </div>\n                      <div class=\"text-muted-foreground flex justify-between\">\n                        <span>Query Scan Latency (P95):</span>\n                        <span class=\"text-success font-mono font-semibold\">220 milliseconds (38x speedup)</span>\n                      </div>\n                      <div class=\"text-muted-foreground flex justify-between\">\n                        <span>S3 GET Request Cost:</span>\n                        <span class=\"text-foreground font-mono\">$12 / month</span>\n                      </div>\n                    </div>\n                  </div>\n                </div>\n              </div>\n            </div>\n          </div>\n        }\n      </ui-tabs>\n    </div>\n  `,\n})\nexport class UiLakehouseTableOptimizerComponent {\n  protected readonly ArrowDownRight = ArrowDownRight\n  protected readonly Check = Check\n  protected readonly CheckCircle2 = CheckCircle2\n  protected readonly Clock = Clock\n  protected readonly Copy = Copy\n  protected readonly Database = Database\n  protected readonly FileCode2 = FileCode2\n  protected readonly FileText = FileText\n  protected readonly FolderArchive = FolderArchive\n  protected readonly HardDrive = HardDrive\n  protected readonly History = History\n  protected readonly Layers = Layers\n  protected readonly RefreshCw = RefreshCw\n  protected readonly Search = Search\n  protected readonly Server = Server\n  protected readonly Terminal = Terminal\n  protected readonly Trash2 = Trash2\n  protected readonly Workflow = Workflow\n  protected readonly Zap = Zap\n\n  protected readonly snapshotOps = snapshotOps\n\n  @Input() set initialTable(v: TableDetails | undefined) {\n    if (v) this.tableOverride.set(v)\n  }\n  @Input() set initialSnapshots(v: TableSnapshot[] | undefined) {\n    if (v) this.snapshots.set([...v])\n  }\n  @Input() set initialPartitions(v: PartitionRecord[] | undefined) {\n    if (v) this.partitions.set([...v])\n  }\n  @Input() set initialTab(v: string) {\n    this.activeTab.set(v ?? 'snapshots')\n  }\n  @Input('class') className?: string\n\n  private readonly tableOverride = signal<TableDetails | undefined>(undefined)\n  readonly table = computed(() => this.tableOverride() ?? defaultTable)\n  readonly snapshots = signal<TableSnapshot[]>([...defaultSnapshots])\n  readonly partitions = signal<PartitionRecord[]>([...defaultPartitions])\n\n  readonly selectedSnapshotId = signal('snap_84920194821')\n  readonly sqlSyntaxMode = signal<SqlSyntaxMode>('system_time')\n  readonly snapshotFilter = signal<string>('ALL')\n  readonly snapshotSearch = signal('')\n  readonly partitionSearch = signal('')\n  readonly activeTab = signal('snapshots')\n\n  readonly isCompacting = signal(false)\n  readonly isExpiring = signal(false)\n  readonly actionNotification = signal<string | null>(null)\n  readonly copiedQuery = signal(false)\n  private copyTimer: ReturnType<typeof setTimeout> | undefined\n  private actionTimer: ReturnType<typeof setTimeout> | undefined\n\n  readonly selectedSnapshot = computed(\n    () => this.snapshots().find((s) => s.id === this.selectedSnapshotId()) ?? this.snapshots()[0]!,\n  )\n\n  readonly filteredSnapshots = computed(() => {\n    const filter = this.snapshotFilter()\n    const q = this.snapshotSearch().toLowerCase().trim()\n    return this.snapshots().filter((snap) => {\n      const matchesOp = filter === 'ALL' || snap.operation === filter\n      const matchesSearch =\n        q === '' ||\n        snap.id.toLowerCase().includes(q) ||\n        snap.author.toLowerCase().includes(q) ||\n        snap.summary.toLowerCase().includes(q) ||\n        snap.operation.toLowerCase().includes(q)\n      return matchesOp && matchesSearch\n    })\n  })\n\n  readonly filteredPartitions = computed(() => {\n    const q = this.partitionSearch().toLowerCase().trim()\n    if (!q) return this.partitions()\n    return this.partitions().filter((p) => p.partitionKey.toLowerCase().includes(q))\n  })\n\n  readonly generatedQuery = computed(() => {\n    const currentSnap = this.selectedSnapshot()\n    const tableName = this.table().name\n    switch (this.sqlSyntaxMode()) {\n      case 'system_time':\n        return `SELECT * FROM ${tableName}\\nFOR SYSTEM_TIME AS OF '${currentSnap.timestamp}';`\n      case 'system_version':\n        return `SELECT * FROM ${tableName}\\nFOR SYSTEM_VERSION AS OF ${currentSnap.numericId};`\n      case 'pyspark':\n        return `# PySpark Iceberg time-travel query\\ndf = spark.read \\\\\\n  .format(\"iceberg\") \\\\\\n  .option(\"as-of-timestamp\", \"${currentSnap.timestamp}\") \\\\\\n  .load(\"${tableName}\")\\n\\ndf.filter(\"customer_id = 'cust_98241'\") \\\\\\n  .select(\"event_id\", \"event_type\", \"event_date\", \"payload\") \\\\\\n  .show(10)`\n      case 'trino':\n        return `SELECT event_id, customer_id, event_type, event_date\\nFROM ${tableName}\\nFOR VERSION AS OF ${currentSnap.numericId}\\nWHERE event_type = 'CHECKOUT_COMPLETED'\\nLIMIT 50;`\n      default:\n        return `SELECT * FROM ${tableName}\\nFOR SYSTEM_TIME AS OF '${currentSnap.timestamp}';`\n    }\n  })\n\n  get rootClass(): string {\n    return cn('text-foreground w-full space-y-6', this.className)\n  }\n\n  setActiveTab(value: string): void {\n    this.activeTab.set(value)\n  }\n\n  selectSnapshot(id: string): void {\n    this.selectedSnapshotId.set(id)\n  }\n\n  selectSnapshotKey(e: KeyboardEvent, id: string): void {\n    e.preventDefault()\n    this.selectSnapshot(id)\n  }\n\n  opPillClass(op: string): string {\n    const active = this.snapshotFilter() === op\n    return cn(\n      'rounded-md px-2 py-1 font-mono text-xs transition-colors',\n      active\n        ? 'bg-primary text-primary-foreground font-semibold'\n        : 'bg-muted text-muted-foreground hover:bg-accent hover:text-foreground',\n    )\n  }\n\n  syntaxClass(mode: SqlSyntaxMode): string {\n    const active = this.sqlSyntaxMode() === mode\n    return cn(\n      'rounded-md px-2 py-1.5 text-center font-mono text-xs transition-colors',\n      active\n        ? 'bg-primary text-primary-foreground font-semibold shadow-xs'\n        : 'bg-muted text-muted-foreground hover:bg-accent hover:text-foreground',\n    )\n  }\n\n  snapshotCardClass(id: string): string {\n    const active = this.selectedSnapshotId() === id\n    return cn(\n      'group relative flex cursor-pointer flex-col gap-3 rounded-lg border p-3.5 transition-colors sm:flex-row sm:items-start sm:gap-4',\n      active\n        ? 'border-primary/60 bg-primary/[0.03] ring-primary/30 shadow-xs ring-1'\n        : 'border-border bg-card/60 hover:border-border hover:bg-accent/40',\n    )\n  }\n\n  operationBadgeVariant(op: SnapshotOperation): 'default' | 'secondary' | 'outline' | 'success' | 'warning' | 'info' {\n    switch (op) {\n      case 'OPTIMIZE':\n        return 'success'\n      case 'MERGE':\n        return 'info'\n      case 'APPEND':\n        return 'secondary'\n      case 'REPLACE_PARTITION':\n        return 'warning'\n      default:\n        return 'outline'\n    }\n  }\n\n  handleCopyQuery(): void {\n    try {\n      void navigator.clipboard?.writeText(this.generatedQuery())\n      this.copiedQuery.set(true)\n      clearTimeout(this.copyTimer)\n      this.copyTimer = setTimeout(() => this.copiedQuery.set(false), 2000)\n    } catch {\n      // Clipboard fallback\n    }\n  }\n\n  private notify(message: string): void {\n    this.actionNotification.set(message)\n    clearTimeout(this.actionTimer)\n    this.actionTimer = setTimeout(() => this.actionNotification.set(null), 6000)\n  }\n\n  runCompaction(): void {\n    if (this.isCompacting()) return\n    this.isCompacting.set(true)\n    this.actionNotification.set(null)\n    setTimeout(() => {\n      this.isCompacting.set(false)\n      this.notify(\n        'Compaction & Vacuum complete: 14,280 small files compacted into 142 optimal 128MB Parquet files. Reclaimed 1.2 TB storage.',\n      )\n    }, 1800)\n  }\n\n  expireSnapshots(): void {\n    if (this.isExpiring()) return\n    this.isExpiring.set(true)\n    this.actionNotification.set(null)\n    setTimeout(() => {\n      this.isExpiring.set(false)\n      this.notify(\n        'Snapshot expiration finished: Removed 12 stale snapshots older than 30-day retention window. Purged 872 GB metadata & unreferenced parquet files.',\n      )\n    }, 1400)\n  }\n}\n",
      "type": "registry:page",
      "target": "~/src/app/components/blocks/lakehouse-table-optimizer/lakehouse-table-optimizer.component.ts"
    },
    {
      "path": "packages/registry-angular/blocks/lakehouse-table-optimizer/index.ts",
      "content": "export {\n  UiLakehouseTableOptimizerComponent,\n  type TableSnapshot,\n  type PartitionRecord,\n  type TableDetails,\n  type SnapshotOperation,\n  type SqlSyntaxMode,\n} from './lakehouse-table-optimizer.component'\n",
      "type": "registry:page",
      "target": "~/src/app/components/blocks/lakehouse-table-optimizer/index.ts"
    }
  ],
  "dependencies": [
    "lucide-angular"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/angular/badge.json",
    "https://uipkge.dev/r/angular/button.json",
    "https://uipkge.dev/r/angular/card.json",
    "https://uipkge.dev/r/angular/progress.json",
    "https://uipkge.dev/r/angular/separator.json",
    "https://uipkge.dev/r/angular/table.json",
    "https://uipkge.dev/r/angular/tabs.json"
  ],
  "description": "Apache Iceberg and Delta Lake table maintenance manager, compaction optimizer, snapshot history visualizer, and time-travel SQL query helper.",
  "categories": [
    "devops",
    "app",
    "analytics"
  ]
}