{
  "$schema": "https://uipkge.dev/schema/registry-item.json",
  "name": "data-retention-policy-manager",
  "title": "Data Retention Policy Manager",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-angular/blocks/data-retention-policy-manager/data-retention-policy-manager.component.ts",
      "content": "// Automated data retention policy manager: storage/cost impact cards, a filterable policy table\n// with per-row enable switches and an actions menu, an add/edit policy dialog, and a simulated\n// 1.2s \"Run Archive Now\" partition sweep dialog. Port of the React block 1:1.\nimport { ChangeDetectionStrategy, Component, DestroyRef, Input, computed, inject, signal } from '@angular/core'\nimport {\n  Archive,\n  Check,\n  CheckCircle2,\n  Clock,\n  Copy,\n  Database,\n  DollarSign,\n  FileText,\n  HardDriveDownload,\n  Info,\n  LucideAngularModule,\n  MoreHorizontal,\n  Pencil,\n  Play,\n  Plus,\n  RefreshCw,\n  Search,\n  ShieldCheck,\n  Trash2,\n  X,\n} from 'lucide-angular'\nimport { cn } from '@/lib/utils'\nimport { UiBadgeComponent, type BadgeVariant } 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 {\n  UiDialogComponent,\n  UiDialogContentComponent,\n  UiDialogDescriptionComponent,\n  UiDialogFooterComponent,\n  UiDialogHeaderComponent,\n  UiDialogTitleComponent,\n} from '@/ui/dialog/dialog.component'\nimport {\n  UiDropdownMenuComponent,\n  UiDropdownMenuContentComponent,\n  UiDropdownMenuItemComponent,\n  UiDropdownMenuLabelComponent,\n  UiDropdownMenuSeparatorComponent,\n  UiDropdownMenuTriggerComponent,\n} from '@/ui/dropdown-menu/dropdown-menu.component'\nimport { UiInputComponent } from '@/ui/input/input.component'\nimport { UiProgressComponent } from '@/ui/progress/progress.component'\nimport {\n  UiSelectComponent,\n  UiSelectContentComponent,\n  UiSelectItemComponent,\n  UiSelectTriggerComponent,\n  UiSelectValueComponent,\n} from '@/ui/select/select.component'\nimport { UiSwitchComponent } from '@/ui/switch/switch.component'\nimport {\n  UiTableBodyComponent,\n  UiTableCellComponent,\n  UiTableComponent,\n  UiTableHeadComponent,\n  UiTableHeaderComponent,\n  UiTableRowComponent,\n} from '@/ui/table/table.component'\n\nexport type EngineType = 'Snowflake' | 'BigQuery' | 'Databricks' | 'Postgres'\nexport type ArchiveTierType = 'Glacier Deep' | 'Coldline' | 'Standard Cold' | 'Purge Immediately'\n\nexport interface RetentionPolicy {\n  id: string\n  tableName: string\n  database: string\n  engine: EngineType\n  partitionColumn: string\n  retentionPeriod: string\n  lifecycleAction: string\n  archiveTier: ArchiveTierType\n  complianceReason: string\n  totalSize: string\n  coldSize: string\n  estimatedMonthlySavings: string\n  enabled: boolean\n  lastRun: string\n  nextRun: string\n  rowCount?: string\n}\n\nexport interface StorageRetentionStats {\n  totalManagedData: string\n  totalManagedSubtitle?: string\n  coldArchivedData: string\n  archivedPercentage: number\n  archivedSubtitle?: string\n  projectedMonthlySavings: string\n  savingsSubtitle?: string\n  purged30d: string\n  purgedSubtitle?: string\n}\n\nexport const defaultPolicies: RetentionPolicy[] = [\n  {\n    id: 'pol-1',\n    tableName: 'audit_logs.events',\n    database: 'SNOWFLAKE_PROD_DWH',\n    engine: 'Snowflake',\n    partitionColumn: 'event_timestamp (DAY)',\n    retentionPeriod: '90 Days Active',\n    lifecycleAction: 'Transition to Cold Glacier at 90d -> Hard Purge at 365d',\n    archiveTier: 'Glacier Deep',\n    complianceReason: 'SOX Compliance',\n    totalSize: '4.2 TB',\n    coldSize: '3.1 TB',\n    estimatedMonthlySavings: '$420.00 / mo',\n    enabled: true,\n    lastRun: '1 hour ago',\n    nextRun: 'Today at 02:00 UTC',\n    rowCount: '1.4B rows',\n  },\n  {\n    id: 'pol-2',\n    tableName: 'telemetry.raw_pings',\n    database: 'BIGQUERY_IOT_STREAM',\n    engine: 'BigQuery',\n    partitionColumn: 'received_at (HOUR)',\n    retentionPeriod: '30 Days TTL',\n    lifecycleAction: 'Direct Partition Drop at 30d TTL -> Zero Archive',\n    archiveTier: 'Purge Immediately',\n    complianceReason: 'Storage Optimization',\n    totalSize: '5.6 TB',\n    coldSize: '0.0 TB',\n    estimatedMonthlySavings: '$560.00 / mo',\n    enabled: true,\n    lastRun: '10 min ago',\n    nextRun: 'Continuous partition sweep',\n    rowCount: '8.9B rows',\n  },\n  {\n    id: 'pol-3',\n    tableName: 'billing.invoices_archive',\n    database: 'SNOWFLAKE_FINANCE',\n    engine: 'Snowflake',\n    partitionColumn: 'invoice_date (MONTH)',\n    retentionPeriod: '7 Years Compliance',\n    lifecycleAction: 'Hot 1 Year -> Glacier Vault Lock Tier 7 Years',\n    archiveTier: 'Glacier Deep',\n    complianceReason: 'SOX Compliance',\n    totalSize: '2.4 TB',\n    coldSize: '2.1 TB',\n    estimatedMonthlySavings: '$210.00 / mo',\n    enabled: true,\n    lastRun: 'Yesterday',\n    nextRun: 'Sep 01 at 00:00 UTC',\n    rowCount: '180M rows',\n  },\n  {\n    id: 'pol-4',\n    tableName: 'analytics.staging_events',\n    database: 'BIGQUERY_INGEST',\n    engine: 'BigQuery',\n    partitionColumn: 'ingest_time (DAY)',\n    retentionPeriod: '14 Days TTL',\n    lifecycleAction: 'Truncate partition > 14d -> Permanent Delete',\n    archiveTier: 'Purge Immediately',\n    complianceReason: 'Storage Optimization',\n    totalSize: '1.5 TB',\n    coldSize: '0.0 TB',\n    estimatedMonthlySavings: '$150.00 / mo',\n    enabled: false,\n    lastRun: '3 days ago',\n    nextRun: 'Paused',\n    rowCount: '420M rows',\n  },\n  {\n    id: 'pol-5',\n    tableName: 'customer_pii.user_sessions',\n    database: 'SNOWFLAKE_CUSTOMER360',\n    engine: 'Snowflake',\n    partitionColumn: 'session_start (DAY)',\n    retentionPeriod: '180 Days Active',\n    lifecycleAction: 'Anonymize at 90d -> Cold Glacier -> Hard Purge at 180d',\n    archiveTier: 'Standard Cold',\n    complianceReason: 'GDPR Art. 17',\n    totalSize: '1.1 TB',\n    coldSize: '0.9 TB',\n    estimatedMonthlySavings: '$80.00 / mo',\n    enabled: true,\n    lastRun: '6 hours ago',\n    nextRun: 'Tomorrow at 04:00 UTC',\n    rowCount: '290M rows',\n  },\n]\n\nexport const defaultStats: StorageRetentionStats = {\n  totalManagedData: '14.8 TB',\n  totalManagedSubtitle: 'Across 48 partitioned tables',\n  coldArchivedData: '9.2 TB',\n  archivedPercentage: 62,\n  archivedSubtitle: '62% archived to Glacier / Cold Tier',\n  projectedMonthlySavings: '$1,420.00 / mo saved',\n  savingsSubtitle: '68% cost drop vs active NVMe',\n  purged30d: '1.8 TB',\n  purgedSubtitle: 'Expired TTL partitions purged',\n}\n\ninterface BannerMessage {\n  type: 'success' | 'info'\n  text: string\n}\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.Eager,\n  selector: 'ui-data-retention-policy-manager, [ui-data-retention-policy-manager]',\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    UiDialogComponent,\n    UiDialogContentComponent,\n    UiDialogDescriptionComponent,\n    UiDialogFooterComponent,\n    UiDialogHeaderComponent,\n    UiDialogTitleComponent,\n    UiDropdownMenuComponent,\n    UiDropdownMenuContentComponent,\n    UiDropdownMenuItemComponent,\n    UiDropdownMenuLabelComponent,\n    UiDropdownMenuSeparatorComponent,\n    UiDropdownMenuTriggerComponent,\n    UiInputComponent,\n    UiProgressComponent,\n    UiSelectComponent,\n    UiSelectContentComponent,\n    UiSelectItemComponent,\n    UiSelectTriggerComponent,\n    UiSelectValueComponent,\n    UiSwitchComponent,\n    UiTableComponent,\n    UiTableBodyComponent,\n    UiTableCellComponent,\n    UiTableHeadComponent,\n    UiTableHeaderComponent,\n    UiTableRowComponent,\n  ],\n  template: `\n    <div data-slot=\"data-retention-policy-manager\" [class]=\"rootClass\">\n      <!-- Header Section -->\n      <div class=\"flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between\">\n        <div class=\"space-y-1\">\n          <div class=\"flex items-center gap-2\">\n            <div class=\"bg-primary/10 text-primary flex size-8 items-center justify-center rounded-lg\">\n              <lucide-icon [img]=\"Archive\" class=\"size-4.5\" />\n            </div>\n            <h1 class=\"text-foreground text-2xl font-bold tracking-tight\">\n              Data Retention &amp; Cold Storage Lifecycle\n            </h1>\n          </div>\n          <p class=\"text-muted-foreground text-sm\">\n            Configure automated table partition expiration, cold storage tiering, and compliance retention periods.\n          </p>\n        </div>\n\n        <div class=\"flex items-center gap-2\">\n          <button ui-button class=\"gap-1.5\" (click)=\"openAddPolicyModal()\">\n            <lucide-icon [img]=\"Plus\" class=\"size-4\" />\n            Add Retention Policy\n          </button>\n        </div>\n      </div>\n\n      <!-- Notification / Action banner -->\n      @if (bannerMessage(); as banner) {\n        <div class=\"border-border bg-card flex items-center justify-between gap-3 rounded-lg border p-3 shadow-xs\">\n          <div class=\"flex items-center gap-2.5 text-sm\">\n            @if (banner.type === 'success') {\n              <lucide-icon [img]=\"CheckCircle2\" class=\"text-success size-4 shrink-0\" />\n            } @else {\n              <lucide-icon [img]=\"Info\" class=\"text-primary size-4 shrink-0\" />\n            }\n            <span class=\"text-foreground text-xs font-medium sm:text-sm\">{{ banner.text }}</span>\n          </div>\n          <button ui-button variant=\"ghost\" size=\"icon\" class=\"size-7\" (click)=\"bannerMessage.set(null)\">\n            <lucide-icon [img]=\"X\" class=\"size-3.5\" />\n            <span class=\"sr-only\">Dismiss</span>\n          </button>\n        </div>\n      }\n\n      <!-- 4 Storage & Cost Impact Cards -->\n      <div class=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n        <!-- Total Managed Data -->\n        <div ui-card class=\"shadow-xs\">\n          <div ui-card-header class=\"flex flex-row items-center justify-between pb-2\">\n            <h3 ui-card-title class=\"text-muted-foreground text-sm font-medium\">Total Managed Data</h3>\n            <div class=\"bg-primary/10 text-primary rounded-lg p-2\">\n              <lucide-icon [img]=\"Database\" class=\"size-4\" />\n            </div>\n          </div>\n          <div ui-card-content class=\"space-y-1\">\n            <div class=\"text-foreground text-2xl font-bold tracking-tight\">{{ stats.totalManagedData }}</div>\n            <p class=\"text-muted-foreground text-xs\">{{ stats.totalManagedSubtitle }}</p>\n          </div>\n        </div>\n\n        <!-- Auto-Archived to Glacier / Cold Tier -->\n        <div ui-card class=\"shadow-xs\">\n          <div ui-card-header class=\"flex flex-row items-center justify-between pb-2\">\n            <h3 ui-card-title class=\"text-muted-foreground text-sm font-medium\">\n              Auto-Archived to Glacier / Cold Tier\n            </h3>\n            <div class=\"bg-success/10 text-success rounded-lg p-2\">\n              <lucide-icon [img]=\"HardDriveDownload\" class=\"size-4\" />\n            </div>\n          </div>\n          <div ui-card-content class=\"space-y-2\">\n            <div class=\"flex items-center justify-between gap-x-2\">\n              <span class=\"text-foreground text-2xl font-bold tracking-tight\">{{ stats.coldArchivedData }}</span>\n              <span ui-badge variant=\"info\" class=\"text-xs\">{{ stats.archivedPercentage }}% archived</span>\n            </div>\n            <div ui-progress [value]=\"stats.archivedPercentage\" class=\"h-1.5\"></div>\n            <p class=\"text-muted-foreground text-xs\">{{ stats.archivedSubtitle }}</p>\n          </div>\n        </div>\n\n        <!-- Projected Monthly Storage Savings -->\n        <div ui-card class=\"shadow-xs\">\n          <div ui-card-header class=\"flex flex-row items-center justify-between pb-2\">\n            <h3 ui-card-title class=\"text-muted-foreground text-sm font-medium\">Projected Monthly Savings</h3>\n            <div class=\"bg-success/10 text-success rounded-lg p-2\">\n              <lucide-icon [img]=\"DollarSign\" class=\"size-4\" />\n            </div>\n          </div>\n          <div ui-card-content class=\"space-y-1\">\n            <div class=\"flex items-center gap-2\">\n              <span class=\"text-foreground text-2xl font-bold tracking-tight\">{{ stats.projectedMonthlySavings }}</span>\n              <span ui-badge variant=\"success\" class=\"text-xs\">Active</span>\n            </div>\n            <p class=\"text-muted-foreground text-xs\">{{ stats.savingsSubtitle }}</p>\n          </div>\n        </div>\n\n        <!-- Expired Data Purged in 30d -->\n        <div ui-card class=\"shadow-xs\">\n          <div ui-card-header class=\"flex flex-row items-center justify-between pb-2\">\n            <h3 ui-card-title class=\"text-muted-foreground text-sm font-medium\">Expired Data Purged (30d)</h3>\n            <div class=\"bg-warning/10 text-warning rounded-lg p-2\">\n              <lucide-icon [img]=\"Trash2\" class=\"size-4\" />\n            </div>\n          </div>\n          <div ui-card-content class=\"space-y-1\">\n            <div class=\"flex items-center gap-2\">\n              <span class=\"text-foreground text-2xl font-bold tracking-tight\">{{ stats.purged30d }}</span>\n              <span ui-badge variant=\"outline\" class=\"text-xs\">TTL Drops</span>\n            </div>\n            <p class=\"text-muted-foreground text-xs\">{{ stats.purgedSubtitle }}</p>\n          </div>\n        </div>\n      </div>\n\n      <!-- Retention Policies Table Card -->\n      <div ui-card class=\"shadow-xs\">\n        <div ui-card-header class=\"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-lg font-semibold\">Table Retention Policies &amp; Partition TTL</h3>\n              <p ui-card-description class=\"text-xs\">\n                Automated lifecycle transition rules, cold tiering, and compliance audit locks across databases.\n              </p>\n            </div>\n\n            <!-- Filter Toolbar -->\n            <div class=\"flex flex-wrap items-center gap-2\">\n              <div class=\"relative w-full sm:w-64\">\n                <lucide-icon\n                  [img]=\"Search\"\n                  class=\"text-muted-foreground pointer-events-none absolute top-1/2 left-3 size-4 -translate-y-1/2\"\n                />\n                <ui-input\n                  [value]=\"searchQuery()\"\n                  (valueChange)=\"searchQuery.set($event)\"\n                  placeholder=\"Search table, database, or compliance...\"\n                  class=\"h-8 pl-9 text-xs\"\n                />\n              </div>\n\n              <ui-select [value]=\"statusFilter()\" (valueChange)=\"statusFilter.set($event)\">\n                <button ui-select-trigger class=\"h-8 w-32 text-xs\">\n                  <ui-select-value placeholder=\"All Status\" />\n                </button>\n                <ui-select-content>\n                  <ui-select-item value=\"all\">All Status</ui-select-item>\n                  <ui-select-item value=\"enabled\">Active</ui-select-item>\n                  <ui-select-item value=\"disabled\">Disabled</ui-select-item>\n                </ui-select-content>\n              </ui-select>\n\n              <ui-select [value]=\"complianceFilter()\" (valueChange)=\"complianceFilter.set($event)\">\n                <button ui-select-trigger class=\"h-8 w-38 text-xs\">\n                  <ui-select-value placeholder=\"All Compliance\" />\n                </button>\n                <ui-select-content>\n                  <ui-select-item value=\"all\">All Compliance</ui-select-item>\n                  <ui-select-item value=\"SOX Compliance\">SOX Compliance</ui-select-item>\n                  <ui-select-item value=\"GDPR Art. 17\">GDPR Art. 17</ui-select-item>\n                  <ui-select-item value=\"Storage Optimization\">Storage Optimization</ui-select-item>\n                </ui-select-content>\n              </ui-select>\n            </div>\n          </div>\n        </div>\n\n        <div ui-card-content class=\"p-0\">\n          <div class=\"overflow-x-auto\">\n            <div ui-table>\n              <thead ui-table-header>\n                <tr ui-table-row class=\"hover:bg-transparent\">\n                  <th ui-table-head class=\"min-w-[240px]\">Table Name &amp; Database</th>\n                  <th ui-table-head class=\"min-w-[150px]\">Retention Period</th>\n                  <th ui-table-head class=\"min-w-[280px]\">Lifecycle Action &amp; Tiering</th>\n                  <th ui-table-head class=\"min-w-[150px]\">Compliance Reason</th>\n                  <th ui-table-head class=\"min-w-[120px]\">Status</th>\n                  <th ui-table-head class=\"w-16 text-right\">Actions</th>\n                </tr>\n              </thead>\n              <tbody ui-table-body>\n                @for (policy of filteredPolicies(); track policy.id) {\n                  <tr ui-table-row [class]=\"rowClass(policy)\">\n                    <!-- Table Name & Database -->\n                    <td ui-table-cell class=\"py-3.5 align-top\">\n                      <div class=\"space-y-1\">\n                        <div class=\"flex items-center gap-1.5\">\n                          <span class=\"text-foreground font-mono text-xs font-semibold\">{{ policy.tableName }}</span>\n                          <button\n                            type=\"button\"\n                            class=\"text-muted-foreground hover:text-foreground inline-flex size-4 shrink-0 items-center justify-center transition-colors\"\n                            [title]=\"copiedTable() === policy.tableName ? 'Copied!' : 'Copy table name'\"\n                            (click)=\"copyTableName(policy.tableName)\"\n                          >\n                            @if (copiedTable() === policy.tableName) {\n                              <lucide-icon [img]=\"Check\" class=\"text-success size-3\" />\n                            } @else {\n                              <lucide-icon [img]=\"Copy\" class=\"size-3\" />\n                            }\n                          </button>\n                        </div>\n                        <div class=\"flex flex-wrap items-center gap-1.5 text-xs\">\n                          <span ui-badge variant=\"outline\" class=\"font-mono text-xs\">{{ policy.engine }}</span>\n                          <span class=\"text-muted-foreground font-mono text-xs\">{{ policy.database }}</span>\n                        </div>\n                        @if (policy.rowCount) {\n                          <div class=\"text-muted-foreground text-xs\">\n                            {{ policy.rowCount }} · {{ policy.totalSize }}\n                          </div>\n                        }\n                      </div>\n                    </td>\n\n                    <!-- Retention Period Badge -->\n                    <td ui-table-cell class=\"py-3.5 align-top\">\n                      <div class=\"space-y-1\">\n                        <span ui-badge [variant]=\"retentionBadgeVariant(policy.retentionPeriod)\" class=\"gap-1 text-xs\">\n                          <lucide-icon [img]=\"Clock\" class=\"size-3\" />\n                          {{ policy.retentionPeriod }}\n                        </span>\n                        <p class=\"text-muted-foreground font-mono text-xs\">Col: {{ policy.partitionColumn }}</p>\n                      </div>\n                    </td>\n\n                    <!-- Lifecycle Action & Tiering -->\n                    <td ui-table-cell class=\"py-3.5 align-top\">\n                      <div class=\"space-y-1\">\n                        <div class=\"text-foreground flex items-center gap-1.5 text-xs font-medium\">\n                          <lucide-icon [img]=\"Archive\" class=\"text-muted-foreground size-3.5 shrink-0\" />\n                          <span>{{ policy.lifecycleAction }}</span>\n                        </div>\n                        <div class=\"text-muted-foreground flex flex-wrap items-center gap-2 text-xs\">\n                          <span>\n                            Tier: <strong class=\"text-foreground font-normal\">{{ policy.archiveTier }}</strong>\n                          </span>\n                          <span>·</span>\n                          <span>\n                            Savings:\n                            <span class=\"text-success font-semibold\">{{ policy.estimatedMonthlySavings }}</span>\n                          </span>\n                        </div>\n                      </div>\n                    </td>\n\n                    <!-- Compliance Reason -->\n                    <td ui-table-cell class=\"py-3.5 align-top\">\n                      <div class=\"space-y-1\">\n                        <span\n                          ui-badge\n                          [variant]=\"complianceBadgeVariant(policy.complianceReason)\"\n                          class=\"gap-1 text-xs\"\n                        >\n                          @if (isShieldCompliance(policy.complianceReason)) {\n                            <lucide-icon [img]=\"ShieldCheck\" class=\"size-3\" />\n                          } @else {\n                            <lucide-icon [img]=\"FileText\" class=\"size-3\" />\n                          }\n                          {{ policy.complianceReason }}\n                        </span>\n                        <p class=\"text-muted-foreground text-xs\">Next: {{ policy.nextRun }}</p>\n                      </div>\n                    </td>\n\n                    <!-- Status Switch -->\n                    <td ui-table-cell class=\"py-3.5 align-middle\">\n                      <div class=\"flex items-center gap-2\">\n                        <button\n                          ui-switch\n                          [checked]=\"policy.enabled\"\n                          [attr.aria-label]=\"'Toggle retention policy for ' + policy.tableName\"\n                          (checkedChange)=\"togglePolicyStatus(policy.id)\"\n                        ></button>\n                        <span [class]=\"statusTextClass(policy)\">{{ policy.enabled ? 'Enabled' : 'Disabled' }}</span>\n                      </div>\n                    </td>\n\n                    <!-- Action Menu -->\n                    <td ui-table-cell class=\"py-3.5 text-right align-middle\">\n                      <ui-dropdown-menu>\n                        <button ui-button ui-dropdown-menu-trigger variant=\"ghost\" size=\"icon\" class=\"size-8\">\n                          <lucide-icon [img]=\"MoreHorizontal\" class=\"size-4\" />\n                          <span class=\"sr-only\">Open actions for {{ policy.tableName }}</span>\n                        </button>\n                        <ui-dropdown-menu-content align=\"end\" class=\"w-52\">\n                          <ui-dropdown-menu-label class=\"text-xs\">Policy Controls</ui-dropdown-menu-label>\n                          <ui-dropdown-menu-separator />\n                          <ui-dropdown-menu-item class=\"cursor-pointer\" (select)=\"openRunArchiveModal(policy)\">\n                            <lucide-icon [img]=\"Play\" class=\"text-success mr-2 size-4\" />\n                            <span>Run Archive Now</span>\n                          </ui-dropdown-menu-item>\n                          <ui-dropdown-menu-item class=\"cursor-pointer\" (select)=\"openEditPolicyModal(policy)\">\n                            <lucide-icon [img]=\"Pencil\" class=\"mr-2 size-4\" />\n                            <span>Edit Policy</span>\n                          </ui-dropdown-menu-item>\n                          <ui-dropdown-menu-item class=\"cursor-pointer\" (select)=\"copyTableName(policy.tableName)\">\n                            <lucide-icon [img]=\"Copy\" class=\"mr-2 size-4\" />\n                            <span>Copy Table Name</span>\n                          </ui-dropdown-menu-item>\n                          <ui-dropdown-menu-separator />\n                          <ui-dropdown-menu-item\n                            class=\"text-destructive focus:text-destructive cursor-pointer\"\n                            (select)=\"deletePolicy(policy.id)\"\n                          >\n                            <lucide-icon [img]=\"Trash2\" class=\"mr-2 size-4\" />\n                            <span>Delete Policy</span>\n                          </ui-dropdown-menu-item>\n                        </ui-dropdown-menu-content>\n                      </ui-dropdown-menu>\n                    </td>\n                  </tr>\n                }\n\n                @if (filteredPolicies().length === 0) {\n                  <tr ui-table-row>\n                    <td ui-table-cell colspan=\"6\" class=\"text-muted-foreground h-32 text-center text-sm\">\n                      <div class=\"flex flex-col items-center justify-center space-y-1\">\n                        <lucide-icon [img]=\"Search\" class=\"text-muted-foreground/40 size-6\" />\n                        <p class=\"text-foreground text-sm font-medium\">No retention policies found</p>\n                        <p class=\"text-muted-foreground text-xs\">Try adjusting your search query or filter settings.</p>\n                      </div>\n                    </td>\n                  </tr>\n                }\n              </tbody>\n            </div>\n          </div>\n        </div>\n      </div>\n\n      <!-- Add / Edit Policy Dialog -->\n      <ui-dialog [open]=\"isPolicyModalOpen()\" (openChange)=\"isPolicyModalOpen.set($event)\">\n        <ui-dialog-content class=\"sm:max-w-lg\">\n          <div ui-dialog-header>\n            <h2 ui-dialog-title>{{ editingPolicy() ? 'Edit Retention Policy' : 'Add Retention Policy' }}</h2>\n            <p ui-dialog-description class=\"text-xs\">\n              Configure partition expiration time-to-live, cold tier transitions, and legal retention mandates.\n            </p>\n          </div>\n\n          <div class=\"space-y-3.5 py-2\">\n            <div class=\"space-y-1\">\n              <label for=\"policy-table-name\" class=\"text-foreground text-xs font-medium\"\n                >Target Table (schema.table)</label\n              >\n              <ui-input\n                id=\"policy-table-name\"\n                [value]=\"formTableName()\"\n                (valueChange)=\"formTableName.set($event)\"\n                placeholder=\"e.g. telemetry.clickstream_raw\"\n                class=\"font-mono text-xs\"\n              />\n            </div>\n\n            <div class=\"grid grid-cols-2 gap-3\">\n              <div class=\"space-y-1\">\n                <label for=\"policy-engine\" class=\"text-foreground text-xs font-medium\">Engine</label>\n                <ui-select [value]=\"formEngine()\" (valueChange)=\"setFormEngine($event)\">\n                  <button ui-select-trigger id=\"policy-engine\" class=\"text-xs\">\n                    <ui-select-value placeholder=\"Engine\" />\n                  </button>\n                  <ui-select-content>\n                    <ui-select-item value=\"Snowflake\">Snowflake</ui-select-item>\n                    <ui-select-item value=\"BigQuery\">BigQuery</ui-select-item>\n                    <ui-select-item value=\"Databricks\">Databricks</ui-select-item>\n                    <ui-select-item value=\"Postgres\">Postgres</ui-select-item>\n                  </ui-select-content>\n                </ui-select>\n              </div>\n\n              <div class=\"space-y-1\">\n                <label for=\"policy-database\" class=\"text-foreground text-xs font-medium\">Database / Cluster</label>\n                <ui-input\n                  id=\"policy-database\"\n                  [value]=\"formDatabase()\"\n                  (valueChange)=\"formDatabase.set($event)\"\n                  placeholder=\"e.g. SNOWFLAKE_PROD_DWH\"\n                  class=\"font-mono text-xs\"\n                />\n              </div>\n            </div>\n\n            <div class=\"grid grid-cols-2 gap-3\">\n              <div class=\"space-y-1\">\n                <label for=\"policy-partition-col\" class=\"text-foreground text-xs font-medium\">Partition Column</label>\n                <ui-input\n                  id=\"policy-partition-col\"\n                  [value]=\"formPartitionCol()\"\n                  (valueChange)=\"formPartitionCol.set($event)\"\n                  placeholder=\"e.g. event_timestamp (DAY)\"\n                  class=\"font-mono text-xs\"\n                />\n              </div>\n\n              <div class=\"space-y-1\">\n                <label for=\"policy-retention-period\" class=\"text-foreground text-xs font-medium\"\n                  >Retention Period</label\n                >\n                <ui-select [value]=\"formRetentionPeriod()\" (valueChange)=\"formRetentionPeriod.set($event)\">\n                  <button ui-select-trigger id=\"policy-retention-period\" class=\"text-xs\">\n                    <ui-select-value placeholder=\"Period\" />\n                  </button>\n                  <ui-select-content>\n                    <ui-select-item value=\"14 Days TTL\">14 Days TTL</ui-select-item>\n                    <ui-select-item value=\"30 Days TTL\">30 Days TTL</ui-select-item>\n                    <ui-select-item value=\"90 Days Active\">90 Days Active</ui-select-item>\n                    <ui-select-item value=\"180 Days Active\">180 Days Active</ui-select-item>\n                    <ui-select-item value=\"365 Days Active\">365 Days Active</ui-select-item>\n                    <ui-select-item value=\"7 Years Compliance\">7 Years Compliance</ui-select-item>\n                  </ui-select-content>\n                </ui-select>\n              </div>\n            </div>\n\n            <div class=\"space-y-1\">\n              <label for=\"policy-lifecycle-action\" class=\"text-foreground text-xs font-medium\">\n                Lifecycle Transition Action\n              </label>\n              <ui-input\n                id=\"policy-lifecycle-action\"\n                [value]=\"formLifecycleAction()\"\n                (valueChange)=\"formLifecycleAction.set($event)\"\n                placeholder=\"e.g. Transition to Cold Glacier at 90d -> Hard Purge at 365d\"\n                class=\"text-xs\"\n              />\n            </div>\n\n            <div class=\"grid grid-cols-2 gap-3\">\n              <div class=\"space-y-1\">\n                <label for=\"policy-archive-tier\" class=\"text-foreground text-xs font-medium\">Cold Storage Tier</label>\n                <ui-select [value]=\"formArchiveTier()\" (valueChange)=\"setFormArchiveTier($event)\">\n                  <button ui-select-trigger id=\"policy-archive-tier\" class=\"text-xs\">\n                    <ui-select-value placeholder=\"Tier\" />\n                  </button>\n                  <ui-select-content>\n                    <ui-select-item value=\"Glacier Deep\">Glacier Deep Archive</ui-select-item>\n                    <ui-select-item value=\"Coldline\">BigQuery Coldline</ui-select-item>\n                    <ui-select-item value=\"Standard Cold\">Standard Cold</ui-select-item>\n                    <ui-select-item value=\"Purge Immediately\">Purge Immediately</ui-select-item>\n                  </ui-select-content>\n                </ui-select>\n              </div>\n\n              <div class=\"space-y-1\">\n                <label for=\"policy-compliance\" class=\"text-foreground text-xs font-medium\">Compliance Framework</label>\n                <ui-select [value]=\"formComplianceReason()\" (valueChange)=\"formComplianceReason.set($event)\">\n                  <button ui-select-trigger id=\"policy-compliance\" class=\"text-xs\">\n                    <ui-select-value placeholder=\"Compliance\" />\n                  </button>\n                  <ui-select-content>\n                    <ui-select-item value=\"SOX Compliance\">SOX Compliance</ui-select-item>\n                    <ui-select-item value=\"GDPR Art. 17\">GDPR Art. 17</ui-select-item>\n                    <ui-select-item value=\"Storage Optimization\">Storage Optimization</ui-select-item>\n                    <ui-select-item value=\"PCI-DSS v4.0\">PCI-DSS v4.0</ui-select-item>\n                  </ui-select-content>\n                </ui-select>\n              </div>\n            </div>\n          </div>\n\n          <div ui-dialog-footer>\n            <button ui-button variant=\"outline\" (click)=\"isPolicyModalOpen.set(false)\">Cancel</button>\n            <button ui-button [disabled]=\"!formTableName().trim()\" (click)=\"savePolicy()\">\n              {{ editingPolicy() ? 'Save Policy Changes' : 'Create Retention Policy' }}\n            </button>\n          </div>\n        </ui-dialog-content>\n      </ui-dialog>\n\n      <!-- Run Archive Dry-Run & Execution Modal -->\n      <ui-dialog [open]=\"isArchiveModalOpen()\" (openChange)=\"isArchiveModalOpen.set($event)\">\n        <ui-dialog-content class=\"sm:max-w-md\">\n          <div ui-dialog-header>\n            <div class=\"flex items-center gap-2\">\n              <div class=\"bg-primary/10 text-primary rounded-lg p-2\">\n                <lucide-icon [img]=\"HardDriveDownload\" class=\"size-5\" />\n              </div>\n              <div>\n                <h2 ui-dialog-title>Run Archive Partition Sweep</h2>\n                <p ui-dialog-description class=\"text-xs\">\n                  Trigger manual partition evaluation and transition expired partitions to cold storage.\n                </p>\n              </div>\n            </div>\n          </div>\n\n          <div class=\"space-y-3 py-2 text-xs\">\n            <div class=\"border-border bg-muted/40 space-y-2 rounded-lg border p-3\">\n              <div class=\"flex items-center justify-between gap-x-2\">\n                <span class=\"text-muted-foreground\">Target Table:</span>\n                <span class=\"text-foreground font-mono font-semibold\">{{ selectedPolicyForArchive()?.tableName }}</span>\n              </div>\n              <div class=\"flex items-center justify-between gap-x-2\">\n                <span class=\"text-muted-foreground\">Database Engine:</span>\n                <span ui-badge variant=\"outline\" class=\"font-mono text-xs\">{{\n                  selectedPolicyForArchive()?.engine\n                }}</span>\n              </div>\n              <div class=\"flex items-center justify-between gap-x-2\">\n                <span class=\"text-muted-foreground\">Lifecycle Action:</span>\n                <span class=\"text-foreground font-medium\">{{ selectedPolicyForArchive()?.lifecycleAction }}</span>\n              </div>\n              <div class=\"flex items-center justify-between gap-x-2\">\n                <span class=\"text-muted-foreground\">Est. Savings:</span>\n                <span class=\"text-success font-semibold\">{{\n                  selectedPolicyForArchive()?.estimatedMonthlySavings\n                }}</span>\n              </div>\n            </div>\n\n            <div class=\"border-border bg-card text-muted-foreground space-y-1 rounded-lg border p-3\">\n              <div class=\"text-foreground flex items-center gap-1.5 font-medium\">\n                <lucide-icon [img]=\"ShieldCheck\" class=\"text-success size-4\" />\n                <span>Dry-Run Check Passed</span>\n              </div>\n              <p class=\"text-xs\">\n                Partitions older than configured threshold will be compressed, archived into cold tier, and purged from\n                active storage without table locks.\n              </p>\n            </div>\n          </div>\n\n          <div ui-dialog-footer>\n            <button ui-button variant=\"outline\" [disabled]=\"isArchiving()\" (click)=\"isArchiveModalOpen.set(false)\">\n              Cancel\n            </button>\n            <button ui-button [disabled]=\"isArchiving()\" class=\"gap-1.5\" (click)=\"executeArchiveRun()\">\n              @if (isArchiving()) {\n                <lucide-icon [img]=\"RefreshCw\" class=\"size-4 animate-spin\" />\n                Archiving Partitions...\n              } @else {\n                <lucide-icon [img]=\"Play\" class=\"size-4\" />\n                Run Archive Sweep Now\n              }\n            </button>\n          </div>\n        </ui-dialog-content>\n      </ui-dialog>\n    </div>\n  `,\n})\nexport class UiDataRetentionPolicyManagerComponent {\n  protected readonly Archive = Archive\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 DollarSign = DollarSign\n  protected readonly FileText = FileText\n  protected readonly HardDriveDownload = HardDriveDownload\n  protected readonly Info = Info\n  protected readonly MoreHorizontal = MoreHorizontal\n  protected readonly Pencil = Pencil\n  protected readonly Play = Play\n  protected readonly Plus = Plus\n  protected readonly RefreshCw = RefreshCw\n  protected readonly Search = Search\n  protected readonly ShieldCheck = ShieldCheck\n  protected readonly Trash2 = Trash2\n  protected readonly X = X\n\n  private readonly destroyRef = inject(DestroyRef)\n  private readonly timers = new Set<ReturnType<typeof setTimeout>>()\n\n  /** Seed rows; later edits live in the component's own state, as in React's useState initialiser. */\n  @Input() set initialPolicies(value: RetentionPolicy[] | undefined) {\n    this.policies.set(value ?? defaultPolicies)\n  }\n  @Input() initialStats?: StorageRetentionStats\n  @Input('class') className?: string\n\n  readonly policies = signal<RetentionPolicy[]>(defaultPolicies)\n  readonly searchQuery = signal('')\n  readonly statusFilter = signal('all')\n  readonly complianceFilter = signal('all')\n  readonly bannerMessage = signal<BannerMessage | null>(null)\n  readonly copiedTable = signal<string | null>(null)\n\n  // Policy dialog state\n  readonly isPolicyModalOpen = signal(false)\n  readonly editingPolicy = signal<RetentionPolicy | null>(null)\n  readonly formTableName = signal('')\n  readonly formDatabase = signal('')\n  readonly formEngine = signal<EngineType>('Snowflake')\n  readonly formPartitionCol = signal('')\n  readonly formRetentionPeriod = signal('90 Days Active')\n  readonly formLifecycleAction = signal('Transition to Cold Glacier at 90d -> Hard Purge at 365d')\n  readonly formArchiveTier = signal<ArchiveTierType>('Glacier Deep')\n  readonly formComplianceReason = signal('Storage Optimization')\n\n  // Instant archive dialog state\n  readonly isArchiveModalOpen = signal(false)\n  readonly selectedPolicyForArchive = signal<RetentionPolicy | null>(null)\n  readonly isArchiving = signal(false)\n\n  constructor() {\n    this.destroyRef.onDestroy(() => {\n      for (const t of this.timers) clearTimeout(t)\n      this.timers.clear()\n    })\n  }\n\n  get stats(): StorageRetentionStats {\n    return this.initialStats ?? defaultStats\n  }\n\n  get rootClass(): string {\n    return cn('w-full space-y-6', this.className)\n  }\n\n  readonly filteredPolicies = computed(() => {\n    const q = this.searchQuery().trim().toLowerCase()\n    const status = this.statusFilter()\n    const compliance = this.complianceFilter()\n    return this.policies().filter((policy) => {\n      if (status === 'enabled' && !policy.enabled) return false\n      if (status === 'disabled' && policy.enabled) return false\n      if (compliance !== 'all' && policy.complianceReason !== compliance) return false\n      if (!q) return true\n      return (\n        policy.tableName.toLowerCase().includes(q) ||\n        policy.database.toLowerCase().includes(q) ||\n        policy.complianceReason.toLowerCase().includes(q) ||\n        policy.lifecycleAction.toLowerCase().includes(q) ||\n        policy.engine.toLowerCase().includes(q)\n      )\n    })\n  })\n\n  rowClass(policy: RetentionPolicy): string {\n    return cn('group transition-colors', !policy.enabled && 'opacity-70 dark:opacity-65')\n  }\n\n  statusTextClass(policy: RetentionPolicy): string {\n    return cn('text-xs font-medium', policy.enabled ? 'text-success' : 'text-muted-foreground')\n  }\n\n  isShieldCompliance(reason: string): boolean {\n    return reason.includes('SOX') || reason.includes('GDPR')\n  }\n\n  togglePolicyStatus(id: string): void {\n    this.policies.update((prev) =>\n      prev.map((policy) => {\n        if (policy.id !== id) return policy\n        const nextState = !policy.enabled\n        this.bannerMessage.set({\n          type: 'info',\n          text: `Retention policy for table \"${policy.tableName}\" has been ${nextState ? 'activated' : 'paused'}.`,\n        })\n        return { ...policy, enabled: nextState }\n      }),\n    )\n  }\n\n  deletePolicy(id: string): void {\n    const target = this.policies().find((p) => p.id === id)\n    this.policies.update((prev) => prev.filter((p) => p.id !== id))\n    if (target) {\n      this.bannerMessage.set({ type: 'info', text: `Deleted retention policy for \"${target.tableName}\".` })\n    }\n  }\n\n  copyTableName(name: string): void {\n    if (typeof navigator !== 'undefined' && navigator.clipboard) {\n      void navigator.clipboard.writeText(name)\n      this.copiedTable.set(name)\n      this.later(() => this.copiedTable.update((curr) => (curr === name ? null : curr)), 2000)\n    }\n  }\n\n  openAddPolicyModal(): void {\n    this.editingPolicy.set(null)\n    this.formTableName.set('')\n    this.formDatabase.set('SNOWFLAKE_PROD_DWH')\n    this.formEngine.set('Snowflake')\n    this.formPartitionCol.set('created_at (DAY)')\n    this.formRetentionPeriod.set('90 Days Active')\n    this.formLifecycleAction.set('Transition to Cold Glacier at 90d -> Hard Purge at 365d')\n    this.formArchiveTier.set('Glacier Deep')\n    this.formComplianceReason.set('Storage Optimization')\n    this.isPolicyModalOpen.set(true)\n  }\n\n  openEditPolicyModal(policy: RetentionPolicy): void {\n    this.editingPolicy.set(policy)\n    this.formTableName.set(policy.tableName)\n    this.formDatabase.set(policy.database)\n    this.formEngine.set(policy.engine)\n    this.formPartitionCol.set(policy.partitionColumn)\n    this.formRetentionPeriod.set(policy.retentionPeriod)\n    this.formLifecycleAction.set(policy.lifecycleAction)\n    this.formArchiveTier.set(policy.archiveTier)\n    this.formComplianceReason.set(policy.complianceReason)\n    this.isPolicyModalOpen.set(true)\n  }\n\n  setFormEngine(value: string): void {\n    this.formEngine.set(value as EngineType)\n  }\n\n  setFormArchiveTier(value: string): void {\n    this.formArchiveTier.set(value as ArchiveTierType)\n  }\n\n  savePolicy(): void {\n    const tableName = this.formTableName().trim()\n    if (!tableName) return\n    const editing = this.editingPolicy()\n\n    if (editing) {\n      this.policies.update((prev) =>\n        prev.map((p) =>\n          p.id === editing.id\n            ? {\n                ...p,\n                tableName,\n                database: this.formDatabase().trim() || 'SNOWFLAKE_PROD_DWH',\n                engine: this.formEngine(),\n                partitionColumn: this.formPartitionCol().trim() || 'event_timestamp',\n                retentionPeriod: this.formRetentionPeriod(),\n                lifecycleAction: this.formLifecycleAction(),\n                archiveTier: this.formArchiveTier(),\n                complianceReason: this.formComplianceReason(),\n              }\n            : p,\n        ),\n      )\n      this.bannerMessage.set({ type: 'success', text: `Updated retention policy for \"${this.formTableName()}\".` })\n    } else {\n      const newPolicy: RetentionPolicy = {\n        id: `pol-${Date.now()}`,\n        tableName,\n        database: this.formDatabase().trim() || 'SNOWFLAKE_PROD_DWH',\n        engine: this.formEngine(),\n        partitionColumn: this.formPartitionCol().trim() || 'created_at (DAY)',\n        retentionPeriod: this.formRetentionPeriod(),\n        lifecycleAction: this.formLifecycleAction(),\n        archiveTier: this.formArchiveTier(),\n        complianceReason: this.formComplianceReason(),\n        totalSize: '1.2 TB',\n        coldSize: '0.8 TB',\n        estimatedMonthlySavings: '$110.00 / mo',\n        enabled: true,\n        lastRun: 'Pending First Run',\n        nextRun: 'Tonight at 00:00 UTC',\n        rowCount: '150M rows',\n      }\n      this.policies.update((prev) => [newPolicy, ...prev])\n      this.bannerMessage.set({\n        type: 'success',\n        text: `Created new automated retention policy for \"${newPolicy.tableName}\".`,\n      })\n    }\n    this.isPolicyModalOpen.set(false)\n  }\n\n  openRunArchiveModal(policy: RetentionPolicy): void {\n    this.selectedPolicyForArchive.set(policy)\n    this.isArchiveModalOpen.set(true)\n  }\n\n  executeArchiveRun(): void {\n    const target = this.selectedPolicyForArchive()\n    if (!target) return\n    this.isArchiving.set(true)\n    this.later(() => {\n      this.isArchiving.set(false)\n      this.isArchiveModalOpen.set(false)\n      this.policies.update((prev) => prev.map((p) => (p.id === target.id ? { ...p, lastRun: 'Just now' } : p)))\n      this.bannerMessage.set({\n        type: 'success',\n        text: `Archive partition sweep successfully completed for \"${target.tableName}\". Cold tier storage synchronized.`,\n      })\n    }, 1200)\n  }\n\n  retentionBadgeVariant(period: string): BadgeVariant {\n    if (period.includes('7 Years') || period.includes('Compliance')) return 'success'\n    if (period.includes('TTL') || period.includes('14 Days') || period.includes('30 Days')) return 'warning'\n    if (period.includes('90 Days') || period.includes('180 Days')) return 'info'\n    return 'secondary'\n  }\n\n  complianceBadgeVariant(reason: string): BadgeVariant {\n    if (reason.includes('GDPR') || reason.includes('CCPA')) return 'info'\n    if (reason.includes('SOX') || reason.includes('HIPAA')) return 'success'\n    if (reason.includes('Storage') || reason.includes('Optimization')) return 'secondary'\n    if (reason.includes('PCI')) return 'warning'\n    return 'outline'\n  }\n\n  private later(fn: () => void, ms: number): void {\n    const t = setTimeout(() => {\n      this.timers.delete(t)\n      fn()\n    }, ms)\n    this.timers.add(t)\n  }\n}\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/data-retention-policy-manager/data-retention-policy-manager.component.ts"
    },
    {
      "path": "packages/registry-angular/blocks/data-retention-policy-manager/index.ts",
      "content": "export {\n  UiDataRetentionPolicyManagerComponent,\n  defaultPolicies,\n  defaultStats,\n  type ArchiveTierType,\n  type EngineType,\n  type RetentionPolicy,\n  type StorageRetentionStats,\n} from './data-retention-policy-manager.component'\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/data-retention-policy-manager/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/dialog.json",
    "https://uipkge.dev/r/angular/dropdown-menu.json",
    "https://uipkge.dev/r/angular/input.json",
    "https://uipkge.dev/r/angular/progress.json",
    "https://uipkge.dev/r/angular/select.json",
    "https://uipkge.dev/r/angular/switch.json",
    "https://uipkge.dev/r/angular/table.json"
  ],
  "description": "Snowflake and BigQuery style automated data retention policy manager, partition TTL scheduler, and cold storage archive tiering with cost impact metrics, lifecycle action execution, and compliance tracking.",
  "categories": [
    "devops",
    "dashboard",
    "app",
    "data"
  ]
}