{
  "$schema": "https://shadcn-vue.com/schema/registry-item.json",
  "name": "dbt-model-graph",
  "title": "Dbt Model Graph",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-vue/blocks/dbt-model-graph/DbtModelGraph.vue",
      "content": "<script setup lang=\"ts\">\nimport { computed, ref } from 'vue'\nimport type { HTMLAttributes } from 'vue'\nimport {\n  ArrowUpRight,\n  Check,\n  CheckCircle2,\n  Clock,\n  Code2,\n  Copy,\n  Database,\n  FileCode,\n  GitBranch,\n  HardDrive,\n  Info,\n  Key,\n  Layers,\n  Link2,\n  Loader2,\n  Play,\n  Search,\n  ShieldCheck,\n  Table2,\n  Tag,\n  User,\n  Workflow,\n  Zap,\n} from 'lucide-vue-next'\nimport { cn } from '@/lib/utils'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { Card } from '@/components/ui/card'\nimport { Input } from '@/components/ui/input'\nimport { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'\nimport { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'\n\ninterface ModelColumn {\n  name: string\n  dataType: string\n  nullable: boolean\n  isPrimaryKey?: boolean\n  isForeignKey?: boolean\n  foreignKeyRef?: string\n  isClusterKey?: boolean\n  tests: Array<{\n    name: 'unique' | 'not_null' | 'relationships' | 'accepted_values'\n    status: 'pass' | 'warn' | 'fail'\n    detail?: string\n  }>\n  testDuration: string\n  description: string\n}\n\ninterface UpstreamNode {\n  id: string\n  name: string\n  type: 'view' | 'table' | 'source'\n  package: string\n  rowCount: string\n  freshness: string\n  freshnessStatus: 'pass' | 'warn'\n  description: string\n}\n\ninterface DownstreamNode {\n  id: string\n  name: string\n  type: 'table' | 'incremental' | 'exposure'\n  package: string\n  consumers: string\n  sla: string\n  description: string\n}\n\nconst props = defineProps<{\n  class?: HTMLAttributes['class']\n}>()\n\n// --- State ---\nconst activeTab = ref<'model-sql' | 'compiled-sql' | 'contract'>('model-sql')\nconst columnSearch = ref('')\nconst isBuilding = ref(false)\nconst isTesting = ref(false)\nconst copiedRef = ref(false)\nconst dbtMacroRef = \"{{ ref('fct_orders') }}\"\nconst copiedSql = ref(false)\nconst copiedCompiled = ref(false)\nconst buildStatusText = ref('Success · Built in 14.2s')\nconst lastBuildTime = ref('12 mins ago')\nconst selectedNodeId = ref<string>('fct_orders')\nconst wrapLines = ref(false)\n\n// --- Data ---\nconst modelSqlSource = `{{\n  config(\n    materialized = 'incremental',\n    unique_key = 'order_id',\n    on_schema_change = 'sync_all_columns',\n    incremental_strategy = 'merge',\n    cluster_by = ['order_date', 'customer_id'],\n    tags = ['finance', 'core', 'daily_sla']\n  )\n}}\n\nWITH payments AS (\n  SELECT\n    payment_id,\n    order_id,\n    payment_method,\n    amount_usd,\n    gateway_fee_usd,\n    status AS payment_status,\n    created_at AS payment_created_at\n  FROM {{ ref('stg_stripe__payments') }}\n  {% if is_incremental() %}\n    WHERE updated_at >= (SELECT coalesce(max(payment_created_at), '1970-01-01') FROM {{ this }})\n  {% endif %}\n),\n\norders_source AS (\n  SELECT\n    order_id,\n    customer_id,\n    order_number,\n    order_status,\n    total_amount_usd,\n    tax_amount_usd,\n    discount_amount_usd,\n    currency_code,\n    order_date,\n    created_at,\n    updated_at\n  FROM {{ ref('stg_shopify__orders') }}\n  {% if is_incremental() %}\n    WHERE updated_at >= (SELECT coalesce(max(updated_at), '1970-01-01') FROM {{ this }})\n  {% endif %}\n),\n\ncustomers AS (\n  SELECT\n    customer_id,\n    customer_tier,\n    country_code,\n    lifetime_order_count\n  FROM {{ ref('dim_customers') }}\n),\n\naggregated_payments AS (\n  SELECT\n    order_id,\n    sum(case when payment_status = 'succeeded' then amount_usd else 0 end) as total_paid_usd,\n    sum(gateway_fee_usd) as total_fees_usd,\n    count(payment_id) as payment_attempts_count,\n    max(payment_created_at) as last_payment_at\n  FROM payments\n  GROUP BY 1\n),\n\nfinal_model AS (\n  SELECT\n    ord.order_id,\n    ord.order_number,\n    ord.customer_id,\n    cust.customer_tier,\n    cust.country_code,\n    ord.order_status,\n    ord.order_date,\n    ord.currency_code,\n    ord.total_amount_usd,\n    ord.tax_amount_usd,\n    ord.discount_amount_usd,\n    coalesce(pay.total_paid_usd, 0.00) as total_paid_usd,\n    coalesce(pay.total_fees_usd, 0.00) as payment_fees_usd,\n    round(ord.total_amount_usd - coalesce(pay.total_fees_usd, 0.00), 2) as net_revenue_usd,\n    case\n      when pay.total_paid_usd >= ord.total_amount_usd then 'fully_paid'\n      when pay.total_paid_usd > 0 then 'partially_paid'\n      else 'unpaid'\n    end as payment_settlement_status,\n    coalesce(pay.payment_attempts_count, 0) as payment_attempts,\n    ord.created_at,\n    ord.updated_at\n  FROM orders_source ord\n  LEFT JOIN aggregated_payments pay ON ord.order_id = pay.order_id\n  LEFT JOIN customers cust ON ord.customer_id = cust.customer_id\n)\n\nSELECT * FROM final_model`\n\nconst compiledSqlSource = `-- Compiled target warehouse query: Snowflake / AWS us-east-1\n-- Execution target: \"ANALYTICS_PROD\".\"MARTS\".\"fct_orders\"\n-- Incremental Merge Strategy with cluster keys [order_date, customer_id]\n\nMERGE INTO \"ANALYTICS_PROD\".\"MARTS\".\"fct_orders\" AS target\nUSING (\n  WITH payments AS (\n    SELECT\n      payment_id,\n      order_id,\n      payment_method,\n      amount_usd,\n      gateway_fee_usd,\n      status AS payment_status,\n      created_at AS payment_created_at\n    FROM \"ANALYTICS_PROD\".\"STAGING\".\"stg_stripe__payments\"\n    WHERE updated_at >= (SELECT coalesce(max(payment_created_at), '1970-01-01') FROM \"ANALYTICS_PROD\".\"MARTS\".\"fct_orders\")\n  ),\n\n  orders_source AS (\n    SELECT\n      order_id,\n      customer_id,\n      order_number,\n      order_status,\n      total_amount_usd,\n      tax_amount_usd,\n      discount_amount_usd,\n      currency_code,\n      order_date,\n      created_at,\n      updated_at\n    FROM \"ANALYTICS_PROD\".\"STAGING\".\"stg_shopify__orders\"\n    WHERE updated_at >= (SELECT coalesce(max(updated_at), '1970-01-01') FROM \"ANALYTICS_PROD\".\"MARTS\".\"fct_orders\")\n  ),\n\n  customers AS (\n    SELECT\n      customer_id,\n      customer_tier,\n      country_code,\n      lifetime_order_count\n    FROM \"ANALYTICS_PROD\".\"CORE\".\"dim_customers\"\n  ),\n\n  aggregated_payments AS (\n    SELECT\n      order_id,\n      sum(case when payment_status = 'succeeded' then amount_usd else 0 end) as total_paid_usd,\n      sum(gateway_fee_usd) as total_fees_usd,\n      count(payment_id) as payment_attempts_count,\n      max(payment_created_at) as last_payment_at\n    FROM payments\n    GROUP BY 1\n  ),\n\n  final_model AS (\n    SELECT\n      ord.order_id,\n      ord.order_number,\n      ord.customer_id,\n      cust.customer_tier,\n      cust.country_code,\n      ord.order_status,\n      ord.order_date,\n      ord.currency_code,\n      ord.total_amount_usd,\n      ord.tax_amount_usd,\n      ord.discount_amount_usd,\n      coalesce(pay.total_paid_usd, 0.00) as total_paid_usd,\n      coalesce(pay.total_fees_usd, 0.00) as payment_fees_usd,\n      round(ord.total_amount_usd - coalesce(pay.total_fees_usd, 0.00), 2) as net_revenue_usd,\n      case\n        when pay.total_paid_usd >= ord.total_amount_usd then 'fully_paid'\n        when pay.total_paid_usd > 0 then 'partially_paid'\n        else 'unpaid'\n      end as payment_settlement_status,\n      coalesce(pay.payment_attempts_count, 0) as payment_attempts,\n      ord.created_at,\n      ord.updated_at\n    FROM orders_source ord\n    LEFT JOIN aggregated_payments pay ON ord.order_id = pay.order_id\n    LEFT JOIN customers cust ON ord.customer_id = cust.customer_id\n  )\n\n  SELECT * FROM final_model\n) AS source\nON target.order_id = source.order_id\nWHEN MATCHED THEN UPDATE SET\n  order_number = source.order_number,\n  customer_id = source.customer_id,\n  customer_tier = source.customer_tier,\n  country_code = source.country_code,\n  order_status = source.order_status,\n  order_date = source.order_date,\n  total_amount_usd = source.total_amount_usd,\n  tax_amount_usd = source.tax_amount_usd,\n  discount_amount_usd = source.discount_amount_usd,\n  total_paid_usd = source.total_paid_usd,\n  payment_fees_usd = source.payment_fees_usd,\n  net_revenue_usd = source.net_revenue_usd,\n  payment_settlement_status = source.payment_settlement_status,\n  payment_attempts = source.payment_attempts,\n  updated_at = source.updated_at\nWHEN NOT MATCHED THEN INSERT (\n  order_id, order_number, customer_id, customer_tier, country_code,\n  order_status, order_date, currency_code, total_amount_usd, tax_amount_usd,\n  discount_amount_usd, total_paid_usd, payment_fees_usd, net_revenue_usd,\n  payment_settlement_status, payment_attempts, created_at, updated_at\n) VALUES (\n  source.order_id, source.order_number, source.customer_id, source.customer_tier, source.country_code,\n  source.order_status, source.order_date, source.currency_code, source.total_amount_usd, source.tax_amount_usd,\n  source.discount_amount_usd, source.total_paid_usd, source.payment_fees_usd, source.net_revenue_usd,\n  source.payment_settlement_status, source.payment_attempts, source.created_at, source.updated_at\n);`\n\nconst upstreamNodes: UpstreamNode[] = [\n  {\n    id: 'stg_stripe__payments',\n    name: 'stg_stripe__payments',\n    type: 'view',\n    package: 'analytics_dw.staging.stripe',\n    rowCount: '1,420,800 rows',\n    freshness: 'Pass · 12m ago',\n    freshnessStatus: 'pass',\n    description: 'Raw webhook payment charges, refunds, and gateway fee captures from Stripe API.',\n  },\n  {\n    id: 'stg_shopify__orders',\n    name: 'stg_shopify__orders',\n    type: 'view',\n    package: 'analytics_dw.staging.shopify',\n    rowCount: '984,200 rows',\n    freshness: 'Pass · 5m ago',\n    freshnessStatus: 'pass',\n    description: 'E-commerce transactional headers, tax summaries, discount allocations, and checkout states.',\n  },\n  {\n    id: 'dim_customers',\n    name: 'dim_customers',\n    type: 'table',\n    package: 'analytics_dw.core',\n    rowCount: '248,500 rows',\n    freshness: 'Pass · 1h ago',\n    freshnessStatus: 'pass',\n    description: 'Type-2 slowly changing dimension master record for authenticated customer accounts.',\n  },\n]\n\nconst downstreamNodes: DownstreamNode[] = [\n  {\n    id: 'mart_finance_mrr',\n    name: 'mart_finance_mrr',\n    type: 'table',\n    package: 'analytics_dw.marts.finance',\n    consumers: 'Finance Team & NetSuite Sync',\n    sla: 'Tier 1 · Daily 06:00 UTC',\n    description: 'Monthly recurring revenue waterfall and cohort retention analysis table.',\n  },\n  {\n    id: 'mart_executive_kpis',\n    name: 'mart_executive_kpis',\n    type: 'table',\n    package: 'analytics_dw.marts.executive',\n    consumers: 'Executive Dashboard & Board Reports',\n    sla: 'Tier 1 · Daily 07:00 UTC',\n    description: 'High-level business health rollup metrics: GMV, net revenue, CAC payback, and refund rates.',\n  },\n  {\n    id: 'tableau_revenue_dashboard',\n    name: 'tableau_revenue_dashboard',\n    type: 'exposure',\n    package: 'exposures.bi.tableau',\n    consumers: '120 Active BI Users',\n    sla: 'Hourly Sync',\n    description: 'Production executive revenue tracking workbook and daily pacing alerts.',\n  },\n]\n\nconst columns: ModelColumn[] = [\n  {\n    name: 'order_id',\n    dataType: 'STRING (VARCHAR)',\n    nullable: false,\n    isPrimaryKey: true,\n    tests: [\n      { name: 'unique', status: 'pass' },\n      { name: 'not_null', status: 'pass' },\n    ],\n    testDuration: '12.4ms',\n    description: 'Surrogate primary key generated for each transactional order record.',\n  },\n  {\n    name: 'order_number',\n    dataType: 'STRING (VARCHAR)',\n    nullable: false,\n    tests: [\n      { name: 'unique', status: 'pass' },\n      { name: 'not_null', status: 'pass' },\n    ],\n    testDuration: '14.1ms',\n    description: 'Human-readable sequential invoice reference number from checkout.',\n  },\n  {\n    name: 'customer_id',\n    dataType: 'STRING (VARCHAR)',\n    nullable: false,\n    isForeignKey: true,\n    foreignKeyRef: 'dim_customers.customer_id',\n    tests: [\n      { name: 'not_null', status: 'pass' },\n      { name: 'relationships', status: 'pass', detail: 'dim_customers' },\n    ],\n    testDuration: '28.6ms',\n    description: 'Foreign key reference linking order to the verified master customer account.',\n  },\n  {\n    name: 'customer_tier',\n    dataType: 'STRING (VARCHAR)',\n    nullable: true,\n    tests: [\n      {\n        name: 'accepted_values',\n        status: 'pass',\n        detail: 'enterprise, pro, starter, free',\n      },\n    ],\n    testDuration: '9.2ms',\n    description: 'Customer loyalty and billing subscription tier at the time of purchase.',\n  },\n  {\n    name: 'country_code',\n    dataType: 'STRING (CHAR(2))',\n    nullable: false,\n    tests: [{ name: 'not_null', status: 'pass' }],\n    testDuration: '8.4ms',\n    description: 'ISO 3166-1 alpha-2 two-letter billing destination country code.',\n  },\n  {\n    name: 'order_status',\n    dataType: 'STRING (VARCHAR)',\n    nullable: false,\n    tests: [\n      {\n        name: 'accepted_values',\n        status: 'pass',\n        detail: 'completed, processing, shipped, cancelled, refunded',\n      },\n      { name: 'not_null', status: 'pass' },\n    ],\n    testDuration: '15.3ms',\n    description: 'Current order fulfillment and delivery lifecycle state.',\n  },\n  {\n    name: 'order_date',\n    dataType: 'DATE',\n    nullable: false,\n    isClusterKey: true,\n    tests: [{ name: 'not_null', status: 'pass' }],\n    testDuration: '7.9ms',\n    description: 'Calendar transaction date used as primary cluster and pruning key.',\n  },\n  {\n    name: 'currency_code',\n    dataType: 'STRING (CHAR(3))',\n    nullable: false,\n    tests: [\n      {\n        name: 'accepted_values',\n        status: 'pass',\n        detail: 'USD, EUR, GBP, CAD',\n      },\n    ],\n    testDuration: '6.8ms',\n    description: 'ISO 4217 three-letter currency code in which the charge was denominated.',\n  },\n  {\n    name: 'total_amount_usd',\n    dataType: 'DECIMAL(12,2)',\n    nullable: false,\n    tests: [{ name: 'not_null', status: 'pass' }],\n    testDuration: '10.1ms',\n    description: 'Gross order amount in base USD currency including tax and discounts.',\n  },\n  {\n    name: 'tax_amount_usd',\n    dataType: 'DECIMAL(10,2)',\n    nullable: false,\n    tests: [{ name: 'not_null', status: 'pass' }],\n    testDuration: '9.0ms',\n    description: 'Total sales tax and VAT amount captured for remittance.',\n  },\n  {\n    name: 'discount_amount_usd',\n    dataType: 'DECIMAL(10,2)',\n    nullable: false,\n    tests: [{ name: 'not_null', status: 'pass' }],\n    testDuration: '8.1ms',\n    description: 'Promotional discount and coupon deductions applied at checkout.',\n  },\n  {\n    name: 'total_paid_usd',\n    dataType: 'DECIMAL(12,2)',\n    nullable: false,\n    tests: [{ name: 'not_null', status: 'pass' }],\n    testDuration: '11.3ms',\n    description: 'Sum of all verified cleared customer payments from Stripe ledger.',\n  },\n  {\n    name: 'payment_fees_usd',\n    dataType: 'DECIMAL(10,2)',\n    nullable: false,\n    tests: [{ name: 'not_null', status: 'pass' }],\n    testDuration: '9.8ms',\n    description: 'Merchant interchange and gateway transaction processing fees.',\n  },\n  {\n    name: 'net_revenue_usd',\n    dataType: 'DECIMAL(12,2)',\n    nullable: false,\n    tests: [{ name: 'not_null', status: 'pass' }],\n    testDuration: '10.5ms',\n    description: 'Net recognized revenue after deducting gateway processing fees.',\n  },\n  {\n    name: 'payment_settlement_status',\n    dataType: 'STRING (VARCHAR)',\n    nullable: false,\n    tests: [\n      {\n        name: 'accepted_values',\n        status: 'pass',\n        detail: 'fully_paid, partially_paid, unpaid',\n      },\n      { name: 'not_null', status: 'pass' },\n    ],\n    testDuration: '8.7ms',\n    description: 'Payment clearing and reconciliation flag calculated against order total.',\n  },\n  {\n    name: 'payment_attempts',\n    dataType: 'INTEGER',\n    nullable: false,\n    tests: [{ name: 'not_null', status: 'pass' }],\n    testDuration: '6.2ms',\n    description: 'Number of authorization attempts recorded in the payment gateway.',\n  },\n  {\n    name: 'created_at',\n    dataType: 'TIMESTAMP_TZ',\n    nullable: false,\n    tests: [{ name: 'not_null', status: 'pass' }],\n    testDuration: '8.0ms',\n    description: 'Initial order creation timestamp in UTC timezone.',\n  },\n  {\n    name: 'updated_at',\n    dataType: 'TIMESTAMP_TZ',\n    nullable: false,\n    tests: [{ name: 'not_null', status: 'pass' }],\n    testDuration: '8.3ms',\n    description: 'Last modified timestamp used as incremental watermark boundary.',\n  },\n]\n\n// --- Computed ---\nconst modelSqlLines = computed(() => modelSqlSource.split('\\n'))\nconst compiledSqlLines = computed(() => compiledSqlSource.split('\\n'))\n\nconst filteredColumns = computed(() => {\n  const query = columnSearch.value.trim().toLowerCase()\n  if (!query) return columns\n  return columns.filter(\n    (col) =>\n      col.name.toLowerCase().includes(query) ||\n      col.dataType.toLowerCase().includes(query) ||\n      col.description.toLowerCase().includes(query) ||\n      col.tests.some(\n        (t) => t.name.toLowerCase().includes(query) || (t.detail && t.detail.toLowerCase().includes(query)),\n      ),\n  )\n})\n\nconst passingTestsCount = computed(() => {\n  return columns.reduce((acc, col) => acc + col.tests.filter((t) => t.status === 'pass').length, 0)\n})\n\n// --- Syntax Highlighting Helpers ---\nfunction escapeHtml(str: string): string {\n  return str\n    .replace(/&/g, '&amp;')\n    .replace(/</g, '&lt;')\n    .replace(/>/g, '&gt;')\n    .replace(/\"/g, '&quot;')\n    .replace(/'/g, '&#039;')\n}\n\nfunction highlightJinjaSqlLine(line: string): string {\n  if (!line) return ''\n  const escaped = escapeHtml(line)\n\n  // SQL & Jinja Comments\n  if (escaped.trim().startsWith('--') || escaped.trim().startsWith('{#')) {\n    return `<span class=\"text-muted-foreground/60 italic\">${escaped}</span>`\n  }\n\n  // Highlight Jinja tags: {{ ... }} and {% ... %}\n  let result = escaped.replace(/(\\{\\{[\\s\\S]*?\\}\\}|\\{%[\\s\\S]*?%\\})/g, (jinjaMatch) => {\n    let inner = jinjaMatch\n      .replace(\n        /\\b(config|ref|source|is_incremental|this|var|materialized|unique_key|on_schema_change|incremental_strategy|cluster_by|tags)\\b/g,\n        '<span class=\"text-warning font-semibold\">$1</span>',\n      )\n      .replace(/(\\{\\{|\\}\\}|\\{%|%\\})/g, '<span class=\"text-chart-1 font-bold\">$1</span>')\n    return `<span class=\"bg-chart-1/10 px-1 py-0.5 rounded text-chart-1\">${inner}</span>`\n  })\n\n  // SQL Keywords\n  result = result.replace(\n    /\\b(WITH|SELECT|FROM|JOIN|LEFT JOIN|INNER JOIN|RIGHT JOIN|FULL JOIN|ON|WHERE|GROUP BY|ORDER BY|AND|OR|NOT|AS|CASE|WHEN|THEN|ELSE|END|MERGE INTO|USING|WHEN MATCHED|WHEN NOT MATCHED|INSERT|UPDATE|SET|VALUES|OVER|PARTITION BY)\\b/g,\n    '<span class=\"text-info font-semibold\">$1</span>',\n  )\n\n  // SQL Aggregate & Utility Functions\n  result = result.replace(\n    /\\b(coalesce|sum|count|max|min|avg|round|cast|date_trunc|concat)\\b/gi,\n    '<span class=\"text-chart-2 font-medium\">$1</span>',\n  )\n\n  // Strings\n  result = result.replace(/(&#039;[^&#039;]*&#039;)/g, '<span class=\"text-success\">$1</span>')\n\n  return result\n}\n\nfunction highlightCompiledSqlLine(line: string): string {\n  if (!line) return ''\n  const escaped = escapeHtml(line)\n\n  // Comments\n  if (escaped.trim().startsWith('--')) {\n    return `<span class=\"text-muted-foreground/60 italic\">${escaped}</span>`\n  }\n\n  let result = escaped.replace(\n    /\\b(MERGE INTO|USING|WHEN MATCHED|WHEN NOT MATCHED|THEN UPDATE SET|THEN INSERT|VALUES|WITH|SELECT|FROM|LEFT JOIN|INNER JOIN|RIGHT JOIN|JOIN|ON|WHERE|GROUP BY|ORDER BY|AND|OR|NOT|AS|CASE|WHEN|THEN|ELSE|END)\\b/g,\n    '<span class=\"text-info font-semibold\">$1</span>',\n  )\n\n  result = result.replace(\n    /\\b(coalesce|sum|count|max|min|avg|round|cast)\\b/gi,\n    '<span class=\"text-chart-2 font-medium\">$1</span>',\n  )\n\n  // Qualified warehouse identifiers in double quotes\n  result = result.replace(/(&quot;[A-Z0-9_]+&quot;)/g, '<span class=\"text-warning font-medium\">$1</span>')\n\n  // Strings\n  result = result.replace(/(&#039;[^&#039;]*&#039;)/g, '<span class=\"text-success\">$1</span>')\n\n  return result\n}\n\n// --- Actions ---\nfunction handleBuildModel() {\n  if (isBuilding.value) return\n  isBuilding.value = true\n  setTimeout(() => {\n    isBuilding.value = false\n    buildStatusText.value = 'Success · Built in 14.2s (Just now)'\n    lastBuildTime.value = 'Just now'\n  }, 1200)\n}\n\nfunction handleTestModel() {\n  if (isTesting.value) return\n  isTesting.value = true\n  setTimeout(() => {\n    isTesting.value = false\n  }, 900)\n}\n\nfunction copyModelRef() {\n  if (typeof navigator !== 'undefined' && navigator.clipboard) {\n    navigator.clipboard.writeText(\"{{ ref('fct_orders') }}\")\n    copiedRef.value = true\n    setTimeout(() => {\n      copiedRef.value = false\n    }, 2000)\n  }\n}\n\nfunction copySourceSql() {\n  if (typeof navigator !== 'undefined' && navigator.clipboard) {\n    navigator.clipboard.writeText(modelSqlSource)\n    copiedSql.value = true\n    setTimeout(() => {\n      copiedSql.value = false\n    }, 2000)\n  }\n}\n\nfunction copyCompiledSql() {\n  if (typeof navigator !== 'undefined' && navigator.clipboard) {\n    navigator.clipboard.writeText(compiledSqlSource)\n    copiedCompiled.value = true\n    setTimeout(() => {\n      copiedCompiled.value = false\n    }, 2000)\n  }\n}\n</script>\n\n<template>\n  <div\n    data-slot=\"dbt-model-graph\"\n    :class=\"\n      cn(\n        'bg-background text-foreground border-border flex w-full flex-col overflow-hidden rounded-xl border shadow-xs',\n        props.class,\n      )\n    \"\n  >\n    <!-- TOP HEADER -->\n    <header class=\"border-border bg-card/70 border-b px-4 py-3 sm:px-6\">\n      <div class=\"flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between\">\n        <!-- Left: Model Identity & Badges -->\n        <div class=\"flex flex-wrap items-center gap-2.5\">\n          <div class=\"bg-primary/10 text-primary flex size-8 items-center justify-center rounded-lg shadow-xs\">\n            <Workflow class=\"size-4\" />\n          </div>\n\n          <div class=\"flex flex-wrap items-center gap-2\">\n            <div class=\"flex items-center gap-1.5 font-mono text-sm font-semibold tracking-tight\">\n              <span class=\"text-muted-foreground font-normal\">model.analytics.</span>\n              <span class=\"text-foreground\">fct_orders</span>\n            </div>\n\n            <!-- Copy ref pill -->\n            <button\n              type=\"button\"\n              class=\"border-border bg-muted/50 text-muted-foreground hover:text-foreground hover:bg-muted inline-flex min-h-6 items-center gap-1 rounded-md border px-2 py-0.5 font-mono text-xs transition-colors\"\n              title=\"Copy dbt ref() macro\"\n              @click=\"copyModelRef\"\n            >\n              <Check v-if=\"copiedRef\" class=\"text-success size-3\" />\n              <Copy v-else class=\"size-3\" />\n              <span>{{ copiedRef ? 'Copied Ref!' : dbtMacroRef }}</span>\n            </button>\n          </div>\n\n          <div class=\"flex flex-wrap items-center gap-1.5\">\n            <!-- Materialization Badge -->\n            <Badge wrap variant=\"outline\" class=\"gap-1 font-mono text-xs font-normal\">\n              <Layers class=\"text-info size-3\" />\n              Table · Incremental\n            </Badge>\n\n            <!-- dbt Package Badge -->\n            <Badge wrap variant=\"secondary\" class=\"font-mono text-xs font-normal\"> analytics_dw v1.8 </Badge>\n\n            <!-- Build Status Badge -->\n            <Badge\n              wrap\n              variant=\"outline\"\n              class=\"border-success/30 bg-success/10 text-success gap-1.5 font-mono text-xs font-medium\"\n            >\n              <span class=\"bg-success size-1.5 animate-pulse rounded-full\" />\n              {{ buildStatusText }}\n            </Badge>\n          </div>\n        </div>\n\n        <!-- Right: Primary & Secondary Actions -->\n        <div class=\"flex flex-wrap items-center gap-2\">\n          <Button\n            variant=\"outline\"\n            size=\"sm\"\n            class=\"h-8 gap-1.5 text-xs font-medium\"\n            :disabled=\"isTesting\"\n            @click=\"handleTestModel\"\n          >\n            <Loader2 v-if=\"isTesting\" class=\"size-3.5 animate-spin\" />\n            <CheckCircle2 v-else class=\"text-success size-3.5\" />\n            {{ isTesting ? 'Running 7 Tests...' : 'Test Model (dbt test)' }}\n          </Button>\n\n          <Button\n            variant=\"default\"\n            size=\"sm\"\n            class=\"bg-primary text-primary-foreground hover:bg-primary/90 h-8 gap-1.5 text-xs font-semibold shadow-xs\"\n            :disabled=\"isBuilding\"\n            @click=\"handleBuildModel\"\n          >\n            <Loader2 v-if=\"isBuilding\" class=\"size-3.5 animate-spin\" />\n            <Play v-else class=\"size-3.5 fill-current\" />\n            {{ isBuilding ? 'Building (dbt run)...' : 'Build Model (dbt run)' }}\n          </Button>\n        </div>\n      </div>\n\n      <!-- Secondary Metadata Strip -->\n      <div\n        class=\"border-border/60 text-muted-foreground mt-3 flex flex-wrap items-center gap-x-4 gap-y-1.5 border-t pt-2.5 font-mono text-xs\"\n      >\n        <div class=\"flex items-center gap-1.5\">\n          <Database class=\"text-info size-3\" />\n          <span>Warehouse:</span>\n          <span class=\"text-foreground font-medium\">Snowflake PROD_WH (XS)</span>\n        </div>\n        <div class=\"flex items-center gap-1.5\">\n          <HardDrive class=\"text-warning size-3\" />\n          <span>Target Schema:</span>\n          <span class=\"text-foreground font-medium\">ANALYTICS_PROD.MARTS</span>\n        </div>\n        <div class=\"flex items-center gap-1.5\">\n          <Clock class=\"text-muted-foreground size-3\" />\n          <span>Last Built:</span>\n          <span class=\"text-foreground\">{{ lastBuildTime }}</span>\n        </div>\n        <div class=\"flex items-center gap-1.5\">\n          <ShieldCheck class=\"text-success size-3\" />\n          <span>Contract Tests:</span>\n          <span class=\"text-success font-medium\">7/7 Passing</span>\n        </div>\n        <div class=\"flex items-center gap-1.5\">\n          <Table2 class=\"text-chart-1 size-3\" />\n          <span>Row Count:</span>\n          <span class=\"text-foreground\">2,840,190 rows</span>\n        </div>\n      </div>\n    </header>\n\n    <!-- 2-COLUMN MODEL STUDIO LAYOUT -->\n    <div class=\"divide-border grid flex-1 grid-cols-1 divide-y lg:grid-cols-12 lg:divide-x lg:divide-y-0\">\n      <!-- LEFT PANEL: METADATA & DAG LINEAGE (lg:col-span-5) -->\n      <aside class=\"bg-muted/15 flex flex-col space-y-4 p-4 sm:p-5 lg:col-span-5\">\n        <!-- Interactive Lineage DAG Card -->\n        <Card class=\"border-border bg-card overflow-hidden border p-3.5 shadow-none\">\n          <div class=\"flex flex-wrap items-center justify-between pb-2.5\">\n            <div class=\"flex items-center gap-1.5 text-xs font-semibold\">\n              <GitBranch class=\"text-primary size-3.5\" />\n              <span>DAG Lineage Dependency Graph</span>\n            </div>\n            <Badge wrap variant=\"secondary\" class=\"font-mono text-xs font-normal\"> -1 Upstream · +1 Downstream </Badge>\n          </div>\n\n          <!-- Visual DAG Node Canvas -->\n          <div class=\"border-border/70 bg-muted/30 relative rounded-lg border p-3\">\n            <div class=\"grid grid-cols-3 items-center gap-2 text-xs\">\n              <!-- Upstream Column (3 Nodes) -->\n              <div class=\"space-y-1.5\">\n                <span class=\"text-muted-foreground block text-center font-mono text-xs font-medium\">Upstream (3)</span>\n                <button\n                  v-for=\"node in upstreamNodes\"\n                  :key=\"node.id\"\n                  type=\"button\"\n                  :class=\"\n                    cn(\n                      'focus-visible:ring-ring flex w-full cursor-pointer flex-col rounded-md border p-1.5 text-left transition-[background-color,box-shadow] focus-visible:ring-2 focus-visible:outline-none',\n                      selectedNodeId === node.id\n                        ? 'border-primary bg-primary/10 text-primary shadow-xs'\n                        : 'border-border bg-background hover:bg-muted/80 text-foreground',\n                    )\n                  \"\n                  :aria-pressed=\"selectedNodeId === node.id\"\n                  @click=\"selectedNodeId = node.id\"\n                >\n                  <div class=\"flex flex-wrap items-center justify-between\">\n                    <span class=\"truncate font-mono text-xs font-medium\">{{ node.name }}</span>\n                  </div>\n                  <div\n                    class=\"text-muted-foreground flex flex-wrap items-center justify-between pt-0.5 font-mono text-xs\"\n                  >\n                    <span class=\"uppercase\">{{ node.type }}</span>\n                    <span class=\"bg-success size-1.5 rounded-full\" />\n                  </div>\n                </button>\n              </div>\n\n              <!-- Center Current Node -->\n              <div class=\"flex flex-col items-center justify-center space-y-1 px-1\">\n                <span class=\"text-primary font-mono text-xs font-semibold\">Current Model</span>\n                <button\n                  type=\"button\"\n                  :class=\"\n                    cn(\n                      'border-primary bg-primary/10 ring-primary/20 focus-visible:ring-ring flex w-full cursor-pointer flex-col items-center justify-center rounded-lg border-2 p-2.5 text-center shadow-xs ring-2 focus-visible:ring-2 focus-visible:outline-none',\n                      selectedNodeId === 'fct_orders' && 'ring-primary/40',\n                    )\n                  \"\n                  :aria-pressed=\"selectedNodeId === 'fct_orders'\"\n                  @click=\"selectedNodeId = 'fct_orders'\"\n                >\n                  <Workflow class=\"text-primary mb-1 size-4\" />\n                  <span class=\"text-foreground font-mono text-xs font-bold\">fct_orders</span>\n                  <Badge wrap variant=\"outline\" class=\"border-primary/40 mt-1 font-mono text-xs\"> incremental </Badge>\n                </button>\n              </div>\n\n              <!-- Downstream Column (3 Nodes) -->\n              <div class=\"space-y-1.5\">\n                <span class=\"text-muted-foreground block text-center font-mono text-xs font-medium\"\n                  >Downstream (3)</span\n                >\n                <button\n                  v-for=\"node in downstreamNodes\"\n                  :key=\"node.id\"\n                  type=\"button\"\n                  :class=\"\n                    cn(\n                      'focus-visible:ring-ring flex w-full cursor-pointer flex-col rounded-md border p-1.5 text-left transition-[background-color,box-shadow] focus-visible:ring-2 focus-visible:outline-none',\n                      selectedNodeId === node.id\n                        ? 'border-primary bg-primary/10 text-primary shadow-xs'\n                        : 'border-border bg-background hover:bg-muted/80 text-foreground',\n                    )\n                  \"\n                  :aria-pressed=\"selectedNodeId === node.id\"\n                  @click=\"selectedNodeId = node.id\"\n                >\n                  <div class=\"flex flex-wrap items-center justify-between\">\n                    <span class=\"truncate font-mono text-xs font-medium\">{{ node.name }}</span>\n                  </div>\n                  <div\n                    class=\"text-muted-foreground flex flex-wrap items-center justify-between pt-0.5 font-mono text-xs\"\n                  >\n                    <span class=\"uppercase\">{{ node.type }}</span>\n                    <span class=\"bg-success size-1.5 rounded-full\" />\n                  </div>\n                </button>\n              </div>\n            </div>\n          </div>\n        </Card>\n\n        <!-- Model Documentation & Metadata Card -->\n        <Card class=\"border-border bg-card space-y-3 border p-4 shadow-none\">\n          <div class=\"border-border flex flex-wrap items-center justify-between border-b pb-2\">\n            <div class=\"flex items-center gap-1.5 text-xs font-semibold\">\n              <Info class=\"text-primary size-3.5\" />\n              <span>Model Documentation & Metadata</span>\n            </div>\n            <Badge wrap variant=\"outline\" class=\"font-mono text-xs\"> Contract Enforced </Badge>\n          </div>\n\n          <p class=\"text-muted-foreground text-xs leading-relaxed\">\n            Core transactional orders fact table at individual order grain. Captures gross revenue metrics, sales tax\n            breakdowns, promotional discount allocations, payment gateway fees, and settlement lifecycle stages.\n          </p>\n\n          <div class=\"grid grid-cols-1 gap-2 sm:grid-cols-2\">\n            <div class=\"border-border/60 bg-muted/20 space-y-0.5 rounded-md border p-2 text-xs\">\n              <span class=\"text-muted-foreground text-xs\">Model Owner</span>\n              <div class=\"flex items-center gap-1.5 font-medium\">\n                <User class=\"text-primary size-3\" />\n                <span>Analytics Engineering</span>\n              </div>\n            </div>\n\n            <div class=\"border-border/60 bg-muted/20 space-y-0.5 rounded-md border p-2 text-xs\">\n              <span class=\"text-muted-foreground text-xs\">Freshness SLA</span>\n              <div class=\"text-success flex items-center gap-1.5 font-medium\">\n                <Zap class=\"text-warning size-3\" />\n                <span>&lt; 2 hours (Compliant)</span>\n              </div>\n            </div>\n          </div>\n\n          <!-- Tags -->\n          <div class=\"space-y-1.5 pt-1\">\n            <span class=\"text-muted-foreground flex items-center gap-1 text-xs\">\n              <Tag class=\"size-3\" />\n              Model Tags\n            </span>\n            <div class=\"flex flex-wrap items-center gap-1.5\">\n              <Badge wrap variant=\"secondary\" class=\"font-mono text-xs font-normal\">#finance</Badge>\n              <Badge wrap variant=\"secondary\" class=\"font-mono text-xs font-normal\">#core</Badge>\n              <Badge wrap variant=\"secondary\" class=\"font-mono text-xs font-normal\">#daily_sla</Badge>\n              <Badge wrap variant=\"secondary\" class=\"font-mono text-xs font-normal\">#tier-1-kpi</Badge>\n            </div>\n          </div>\n\n          <!-- Cluster Keys & Strategy -->\n          <div class=\"border-border/60 bg-muted/30 space-y-1.5 rounded-lg border p-2.5 font-mono text-xs\">\n            <div class=\"flex justify-between\">\n              <span class=\"text-muted-foreground\">Incremental Strategy:</span>\n              <span class=\"text-foreground font-semibold\">Merge (unique_key: order_id)</span>\n            </div>\n            <div class=\"flex justify-between\">\n              <span class=\"text-muted-foreground\">Cluster Keys:</span>\n              <span class=\"text-foreground font-semibold\">order_date, customer_id</span>\n            </div>\n          </div>\n        </Card>\n\n        <!-- Upstream Sources & References List -->\n        <Card class=\"border-border bg-card space-y-2.5 border p-4 shadow-none\">\n          <div class=\"flex flex-wrap items-center justify-between\">\n            <div class=\"flex items-center gap-1.5 text-xs font-semibold\">\n              <Link2 class=\"text-info size-3.5\" />\n              <span>Upstream Sources & References ({{ upstreamNodes.length }})</span>\n            </div>\n            <Badge wrap variant=\"secondary\" class=\"font-mono text-xs font-normal\">\n              {{ upstreamNodes.length }} models\n            </Badge>\n          </div>\n\n          <div class=\"space-y-2\">\n            <div\n              v-for=\"node in upstreamNodes\"\n              :key=\"node.id\"\n              class=\"border-border/70 bg-muted/20 hover:bg-muted/40 rounded-lg border p-2.5 text-xs transition-colors\"\n            >\n              <div class=\"flex flex-wrap items-center justify-between\">\n                <span class=\"text-foreground font-mono font-semibold\">{{ node.name }}</span>\n                <Badge wrap variant=\"outline\" class=\"font-mono text-xs uppercase\">\n                  {{ node.type }}\n                </Badge>\n              </div>\n              <p class=\"text-muted-foreground mt-1 text-xs\">\n                {{ node.description }}\n              </p>\n              <div class=\"text-muted-foreground mt-2 flex flex-wrap items-center justify-between font-mono text-xs\">\n                <span>{{ node.rowCount }}</span>\n                <span class=\"text-success font-medium\">{{ node.freshness }}</span>\n              </div>\n            </div>\n          </div>\n        </Card>\n\n        <!-- Downstream Marts & BI Exporters List -->\n        <Card class=\"border-border bg-card space-y-2.5 border p-4 shadow-none\">\n          <div class=\"flex flex-wrap items-center justify-between\">\n            <div class=\"flex items-center gap-1.5 text-xs font-semibold\">\n              <ArrowUpRight class=\"text-warning size-3.5\" />\n              <span>Downstream Marts & BI Exposures ({{ downstreamNodes.length }})</span>\n            </div>\n            <Badge wrap variant=\"secondary\" class=\"font-mono text-xs font-normal\">\n              {{ downstreamNodes.length }} targets\n            </Badge>\n          </div>\n\n          <div class=\"space-y-2\">\n            <div\n              v-for=\"node in downstreamNodes\"\n              :key=\"node.id\"\n              class=\"border-border/70 bg-muted/20 hover:bg-muted/40 rounded-lg border p-2.5 text-xs transition-colors\"\n            >\n              <div class=\"flex flex-wrap items-center justify-between\">\n                <span class=\"text-foreground font-mono font-semibold\">{{ node.name }}</span>\n                <Badge wrap variant=\"secondary\" class=\"font-mono text-xs uppercase\">\n                  {{ node.type }}\n                </Badge>\n              </div>\n              <p class=\"text-muted-foreground mt-1 text-xs\">\n                {{ node.description }}\n              </p>\n              <div class=\"text-muted-foreground mt-2 flex flex-wrap items-center justify-between font-mono text-xs\">\n                <span class=\"truncate pr-2\">Consumers: {{ node.consumers }}</span>\n                <span class=\"text-foreground shrink-0 font-medium\">{{ node.sla }}</span>\n              </div>\n            </div>\n          </div>\n        </Card>\n      </aside>\n\n      <!-- RIGHT PANEL: TABS STUDIO (lg:col-span-7) -->\n      <main class=\"bg-card flex flex-col overflow-hidden lg:col-span-7\">\n        <Tabs v-model=\"activeTab\" default-value=\"model-sql\" class=\"flex flex-1 flex-col\">\n          <!-- Right Tab Header -->\n          <div class=\"border-border bg-muted/30 flex flex-wrap items-center justify-between gap-2 border-b px-4 py-2\">\n            <TabsList class=\"grid h-8 grid-cols-3\">\n              <TabsTrigger value=\"model-sql\" class=\"gap-1.5 text-xs\">\n                <Code2 class=\"text-primary size-3.5\" />\n                <span>Model SQL</span>\n              </TabsTrigger>\n              <TabsTrigger value=\"compiled-sql\" class=\"gap-1.5 text-xs\">\n                <FileCode class=\"text-info size-3.5\" />\n                <span>Compiled SQL</span>\n              </TabsTrigger>\n              <TabsTrigger value=\"contract\" class=\"gap-1.5 text-xs\">\n                <ShieldCheck class=\"text-success size-3.5\" />\n                <span>Model Contract & Tests</span>\n              </TabsTrigger>\n            </TabsList>\n\n            <!-- Actions per active tab -->\n            <div class=\"flex items-center gap-2\">\n              <template v-if=\"activeTab === 'model-sql'\">\n                <Button variant=\"ghost\" size=\"sm\" class=\"h-7 gap-1 text-xs\" @click=\"copySourceSql\">\n                  <Check v-if=\"copiedSql\" class=\"text-success size-3\" />\n                  <Copy v-else class=\"size-3\" />\n                  <span>{{ copiedSql ? 'Copied' : 'Copy SQL' }}</span>\n                </Button>\n              </template>\n\n              <template v-else-if=\"activeTab === 'compiled-sql'\">\n                <Button variant=\"ghost\" size=\"sm\" class=\"h-7 gap-1 text-xs\" @click=\"copyCompiledSql\">\n                  <Check v-if=\"copiedCompiled\" class=\"text-success size-3\" />\n                  <Copy v-else class=\"size-3\" />\n                  <span>{{ copiedCompiled ? 'Copied' : 'Copy Compiled' }}</span>\n                </Button>\n              </template>\n\n              <template v-else-if=\"activeTab === 'contract'\">\n                <Badge wrap variant=\"outline\" class=\"text-success font-mono text-xs\">\n                  {{ passingTestsCount }} Tests Passing\n                </Badge>\n              </template>\n            </div>\n          </div>\n\n          <!-- TAB 1: MODEL SQL -->\n          <TabsContent value=\"model-sql\" class=\"mt-0 flex flex-1 flex-col overflow-hidden\">\n            <!-- Code Bar Meta -->\n            <div\n              class=\"border-border bg-muted/15 text-muted-foreground flex flex-wrap items-center justify-between border-b px-4 py-1.5 font-mono text-xs\"\n            >\n              <div class=\"flex items-center gap-2\">\n                <span class=\"text-foreground font-medium\">fct_orders.sql</span>\n                <span>·</span>\n                <span>Jinja + Snowflake Dialect</span>\n              </div>\n              <div class=\"flex items-center gap-3\">\n                <span>{{ modelSqlLines.length }} lines · {{ modelSqlSource.length }} chars</span>\n              </div>\n            </div>\n\n            <!-- Code Gutter & Viewer -->\n            <div class=\"relative flex flex-1 overflow-auto bg-neutral-950 text-neutral-100 dark:bg-neutral-950\">\n              <!-- Line Numbers Gutter -->\n              <div\n                class=\"w-11 shrink-0 overflow-hidden border-r border-neutral-800 bg-neutral-900/60 py-3 pr-2 text-right font-mono text-xs leading-relaxed text-neutral-500 select-none\"\n              >\n                <div v-for=\"n in modelSqlLines.length\" :key=\"n\">{{ n }}</div>\n              </div>\n\n              <!-- Highlighted Code Body -->\n              <div class=\"flex-1 overflow-auto p-3 font-mono text-xs leading-relaxed\">\n                <div\n                  v-for=\"(line, idx) in modelSqlLines\"\n                  :key=\"idx\"\n                  class=\"font-mono whitespace-pre\"\n                  v-html=\"highlightJinjaSqlLine(line)\"\n                />\n              </div>\n            </div>\n          </TabsContent>\n\n          <!-- TAB 2: COMPILED SQL -->\n          <TabsContent value=\"compiled-sql\" class=\"mt-0 flex flex-1 flex-col overflow-hidden\">\n            <!-- Code Bar Meta -->\n            <div\n              class=\"border-border bg-muted/15 text-muted-foreground flex flex-wrap items-center justify-between border-b px-4 py-1.5 font-mono text-xs\"\n            >\n              <div class=\"flex items-center gap-2\">\n                <span class=\"text-foreground font-medium\"\n                  >target/compiled/analytics_dw/models/marts/fct_orders.sql</span\n                >\n              </div>\n              <div class=\"flex items-center gap-2\">\n                <Badge wrap variant=\"outline\" class=\"font-mono text-xs\"> Est. Cost: 0.14 Credits · 1.4 GB Scan </Badge>\n              </div>\n            </div>\n\n            <!-- Code Gutter & Viewer -->\n            <div class=\"relative flex flex-1 overflow-auto bg-neutral-950 text-neutral-100 dark:bg-neutral-950\">\n              <!-- Line Numbers Gutter -->\n              <div\n                class=\"w-11 shrink-0 overflow-hidden border-r border-neutral-800 bg-neutral-900/60 py-3 pr-2 text-right font-mono text-xs leading-relaxed text-neutral-500 select-none\"\n              >\n                <div v-for=\"n in compiledSqlLines.length\" :key=\"n\">{{ n }}</div>\n              </div>\n\n              <!-- Highlighted Code Body -->\n              <div class=\"flex-1 overflow-auto p-3 font-mono text-xs leading-relaxed\">\n                <div\n                  v-for=\"(line, idx) in compiledSqlLines\"\n                  :key=\"idx\"\n                  class=\"font-mono whitespace-pre\"\n                  v-html=\"highlightCompiledSqlLine(line)\"\n                />\n              </div>\n            </div>\n          </TabsContent>\n\n          <!-- TAB 3: MODEL CONTRACT & TESTS -->\n          <TabsContent value=\"contract\" class=\"mt-0 flex flex-1 flex-col space-y-4 overflow-hidden p-4 sm:p-5\">\n            <!-- Contract Control Bar -->\n            <div class=\"flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n              <div class=\"relative w-full sm:w-72\">\n                <Search class=\"text-muted-foreground absolute top-1/2 left-2.5 size-3.5 -translate-y-1/2\" />\n                <Input\n                  v-model=\"columnSearch\"\n                  placeholder=\"Filter columns or tests...\"\n                  class=\"h-8 pl-8 font-mono text-xs\"\n                />\n              </div>\n\n              <div class=\"flex flex-wrap items-center gap-2\">\n                <Badge wrap variant=\"outline\" class=\"text-success gap-1 font-mono text-xs\">\n                  <ShieldCheck class=\"size-3\" />\n                  contract.enforced: true\n                </Badge>\n                <Badge wrap variant=\"secondary\" class=\"font-mono text-xs\">\n                  {{ filteredColumns.length }} of {{ columns.length }} columns\n                </Badge>\n              </div>\n            </div>\n\n            <!-- Specifications Table -->\n            <Card class=\"border-border flex-1 overflow-hidden border shadow-none\">\n              <div class=\"overflow-x-auto\">\n                <Table>\n                  <TableHeader>\n                    <TableRow class=\"bg-muted/40 hover:bg-muted/40\">\n                      <TableHead class=\"text-xs font-semibold\">Column Name</TableHead>\n                      <TableHead class=\"text-xs font-semibold\">Data Type</TableHead>\n                      <TableHead class=\"text-xs font-semibold\">Nullability</TableHead>\n                      <TableHead class=\"text-xs font-semibold\">Active Tests & Constraints</TableHead>\n                      <TableHead class=\"text-xs font-semibold\">Latency</TableHead>\n                      <TableHead class=\"text-xs font-semibold\">Description</TableHead>\n                    </TableRow>\n                  </TableHeader>\n                  <TableBody>\n                    <TableRow v-for=\"col in filteredColumns\" :key=\"col.name\" class=\"text-xs\">\n                      <TableCell class=\"font-mono font-medium\">\n                        <div class=\"flex items-center gap-1.5\">\n                          <Key v-if=\"col.isPrimaryKey\" class=\"text-warning size-3.5 shrink-0\" />\n                          <Link2 v-else-if=\"col.isForeignKey\" class=\"text-info size-3.5 shrink-0\" />\n                          <span :class=\"cn(col.isPrimaryKey && 'text-warning font-semibold')\">\n                            {{ col.name }}\n                          </span>\n                        </div>\n                      </TableCell>\n                      <TableCell>\n                        <Badge wrap variant=\"secondary\" class=\"font-mono text-xs font-normal\">\n                          {{ col.dataType }}\n                        </Badge>\n                      </TableCell>\n                      <TableCell>\n                        <Badge\n                          wrap\n                          v-if=\"!col.nullable\"\n                          variant=\"outline\"\n                          class=\"text-muted-foreground font-mono text-xs\"\n                        >\n                          NOT NULL\n                        </Badge>\n                        <span v-else class=\"text-muted-foreground font-mono text-xs\">NULLABLE</span>\n                      </TableCell>\n                      <TableCell>\n                        <div class=\"flex flex-wrap items-center gap-1\">\n                          <Badge\n                            wrap\n                            v-if=\"col.isPrimaryKey\"\n                            class=\"border-warning/30 bg-warning/15 text-warning font-mono text-xs\"\n                          >\n                            PK\n                          </Badge>\n                          <Badge\n                            wrap\n                            v-if=\"col.isClusterKey\"\n                            variant=\"secondary\"\n                            class=\"border-chart-1/30 bg-chart-1/15 text-chart-1 font-mono text-xs\"\n                          >\n                            CLUSTER\n                          </Badge>\n                          <Badge\n                            wrap\n                            v-for=\"test in col.tests\"\n                            :key=\"test.name\"\n                            variant=\"secondary\"\n                            class=\"gap-1 font-mono text-xs\"\n                          >\n                            <span class=\"bg-success size-1.5 rounded-full\" />\n                            {{ test.name }}{{ test.detail ? ` (${test.detail})` : '' }}\n                          </Badge>\n                        </div>\n                      </TableCell>\n                      <TableCell class=\"text-muted-foreground font-mono text-xs\">\n                        {{ col.testDuration }}\n                      </TableCell>\n                      <TableCell class=\"text-muted-foreground max-w-[220px] truncate text-xs\">\n                        {{ col.description }}\n                      </TableCell>\n                    </TableRow>\n                  </TableBody>\n                </Table>\n              </div>\n            </Card>\n\n            <!-- Bottom Summary Banner -->\n            <div\n              class=\"border-border bg-muted/20 flex flex-wrap items-center justify-between gap-3 rounded-lg border p-3 text-xs\"\n            >\n              <div class=\"flex items-center gap-2\">\n                <ShieldCheck class=\"text-success size-4\" />\n                <span class=\"text-foreground font-medium\">Model Contract Coverage: 100% Enforced</span>\n              </div>\n              <div class=\"text-muted-foreground flex items-center gap-4 font-mono text-xs\">\n                <span>18 Columns</span>\n                <span>·</span>\n                <span>21 Assertions</span>\n                <span>·</span>\n                <span class=\"text-success font-semibold\">0 Failures</span>\n              </div>\n            </div>\n          </TabsContent>\n        </Tabs>\n      </main>\n    </div>\n  </div>\n</template>\n",
      "type": "registry:block",
      "target": "~/app/components/blocks/DbtModelGraph.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/table.json",
    "https://uipkge.dev/r/vue/tabs.json"
  ],
  "description": "dbt Cloud style data modeling DAG dependency graph, compiled SQL view, and model documentation with lineage tree, Jinja/SQL source editor, compiled warehouse query, and column contract test suite.",
  "categories": [
    "devops",
    "app"
  ]
}