{
  "$schema": "https://uipkge.dev/schema/registry-item.json",
  "name": "secrets-rotation-scheduler",
  "title": "Secrets Rotation Scheduler",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-angular/blocks/secrets-rotation-scheduler/secrets-rotation-scheduler.component.ts",
      "content": "// AWS Secrets Manager style automated credential rotation scheduler: lifecycle\n// telemetry cards, searchable/filterable secrets table, zero-downtime instant-rotate\n// dialog, schedule create/edit dialog, and rotation lambda log viewer. Port of the\n// React block 1:1.\nimport { ChangeDetectionStrategy, Component, Input, computed, signal } from '@angular/core'\nimport {\n  AlertTriangle,\n  Check,\n  CheckCircle2,\n  Clock,\n  Copy,\n  Database,\n  Globe,\n  Info,\n  KeyRound,\n  Lock,\n  LucideAngularModule,\n  MoreHorizontal,\n  Pause,\n  Pencil,\n  Play,\n  Plus,\n  RefreshCw,\n  Search,\n  Server,\n  ShieldCheck,\n  Terminal,\n  X,\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 {\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 {\n  UiSelectComponent,\n  UiSelectContentComponent,\n  UiSelectItemComponent,\n  UiSelectTriggerComponent,\n  UiSelectValueComponent,\n} from '@/ui/select/select.component'\nimport {\n  UiTableBodyComponent,\n  UiTableCellComponent,\n  UiTableComponent,\n  UiTableHeadComponent,\n  UiTableHeaderComponent,\n  UiTableRowComponent,\n} from '@/ui/table/table.component'\n\nexport type SecretType = 'Postgres DB' | 'API Key' | 'RSA Keypair' | 'KMS Key' | 'Redis Auth' | 'MySQL DB'\nexport type RotationStatus = 'healthy' | 'due-soon' | 'manual-needed' | 'paused' | 'rotating'\n\nexport interface RotationSchedule {\n  interval: string\n  daysInterval: number\n  lambdaArn?: string\n  zeroDowntimeVerified: boolean\n}\n\nexport interface ManagedSecret {\n  id: string\n  name: string\n  arn: string\n  type: SecretType\n  schedule: RotationSchedule\n  lastRotated: string\n  nextRotationDue: string\n  dueRelative: string\n  status: RotationStatus\n  currentVersion: string\n  stagingVersion?: string\n  lastLogSnippet?: string\n}\n\nexport interface SecretsRotationStats {\n  totalSecrets: number\n  autoRotationActive: number\n  autoRotationPercentage: number\n  dueSoonCount: number\n  overdueCount: number\n}\n\nconst defaultSecrets: ManagedSecret[] = [\n  {\n    id: 'sec-1',\n    name: 'prod/postgres/master-credentials',\n    arn: 'arn:aws:secretsmanager:us-east-1:182938491029:secret:prod/postgres/master-cred-9aF1x',\n    type: 'Postgres DB',\n    schedule: {\n      interval: 'Every 30 Days',\n      daysInterval: 30,\n      lambdaArn: 'arn:aws:lambda:us-east-1:182938491029:function:RotatePostgresMaster',\n      zeroDowntimeVerified: true,\n    },\n    lastRotated: 'Aug 10, 2026',\n    nextRotationDue: 'Sep 09, 2026',\n    dueRelative: 'in 19 days',\n    status: 'healthy',\n    currentVersion: 'v2.4 (AWSCURRENT)',\n    stagingVersion: 'v2.5 (AWSPENDING)',\n    lastLogSnippet:\n      'Postgres dual-user handshake verified. Master role privileges synchronized with 0 connection terminations.',\n  },\n  {\n    id: 'sec-2',\n    name: 'prod/stripe/webhook-secret',\n    arn: 'arn:aws:secretsmanager:us-east-1:182938491029:secret:prod/stripe/wh-sec-48k2p',\n    type: 'API Key',\n    schedule: {\n      interval: 'Every 90 Days',\n      daysInterval: 90,\n      lambdaArn: 'arn:aws:lambda:us-east-1:182938491029:function:RotateStripeWebhook',\n      zeroDowntimeVerified: true,\n    },\n    lastRotated: 'Jul 14, 2026',\n    nextRotationDue: 'Aug 22, 2026',\n    dueRelative: 'in 24 hours',\n    status: 'due-soon',\n    currentVersion: 'v1.8 (AWSCURRENT)',\n    stagingVersion: 'v1.9 (AWSPENDING)',\n    lastLogSnippet: 'Dual webhook signature validation window active. Webhook endpoint test passed with 200 OK.',\n  },\n  {\n    id: 'sec-3',\n    name: 'prod/jwt/signing-key-rsa',\n    arn: 'arn:aws:secretsmanager:us-east-1:182938491029:secret:prod/jwt/rsa-pair-71b3e',\n    type: 'RSA Keypair',\n    schedule: {\n      interval: 'Every 7 Days',\n      daysInterval: 7,\n      lambdaArn: 'arn:aws:lambda:us-east-1:182938491029:function:RotateJWTRSAKeys',\n      zeroDowntimeVerified: true,\n    },\n    lastRotated: 'Aug 18, 2026',\n    nextRotationDue: 'Aug 25, 2026',\n    dueRelative: 'in 4 days',\n    status: 'healthy',\n    currentVersion: 'v9.1 (AWSCURRENT)',\n    stagingVersion: 'v9.2 (AWSPENDING)',\n    lastLogSnippet:\n      'JWKS endpoint updated with secondary public key kid:rsa-2026-w34. Token signature verification succeeded.',\n  },\n  {\n    id: 'sec-4',\n    name: 'prod/aws/kms-envelope-key',\n    arn: 'arn:aws:kms:us-east-1:182938491029:key/mrk-8492019a-9e1b-4f21-99ad',\n    type: 'KMS Key',\n    schedule: {\n      interval: 'Every 365 Days',\n      daysInterval: 365,\n      lambdaArn: 'arn:aws:lambda:us-east-1:182938491029:function:KmsEnvelopeRotationHandler',\n      zeroDowntimeVerified: true,\n    },\n    lastRotated: 'Oct 01, 2025',\n    nextRotationDue: 'Oct 01, 2026',\n    dueRelative: 'in 41 days',\n    status: 'healthy',\n    currentVersion: 'v3.0 (AWSCURRENT)',\n    stagingVersion: 'v3.1 (AWSPENDING)',\n    lastLogSnippet:\n      'Hardware Security Module (HSM) backing key refreshed. Transparent decryption verified for existing ciphertexts.',\n  },\n  {\n    id: 'sec-5',\n    name: 'prod/redis/cache-auth',\n    arn: 'arn:aws:secretsmanager:us-east-1:182938491029:secret:prod/redis/auth-token-6c90d',\n    type: 'Redis Auth',\n    schedule: {\n      interval: 'Manual Only',\n      daysInterval: 0,\n      zeroDowntimeVerified: false,\n    },\n    lastRotated: 'May 12, 2026',\n    nextRotationDue: 'Aug 20, 2026',\n    dueRelative: 'Overdue (1 day)',\n    status: 'manual-needed',\n    currentVersion: 'v1.0 (AWSCURRENT)',\n    stagingVersion: undefined,\n    lastLogSnippet:\n      'Automated lambda execution unconfigured. Dual-AUTH token rotation requires manual trigger or handler attachment.',\n  },\n]\n\nconst defaultStats: SecretsRotationStats = {\n  totalSecrets: 18,\n  autoRotationActive: 15,\n  autoRotationPercentage: 83.3,\n  dueSoonCount: 2,\n  overdueCount: 0,\n}\n\nconst SECRET_TYPES: SecretType[] = ['Postgres DB', 'MySQL DB', 'API Key', 'RSA Keypair', 'KMS Key', 'Redis Auth']\nconst INTERVALS = ['Every 7 Days', 'Every 30 Days', 'Every 60 Days', 'Every 90 Days', 'Every 365 Days', 'Manual Only']\n\nfunction typeBadgeVariant(type: SecretType): 'default' | 'secondary' | 'outline' | 'info' | 'warning' {\n  switch (type) {\n    case 'Postgres DB':\n    case 'MySQL DB':\n      return 'info'\n    case 'API Key':\n      return 'secondary'\n    case 'RSA Keypair':\n      return 'outline'\n    case 'KMS Key':\n      return 'default'\n    case 'Redis Auth':\n      return 'warning'\n    default:\n      return 'outline'\n  }\n}\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.Eager,\n  selector: 'ui-secrets-rotation-scheduler, [ui-secrets-rotation-scheduler]',\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    UiSelectComponent,\n    UiSelectContentComponent,\n    UiSelectItemComponent,\n    UiSelectTriggerComponent,\n    UiSelectValueComponent,\n    UiTableBodyComponent,\n    UiTableCellComponent,\n    UiTableComponent,\n    UiTableHeadComponent,\n    UiTableHeaderComponent,\n    UiTableRowComponent,\n  ],\n  template: `\n    <div data-slot=\"secrets-rotation-scheduler\" [class]=\"rootClass\">\n      <!-- Header -->\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]=\"Lock\" class=\"size-4.5\" />\n            </div>\n            <h1 class=\"text-foreground text-2xl font-bold tracking-tight\">\n              Automated Secrets Rotation & Key Lifecycle\n            </h1>\n          </div>\n          <p class=\"text-muted-foreground text-sm\">\n            Configure zero-downtime rotation schedules for database credentials, API keys, and certificates.\n          </p>\n        </div>\n\n        <div class=\"flex items-center gap-2\">\n          <button ui-button (click)=\"openScheduleModal()\">\n            <lucide-icon [img]=\"Plus\" class=\"mr-1.5 size-4\" />\n            <span>Schedule New Rotation</span>\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 font-medium\">{{ banner.text }}</span>\n          </div>\n          <button\n            ui-button\n            variant=\"ghost\"\n            size=\"icon\"\n            class=\"size-7\"\n            aria-label=\"Dismiss\"\n            (click)=\"bannerMessage.set(null)\"\n          >\n            <lucide-icon [img]=\"X\" class=\"size-3.5\" />\n            <span class=\"sr-only\">Dismiss</span>\n          </button>\n        </div>\n      }\n\n      <!-- 4 Key Lifecycle Telemetry Cards -->\n      <div class=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\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 Secrets</h3>\n            <div class=\"bg-primary/10 text-primary rounded-lg p-2\">\n              <lucide-icon [img]=\"KeyRound\" 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().totalSecrets }} credentials</div>\n            <p class=\"text-muted-foreground text-xs\">Across 4 cloud regions</p>\n          </div>\n        </div>\n\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\">Auto-Rotation Active</h3>\n            <div class=\"bg-success/10 text-success rounded-lg p-2\">\n              <lucide-icon [img]=\"RefreshCw\" 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\">\n                {{ stats().autoRotationActive }} / {{ stats().totalSecrets }} secrets\n              </span>\n              <span ui-badge variant=\"success\" class=\"text-xs\">{{ stats().autoRotationPercentage }}%</span>\n            </div>\n            <p class=\"text-muted-foreground text-xs\">Zero-downtime dual versioning enabled</p>\n          </div>\n        </div>\n\n        <div ui-card class=\"border-warning/30 bg-warning/5 bg-warning/10 shadow-xs\">\n          <div ui-card-header class=\"flex flex-row items-center justify-between pb-2\">\n            <h3 ui-card-title class=\"text-warning text-sm font-medium\">Rotation Due Soon</h3>\n            <div class=\"bg-warning/20 text-warning rounded-lg p-2\">\n              <lucide-icon [img]=\"Clock\" 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-warning text-2xl font-bold tracking-tight\">{{ stats().dueSoonCount }} secrets</span>\n              <span ui-badge variant=\"warning\" class=\"text-xs\">Next 48h</span>\n            </div>\n            <p class=\"text-warning/90 text-xs\">Automated queue pre-scheduled</p>\n          </div>\n        </div>\n\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 / Overdue</h3>\n            <div class=\"bg-success/10 text-success rounded-lg p-2\">\n              <lucide-icon [img]=\"ShieldCheck\" 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\">\n                {{ stats().overdueCount }} critical overdue\n              </span>\n              <span ui-badge variant=\"outline\" class=\"text-xs\">Compliant</span>\n            </div>\n            <p class=\"text-muted-foreground text-xs\">Zero security compliance violations</p>\n          </div>\n        </div>\n      </div>\n\n      <!-- Secrets Rotation 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\">Managed Secrets & Automated Rotation</h3>\n              <p ui-card-description class=\"text-xs\">\n                {{ filteredSecrets().length }} of {{ secrets().length }} cryptographic secrets configured for automated\n                lifecycle management.\n              </p>\n            </div>\n\n            <div class=\"flex flex-wrap items-center gap-2\">\n              <div class=\"relative w-full min-w-0 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]=\"search()\"\n                  (valueChange)=\"search.set($event)\"\n                  placeholder=\"Search secrets or ARN\"\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-36 text-xs\">\n                  <ui-select-value placeholder=\"All Statuses\" />\n                </button>\n                <ui-select-content>\n                  <ui-select-item value=\"all\">All Statuses</ui-select-item>\n                  <ui-select-item value=\"healthy\">Automated · Healthy</ui-select-item>\n                  <ui-select-item value=\"due-soon\">Due Soon (&lt;48h)</ui-select-item>\n                  <ui-select-item value=\"manual-needed\">Manual Needed</ui-select-item>\n                  <ui-select-item value=\"paused\">Paused</ui-select-item>\n                </ui-select-content>\n              </ui-select>\n\n              <span ui-badge variant=\"outline\" class=\"hidden h-8 items-center gap-1 font-mono text-xs md:inline-flex\">\n                <lucide-icon [img]=\"Globe\" class=\"size-3\" />\n                <span>AWS us-east-1</span>\n              </span>\n            </div>\n          </div>\n        </div>\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=\"min-w-[260px]\">Secret Name & ARN Identifier</th>\n                  <th ui-table-head class=\"min-w-[130px]\">Secret Type</th>\n                  <th ui-table-head class=\"min-w-[170px]\">Rotation Interval</th>\n                  <th ui-table-head class=\"min-w-[200px]\">Last Rotated & Next Due</th>\n                  <th ui-table-head class=\"min-w-[170px]\">Rotation 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 (secret of filteredSecrets(); track secret.id) {\n                  <tr ui-table-row class=\"group transition-colors\">\n                    <td ui-table-cell class=\"py-3.5\">\n                      <div class=\"space-y-1\">\n                        <div class=\"flex items-center gap-1.5\">\n                          <span class=\"text-foreground text-sm font-medium\">{{ secret.name }}</span>\n                          @if (rotatingSecretId() === secret.id) {\n                            <lucide-icon\n                              [img]=\"RefreshCw\"\n                              class=\"text-primary size-3.5 animate-spin\"\n                              aria-label=\"Rotating now\"\n                            />\n                          }\n                        </div>\n                        <div class=\"flex items-center gap-1.5\">\n                          <code\n                            class=\"text-muted-foreground max-w-[260px] truncate font-mono text-xs sm:max-w-[320px]\"\n                            [attr.title]=\"secret.arn\"\n                          >\n                            {{ secret.arn }}\n                          </code>\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                            [attr.aria-label]=\"'Copy ARN for ' + secret.name\"\n                            (click)=\"copyToClipboard(secret.arn, secret.id)\"\n                          >\n                            @if (copiedArn() === secret.id) {\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>\n                    </td>\n                    <td ui-table-cell class=\"py-3.5\">\n                      <span ui-badge [variant]=\"typeVariant(secret.type)\" class=\"gap-1 text-xs\">\n                        @if (secret.type === 'Postgres DB' || secret.type === 'MySQL DB') {\n                          <lucide-icon [img]=\"Database\" class=\"size-3\" />\n                        } @else if (secret.type === 'API Key') {\n                          <lucide-icon [img]=\"KeyRound\" class=\"size-3\" />\n                        } @else if (secret.type === 'RSA Keypair') {\n                          <lucide-icon [img]=\"ShieldCheck\" class=\"size-3\" />\n                        } @else if (secret.type === 'KMS Key') {\n                          <lucide-icon [img]=\"Lock\" class=\"size-3\" />\n                        } @else if (secret.type === 'Redis Auth') {\n                          <lucide-icon [img]=\"Server\" class=\"size-3\" />\n                        }\n                        <span>{{ secret.type }}</span>\n                      </span>\n                    </td>\n                    <td ui-table-cell class=\"py-3.5\">\n                      <div class=\"space-y-0.5\">\n                        <div class=\"flex items-center gap-1.5 text-xs font-medium\">\n                          <lucide-icon [img]=\"Clock\" class=\"text-muted-foreground size-3.5 shrink-0\" />\n                          <span class=\"text-foreground\">{{ secret.schedule.interval }}</span>\n                        </div>\n                        @if (secret.schedule.lambdaArn) {\n                          <p\n                            class=\"text-muted-foreground max-w-[160px] truncate font-mono text-xs\"\n                            [attr.title]=\"secret.schedule.lambdaArn\"\n                          >\n                            λ {{ lambdaShort(secret.schedule.lambdaArn) }}\n                          </p>\n                        } @else {\n                          <p class=\"text-muted-foreground font-mono text-xs\">Manual trigger</p>\n                        }\n                      </div>\n                    </td>\n                    <td ui-table-cell class=\"py-3.5\">\n                      <div class=\"space-y-0.5 text-xs\">\n                        <div class=\"text-foreground font-medium\">\n                          {{ secret.nextRotationDue }}\n                          @if (secret.status === 'due-soon') {\n                            <span class=\"text-warning font-semibold\"> ({{ secret.dueRelative }})</span>\n                          } @else {\n                            <span class=\"text-muted-foreground\"> ({{ secret.dueRelative }})</span>\n                          }\n                        </div>\n                        <p class=\"text-muted-foreground text-xs\">\n                          Last: <span class=\"font-mono\">{{ secret.lastRotated }}</span>\n                        </p>\n                      </div>\n                    </td>\n                    <td ui-table-cell class=\"py-3.5\">\n                      <div class=\"space-y-1\">\n                        @if (secret.status === 'healthy') {\n                          <span ui-badge variant=\"success\" class=\"gap-1 text-xs\">\n                            <span class=\"bg-success size-1.5 animate-pulse rounded-full\"></span>\n                            <span>Automated · Healthy</span>\n                          </span>\n                        } @else if (secret.status === 'due-soon') {\n                          <span ui-badge variant=\"warning\" class=\"gap-1 text-xs\">\n                            <lucide-icon [img]=\"Clock\" class=\"size-3\" />\n                            <span>Rotation Due Soon</span>\n                          </span>\n                        } @else if (secret.status === 'manual-needed') {\n                          <span ui-badge variant=\"warning\" class=\"gap-1 text-xs\">\n                            <lucide-icon [img]=\"AlertTriangle\" class=\"size-3\" />\n                            <span>Manual Rotation Needed</span>\n                          </span>\n                        } @else if (secret.status === 'paused') {\n                          <span ui-badge variant=\"secondary\" class=\"gap-1 text-xs\">\n                            <lucide-icon [img]=\"Pause\" class=\"size-3\" />\n                            <span>Paused</span>\n                          </span>\n                        } @else {\n                          <span ui-badge variant=\"outline\" class=\"gap-1 text-xs\">\n                            <lucide-icon [img]=\"RefreshCw\" class=\"size-3 animate-spin\" />\n                            <span>Rotating</span>\n                          </span>\n                        }\n                        <div class=\"text-muted-foreground font-mono text-xs\">{{ secret.currentVersion }}</div>\n                      </div>\n                    </td>\n                    <td ui-table-cell class=\"py-3.5 text-right\">\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 menu</span>\n                        </button>\n                        <ui-dropdown-menu-content align=\"end\" class=\"w-56\">\n                          <ui-dropdown-menu-label class=\"text-xs\">Rotation Controls</ui-dropdown-menu-label>\n                          <ui-dropdown-menu-separator />\n                          <ui-dropdown-menu-item (select)=\"openInstantRotate(secret)\">\n                            <lucide-icon [img]=\"Play\" class=\"text-success mr-2 size-4\" />\n                            <span>Rotate Now (Zero Downtime)</span>\n                          </ui-dropdown-menu-item>\n                          <ui-dropdown-menu-item (select)=\"openScheduleModal(secret)\">\n                            <lucide-icon [img]=\"Pencil\" class=\"mr-2 size-4\" />\n                            <span>Edit Schedule</span>\n                          </ui-dropdown-menu-item>\n                          <ui-dropdown-menu-item (select)=\"openLogsModal(secret)\">\n                            <lucide-icon [img]=\"Terminal\" class=\"mr-2 size-4\" />\n                            <span>View Rotation Lambda Log</span>\n                          </ui-dropdown-menu-item>\n                          <ui-dropdown-menu-separator />\n                          <ui-dropdown-menu-item (select)=\"togglePause(secret)\">\n                            @if (secret.status !== 'paused') {\n                              <lucide-icon [img]=\"Pause\" class=\"mr-2 size-4\" />\n                              <span>Pause Auto-Rotation</span>\n                            } @else {\n                              <lucide-icon [img]=\"Play\" class=\"text-success mr-2 size-4\" />\n                              <span>Resume Auto-Rotation</span>\n                            }\n                          </ui-dropdown-menu-item>\n                        </ui-dropdown-menu-content>\n                      </ui-dropdown-menu>\n                    </td>\n                  </tr>\n                }\n                @if (filteredSecrets().length === 0) {\n                  <tr ui-table-row>\n                    <td ui-table-cell [attr.colspan]=\"6\" class=\"text-muted-foreground h-32 text-center text-sm\">\n                      No secrets found matching the selected filter criteria.\n                    </td>\n                  </tr>\n                }\n              </tbody>\n            </table>\n          </div>\n        </div>\n      </div>\n\n      <!-- Instant Rotate Dialog (Zero-Downtime Confirmation) -->\n      <ui-dialog [open]=\"isRotateModalOpen()\" (openChange)=\"isRotateModalOpen.set($event)\">\n        <ui-dialog-content class=\"sm:max-w-xl\">\n          <div ui-dialog-header>\n            <div class=\"flex items-center gap-2\">\n              <div class=\"bg-success/10 text-success rounded-lg p-2\">\n                <lucide-icon [img]=\"RefreshCw\" class=\"size-5\" />\n              </div>\n              <div>\n                <h2 ui-dialog-title>Trigger Zero-Downtime Rotation</h2>\n                <p ui-dialog-description class=\"text-xs\">\n                  AWS Secrets Manager 4-step staging promotion for credential lifecycle safety.\n                </p>\n              </div>\n            </div>\n          </div>\n\n          <div class=\"space-y-4 py-2\">\n            <div class=\"border-border bg-muted/50 space-y-2 rounded-lg border p-3\">\n              <div class=\"flex items-center justify-between text-xs\">\n                <span class=\"text-muted-foreground\">Target Secret:</span>\n                <span class=\"text-foreground font-mono font-semibold\">{{ selectedSecretForRotate()?.name }}</span>\n              </div>\n              <div class=\"flex items-center justify-between text-xs\">\n                <span class=\"text-muted-foreground\">Current Active:</span>\n                <span ui-badge variant=\"outline\" class=\"font-mono text-xs\">\n                  {{ selectedSecretForRotate()?.currentVersion }}\n                </span>\n              </div>\n              <div class=\"flex items-center justify-between text-xs\">\n                <span class=\"text-muted-foreground\">Staging Target:</span>\n                <span ui-badge variant=\"info\" class=\"font-mono text-xs\">\n                  {{ selectedSecretForRotate()?.stagingVersion || 'v2.5 (AWSPENDING)' }}\n                </span>\n              </div>\n            </div>\n\n            <div class=\"space-y-2\">\n              <span class=\"text-foreground text-xs font-semibold tracking-wider uppercase\">\n                Dual-Version Execution Workflow\n              </span>\n              <div class=\"border-border bg-card space-y-2.5 rounded-lg border p-3.5 text-xs\">\n                <div class=\"flex items-start gap-2.5\">\n                  <div\n                    class=\"bg-primary text-primary-foreground flex size-5 shrink-0 items-center justify-center rounded-full text-xs font-bold\"\n                  >\n                    1\n                  </div>\n                  <div class=\"space-y-0.5\">\n                    <p class=\"text-foreground font-semibold\">createSecret (Staging)</p>\n                    <p class=\"text-muted-foreground text-xs\">\n                      Generates 32-byte cryptographic entropy and provisions version\n                      <code class=\"font-mono font-semibold\">AWSPENDING</code>.\n                    </p>\n                  </div>\n                </div>\n                <div class=\"flex items-start gap-2.5\">\n                  <div\n                    class=\"bg-primary text-primary-foreground flex size-5 shrink-0 items-center justify-center rounded-full text-xs font-bold\"\n                  >\n                    2\n                  </div>\n                  <div class=\"space-y-0.5\">\n                    <p class=\"text-foreground font-semibold\">setSecret (Dual-Authentication)</p>\n                    <p class=\"text-muted-foreground text-xs\">\n                      Updates target resource (Postgres / API / KMS) so both Version A and Version B remain valid.\n                    </p>\n                  </div>\n                </div>\n                <div class=\"flex items-start gap-2.5\">\n                  <div\n                    class=\"bg-primary text-primary-foreground flex size-5 shrink-0 items-center justify-center rounded-full text-xs font-bold\"\n                  >\n                    3\n                  </div>\n                  <div class=\"space-y-0.5\">\n                    <p class=\"text-foreground font-semibold\">testSecret (Handshake Verification)</p>\n                    <p class=\"text-muted-foreground text-xs\">\n                      Lambda executes synthetic database query using new credentials to verify validity.\n                    </p>\n                  </div>\n                </div>\n                <div class=\"flex items-start gap-2.5\">\n                  <div\n                    class=\"bg-primary text-primary-foreground flex size-5 shrink-0 items-center justify-center rounded-full text-xs font-bold\"\n                  >\n                    4\n                  </div>\n                  <div class=\"space-y-0.5\">\n                    <p class=\"text-foreground font-semibold\">finishSecret (Label Promotion)</p>\n                    <p class=\"text-muted-foreground text-xs\">\n                      Moves <code class=\"font-mono font-semibold\">AWSCURRENT</code> to Version B and demotes old version\n                      to <code class=\"font-mono font-semibold\">AWSPREVIOUS</code>.\n                    </p>\n                  </div>\n                </div>\n              </div>\n            </div>\n\n            <div\n              class=\"border-success/20 bg-success/5 text-success flex items-center gap-2.5 rounded-lg border p-3 text-xs\"\n            >\n              <lucide-icon [img]=\"ShieldCheck\" class=\"text-success size-5 shrink-0\" />\n              <span>\n                <strong>Zero-Downtime Guarantee:</strong> Existing connections continue using Version A until Version B\n                is 100% verified. No dropped TCP sockets or authentication spikes.\n              </span>\n            </div>\n          </div>\n\n          <div ui-dialog-footer>\n            <button\n              ui-button\n              variant=\"outline\"\n              [disabled]=\"isRotatingInProgress()\"\n              (click)=\"isRotateModalOpen.set(false)\"\n            >\n              Cancel\n            </button>\n            <button ui-button [disabled]=\"isRotatingInProgress()\" class=\"gap-1.5\" (click)=\"executeRotation()\">\n              @if (isRotatingInProgress()) {\n                <lucide-icon [img]=\"RefreshCw\" class=\"size-4 animate-spin\" />\n                <span>Executing Dual-Stage Rotation...</span>\n              } @else {\n                <lucide-icon [img]=\"Play\" class=\"size-4\" />\n                <span>Confirm & Rotate Immediately</span>\n              }\n            </button>\n          </div>\n        </ui-dialog-content>\n      </ui-dialog>\n\n      <!-- Schedule / Edit Schedule Dialog -->\n      <ui-dialog [open]=\"isScheduleModalOpen()\" (openChange)=\"isScheduleModalOpen.set($event)\">\n        <ui-dialog-content class=\"sm:max-w-lg\">\n          <div ui-dialog-header>\n            <h2 ui-dialog-title>{{ editingSecret() ? 'Edit Rotation Schedule' : 'Schedule Secret Rotation' }}</h2>\n            <p ui-dialog-description class=\"text-xs\">\n              Configure automated periodic rotation interval and AWS Lambda rotation handler.\n            </p>\n          </div>\n\n          <div class=\"space-y-4 py-2\">\n            <div class=\"space-y-1.5\">\n              <label for=\"angular-secret-name\" class=\"text-foreground text-xs font-medium\">Secret Name / Path</label>\n              <ui-input\n                id=\"angular-secret-name\"\n                [value]=\"formName()\"\n                (valueChange)=\"formName.set($event)\"\n                placeholder=\"e.g. prod/postgres/replica-credentials\"\n                class=\"text-xs\"\n              />\n            </div>\n\n            <div class=\"grid grid-cols-2 gap-3\">\n              <div class=\"space-y-1.5\">\n                <label class=\"text-foreground text-xs font-medium\">Secret Type</label>\n                <ui-select [value]=\"formType()\" (valueChange)=\"setFormType($event)\">\n                  <button ui-select-trigger class=\"text-xs\">\n                    <ui-select-value placeholder=\"Secret Type\" />\n                  </button>\n                  <ui-select-content>\n                    @for (t of secretTypes; track t) {\n                      <ui-select-item [value]=\"t\">{{ t }}</ui-select-item>\n                    }\n                  </ui-select-content>\n                </ui-select>\n              </div>\n\n              <div class=\"space-y-1.5\">\n                <label class=\"text-foreground text-xs font-medium\">Rotation Interval</label>\n                <ui-select [value]=\"formInterval()\" (valueChange)=\"formInterval.set($event)\">\n                  <button ui-select-trigger class=\"text-xs\">\n                    <ui-select-value placeholder=\"Interval\" />\n                  </button>\n                  <ui-select-content>\n                    @for (iv of intervals; track iv) {\n                      <ui-select-item [value]=\"iv\">{{ iv }}</ui-select-item>\n                    }\n                  </ui-select-content>\n                </ui-select>\n              </div>\n            </div>\n\n            <div class=\"space-y-1.5\">\n              <label for=\"angular-secret-lambda\" class=\"text-foreground text-xs font-medium\">\n                Rotation Lambda Function ARN\n              </label>\n              <ui-input\n                id=\"angular-secret-lambda\"\n                [value]=\"formLambdaArn()\"\n                (valueChange)=\"formLambdaArn.set($event)\"\n                placeholder=\"arn:aws:lambda:us-east-1:182938491029:function:RotateSecret\"\n                class=\"font-mono text-xs\"\n              />\n            </div>\n\n            <div class=\"border-border bg-muted/40 flex items-center justify-between rounded-lg border p-3\">\n              <div class=\"space-y-0.5\">\n                <p class=\"text-foreground text-xs font-medium\">Zero-Downtime Dual Versioning</p>\n                <p class=\"text-muted-foreground text-xs\">Verify staging version before promoting AWSCURRENT</p>\n              </div>\n              <span ui-badge variant=\"success\" class=\"text-xs\">Active</span>\n            </div>\n          </div>\n\n          <div ui-dialog-footer>\n            <button ui-button variant=\"outline\" (click)=\"isScheduleModalOpen.set(false)\">Cancel</button>\n            <button ui-button [disabled]=\"!formName().trim()\" (click)=\"saveSchedule()\">\n              {{ editingSecret() ? 'Save Changes' : 'Create Rotation Schedule' }}\n            </button>\n          </div>\n        </ui-dialog-content>\n      </ui-dialog>\n\n      <!-- View Rotation Lambda Log Dialog -->\n      <ui-dialog [open]=\"isLogsModalOpen()\" (openChange)=\"isLogsModalOpen.set($event)\">\n        <ui-dialog-content class=\"sm:max-w-2xl\">\n          <div ui-dialog-header>\n            <div class=\"flex items-center gap-2\">\n              <lucide-icon [img]=\"Terminal\" class=\"text-primary size-5\" />\n              <h2 ui-dialog-title class=\"font-mono text-base\">{{ selectedSecretForLogs()?.name }}</h2>\n            </div>\n            <p ui-dialog-description class=\"font-mono text-xs\">\n              Lambda Handler: {{ selectedSecretForLogs()?.schedule?.lambdaArn || 'arn:aws:lambda:...:RotateDefault' }}\n            </p>\n          </div>\n\n          <div class=\"space-y-3 py-1\">\n            <div\n              class=\"border-border bg-muted/60 flex items-center justify-between rounded-md border px-3 py-2 text-xs\"\n            >\n              <div class=\"flex items-center gap-2\">\n                <span class=\"text-muted-foreground\">Last Invocation:</span>\n                <span class=\"text-foreground font-mono font-medium\">{{ selectedSecretForLogs()?.lastRotated }}</span>\n              </div>\n              <div class=\"flex items-center gap-2\">\n                <span class=\"text-muted-foreground\">Status:</span>\n                <span ui-badge variant=\"success\" class=\"font-mono text-xs\">200 OK - SUCCESS</span>\n              </div>\n            </div>\n\n            <div\n              class=\"border-border text-success space-y-1.5 overflow-x-auto rounded-lg border bg-black/90 p-4 font-mono text-xs dark:bg-black\"\n            >\n              <p class=\"text-muted-foreground\">START RequestId: 4f8b91a2-631c-4b89-9801-ec8492019a Version: $LATEST</p>\n              <p class=\"text-success\">\n                [INFO] Step 1/4 createSecret: Generating 32-byte cryptographic entropy for AWSPENDING...\n              </p>\n              <p class=\"text-success\">\n                [INFO] Step 2/4 setSecret: Applying shadow credentials to destination cluster. Dual-auth enabled.\n              </p>\n              <p class=\"text-success\">\n                [INFO] Step 3/4 testSecret: Executing test query from staging connection pool -&gt; Verified (6.4ms)\n              </p>\n              <p class=\"text-success\">\n                [INFO] Step 4/4 finishSecret: Swapped AWSCURRENT label to staging version. Previous marked AWSPREVIOUS.\n              </p>\n              <p class=\"text-muted-foreground\">END RequestId: 4f8b91a2-631c-4b89-9801-ec8492019a</p>\n              <p class=\"text-muted-foreground\">\n                REPORT RequestId: 4f8b91a2-631c-4b89-9801-ec8492019a Duration: 342.15 ms Billed Duration: 343 ms\n              </p>\n            </div>\n          </div>\n\n          <div ui-dialog-footer>\n            <button ui-button variant=\"outline\" (click)=\"isLogsModalOpen.set(false)\">Close Logs</button>\n          </div>\n        </ui-dialog-content>\n      </ui-dialog>\n    </div>\n  `,\n})\nexport class UiSecretsRotationSchedulerComponent {\n  protected readonly AlertTriangle = AlertTriangle\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 Globe = Globe\n  protected readonly Info = Info\n  protected readonly KeyRound = KeyRound\n  protected readonly Lock = Lock\n  protected readonly MoreHorizontal = MoreHorizontal\n  protected readonly Pause = Pause\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 Server = Server\n  protected readonly ShieldCheck = ShieldCheck\n  protected readonly Terminal = Terminal\n  protected readonly X = X\n\n  protected readonly secretTypes = SECRET_TYPES\n  protected readonly intervals = INTERVALS\n\n  @Input() set initialSecrets(v: ManagedSecret[] | undefined) {\n    this.secrets.set((v ?? defaultSecrets).map((s) => ({ ...s, schedule: { ...s.schedule } })))\n  }\n  @Input() set initialStats(v: SecretsRotationStats | undefined) {\n    this.stats.set({ ...(v ?? defaultStats) })\n  }\n  @Input('class') className?: string\n\n  readonly secrets = signal<ManagedSecret[]>(defaultSecrets.map((s) => ({ ...s, schedule: { ...s.schedule } })))\n  readonly stats = signal<SecretsRotationStats>({ ...defaultStats })\n  readonly search = signal('')\n  readonly statusFilter = signal('all')\n  readonly bannerMessage = signal<{ type: 'success' | 'info'; text: string } | null>(null)\n  readonly rotatingSecretId = signal<string | null>(null)\n  readonly copiedArn = signal<string | null>(null)\n\n  readonly isRotateModalOpen = signal(false)\n  readonly selectedSecretForRotate = signal<ManagedSecret | null>(null)\n  readonly isRotatingInProgress = signal(false)\n\n  readonly isScheduleModalOpen = signal(false)\n  readonly editingSecret = signal<ManagedSecret | null>(null)\n  readonly formName = signal('')\n  readonly formArn = signal('')\n  readonly formType = signal<SecretType>('Postgres DB')\n  readonly formInterval = signal('Every 30 Days')\n  readonly formLambdaArn = signal('')\n  readonly formZeroDowntime = signal(true)\n\n  readonly isLogsModalOpen = signal(false)\n  readonly selectedSecretForLogs = signal<ManagedSecret | null>(null)\n\n  readonly filteredSecrets = computed(() => {\n    const q = this.search().trim().toLowerCase()\n    const status = this.statusFilter()\n    return this.secrets().filter((sec) => {\n      const matchesStatus = status === 'all' || sec.status === status\n      const matchesSearch =\n        !q ||\n        sec.name.toLowerCase().includes(q) ||\n        sec.arn.toLowerCase().includes(q) ||\n        sec.type.toLowerCase().includes(q)\n      return matchesStatus && matchesSearch\n    })\n  })\n\n  get rootClass(): string {\n    return cn('w-full space-y-6', this.className)\n  }\n\n  typeVariant(type: SecretType): 'default' | 'secondary' | 'outline' | 'info' | 'warning' {\n    return typeBadgeVariant(type)\n  }\n\n  lambdaShort(arn: string): string {\n    return arn.split(':function:')[1] || 'Lambda'\n  }\n\n  setFormType(v: string): void {\n    this.formType.set(v as SecretType)\n  }\n\n  copyToClipboard(text: string, id: string): void {\n    try {\n      navigator.clipboard.writeText(text)\n    } catch {\n      // Clipboard unavailable in this context.\n    }\n    this.copiedArn.set(id)\n    setTimeout(() => {\n      if (this.copiedArn() === id) this.copiedArn.set(null)\n    }, 2000)\n  }\n\n  openInstantRotate(secret: ManagedSecret): void {\n    this.selectedSecretForRotate.set(secret)\n    this.isRotateModalOpen.set(true)\n  }\n\n  executeRotation(): void {\n    const target = this.selectedSecretForRotate()\n    if (!target) return\n    this.isRotatingInProgress.set(true)\n    const targetId = target.id\n    const targetName = target.name\n    this.rotatingSecretId.set(targetId)\n    setTimeout(() => {\n      this.isRotatingInProgress.set(false)\n      this.isRotateModalOpen.set(false)\n      this.rotatingSecretId.set(null)\n      this.secrets.update((prev) =>\n        prev.map((s) =>\n          s.id === targetId\n            ? {\n                ...s,\n                lastRotated: 'Just now',\n                nextRotationDue: 'Sep 20, 2026',\n                dueRelative: 'in 30 days',\n                status: 'healthy' as RotationStatus,\n                currentVersion: 'v2.5 (AWSCURRENT)',\n                stagingVersion: undefined,\n                lastLogSnippet:\n                  'Zero-downtime rotation completed successfully. Version B verified, promoted to AWSCURRENT, and staged safely.',\n              }\n            : s,\n        ),\n      )\n      this.bannerMessage.set({\n        type: 'success',\n        text: `Zero-downtime rotation successfully completed for \"${targetName}\". Credentials validated with 0 dropped sockets.`,\n      })\n    }, 1400)\n  }\n\n  openScheduleModal(secret?: ManagedSecret): void {\n    if (secret) {\n      this.editingSecret.set(secret)\n      this.formName.set(secret.name)\n      this.formArn.set(secret.arn)\n      this.formType.set(secret.type)\n      this.formInterval.set(secret.schedule.interval)\n      this.formLambdaArn.set(secret.schedule.lambdaArn || '')\n      this.formZeroDowntime.set(secret.schedule.zeroDowntimeVerified)\n    } else {\n      this.editingSecret.set(null)\n      this.formName.set('')\n      this.formArn.set('')\n      this.formType.set('Postgres DB')\n      this.formInterval.set('Every 30 Days')\n      this.formLambdaArn.set('arn:aws:lambda:us-east-1:182938491029:function:RotateSecretHandler')\n      this.formZeroDowntime.set(true)\n    }\n    this.isScheduleModalOpen.set(true)\n  }\n\n  saveSchedule(): void {\n    if (!this.formName().trim()) return\n    const editing = this.editingSecret()\n    if (editing) {\n      const name = this.formName().trim()\n      const arn = this.formArn().trim()\n      this.secrets.update((prev) =>\n        prev.map((s) =>\n          s.id === editing.id\n            ? {\n                ...s,\n                name,\n                arn: arn || s.arn,\n                type: this.formType(),\n                schedule: {\n                  ...s.schedule,\n                  interval: this.formInterval(),\n                  lambdaArn: this.formLambdaArn().trim() || undefined,\n                  zeroDowntimeVerified: this.formZeroDowntime(),\n                },\n              }\n            : s,\n        ),\n      )\n      this.bannerMessage.set({ type: 'info', text: `Rotation schedule for \"${name}\" updated successfully.` })\n    } else {\n      const name = this.formName().trim()\n      const newSecret: ManagedSecret = {\n        id: `sec-${Date.now()}`,\n        name,\n        arn:\n          this.formArn().trim() || `arn:aws:secretsmanager:us-east-1:182938491029:secret:${name.toLowerCase()}-pending`,\n        type: this.formType(),\n        schedule: {\n          interval: this.formInterval(),\n          daysInterval: this.formInterval().includes('7') ? 7 : this.formInterval().includes('90') ? 90 : 30,\n          lambdaArn: this.formLambdaArn().trim() || undefined,\n          zeroDowntimeVerified: this.formZeroDowntime(),\n        },\n        lastRotated: 'Never (Initial)',\n        nextRotationDue: 'Pending First Run',\n        dueRelative: 'in 2 hours',\n        status: 'healthy',\n        currentVersion: 'v1.0 (AWSCURRENT)',\n        stagingVersion: undefined,\n        lastLogSnippet: 'Initial rotation schedule registered with automated zero-downtime dual-version handshake.',\n      }\n      this.secrets.update((prev) => [newSecret, ...prev])\n      this.bannerMessage.set({ type: 'success', text: `New secret rotation schedule registered for \"${name}\".` })\n    }\n    this.isScheduleModalOpen.set(false)\n  }\n\n  togglePause(secret: ManagedSecret): void {\n    const nextStatus: RotationStatus = secret.status === 'paused' ? 'healthy' : 'paused'\n    this.secrets.update((prev) => prev.map((s) => (s.id === secret.id ? { ...s, status: nextStatus } : s)))\n    this.bannerMessage.set({\n      type: 'info',\n      text: `Rotation schedule for \"${secret.name}\" ${nextStatus === 'paused' ? 'paused' : 'resumed'}.`,\n    })\n  }\n\n  openLogsModal(secret: ManagedSecret): void {\n    this.selectedSecretForLogs.set(secret)\n    this.isLogsModalOpen.set(true)\n  }\n}\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/secrets-rotation-scheduler/secrets-rotation-scheduler.component.ts"
    },
    {
      "path": "packages/registry-angular/blocks/secrets-rotation-scheduler/index.ts",
      "content": "export {\n  UiSecretsRotationSchedulerComponent,\n  type SecretType,\n  type RotationStatus,\n  type RotationSchedule,\n  type ManagedSecret,\n  type SecretsRotationStats,\n} from './secrets-rotation-scheduler.component'\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/secrets-rotation-scheduler/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/select.json",
    "https://uipkge.dev/r/angular/table.json"
  ],
  "description": "AWS Secrets Manager style automated credential rotation scheduler and security key audit with lifecycle telemetry cards, zero-downtime dual-version rotation workflow, rotation lambda log inspection, and schedule configuration dialogs.",
  "categories": [
    "security",
    "app",
    "devops",
    "dashboard"
  ]
}