{
  "$schema": "https://shadcn-vue.com/schema/registry-item.json",
  "name": "reverse-etl-sync-manager",
  "title": "Reverse Etl Sync Manager",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-vue/blocks/reverse-etl-sync-manager/ReverseEtlSyncManager.vue",
      "content": "<script setup lang=\"ts\">\nimport { computed, ref } from 'vue'\nimport type { HTMLAttributes } from 'vue'\nimport {\n  Activity,\n  ArrowRight,\n  ArrowRightLeft,\n  CalendarClock,\n  Check,\n  CheckCircle2,\n  ChevronRight,\n  Clock,\n  Copy,\n  Database,\n  Download,\n  Filter,\n  Key,\n  Layers,\n  Pencil,\n  RefreshCw,\n  Search,\n  Server,\n  ShieldCheck,\n  Timer,\n} from 'lucide-vue-next'\nimport { cn } from '@/lib/utils'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'\nimport { Input } from '@/components/ui/input'\nimport { Separator } from '@/components/ui/separator'\nimport { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'\n\nexport type SyncMode =\n  | 'Upsert on Match Key'\n  | 'Update if Newer'\n  | 'Update only (Null overwrite off)'\n  | 'Always Overwrite'\n\nexport interface FieldMapping {\n  id: string\n  sourceColumn: string\n  sourceType: string\n  sourceTable?: string\n  destinationField: string\n  destinationObject: string\n  destinationType: string\n  isMatchKey?: boolean\n  syncMode: SyncMode\n  transform: string\n  sampleValue: string\n  active: boolean\n}\n\nexport interface SyncRunRecord {\n  id: string\n  runNumber: string\n  startedAt: string\n  duration: string\n  durationSec: number\n  status: 'succeeded' | 'running' | 'failed' | 'warning'\n  statusLabel: string\n  totalRecords: number\n  insertedRecords: number\n  updatedRecords: number\n  deletedRecords: number\n  failedRecords: number\n  warehouse: string\n  queryId: string\n  batchId: string\n  syncTrigger: 'Scheduled Cron' | 'Manual Trigger' | 'dbt Cloud Webhook' | 'API Dispatch'\n  errorSummary?: string\n}\n\nexport interface ReverseEtlMetrics {\n  recordsSynced: number\n  successRate: number\n  duration: string\n  warehouseName: string\n  insertions: number\n  updates: number\n  deletions: number\n  scheduleInterval: string\n  nextRunIn: string\n}\n\ninterface Props {\n  initialMappings?: FieldMapping[]\n  initialRuns?: SyncRunRecord[]\n  initialMetrics?: ReverseEtlMetrics\n  class?: HTMLAttributes['class']\n}\n\nconst defaultMappings: FieldMapping[] = [\n  {\n    id: 'map-1',\n    sourceColumn: 'customer_id',\n    sourceType: 'VARCHAR(64) [PK]',\n    sourceTable: 'analytics.dim_high_value_customers',\n    destinationField: 'External_ID__c',\n    destinationObject: 'Account',\n    destinationType: 'Text(64) [Unique Match Key]',\n    isMatchKey: true,\n    syncMode: 'Upsert on Match Key',\n    transform: 'Direct Map (Primary Key)',\n    sampleValue: 'CUST_9918203',\n    active: true,\n  },\n  {\n    id: 'map-2',\n    sourceColumn: 'calculated_arr',\n    sourceType: 'NUMBER(14,2)',\n    sourceTable: 'analytics.dim_high_value_customers',\n    destinationField: 'AnnualRevenue',\n    destinationObject: 'Account',\n    destinationType: 'Currency(16,2)',\n    isMatchKey: false,\n    syncMode: 'Update if Newer',\n    transform: 'Currency Cast (USD)',\n    sampleValue: '$14,250.00',\n    active: true,\n  },\n  {\n    id: 'map-3',\n    sourceColumn: 'last_login_at',\n    sourceType: 'TIMESTAMP_TZ',\n    sourceTable: 'analytics.dim_high_value_customers',\n    destinationField: 'Last_Active_Date__c',\n    destinationObject: 'Contact',\n    destinationType: 'DateTime',\n    isMatchKey: false,\n    syncMode: 'Update only (Null overwrite off)',\n    transform: 'ISO8601 Date Parse',\n    sampleValue: '2026-08-21 14:30:00',\n    active: true,\n  },\n  {\n    id: 'map-4',\n    sourceColumn: 'health_score',\n    sourceType: 'INTEGER',\n    sourceTable: 'analytics.dim_high_value_customers',\n    destinationField: 'Health_Score__c',\n    destinationObject: 'Account',\n    destinationType: 'Number(3,0)',\n    isMatchKey: false,\n    syncMode: 'Update if Newer',\n    transform: 'Score Normalizer (0-100)',\n    sampleValue: '94.8 / 100',\n    active: true,\n  },\n  {\n    id: 'map-5',\n    sourceColumn: 'plan_tier',\n    sourceType: 'VARCHAR(50)',\n    sourceTable: 'analytics.dim_high_value_customers',\n    destinationField: 'Plan_Tier__c',\n    destinationObject: 'Account',\n    destinationType: 'Picklist',\n    isMatchKey: false,\n    syncMode: 'Upsert on Match Key',\n    transform: 'Enum Mapping (3 Tiers)',\n    sampleValue: 'Tier 1 Enterprise',\n    active: true,\n  },\n]\n\nconst defaultRuns: SyncRunRecord[] = [\n  {\n    id: 'run-8821',\n    runNumber: '#SYNC-8821',\n    startedAt: '2026-08-21T14:00:00Z',\n    duration: '01m:12s',\n    durationSec: 72,\n    status: 'succeeded',\n    statusLabel: 'Succeeded',\n    totalRecords: 14290,\n    insertedRecords: 428,\n    updatedRecords: 13862,\n    deletedRecords: 0,\n    failedRecords: 0,\n    warehouse: 'SNOWFLAKE_WH_XS',\n    queryId: '01b64e9a-0001-2a81-0000-00049281a8b1',\n    batchId: 'sf-bulk-batch-7718902',\n    syncTrigger: 'Scheduled Cron',\n  },\n  {\n    id: 'run-8820',\n    runNumber: '#SYNC-8820',\n    startedAt: '2026-08-21T13:00:00Z',\n    duration: '00m:58s',\n    durationSec: 58,\n    status: 'succeeded',\n    statusLabel: 'Succeeded',\n    totalRecords: 3410,\n    insertedRecords: 85,\n    updatedRecords: 3325,\n    deletedRecords: 0,\n    failedRecords: 0,\n    warehouse: 'SNOWFLAKE_WH_XS',\n    queryId: '01b64e9a-0001-2a80-0000-00049279b904',\n    batchId: 'sf-bulk-batch-7718819',\n    syncTrigger: 'Scheduled Cron',\n  },\n  {\n    id: 'run-8819',\n    runNumber: '#SYNC-8819',\n    startedAt: '2026-08-21T12:00:00Z',\n    duration: '01m:45s',\n    durationSec: 105,\n    status: 'succeeded',\n    statusLabel: 'Succeeded',\n    totalRecords: 12850,\n    insertedRecords: 310,\n    updatedRecords: 12540,\n    deletedRecords: 0,\n    failedRecords: 0,\n    warehouse: 'SNOWFLAKE_WH_XS',\n    queryId: '01b64e9a-0001-2a7f-0000-00049265f128',\n    batchId: 'sf-bulk-batch-7718744',\n    syncTrigger: 'dbt Cloud Webhook',\n  },\n  {\n    id: 'run-8818',\n    runNumber: '#SYNC-8818',\n    startedAt: '2026-08-21T11:00:00Z',\n    duration: '00m:42s',\n    durationSec: 42,\n    status: 'succeeded',\n    statusLabel: 'Succeeded',\n    totalRecords: 980,\n    insertedRecords: 12,\n    updatedRecords: 968,\n    deletedRecords: 0,\n    failedRecords: 0,\n    warehouse: 'SNOWFLAKE_WH_XS',\n    queryId: '01b64e9a-0001-2a7e-0000-00049251cc90',\n    batchId: 'sf-bulk-batch-7718690',\n    syncTrigger: 'Scheduled Cron',\n  },\n]\n\nconst defaultMetrics: ReverseEtlMetrics = {\n  recordsSynced: 14290,\n  successRate: 100,\n  duration: '01m:12s',\n  warehouseName: 'Snowflake SQL Warehouse',\n  insertions: 428,\n  updates: 13862,\n  deletions: 0,\n  scheduleInterval: 'Every 1 hour',\n  nextRunIn: '48m',\n}\n\nconst props = defineProps<Props>()\n\nconst mappings = ref<FieldMapping[]>(props.initialMappings ? [...props.initialMappings] : [...defaultMappings])\nconst runs = ref<SyncRunRecord[]>(props.initialRuns ? [...props.initialRuns] : [...defaultRuns])\nconst metrics = ref<ReverseEtlMetrics>(props.initialMetrics ? { ...props.initialMetrics } : { ...defaultMetrics })\n\nconst isSyncing = ref(false)\nconst syncNotice = ref(false)\nconst isEditingMappings = ref(false)\nconst mappingSearch = ref('')\nconst selectedModeFilter = ref<string>('all')\nconst expandedRunIds = ref<Record<string, boolean>>({ 'run-8821': true })\nconst copiedQueryId = ref<string | null>(null)\nconst copiedManifest = ref(false)\n\nconst filteredMappings = computed(() => {\n  return mappings.value.filter((m) => {\n    const matchesSearch =\n      mappingSearch.value.trim() === '' ||\n      m.sourceColumn.toLowerCase().includes(mappingSearch.value.toLowerCase()) ||\n      m.destinationField.toLowerCase().includes(mappingSearch.value.toLowerCase()) ||\n      m.destinationObject.toLowerCase().includes(mappingSearch.value.toLowerCase()) ||\n      m.syncMode.toLowerCase().includes(mappingSearch.value.toLowerCase()) ||\n      m.sampleValue.toLowerCase().includes(mappingSearch.value.toLowerCase())\n\n    const matchesMode =\n      selectedModeFilter.value === 'all' ||\n      (selectedModeFilter.value === 'upsert' && m.syncMode.includes('Upsert')) ||\n      (selectedModeFilter.value === 'update_if_newer' && m.syncMode === 'Update if Newer') ||\n      (selectedModeFilter.value === 'update_only' && m.syncMode.includes('Update only'))\n\n    return matchesSearch && matchesMode\n  })\n})\n\nfunction triggerManualSync() {\n  if (isSyncing.value) return\n  isSyncing.value = true\n  syncNotice.value = true\n\n  setTimeout(() => {\n    isSyncing.value = false\n    const newRunId = `run-${Date.now()}`\n    runs.value.unshift({\n      id: newRunId,\n      runNumber: `#SYNC-${8822 + (runs.value.length - 4)}`,\n      startedAt: new Date().toISOString(),\n      duration: '01m:08s',\n      durationSec: 68,\n      status: 'succeeded',\n      statusLabel: 'Succeeded',\n      totalRecords: 14290,\n      insertedRecords: 428,\n      updatedRecords: 13862,\n      deletedRecords: 0,\n      failedRecords: 0,\n      warehouse: 'SNOWFLAKE_WH_XS',\n      queryId: `01b64e9a-0001-${Math.floor(1000 + Math.random() * 9000)}-0000-${Math.floor(100000000000 + Math.random() * 900000000000).toString(16)}`,\n      batchId: `sf-bulk-batch-${Math.floor(7718900 + Math.random() * 1000)}`,\n      syncTrigger: 'Manual Trigger',\n    })\n    expandedRunIds.value[newRunId] = true\n  }, 2200)\n\n  setTimeout(() => {\n    syncNotice.value = false\n  }, 6500)\n}\n\nfunction toggleEditMappings() {\n  isEditingMappings.value = !isEditingMappings.value\n}\n\nfunction toggleRunExpand(id: string) {\n  expandedRunIds.value[id] = !expandedRunIds.value[id]\n}\n\nfunction copyQueryId(id: string, text: string) {\n  if (typeof navigator !== 'undefined' && navigator.clipboard) {\n    navigator.clipboard.writeText(text)\n    copiedQueryId.value = id\n    setTimeout(() => {\n      if (copiedQueryId.value === id) {\n        copiedQueryId.value = null\n      }\n    }, 2000)\n  }\n}\n\nfunction exportSyncManifest() {\n  const manifestData = {\n    syncName: 'Snowflake Gold Marts → Salesforce Accounts & Hubspot',\n    source: 'Snowflake: analytics.dim_high_value_customers',\n    destination: 'Salesforce CRM & HubSpot Marketing',\n    exportTimestamp: new Date().toISOString(),\n    metrics: metrics.value,\n    fieldMappings: mappings.value,\n    recentRuns: runs.value,\n  }\n\n  if (typeof document !== 'undefined') {\n    const dataStr = 'data:text/json;charset=utf-8,' + encodeURIComponent(JSON.stringify(manifestData, null, 2))\n    const downloadAnchor = document.createElement('a')\n    downloadAnchor.setAttribute('href', dataStr)\n    downloadAnchor.setAttribute(\n      'download',\n      `reverse-etl-sync-manifest-${new Date().toISOString().slice(0, 19).replace(/:/g, '-')}.json`,\n    )\n    document.body.appendChild(downloadAnchor)\n    downloadAnchor.click()\n    downloadAnchor.remove()\n    copiedManifest.value = true\n    setTimeout(() => {\n      copiedManifest.value = false\n    }, 2000)\n  }\n}\n\nfunction formatNumber(num: number): string {\n  return new Intl.NumberFormat('en-US').format(num)\n}\n\nfunction formatTimestamp(iso: string): string {\n  try {\n    const d = new Date(iso)\n    return d.toISOString().replace('T', ' ').replace('.000Z', ' UTC').replace('Z', ' UTC')\n  } catch {\n    return iso\n  }\n}\n</script>\n\n<template>\n  <div data-slot=\"reverse-etl-sync-manager\" :class=\"cn('w-full space-y-4', props.class)\">\n    <!-- Top Header: Sync Pipeline Name, Source, Destination & Global Triggers -->\n    <div class=\"flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between\">\n      <div class=\"flex items-start gap-3 sm:items-center\">\n        <div class=\"bg-card flex size-10 shrink-0 items-center justify-center rounded-lg border shadow-xs\">\n          <ArrowRightLeft class=\"text-primary size-5\" aria-hidden=\"true\" />\n        </div>\n        <div class=\"space-y-1\">\n          <div class=\"flex flex-wrap items-center gap-2\">\n            <h2 class=\"text-foreground text-xl font-bold tracking-tight sm:text-2xl\">\n              Snowflake Gold Marts → Salesforce Accounts & Hubspot\n            </h2>\n\n            <!-- Real-Time Sync Status Badge -->\n            <div\n              v-if=\"isSyncing\"\n              class=\"border-info/30 bg-info/10 text-info inline-flex items-center gap-1.5 rounded-full border px-2.5 py-0.5 text-xs font-medium\"\n            >\n              <RefreshCw class=\"size-3 animate-spin\" aria-hidden=\"true\" />\n              <span>Syncing Warehouse Deltas...</span>\n            </div>\n            <div\n              v-else\n              class=\"border-success/30 bg-success/10 text-success inline-flex items-center gap-1.5 rounded-full border px-2.5 py-0.5 text-xs font-medium\"\n            >\n              <span class=\"relative flex size-2 shrink-0\">\n                <span class=\"bg-success absolute inline-flex h-full w-full rounded-full opacity-75\" />\n                <span class=\"bg-success relative inline-flex size-2 rounded-full\" />\n              </span>\n              <span>Sync Succeeded · {{ formatNumber(metrics.recordsSynced) }} Records Updated</span>\n            </div>\n          </div>\n\n          <!-- Source to Destination Breadcrumb -->\n          <div class=\"flex flex-wrap items-center gap-1.5 text-xs\">\n            <span class=\"text-foreground inline-flex items-center gap-1 font-semibold\">\n              <Database class=\"text-info size-3.5\" aria-hidden=\"true\" />\n              Snowflake:\n              <code class=\"text-foreground/90 font-mono font-medium\">analytics.dim_high_value_customers</code>\n            </span>\n            <ArrowRight class=\"text-muted-foreground size-3.5\" aria-hidden=\"true\" />\n            <span class=\"text-primary inline-flex items-center gap-1 font-semibold\">\n              <Layers class=\"text-primary size-3.5\" aria-hidden=\"true\" />\n              Salesforce CRM & HubSpot Marketing\n            </span>\n            <span class=\"text-muted-foreground hidden font-mono sm:inline\">Reverse ETL · Hightouch/Census Model</span>\n          </div>\n        </div>\n      </div>\n\n      <!-- Header Action Controls -->\n      <div class=\"flex flex-wrap items-center gap-2\">\n        <Button\n          variant=\"outline\"\n          size=\"sm\"\n          :class=\"isEditingMappings ? 'border-primary bg-primary/10 text-primary' : ''\"\n          class=\"gap-1.5\"\n          @click=\"toggleEditMappings\"\n        >\n          <Pencil class=\"size-3.5\" aria-hidden=\"true\" />\n          <span>{{ isEditingMappings ? 'Exit Mapping Mode' : 'Edit Field Mappings' }}</span>\n        </Button>\n\n        <Button\n          aria-label=\"Download attachment\"\n          variant=\"outline\"\n          size=\"sm\"\n          class=\"gap-1.5\"\n          @click=\"exportSyncManifest\"\n        >\n          <Check v-if=\"copiedManifest\" class=\"text-success size-3.5\" aria-hidden=\"true\" />\n          <Download v-else class=\"size-3.5\" aria-hidden=\"true\" />\n          <span>{{ copiedManifest ? 'Exported' : 'Export Audit JSON' }}</span>\n        </Button>\n\n        <Button variant=\"default\" size=\"sm\" :disabled=\"isSyncing\" class=\"gap-1.5 shadow-xs\" @click=\"triggerManualSync\">\n          <RefreshCw :class=\"cn('size-3.5', isSyncing && 'animate-spin')\" aria-hidden=\"true\" />\n          <span>{{ isSyncing ? 'Dispatching Batch...' : 'Trigger Sync Now' }}</span>\n        </Button>\n      </div>\n    </div>\n\n    <!-- Active Sync Notification Alert Banner -->\n    <div\n      v-if=\"syncNotice\"\n      class=\"text-foreground border-info/30 bg-info/10 flex items-center justify-between rounded-lg border p-3 text-xs shadow-xs\"\n    >\n      <div class=\"flex items-center gap-2.5\">\n        <RefreshCw class=\"text-info size-4 shrink-0\" aria-hidden=\"true\" />\n        <div>\n          <span class=\"text-info font-semibold\">Manual Reverse ETL Sync Triggered:</span>\n          <span>\n            Executing incremental delta reconciliation on\n            <code class=\"font-mono font-medium\">analytics.dim_high_value_customers</code>\n            via Snowflake Warehouse\n            <code class=\"font-mono font-medium\">SNOWFLAKE_WH_XS</code>.\n          </span>\n        </div>\n      </div>\n      <Badge variant=\"outline\" class=\"font-mono text-xs\"> Salesforce Bulk API 2.0 </Badge>\n    </div>\n\n    <!-- 4 Reverse ETL KPI Cards -->\n    <div class=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n      <!-- 1. Records Synced -->\n      <Card class=\"border-border shadow-xs\">\n        <CardContent class=\"p-4\">\n          <div class=\"flex items-center justify-between\">\n            <span class=\"text-muted-foreground text-xs font-medium\">Records Synced</span>\n            <div\n              class=\"border-success/20 bg-success/10 text-success flex size-8 items-center justify-center rounded-md border\"\n            >\n              <CheckCircle2 class=\"size-4\" aria-hidden=\"true\" />\n            </div>\n          </div>\n          <div class=\"mt-3 space-y-1.5\">\n            <div class=\"flex items-baseline gap-1.5\">\n              <span class=\"text-foreground font-mono text-2xl font-bold tracking-tight tabular-nums\">\n                {{ formatNumber(metrics.recordsSynced) }}\n              </span>\n              <span class=\"text-muted-foreground text-xs\">Records</span>\n            </div>\n            <div class=\"flex items-center gap-2\">\n              <Badge variant=\"success\" class=\"font-mono text-xs\"> {{ metrics.successRate }}% Success </Badge>\n            </div>\n            <div class=\"text-muted-foreground flex items-center justify-between pt-1 text-xs\">\n              <span>Failed Records</span>\n              <span class=\"text-success font-mono font-medium\">0 Errors</span>\n            </div>\n          </div>\n        </CardContent>\n      </Card>\n\n      <!-- 2. Sync Duration -->\n      <Card class=\"border-border shadow-xs\">\n        <CardContent class=\"p-4\">\n          <div class=\"flex items-center justify-between\">\n            <span class=\"text-muted-foreground text-xs font-medium\">Sync Duration</span>\n            <div class=\"border-info/20 bg-info/10 text-info flex size-8 items-center justify-center rounded-md border\">\n              <Timer class=\"size-4\" aria-hidden=\"true\" />\n            </div>\n          </div>\n          <div class=\"mt-3 space-y-1.5\">\n            <div class=\"flex items-baseline gap-1.5\">\n              <span class=\"text-foreground font-mono text-2xl font-bold tracking-tight tabular-nums\">\n                {{ metrics.duration }}\n              </span>\n              <span class=\"text-muted-foreground text-xs\">runtime</span>\n            </div>\n            <div class=\"flex items-center gap-2\">\n              <Badge variant=\"info\" class=\"font-mono text-xs\">\n                {{ metrics.warehouseName }}\n              </Badge>\n            </div>\n            <div class=\"text-muted-foreground flex items-center justify-between pt-1 text-xs\">\n              <span>Throughput</span>\n              <span class=\"text-foreground font-mono font-medium\">198 rows/sec</span>\n            </div>\n          </div>\n        </CardContent>\n      </Card>\n\n      <!-- 3. Changes Detected -->\n      <Card class=\"border-border shadow-xs\">\n        <CardContent class=\"p-4\">\n          <div class=\"flex items-center justify-between\">\n            <span class=\"text-muted-foreground text-xs font-medium\">Changes Detected</span>\n            <div\n              class=\"border-primary/20 bg-primary/10 text-primary flex size-8 items-center justify-center rounded-md border\"\n            >\n              <Activity class=\"size-4\" aria-hidden=\"true\" />\n            </div>\n          </div>\n          <div class=\"mt-3 space-y-1.5\">\n            <div class=\"flex items-baseline gap-1.5\">\n              <span class=\"text-foreground font-mono text-2xl font-bold tracking-tight tabular-nums\">\n                {{ formatNumber(metrics.recordsSynced) }}\n              </span>\n              <span class=\"text-muted-foreground text-xs\">Total Deltas</span>\n            </div>\n            <div class=\"flex flex-wrap items-center gap-1.5 font-mono text-xs\">\n              <span class=\"bg-success/10 text-success rounded px-1.5 py-0.5 font-medium\">\n                {{ metrics.insertions }} Insertions\n              </span>\n              <span class=\"bg-info/10 text-info rounded px-1.5 py-0.5 font-medium\">\n                {{ formatNumber(metrics.updates) }} Updates\n              </span>\n              <span class=\"bg-muted text-muted-foreground rounded px-1.5 py-0.5 font-medium\">\n                {{ metrics.deletions }} Deletions\n              </span>\n            </div>\n            <!-- Segmented distribution progress bar -->\n            <div class=\"bg-muted flex h-1.5 w-full overflow-hidden rounded-full border pt-0\">\n              <div\n                class=\"bg-success transition-colors duration-300\"\n                :style=\"{ width: `${(metrics.insertions / metrics.recordsSynced) * 100}%` }\"\n              />\n              <div\n                class=\"bg-info transition-colors duration-300\"\n                :style=\"{ width: `${(metrics.updates / metrics.recordsSynced) * 100}%` }\"\n              />\n            </div>\n          </div>\n        </CardContent>\n      </Card>\n\n      <!-- 4. Next Scheduled Run -->\n      <Card class=\"border-border shadow-xs\">\n        <CardContent class=\"p-4\">\n          <div class=\"flex items-center justify-between\">\n            <span class=\"text-muted-foreground text-xs font-medium\">Next Scheduled Run</span>\n            <div\n              class=\"border-warning/20 bg-warning/10 text-warning flex size-8 items-center justify-center rounded-md border\"\n            >\n              <CalendarClock class=\"size-4\" aria-hidden=\"true\" />\n            </div>\n          </div>\n          <div class=\"mt-3 space-y-1.5\">\n            <div class=\"flex items-baseline gap-1.5\">\n              <span class=\"text-foreground font-mono text-2xl font-bold tracking-tight tabular-nums\">\n                in {{ metrics.nextRunIn }}\n              </span>\n              <span class=\"text-muted-foreground text-xs\">remaining</span>\n            </div>\n            <div class=\"flex items-center gap-2\">\n              <Badge variant=\"outline\" class=\"border-warning/30 text-warning font-mono text-xs\">\n                {{ metrics.scheduleInterval }}\n              </Badge>\n            </div>\n            <div class=\"text-muted-foreground flex items-center justify-between pt-1 text-xs\">\n              <span>Cron Expression</span>\n              <span class=\"text-foreground font-mono font-medium\">0 * * * *</span>\n            </div>\n          </div>\n        </CardContent>\n      </Card>\n    </div>\n\n    <!-- Field Mapping Configuration Table Card -->\n    <Card class=\"border-border shadow-xs\">\n      <CardHeader class=\"pb-3\">\n        <div class=\"flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between\">\n          <div>\n            <div class=\"flex items-center gap-2\">\n              <CardTitle class=\"text-base font-semibold\">\n                Field Mapping Configuration ({{ mappings.length }} Mappings Active)\n              </CardTitle>\n              <Badge v-if=\"isEditingMappings\" variant=\"default\" class=\"text-xs\"> Editing Mode Active </Badge>\n            </div>\n            <CardDescription class=\"text-xs\">\n              Schema transformation matrix mapping Snowflake warehouse marts to Salesforce CRM object attributes and\n              match keys\n            </CardDescription>\n          </div>\n\n          <div class=\"flex items-center gap-2\">\n            <Badge variant=\"outline\" class=\"font-mono text-xs\"> Primary Match: Account: External_ID__c </Badge>\n          </div>\n        </div>\n      </CardHeader>\n\n      <!-- Filter / Search Toolbar for Mappings -->\n      <div class=\"border-b px-4 py-3\">\n        <div class=\"flex flex-col flex-wrap gap-3 sm:flex-row sm:items-center sm:justify-between\">\n          <div class=\"relative w-full sm:min-w-[12rem] sm:flex-1\">\n            <Search\n              class=\"text-muted-foreground pointer-events-none absolute top-1/2 left-3 size-4 -translate-y-1/2\"\n              aria-hidden=\"true\"\n            />\n            <Input v-model=\"mappingSearch\" placeholder=\"Search mappings...\" class=\"pl-9 text-xs\" />\n          </div>\n\n          <div class=\"flex flex-wrap items-center gap-1.5\">\n            <span class=\"text-muted-foreground mr-1 flex items-center gap-1 text-xs font-medium\">\n              <Filter class=\"size-3\" aria-hidden=\"true\" />\n              Mode:\n            </span>\n\n            <button\n              type=\"button\"\n              :class=\"\n                cn(\n                  'focus-visible:ring-ring inline-flex items-center gap-1.5 rounded-full border px-2.5 py-1 text-xs font-medium transition-colors focus-visible:ring-2 focus-visible:outline-none',\n                  selectedModeFilter === 'all'\n                    ? 'border-primary bg-primary text-primary-foreground shadow-xs'\n                    : 'border-border bg-card text-muted-foreground hover:bg-accent hover:text-foreground',\n                )\n              \"\n              @click=\"selectedModeFilter = 'all'\"\n            >\n              All ({{ mappings.length }})\n            </button>\n\n            <button\n              type=\"button\"\n              :class=\"\n                cn(\n                  'focus-visible:ring-ring inline-flex items-center gap-1.5 rounded-full border px-2.5 py-1 text-xs font-medium transition-colors focus-visible:ring-2 focus-visible:outline-none',\n                  selectedModeFilter === 'upsert'\n                    ? 'border-primary bg-primary text-primary-foreground shadow-xs'\n                    : 'border-border bg-card text-muted-foreground hover:bg-accent hover:text-foreground',\n                )\n              \"\n              @click=\"selectedModeFilter = 'upsert'\"\n            >\n              Upsert Keys (2)\n            </button>\n\n            <button\n              type=\"button\"\n              :class=\"\n                cn(\n                  'focus-visible:ring-ring inline-flex items-center gap-1.5 rounded-full border px-2.5 py-1 text-xs font-medium transition-colors focus-visible:ring-2 focus-visible:outline-none',\n                  selectedModeFilter === 'update_if_newer'\n                    ? 'border-primary bg-primary text-primary-foreground shadow-xs'\n                    : 'border-border bg-card text-muted-foreground hover:bg-accent hover:text-foreground',\n                )\n              \"\n              @click=\"selectedModeFilter = 'update_if_newer'\"\n            >\n              Update if Newer (2)\n            </button>\n\n            <button\n              type=\"button\"\n              :class=\"\n                cn(\n                  'focus-visible:ring-ring inline-flex items-center gap-1.5 rounded-full border px-2.5 py-1 text-xs font-medium transition-colors focus-visible:ring-2 focus-visible:outline-none',\n                  selectedModeFilter === 'update_only'\n                    ? 'border-primary bg-primary text-primary-foreground shadow-xs'\n                    : 'border-border bg-card text-muted-foreground hover:bg-accent hover:text-foreground',\n                )\n              \"\n              @click=\"selectedModeFilter = 'update_only'\"\n            >\n              Update Only (1)\n            </button>\n          </div>\n        </div>\n      </div>\n\n      <CardContent class=\"p-0\">\n        <div class=\"overflow-x-auto\">\n          <Table density=\"cozy\">\n            <TableHeader>\n              <TableRow>\n                <TableHead class=\"text-xs font-semibold\">Source Column (Snowflake)</TableHead>\n                <TableHead class=\"w-12 text-center text-xs font-semibold\" aria-label=\"Mapping Direction\" />\n                <TableHead class=\"text-xs font-semibold\">Destination Field (Salesforce CRM)</TableHead>\n                <TableHead class=\"text-xs font-semibold\">Data Type & Sync Mode</TableHead>\n                <TableHead class=\"text-xs font-semibold\">Sample Sync Value</TableHead>\n                <TableHead class=\"text-center text-xs font-semibold\">Status</TableHead>\n              </TableRow>\n            </TableHeader>\n            <TableBody>\n              <TableRow v-for=\"mapping in filteredMappings\" :key=\"mapping.id\" class=\"group\">\n                <!-- Source Column (Snowflake) -->\n                <TableCell class=\"py-3\">\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\">\n                        {{ mapping.sourceColumn }}\n                      </span>\n                      <Badge v-if=\"mapping.isMatchKey\" variant=\"info\" class=\"gap-1 font-mono text-xs\">\n                        <Key class=\"size-3\" aria-hidden=\"true\" />\n                        Match Key\n                      </Badge>\n                    </div>\n                    <div class=\"text-muted-foreground flex items-center gap-1.5 text-xs\">\n                      <span class=\"font-mono text-xs\">{{ mapping.sourceType }}</span>\n                      <span>·</span>\n                      <span class=\"text-muted-foreground/80 truncate font-mono text-xs\">\n                        {{ mapping.transform }}\n                      </span>\n                    </div>\n                  </div>\n                </TableCell>\n\n                <!-- Mapping Arrow (→) -->\n                <TableCell class=\"text-muted-foreground group-hover:text-primary w-12 py-3 text-center\">\n                  <div class=\"flex items-center justify-center\">\n                    <ArrowRight class=\"size-4 transition-transform group-hover:translate-x-0.5\" aria-hidden=\"true\" />\n                  </div>\n                </TableCell>\n\n                <!-- Destination Field (Salesforce CRM) -->\n                <TableCell class=\"py-3\">\n                  <div class=\"space-y-1\">\n                    <div class=\"flex items-center gap-1.5\">\n                      <Badge variant=\"outline\" class=\"font-mono text-xs\">\n                        {{ mapping.destinationObject }}\n                      </Badge>\n                      <span class=\"text-foreground font-mono text-xs font-semibold\">\n                        {{ mapping.destinationField }}\n                      </span>\n                    </div>\n                    <p class=\"text-muted-foreground font-mono text-xs\">Target Type: {{ mapping.destinationType }}</p>\n                  </div>\n                </TableCell>\n\n                <!-- Data Type & Sync Mode -->\n                <TableCell class=\"py-3\">\n                  <div class=\"space-y-1\">\n                    <Badge\n                      :variant=\"mapping.syncMode.includes('Upsert') ? 'default' : 'outline'\"\n                      class=\"font-mono text-xs\"\n                    >\n                      {{ mapping.syncMode }}\n                    </Badge>\n                    <p class=\"text-muted-foreground text-xs\">\n                      {{ mapping.isMatchKey ? 'Primary deduplication index' : 'Safe incremental sync' }}\n                    </p>\n                  </div>\n                </TableCell>\n\n                <!-- Sample Sync Value -->\n                <TableCell class=\"py-3\">\n                  <div class=\"space-y-0.5\">\n                    <div\n                      class=\"bg-muted/50 text-foreground inline-flex items-center gap-1.5 rounded-md border px-2 py-1 font-mono text-xs font-medium\"\n                    >\n                      <span class=\"text-primary font-semibold\">›</span>\n                      <span>{{ mapping.sampleValue }}</span>\n                    </div>\n                    <p class=\"text-muted-foreground text-xs\">Live sample preview</p>\n                  </div>\n                </TableCell>\n\n                <!-- Status Badge / Toggle -->\n                <TableCell class=\"py-3 text-center\">\n                  <Badge variant=\"success\" class=\"gap-1 font-mono text-xs\">\n                    <span class=\"bg-success size-1.5 rounded-full\" />\n                    Active\n                  </Badge>\n                </TableCell>\n              </TableRow>\n            </TableBody>\n          </Table>\n        </div>\n      </CardContent>\n    </Card>\n\n    <!-- Sync Run History & Error Queue Table Card -->\n    <Card class=\"border-border shadow-xs\">\n      <CardHeader class=\"pb-3\">\n        <div class=\"flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between\">\n          <div>\n            <CardTitle class=\"text-base font-semibold\">\n              Sync Run History & Execution Log (Recent {{ runs.length }} Runs)\n            </CardTitle>\n            <CardDescription class=\"text-xs\">\n              Audit trail of automated and manual reverse ETL execution runs, Snowflake query IDs, and Salesforce Bulk\n              API ingestion\n            </CardDescription>\n          </div>\n\n          <div class=\"flex items-center gap-2\">\n            <div\n              class=\"bg-success/10 text-success flex items-center gap-1.5 rounded-md border px-2.5 py-1 text-xs font-medium\"\n            >\n              <ShieldCheck class=\"size-3.5\" aria-hidden=\"true\" />\n              <span>Error DLQ: 0 Failed Records</span>\n            </div>\n          </div>\n        </div>\n      </CardHeader>\n\n      <CardContent class=\"p-0\">\n        <div class=\"divide-border/60 divide-y\">\n          <div\n            v-for=\"run in runs\"\n            :key=\"run.id\"\n            :class=\"cn('group transition-colors', expandedRunIds[run.id] ? 'bg-muted/30' : 'hover:bg-muted/20')\"\n          >\n            <!-- Run Summary Header Row -->\n            <div\n              role=\"button\"\n              tabindex=\"0\"\n              :aria-expanded=\"!!expandedRunIds[run.id]\"\n              class=\"focus-visible:ring-ring flex cursor-pointer flex-col gap-3 p-3.5 focus-visible:ring-2 focus-visible:outline-none focus-visible:ring-inset sm:flex-row sm:items-center sm:justify-between\"\n              @click=\"toggleRunExpand(run.id)\"\n              @keydown.enter.prevent=\"toggleRunExpand(run.id)\"\n              @keydown.space.prevent=\"toggleRunExpand(run.id)\"\n            >\n              <!-- Left Rail: Chevron, Run ID, Status, Timestamp & Trigger -->\n              <div class=\"flex min-w-0 items-start gap-3 sm:items-center\">\n                <button\n                  type=\"button\"\n                  aria-label=\"Toggle sync run details\"\n                  class=\"text-muted-foreground group-hover:text-foreground mt-0.5 shrink-0 transition-transform sm:mt-0\"\n                  :class=\"expandedRunIds[run.id] ? 'text-foreground rotate-90' : ''\"\n                >\n                  <ChevronRight class=\"size-4\" aria-hidden=\"true\" />\n                </button>\n\n                <div class=\"space-y-1 sm:space-y-0.5\">\n                  <div class=\"flex flex-wrap items-center gap-2\">\n                    <span class=\"text-foreground font-mono text-xs font-bold\">\n                      {{ run.runNumber }}\n                    </span>\n\n                    <Badge variant=\"success\" class=\"gap-1 font-mono text-xs\">\n                      <span class=\"bg-success size-1.5 rounded-full\" />\n                      {{ run.statusLabel }}\n                    </Badge>\n\n                    <span class=\"text-muted-foreground font-mono text-xs whitespace-nowrap\">\n                      {{ formatTimestamp(run.startedAt) }}\n                    </span>\n\n                    <Badge variant=\"outline\" class=\"font-mono text-xs\">\n                      {{ run.syncTrigger }}\n                    </Badge>\n                  </div>\n\n                  <p class=\"text-muted-foreground text-xs\">\n                    Processed {{ formatNumber(run.totalRecords) }} records ({{\n                      formatNumber(run.insertedRecords)\n                    }}\n                    added, {{ formatNumber(run.updatedRecords) }} updated) · 0 failed\n                  </p>\n                </div>\n              </div>\n\n              <!-- Right Rail: Duration, Rows Affected, Warehouse -->\n              <div class=\"flex shrink-0 flex-wrap items-center gap-3 sm:justify-end\">\n                <div class=\"bg-muted/60 flex items-center gap-1.5 rounded-md border px-2 py-1 font-mono text-xs\">\n                  <Clock class=\"text-muted-foreground size-3\" aria-hidden=\"true\" />\n                  <span class=\"text-muted-foreground\">Duration:</span>\n                  <span class=\"text-foreground font-medium tabular-nums\">{{ run.duration }}</span>\n                </div>\n\n                <div class=\"text-muted-foreground flex items-center gap-1.5 font-mono text-xs\">\n                  <span class=\"text-foreground/90 font-medium\">{{ run.warehouse }}</span>\n                </div>\n              </div>\n            </div>\n\n            <!-- Expanded Run Diagnostics Details -->\n            <div v-if=\"expandedRunIds[run.id]\" class=\"bg-muted/15 border-t px-4 py-3.5\">\n              <div class=\"space-y-3\">\n                <div class=\"grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-3\">\n                  <!-- Snowflake Query Identifier -->\n                  <div class=\"bg-card space-y-1 rounded-md border p-3\">\n                    <div class=\"flex items-center justify-between\">\n                      <span class=\"text-muted-foreground text-xs font-medium\">Snowflake Query ID</span>\n                      <Button\n                        variant=\"ghost\"\n                        size=\"xs\"\n                        class=\"h-6 gap-1 px-2 text-xs\"\n                        @click=\"copyQueryId(run.id, run.queryId)\"\n                      >\n                        <Check v-if=\"copiedQueryId === run.id\" class=\"text-success size-3\" aria-hidden=\"true\" />\n                        <Copy v-else class=\"size-3\" aria-hidden=\"true\" />\n                        <span>{{ copiedQueryId === run.id ? 'Copied' : 'Copy' }}</span>\n                      </Button>\n                    </div>\n                    <p class=\"text-foreground font-mono text-xs font-semibold\">\n                      {{ run.queryId }}\n                    </p>\n                    <p class=\"text-muted-foreground text-xs\">SQL compilation: 180ms · Warehousing tier: XS</p>\n                  </div>\n\n                  <!-- Salesforce Bulk API Batch ID -->\n                  <div class=\"bg-card space-y-1 rounded-md border p-3\">\n                    <div class=\"flex items-center justify-between\">\n                      <span class=\"text-muted-foreground text-xs font-medium\">Salesforce Bulk Batch ID</span>\n                      <Badge variant=\"outline\" class=\"font-mono text-xs\"> Bulk 2.0 </Badge>\n                    </div>\n                    <p class=\"text-foreground font-mono text-xs font-semibold\">\n                      {{ run.batchId }}\n                    </p>\n                    <p class=\"text-muted-foreground text-xs\">Chunk size: 10,000 records/batch · HTTP 200 OK</p>\n                  </div>\n\n                  <!-- Ingestion Breakdown -->\n                  <div class=\"bg-card space-y-1 rounded-md border p-3 sm:col-span-2 lg:col-span-1\">\n                    <div class=\"flex items-center justify-between\">\n                      <span class=\"text-muted-foreground text-xs font-medium\">Ingestion Breakdown</span>\n                      <span class=\"text-success font-mono text-xs\">100% Ingested</span>\n                    </div>\n                    <div class=\"flex items-center gap-2 pt-1 font-mono text-xs\">\n                      <span class=\"text-success font-medium\"> +{{ formatNumber(run.insertedRecords) }} Ins </span>\n                      <span class=\"text-info font-medium\"> ~{{ formatNumber(run.updatedRecords) }} Upd </span>\n                      <span class=\"text-muted-foreground\"> {{ run.deletedRecords }} Del </span>\n                    </div>\n                    <p class=\"text-muted-foreground text-xs\">Zero dead-letter quarantine items</p>\n                  </div>\n                </div>\n              </div>\n            </div>\n          </div>\n        </div>\n      </CardContent>\n\n      <!-- Bottom Engine & Sync Ingestion Protocol Telemetry Bar -->\n      <div\n        class=\"bg-muted/40 flex flex-col gap-2.5 border-t px-4 py-3 text-xs sm:flex-row sm:items-center sm:justify-between\"\n      >\n        <div class=\"text-muted-foreground flex flex-wrap items-center gap-4\">\n          <div class=\"text-foreground flex items-center gap-1.5 font-medium\">\n            <Activity class=\"text-success size-3.5\" aria-hidden=\"true\" />\n            <span>Reverse ETL Engine:</span>\n            <span class=\"font-mono\">Census / Hightouch Protocol v4.2</span>\n          </div>\n\n          <Separator orientation=\"vertical\" class=\"hidden h-3.5 sm:block\" />\n\n          <div class=\"flex items-center gap-1.5\">\n            <Database class=\"text-info size-3.5\" aria-hidden=\"true\" />\n            <span>Source DW:</span>\n            <span class=\"text-foreground font-mono\">Snowflake (AWS us-east-1)</span>\n          </div>\n\n          <Separator orientation=\"vertical\" class=\"hidden h-3.5 sm:block\" />\n\n          <div class=\"flex items-center gap-1.5\">\n            <Server class=\"text-primary size-3.5\" aria-hidden=\"true\" />\n            <span>Target SaaS:</span>\n            <span class=\"text-foreground font-mono\">Salesforce Bulk API 2.0 + HubSpot v3</span>\n          </div>\n        </div>\n\n        <div class=\"text-muted-foreground flex items-center gap-2 font-mono\">\n          <span class=\"bg-success size-1.5 rounded-full\" />\n          <span>Daily API Quota: 94,200 / 100,000 remaining</span>\n        </div>\n      </div>\n    </Card>\n  </div>\n</template>\n",
      "type": "registry:block",
      "target": "~/app/components/blocks/ReverseEtlSyncManager.vue"
    }
  ],
  "dependencies": [
    "lucide-vue-next"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/vue/badge.json",
    "https://uipkge.dev/r/vue/button.json",
    "https://uipkge.dev/r/vue/card.json",
    "https://uipkge.dev/r/vue/input.json",
    "https://uipkge.dev/r/vue/separator.json",
    "https://uipkge.dev/r/vue/table.json"
  ],
  "description": "Census and Hightouch style Reverse ETL sync manager and data activation pipeline for synchronizing Snowflake data warehouse marts to SaaS destinations (Salesforce CRM and HubSpot) with live telemetry cards, schema field mapping matrix, and sync run history log.",
  "categories": [
    "devops",
    "app",
    "analytics",
    "data"
  ]
}