{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "data-quality-metrics",
  "title": "Data Quality Metrics",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-react/blocks/data-quality-metrics/DataQualityMetrics.tsx",
      "content": "'use client'\n\nimport * as React from 'react'\nimport {\n  Activity,\n  AlertCircle,\n  AlertTriangle,\n  Check,\n  CheckCircle2,\n  Clock,\n  Copy,\n  Database,\n  Download,\n  FileCode2,\n  Filter,\n  GitBranch,\n  Layers,\n  RefreshCw,\n  Search,\n  ShieldCheck,\n} from 'lucide-react'\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 { Progress } from '@/components/ui/progress'\nimport { Separator } from '@/components/ui/separator'\nimport {\n  Sheet,\n  SheetClose,\n  SheetContent,\n  SheetDescription,\n  SheetFooter,\n  SheetHeader,\n  SheetTitle,\n} from '@/components/ui/sheet'\nimport { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'\n\nexport type AssertionStatus = 'Passing' | 'Warning' | 'Failed'\nexport type AssertionCategory = 'Completeness' | 'Uniqueness' | 'Validity' | 'Volume' | 'Schema'\n\nexport interface AnomalyRecord {\n  recordId: string\n  column: string\n  value: string\n  reason: string\n}\n\nexport interface AssertionItem {\n  id: string\n  assertionType: string\n  columnName: string\n  category: AssertionCategory\n  ruleDefinition: string\n  targetThreshold: string\n  observedValue: string\n  observedPercent: number\n  failedCount: number\n  totalEvaluated: number\n  status: AssertionStatus\n  statusVariant: 'success' | 'warning' | 'destructive'\n  executionTime: string\n  expectationConfig: Record<string, unknown>\n  remediationQuery: string\n  anomalies: AnomalyRecord[]\n}\n\nexport interface DataQualityMetricsProps {\n  datasetTitle?: string\n  suiteName?: string\n  qualityScore?: number\n  lastRun?: string\n  passedAssertions?: string\n  failedWarnings?: string\n  schemaDriftStatus?: string\n  totalRowsAudited?: string\n  assertions?: AssertionItem[]\n  className?: string\n}\n\nconst defaultAssertions: AssertionItem[] = [\n  {\n    id: 'dq-assert-1',\n    assertionType: 'expect_column_values_to_not_be_null',\n    columnName: 'user_id',\n    category: 'Completeness',\n    ruleDefinition: 'Primary key non-null identity constraint verification across all partition shards.',\n    targetThreshold: '100.0%',\n    observedValue: '100.0%',\n    observedPercent: 100.0,\n    failedCount: 0,\n    totalEvaluated: 1480000,\n    status: 'Passing',\n    statusVariant: 'success',\n    executionTime: '142ms',\n    expectationConfig: {\n      expectation_type: 'expect_column_values_to_not_be_null',\n      kwargs: {\n        column: 'user_id',\n        mostly: 1.0,\n      },\n    },\n    remediationQuery: `-- Primary key check passed cleanly. No quarantine needed.\\nSELECT COUNT(*) FROM production_analytics.dim_users WHERE user_id IS NULL;`,\n    anomalies: [],\n  },\n  {\n    id: 'dq-assert-2',\n    assertionType: 'expect_column_values_to_be_unique',\n    columnName: 'email',\n    category: 'Uniqueness',\n    ruleDefinition: 'Global case-insensitive deduplication check across customer directory.',\n    targetThreshold: '100.0%',\n    observedValue: '100.0%',\n    observedPercent: 100.0,\n    failedCount: 0,\n    totalEvaluated: 1480000,\n    status: 'Passing',\n    statusVariant: 'success',\n    executionTime: '380ms',\n    expectationConfig: {\n      expectation_type: 'expect_column_values_to_be_unique',\n      kwargs: {\n        column: 'email',\n        mostly: 1.0,\n      },\n    },\n    remediationQuery: `-- Zero duplicate emails detected in active partition.\\nSELECT LOWER(email), COUNT(*) FROM production_analytics.dim_users GROUP BY 1 HAVING COUNT(*) > 1;`,\n    anomalies: [],\n  },\n  {\n    id: 'dq-assert-3',\n    assertionType: 'expect_column_values_to_match_regex',\n    columnName: 'phone_e164',\n    category: 'Validity',\n    ruleDefinition: 'International telecommunications ITU-T E.164 format pattern matching (^\\\\+[1-9]\\\\d{1,14}$).',\n    targetThreshold: '≥ 98.0%',\n    observedValue: '98.8%',\n    observedPercent: 98.8,\n    failedCount: 17760,\n    totalEvaluated: 1480000,\n    status: 'Warning',\n    statusVariant: 'warning',\n    executionTime: '890ms',\n    expectationConfig: {\n      expectation_type: 'expect_column_values_to_match_regex',\n      kwargs: {\n        column: 'phone_e164',\n        regex: '^\\\\+[1-9]\\\\d{1,14}$',\n        mostly: 0.98,\n      },\n    },\n    remediationQuery: `-- Quarantine 17,760 legacy unformatted phone numbers for libphonenumber normalization:\\nCREATE OR REPLACE TABLE staging.unformatted_phones AS\\nSELECT user_id, email, phone_e164, 'MALFORMED_E164' AS failure_reason\\nFROM production_analytics.dim_users\\nWHERE phone_e164 NOT RLIKE '^\\\\+[1-9]\\\\d{1,14}$';`,\n    anomalies: [\n      {\n        recordId: 'usr_9941a8',\n        column: 'phone_e164',\n        value: '+1-555-019',\n        reason: 'Invalid E.164 length (incomplete national number)',\n      },\n      {\n        recordId: 'usr_1082fc',\n        column: 'phone_e164',\n        value: '0784910293',\n        reason: 'Missing international country dial prefix (+)',\n      },\n      {\n        recordId: 'usr_7729de',\n        column: 'phone_e164',\n        value: '+44 (0)20 7946',\n        reason: 'Unstripped parentheses and whitespace delimiter',\n      },\n      {\n        recordId: 'usr_4019ab',\n        column: 'phone_e164',\n        value: 'NULL',\n        reason: 'Unexpected empty field on SMS-enrolled user',\n      },\n    ],\n  },\n  {\n    id: 'dq-assert-4',\n    assertionType: 'expect_table_row_count_to_be_between',\n    columnName: 'table: dim_users',\n    category: 'Volume',\n    ruleDefinition: 'Daily snapshot table row count volumetric boundary expectation between 1.0M and 2.0M rows.',\n    targetThreshold: '1.0M .. 2.0M',\n    observedValue: '1,480,000',\n    observedPercent: 100.0,\n    failedCount: 0,\n    totalEvaluated: 1480000,\n    status: 'Passing',\n    statusVariant: 'success',\n    executionTime: '95ms',\n    expectationConfig: {\n      expectation_type: 'expect_table_row_count_to_be_between',\n      kwargs: {\n        min_value: 1000000,\n        max_value: 2000000,\n      },\n    },\n    remediationQuery: `-- Row count volumetric validation passed within safety boundaries (1.48M in [1.0M, 2.0M]).\\nSELECT COUNT(*) AS total_rows FROM production_analytics.dim_users;`,\n    anomalies: [],\n  },\n  {\n    id: 'dq-assert-5',\n    assertionType: 'expect_column_values_to_be_between',\n    columnName: 'age',\n    category: 'Validity',\n    ruleDefinition: 'Demographic account age boundary distribution constraint between 18 and 120 years.',\n    targetThreshold: '100.0%',\n    observedValue: '100.0%',\n    observedPercent: 100.0,\n    failedCount: 0,\n    totalEvaluated: 1480000,\n    status: 'Passing',\n    statusVariant: 'success',\n    executionTime: '210ms',\n    expectationConfig: {\n      expectation_type: 'expect_column_values_to_be_between',\n      kwargs: {\n        column: 'age',\n        min_value: 18,\n        max_value: 120,\n        mostly: 1.0,\n      },\n    },\n    remediationQuery: `-- All verified user ages lie cleanly between min 18 and max 94 (100.0% compliant).\\nSELECT MIN(age), MAX(age), AVG(age) FROM production_analytics.dim_users;`,\n    anomalies: [],\n  },\n]\n\nexport function DataQualityMetrics({\n  datasetTitle = 'production_analytics.dim_users',\n  suiteName = 'user_profile_integrity_v3',\n  qualityScore = 98.4,\n  lastRun = 'Ran 14m ago · 48 assertions evaluated',\n  passedAssertions = '47 / 48 Passing · 98%',\n  failedWarnings = '1 Warning · Null phone numbers 1.2%',\n  schemaDriftStatus = '0 breaking schema changes',\n  totalRowsAudited = '1,480,000 rows',\n  assertions = defaultAssertions,\n  className,\n}: DataQualityMetricsProps) {\n  const [searchQuery, setSearchQuery] = React.useState('')\n  const [selectedStatus, setSelectedStatus] = React.useState<string>('all')\n  const [selectedCategory, setSelectedCategory] = React.useState<string>('all')\n  const [isRunningSuite, setIsRunningSuite] = React.useState(false)\n  const [currentLastRun, setCurrentLastRun] = React.useState(lastRun)\n  const [selectedAssertion, setSelectedAssertion] = React.useState<AssertionItem | null>(null)\n  const [isDrawerOpen, setIsDrawerOpen] = React.useState(false)\n  const [copiedSnippetKey, setCopiedSnippetKey] = React.useState<string | null>(null)\n  const [exportSuccess, setExportSuccess] = React.useState(false)\n  const [anomalyExportSuccess, setAnomalyExportSuccess] = React.useState(false)\n\n  const availableCategories = React.useMemo(() => {\n    const categories = new Set<string>()\n    assertions.forEach((item) => categories.add(item.category))\n    return ['all', ...Array.from(categories)]\n  }, [assertions])\n\n  const filteredAssertions = React.useMemo(() => {\n    const query = searchQuery.trim().toLowerCase()\n    const statusFilter = selectedStatus\n    const categoryFilter = selectedCategory\n\n    return assertions.filter((item) => {\n      const matchesStatus = statusFilter === 'all' || item.status.toLowerCase() === statusFilter.toLowerCase()\n      const matchesCategory = categoryFilter === 'all' || item.category.toLowerCase() === categoryFilter.toLowerCase()\n      const matchesQuery =\n        !query ||\n        item.assertionType.toLowerCase().includes(query) ||\n        item.columnName.toLowerCase().includes(query) ||\n        item.ruleDefinition.toLowerCase().includes(query) ||\n        item.category.toLowerCase().includes(query)\n\n      return matchesStatus && matchesCategory && matchesQuery\n    })\n  }, [assertions, searchQuery, selectedStatus, selectedCategory])\n\n  const handleRunSuite = React.useCallback(() => {\n    if (isRunningSuite) return\n    setIsRunningSuite(true)\n\n    setTimeout(() => {\n      setIsRunningSuite(false)\n      setCurrentLastRun('Ran just now · 48 assertions evaluated')\n    }, 750)\n  }, [isRunningSuite])\n\n  const handleInspectAnomalies = React.useCallback((assertion: AssertionItem) => {\n    setSelectedAssertion(assertion)\n    setIsDrawerOpen(true)\n  }, [])\n\n  const copyCodeSnippet = React.useCallback((key: string, content: string) => {\n    if (typeof navigator !== 'undefined' && navigator.clipboard) {\n      navigator.clipboard.writeText(content)\n      setCopiedSnippetKey(key)\n      setTimeout(() => {\n        setCopiedSnippetKey((curr) => (curr === key ? null : curr))\n      }, 2000)\n    }\n  }, [])\n\n  const exportQualityReport = React.useCallback(() => {\n    const report = {\n      dataset: datasetTitle,\n      suite: suiteName,\n      overallQualityScore: qualityScore,\n      evaluatedAt: new Date().toISOString(),\n      engine: 'Great Expectations v0.18 / SodaCL',\n      summary: {\n        passed: passedAssertions,\n        warnings: failedWarnings,\n        schemaDrift: schemaDriftStatus,\n        totalRows: totalRowsAudited,\n      },\n      assertions,\n    }\n\n    const jsonStr = 'data:text/json;charset=utf-8,' + encodeURIComponent(JSON.stringify(report, null, 2))\n    if (typeof document !== 'undefined') {\n      const link = document.createElement('a')\n      link.setAttribute('href', jsonStr)\n      link.setAttribute('download', `dq-report-${suiteName}-${new Date().toISOString().slice(0, 10)}.json`)\n      document.body.appendChild(link)\n      link.click()\n      link.remove()\n\n      setExportSuccess(true)\n      setTimeout(() => {\n        setExportSuccess(false)\n      }, 2000)\n    }\n  }, [\n    datasetTitle,\n    suiteName,\n    qualityScore,\n    passedAssertions,\n    failedWarnings,\n    schemaDriftStatus,\n    totalRowsAudited,\n    assertions,\n  ])\n\n  const exportAnomalyCsv = React.useCallback(() => {\n    if (!selectedAssertion || selectedAssertion.anomalies.length === 0) return\n\n    const headers = ['Record ID', 'Column', 'Observed Value', 'Failure Reason']\n    const rows = selectedAssertion.anomalies.map((a) => [a.recordId, a.column, `\"${a.value}\"`, `\"${a.reason}\"`])\n    const csvContent = [headers.join(','), ...rows.map((r) => r.join(','))].join('\\n')\n\n    const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' })\n    const url = URL.createObjectURL(blob)\n    const link = document.createElement('a')\n    link.setAttribute('href', url)\n    link.setAttribute('download', `anomalies-${selectedAssertion.columnName}.csv`)\n    document.body.appendChild(link)\n    link.click()\n    link.remove()\n\n    setAnomalyExportSuccess(true)\n    setTimeout(() => {\n      setAnomalyExportSuccess(false)\n    }, 2000)\n  }, [selectedAssertion])\n\n  return (\n    <div data-slot=\"data-quality-metrics\" className={cn('w-full space-y-6', className)}>\n      {/* Header Section */}\n      <Card className=\"border-border bg-card shadow-xs\">\n        <CardContent className=\"p-5 sm:p-6\">\n          <div className=\"flex flex-col gap-6 lg:flex-row lg:items-center lg:justify-between\">\n            {/* Left: Dataset and Suite Metadata */}\n            <div className=\"space-y-2\">\n              <div className=\"flex flex-wrap items-center gap-2.5\">\n                <div className=\"bg-muted text-foreground border-border flex size-9 shrink-0 items-center justify-center rounded-lg border shadow-xs\">\n                  <Database className=\"text-success size-4.5\" />\n                </div>\n                <div>\n                  <div className=\"flex flex-wrap items-center gap-2\">\n                    <h1 className=\"text-foreground font-mono text-lg font-bold tracking-tight break-all sm:text-xl\">\n                      {datasetTitle}\n                    </h1>\n                    <Badge wrap variant=\"secondary\" className=\"font-mono text-xs\">\n                      {suiteName}\n                    </Badge>\n                  </div>\n                  <div className=\"text-muted-foreground flex flex-wrap items-center gap-2 pt-1 text-xs\">\n                    <span className=\"flex items-center gap-1\">\n                      <Clock className=\"size-3.5\" />\n                      {currentLastRun}\n                    </span>\n                    <span className=\"opacity-40\">·</span>\n                    <span className=\"font-mono\">Snowflake DW</span>\n                    <span className=\"opacity-40\">·</span>\n                    <span className=\"font-mono\">dbt Core v1.8</span>\n                  </div>\n                </div>\n              </div>\n            </div>\n\n            {/* Right: Overall Score Card & Action Buttons */}\n            <div className=\"flex flex-col gap-4 sm:flex-row sm:items-center\">\n              {/* Overall Score Pill Card */}\n              <div className=\"border-success/30 bg-success/10 flex flex-wrap items-center gap-3.5 rounded-xl border p-3.5 shadow-xs\">\n                <div className=\"bg-success/20 text-success flex size-11 shrink-0 items-center justify-center rounded-lg\">\n                  <CheckCircle2 className=\"size-6\" />\n                </div>\n                <div className=\"min-w-0 space-y-0.5\">\n                  <div className=\"flex flex-wrap items-baseline gap-2\">\n                    <span className=\"text-success text-success text-2xl font-bold tracking-tight tabular-nums sm:text-3xl\">\n                      {qualityScore}%\n                    </span>\n                    <Badge wrap variant=\"success\" className=\"gap-1 px-2 text-xs font-semibold\">\n                      <ShieldCheck className=\"size-3\" />\n                      Quality Score\n                    </Badge>\n                  </div>\n                  <p className=\"text-muted-foreground text-xs\">Automated Sodacl / GX Engine</p>\n                </div>\n              </div>\n\n              {/* Action Buttons */}\n              <div className=\"flex flex-wrap gap-2.5 sm:flex-col\">\n                <Button\n                  variant=\"default\"\n                  size=\"sm\"\n                  className=\"gap-2 shadow-xs\"\n                  disabled={isRunningSuite}\n                  onClick={handleRunSuite}\n                >\n                  <RefreshCw className={cn('size-4', isRunningSuite && 'animate-spin')} />\n                  <span>{isRunningSuite ? 'Evaluating Suite...' : 'Run Assertions Suite'}</span>\n                </Button>\n\n                <Button variant=\"outline\" size=\"sm\" className=\"gap-2 shadow-xs\" onClick={exportQualityReport}>\n                  {exportSuccess ? <Check className=\"text-success size-4\" /> : <Download className=\"size-4\" />}\n                  <span>{exportSuccess ? 'Report Downloaded!' : 'Export Quality Report'}</span>\n                </Button>\n              </div>\n            </div>\n          </div>\n        </CardContent>\n\n        {/* Sub-bar Contract Guarantee */}\n        <div className=\"bg-muted/40 border-border text-muted-foreground flex flex-col gap-2 border-t px-5 py-2.5 text-xs sm:flex-row sm:items-center sm:justify-between\">\n          <div className=\"flex items-center gap-2 font-mono\">\n            <span className=\"bg-success size-2 rounded-full\" />\n            <span>Schema Contract: Locked v3.2 · Zero Breaking Schema Drift</span>\n          </div>\n          <div className=\"flex items-center gap-3\">\n            <span>\n              Engine SLA: <strong className=\"text-foreground font-medium\">Strict Production</strong>\n            </span>\n            <Separator orientation=\"vertical\" className=\"hidden h-3 sm:block\" />\n            <span>48 assertions evaluated</span>\n          </div>\n        </div>\n      </Card>\n\n      {/* 4 Assertion Metric Cards */}\n      <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n        {/* Card 1: Passed Assertions */}\n        <Card className=\"border-border bg-card hover:border-border shadow-xs transition-colors\">\n          <CardHeader className=\"p-4 pb-2\">\n            <div className=\"flex items-start justify-between gap-2\">\n              <p className=\"text-muted-foreground text-xs font-medium tracking-wider uppercase\">Passed Assertions</p>\n              <div className=\"border-success/20 bg-success/10 text-success flex size-7 items-center justify-center rounded-md border\">\n                <CheckCircle2 className=\"size-4\" />\n              </div>\n            </div>\n            <div className=\"flex items-baseline gap-2 pt-1\">\n              <span className=\"text-foreground font-mono text-2xl font-bold tracking-tight tabular-nums\">47 / 48</span>\n              <Badge wrap variant=\"success\" className=\"text-xs font-medium\">\n                98% Passing\n              </Badge>\n            </div>\n          </CardHeader>\n          <CardContent className=\"space-y-2 p-4 pt-1\">\n            <Progress value={98} className=\"h-1.5 w-full\" />\n            <p className=\"text-muted-foreground text-xs\">{passedAssertions}</p>\n          </CardContent>\n        </Card>\n\n        {/* Card 2: Failed / Warnings */}\n        <Card className=\"border-border bg-card hover:border-border shadow-xs transition-colors\">\n          <CardHeader className=\"p-4 pb-2\">\n            <div className=\"flex items-start justify-between gap-2\">\n              <p className=\"text-muted-foreground text-xs font-medium tracking-wider uppercase\">Failed / Warnings</p>\n              <div className=\"border-warning/20 bg-warning/10 text-warning flex size-7 items-center justify-center rounded-md border\">\n                <AlertTriangle className=\"size-4\" />\n              </div>\n            </div>\n            <div className=\"flex items-baseline gap-2 pt-1\">\n              <span className=\"text-foreground font-mono text-2xl font-bold tracking-tight tabular-nums\">\n                1 Warning\n              </span>\n              <Badge wrap variant=\"warning\" className=\"text-xs font-medium\">\n                1.2% Non-conformant\n              </Badge>\n            </div>\n          </CardHeader>\n          <CardContent className=\"space-y-2 p-4 pt-1\">\n            <Progress value={1.2} className=\"h-1.5 w-full\" />\n            <p className=\"text-muted-foreground text-xs\">{failedWarnings}</p>\n          </CardContent>\n        </Card>\n\n        {/* Card 3: Schema Drift Status */}\n        <Card className=\"border-border bg-card hover:border-border shadow-xs transition-colors\">\n          <CardHeader className=\"p-4 pb-2\">\n            <div className=\"flex items-start justify-between gap-2\">\n              <p className=\"text-muted-foreground text-xs font-medium tracking-wider uppercase\">Schema Drift Status</p>\n              <div className=\"border-info/20 bg-info/10 text-info flex size-7 items-center justify-center rounded-md border\">\n                <GitBranch className=\"size-4\" />\n              </div>\n            </div>\n            <div className=\"flex items-baseline gap-2 pt-1\">\n              <span className=\"text-foreground font-mono text-2xl font-bold tracking-tight tabular-nums\">\n                0 Breaking\n              </span>\n              <Badge wrap variant=\"outline\" className=\"text-success text-xs font-medium\">\n                No Drift\n              </Badge>\n            </div>\n          </CardHeader>\n          <CardContent className=\"space-y-2 p-4 pt-1\">\n            <div className=\"bg-muted/40 flex items-center justify-between gap-x-2 rounded-md px-2 py-1 text-xs\">\n              <span className=\"text-muted-foreground\">Columns Synced</span>\n              <span className=\"text-foreground font-mono font-medium\">14 / 14 matched</span>\n            </div>\n            <p className=\"text-muted-foreground text-xs\">{schemaDriftStatus}</p>\n          </CardContent>\n        </Card>\n\n        {/* Card 4: Total Rows Audited */}\n        <Card className=\"border-border bg-card hover:border-border shadow-xs transition-colors\">\n          <CardHeader className=\"p-4 pb-2\">\n            <div className=\"flex items-start justify-between gap-2\">\n              <p className=\"text-muted-foreground text-xs font-medium tracking-wider uppercase\">Total Rows Audited</p>\n              <div className=\"bg-muted text-foreground border-border flex size-7 items-center justify-center rounded-md border\">\n                <Layers className=\"size-4\" />\n              </div>\n            </div>\n            <div className=\"flex items-baseline gap-2 pt-1\">\n              <span className=\"text-foreground font-mono text-2xl font-bold tracking-tight tabular-nums\">\n                1,480,000\n              </span>\n              <Badge wrap variant=\"outline\" className=\"font-mono text-xs font-normal\">\n                1.48M Rows\n              </Badge>\n            </div>\n          </CardHeader>\n          <CardContent className=\"space-y-2 p-4 pt-1\">\n            <div className=\"bg-muted/40 flex items-center justify-between gap-x-2 rounded-md px-2 py-1 text-xs\">\n              <span className=\"text-muted-foreground\">Partition Range</span>\n              <span className=\"text-foreground font-mono font-medium\">1.0M .. 2.0M</span>\n            </div>\n            <p className=\"text-muted-foreground text-xs\">{totalRowsAudited}</p>\n          </CardContent>\n        </Card>\n      </div>\n\n      {/* Data Quality Test Assertions Table Card */}\n      <Card className=\"border-border bg-card shadow-xs\">\n        <CardHeader className=\"flex flex-col gap-4 pb-4 sm:flex-row sm:items-center sm:justify-between\">\n          <div>\n            <div className=\"flex items-center gap-2\">\n              <CardTitle className=\"text-base font-semibold\">Data Quality Test Assertions</CardTitle>\n              <Badge wrap variant=\"secondary\" className=\"font-mono text-xs\">\n                {filteredAssertions.length} of {assertions.length} Assertions\n              </Badge>\n            </div>\n            <CardDescription className=\"text-xs\">\n              Automated expectations, boundary validations, regex format rules, and volume anomaly checks.\n            </CardDescription>\n          </div>\n\n          {/* Filter Pills by Status */}\n          <div className=\"flex flex-wrap items-center gap-1.5\">\n            <button\n              type=\"button\"\n              className={cn(\n                'focus-visible:ring-ring inline-flex items-center rounded-full border px-2.5 py-1 text-xs font-medium transition-colors focus-visible:ring-2 focus-visible:outline-none',\n                selectedStatus === '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              onClick={() => setSelectedStatus('all')}\n            >\n              All Assertions ({assertions.length})\n            </button>\n            <button\n              type=\"button\"\n              className={cn(\n                'focus-visible:ring-ring inline-flex items-center rounded-full border px-2.5 py-1 text-xs font-medium transition-colors focus-visible:ring-2 focus-visible:outline-none',\n                selectedStatus === 'passing'\n                  ? 'border-success bg-success bg-success text-white shadow-xs'\n                  : 'border-border bg-card text-muted-foreground hover:bg-accent hover:text-foreground',\n              )}\n              onClick={() => setSelectedStatus('passing')}\n            >\n              Passing (4)\n            </button>\n            <button\n              type=\"button\"\n              className={cn(\n                'focus-visible:ring-ring inline-flex items-center rounded-full border px-2.5 py-1 text-xs font-medium transition-colors focus-visible:ring-2 focus-visible:outline-none',\n                selectedStatus === 'warning'\n                  ? 'border-warning bg-warning bg-warning text-white shadow-xs'\n                  : 'border-border bg-card text-muted-foreground hover:bg-accent hover:text-foreground',\n              )}\n              onClick={() => setSelectedStatus('warning')}\n            >\n              Warnings (1)\n            </button>\n          </div>\n        </CardHeader>\n\n        {/* Filter & Search Toolbar */}\n        <div className=\"border-border/60 border-t p-4 pt-3 pb-3\">\n          <div className=\"flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between\">\n            <div className=\"relative flex-1\">\n              <Search className=\"text-muted-foreground pointer-events-none absolute top-1/2 left-3 size-3.5 -translate-y-1/2\" />\n              <input\n                value={searchQuery}\n                onChange={(e) => setSearchQuery(e.target.value)}\n                type=\"text\"\n                placeholder=\"Search by assertion type, column name, or rule definition...\"\n                className=\"border-border bg-background placeholder:text-muted-foreground focus-visible:ring-ring h-8 w-full rounded-md border px-3 pl-8 text-xs focus-visible:ring-2 focus-visible:outline-none\"\n              />\n            </div>\n\n            <div className=\"flex flex-wrap items-center gap-1.5\">\n              <span className=\"text-muted-foreground mr-1 flex items-center gap-1 text-xs font-medium\">\n                <Filter className=\"size-3\" />\n                Category:\n              </span>\n              {availableCategories.map((cat) => (\n                <button\n                  key={cat}\n                  type=\"button\"\n                  className={cn(\n                    'focus-visible:ring-ring inline-flex items-center rounded-md border px-2 py-1 font-mono text-xs font-medium transition-colors focus-visible:ring-2 focus-visible:outline-none',\n                    selectedCategory === cat\n                      ? 'border-foreground bg-foreground text-background shadow-xs'\n                      : 'border-border bg-card text-muted-foreground hover:bg-accent hover:text-foreground',\n                  )}\n                  onClick={() => setSelectedCategory(cat)}\n                >\n                  {cat === 'all' ? 'All Categories' : cat}\n                </button>\n              ))}\n            </div>\n          </div>\n        </div>\n\n        {/* Table Container */}\n        <CardContent className=\"p-0\">\n          <div className=\"border-border/60 overflow-x-auto border-t\">\n            <Table>\n              <TableHeader className=\"bg-muted/50\">\n                <TableRow>\n                  <TableHead className=\"min-w-[260px] text-xs\">Assertion & Target Column</TableHead>\n                  <TableHead className=\"min-w-[100px] text-xs\">Category</TableHead>\n                  <TableHead className=\"min-w-[120px] text-xs\">Target Threshold</TableHead>\n                  <TableHead className=\"min-w-[120px] text-xs\">Observed Value</TableHead>\n                  <TableHead className=\"min-w-[110px] text-xs\">Status</TableHead>\n                  <TableHead className=\"min-w-[130px] text-right text-xs\">Actions</TableHead>\n                </TableRow>\n              </TableHeader>\n              <TableBody>\n                {filteredAssertions.map((assertion) => (\n                  <TableRow key={assertion.id} className=\"hover:bg-muted/20 transition-colors\">\n                    {/* Assertion Type & Target Column */}\n                    <TableCell className=\"py-3\">\n                      <div className=\"space-y-1\">\n                        <div className=\"flex flex-wrap items-center gap-2\">\n                          <Badge wrap variant=\"outline\" className=\"border-border font-mono text-xs font-semibold\">\n                            {assertion.columnName}\n                          </Badge>\n                          <span className=\"text-foreground font-mono text-xs font-medium\">\n                            {assertion.assertionType}\n                          </span>\n                        </div>\n                        <p className=\"text-muted-foreground max-w-sm text-xs leading-relaxed sm:max-w-md\">\n                          {assertion.ruleDefinition}\n                        </p>\n                      </div>\n                    </TableCell>\n\n                    {/* Category */}\n                    <TableCell className=\"py-3\">\n                      <Badge wrap variant=\"secondary\" className=\"font-normal\">\n                        {assertion.category}\n                      </Badge>\n                    </TableCell>\n\n                    {/* Target Threshold */}\n                    <TableCell className=\"py-3\">\n                      <span className=\"text-muted-foreground font-mono text-xs font-medium\">\n                        {assertion.targetThreshold}\n                      </span>\n                    </TableCell>\n\n                    {/* Observed Value */}\n                    <TableCell className=\"py-3\">\n                      <div className=\"space-y-0.5 font-mono text-xs\">\n                        <span\n                          className={cn(\n                            'font-bold tabular-nums',\n                            assertion.status === 'Passing' ? 'text-success' : 'text-warning',\n                          )}\n                        >\n                          {assertion.observedValue}\n                        </span>\n                        <span className=\"text-muted-foreground/70 block text-xs\">{assertion.executionTime} eval</span>\n                      </div>\n                    </TableCell>\n\n                    {/* Status Badge */}\n                    <TableCell className=\"py-3\">\n                      <Badge wrap variant={assertion.statusVariant} className=\"gap-1 text-xs font-medium\">\n                        {assertion.status === 'Passing' ? (\n                          <CheckCircle2 className=\"size-3\" />\n                        ) : assertion.status === 'Warning' ? (\n                          <AlertTriangle className=\"size-3\" />\n                        ) : (\n                          <AlertCircle className=\"size-3\" />\n                        )}\n                        {assertion.status}\n                      </Badge>\n                    </TableCell>\n\n                    {/* Action Button */}\n                    <TableCell className=\"py-3 text-right\">\n                      <Button\n                        variant=\"outline\"\n                        size=\"xs\"\n                        className=\"h-7 gap-1 text-xs font-medium shadow-xs\"\n                        onClick={() => handleInspectAnomalies(assertion)}\n                      >\n                        <Activity className=\"size-3\" />\n                        <span>Inspect Anomalies</span>\n                      </Button>\n                    </TableCell>\n                  </TableRow>\n                ))}\n\n                {filteredAssertions.length === 0 && (\n                  <TableRow>\n                    <TableCell colSpan={6} className=\"py-8 text-center\">\n                      <div className=\"flex flex-col items-center justify-center gap-1.5\">\n                        <ShieldCheck className=\"text-success size-7\" />\n                        <p className=\"text-foreground text-sm font-medium\">No assertions match your filter query</p>\n                        <p className=\"text-muted-foreground text-xs\">\n                          All assertions meet standard quality constraints.\n                        </p>\n                      </div>\n                    </TableCell>\n                  </TableRow>\n                )}\n              </TableBody>\n            </Table>\n          </div>\n\n          {/* Table Footer */}\n          <div className=\"border-border/60 bg-muted/20 text-muted-foreground flex flex-col gap-2 border-t px-4 py-2.5 text-xs sm:flex-row sm:items-center sm:justify-between\">\n            <div className=\"flex items-center gap-2\">\n              <span className=\"bg-success size-2 rounded-full\" />\n              <span>Great Expectations Assertions Runner: 100% evaluated</span>\n            </div>\n            <span className=\"font-mono text-xs\">Dataset: {datasetTitle} · Last Batch: 1,480,000 rows</span>\n          </div>\n        </CardContent>\n      </Card>\n\n      {/* Anomaly Inspector Drawer / Sheet */}\n      <Sheet open={isDrawerOpen} onOpenChange={setIsDrawerOpen}>\n        <SheetContent className=\"w-full space-y-6 overflow-y-auto p-6 sm:max-w-xl md:max-w-2xl\">\n          {selectedAssertion && (\n            <>\n              <SheetHeader className=\"space-y-2 p-0 text-left\">\n                <div className=\"flex items-center justify-between gap-3 pr-6\">\n                  <div className=\"flex items-center gap-2\">\n                    <Badge\n                      wrap\n                      variant={selectedAssertion.statusVariant}\n                      className=\"gap-1 font-mono text-xs font-semibold\"\n                    >\n                      {selectedAssertion.status === 'Passing' ? (\n                        <CheckCircle2 className=\"size-3\" />\n                      ) : (\n                        <AlertTriangle className=\"size-3\" />\n                      )}\n                      {selectedAssertion.status.toUpperCase()}\n                    </Badge>\n                    <Badge wrap variant=\"outline\" className=\"font-mono text-xs font-semibold\">\n                      {selectedAssertion.category}\n                    </Badge>\n                  </div>\n\n                  <span className=\"text-muted-foreground font-mono text-xs\">\n                    Latency: {selectedAssertion.executionTime}\n                  </span>\n                </div>\n\n                <SheetTitle className=\"text-lg font-bold tracking-tight\">{selectedAssertion.assertionType}</SheetTitle>\n                <SheetDescription className=\"text-foreground/90 font-mono text-xs\">\n                  Target Column:{' '}\n                  <strong className=\"text-foreground font-semibold\">{selectedAssertion.columnName}</strong>\n                </SheetDescription>\n              </SheetHeader>\n\n              <div className=\"space-y-5 text-xs\">\n                {/* Summary Metrics Cards Grid */}\n                <div className=\"grid grid-cols-2 gap-2.5 sm:grid-cols-4\">\n                  <div className=\"bg-muted/40 border-border/80 rounded-lg border p-3\">\n                    <span className=\"text-muted-foreground text-xs\">Target Threshold</span>\n                    <p className=\"text-foreground mt-1 font-mono text-sm font-bold\">\n                      {selectedAssertion.targetThreshold}\n                    </p>\n                  </div>\n                  <div className=\"bg-muted/40 border-border/80 rounded-lg border p-3\">\n                    <span className=\"text-muted-foreground text-xs\">Observed Pass Rate</span>\n                    <p\n                      className={cn(\n                        'mt-1 font-mono text-sm font-bold tabular-nums',\n                        selectedAssertion.status === 'Passing' ? 'text-success' : 'text-warning',\n                      )}\n                    >\n                      {selectedAssertion.observedValue}\n                    </p>\n                  </div>\n                  <div className=\"bg-muted/40 border-border/80 rounded-lg border p-3\">\n                    <span className=\"text-muted-foreground text-xs\">Audited Records</span>\n                    <p className=\"text-foreground mt-1 font-mono text-sm font-bold tabular-nums\">\n                      {selectedAssertion.totalEvaluated.toLocaleString()}\n                    </p>\n                  </div>\n                  <div className=\"bg-muted/40 border-border/80 rounded-lg border p-3\">\n                    <span className=\"text-muted-foreground text-xs\">Failed Anomalies</span>\n                    <p\n                      className={cn(\n                        'mt-1 font-mono text-sm font-bold tabular-nums',\n                        selectedAssertion.failedCount > 0 ? 'text-warning' : 'text-success',\n                      )}\n                    >\n                      {selectedAssertion.failedCount.toLocaleString()}\n                    </p>\n                  </div>\n                </div>\n\n                {/* Expectation Configuration DSL Box */}\n                <div className=\"space-y-2\">\n                  <div className=\"flex items-center justify-between gap-x-2\">\n                    <h3 className=\"text-muted-foreground text-xs font-semibold tracking-wider uppercase\">\n                      Great Expectations Specification\n                    </h3>\n                    <Button\n                      variant=\"ghost\"\n                      size=\"xs\"\n                      className=\"h-6 gap-1 px-2 text-xs\"\n                      onClick={() =>\n                        copyCodeSnippet('dsl', JSON.stringify(selectedAssertion.expectationConfig, null, 2))\n                      }\n                    >\n                      {copiedSnippetKey === 'dsl' ? (\n                        <Check className=\"text-success size-3\" />\n                      ) : (\n                        <Copy className=\"size-3\" />\n                      )}\n                      <span>{copiedSnippetKey === 'dsl' ? 'Copied' : 'Copy Config'}</span>\n                    </Button>\n                  </div>\n                  <div className=\"overflow-hidden rounded-md border bg-zinc-950 font-mono text-xs text-zinc-100 shadow-inner\">\n                    <div className=\"text-muted-foreground flex items-center gap-2 border-b border-zinc-800 bg-zinc-900/90 px-3 py-1.5 text-xs\">\n                      <FileCode2 className=\"size-3.5\" />\n                      <span>expectation_suite.json</span>\n                    </div>\n                    <pre className=\"overflow-x-auto p-3 text-xs leading-relaxed text-zinc-300 select-text\">\n                      {JSON.stringify(selectedAssertion.expectationConfig, null, 2)}\n                    </pre>\n                  </div>\n                </div>\n\n                {/* Anomalous Samples Table or Clean Pass State */}\n                <div className=\"space-y-2\">\n                  <div className=\"flex items-center justify-between gap-x-2\">\n                    <h3 className=\"text-muted-foreground text-xs font-semibold tracking-wider uppercase\">\n                      Anomalous Sample Records\n                    </h3>\n                    {selectedAssertion.anomalies.length > 0 && (\n                      <span className=\"text-muted-foreground font-mono text-xs\">\n                        Showing {selectedAssertion.anomalies.length} failure samples\n                      </span>\n                    )}\n                  </div>\n\n                  {selectedAssertion.anomalies.length > 0 ? (\n                    <div className=\"border-border/80 overflow-hidden rounded-md border shadow-xs\">\n                      <Table>\n                        <TableHeader className=\"bg-muted/40\">\n                          <TableRow>\n                            <TableHead className=\"text-xs\">Record ID</TableHead>\n                            <TableHead className=\"text-xs\">Column</TableHead>\n                            <TableHead className=\"text-xs\">Observed Value</TableHead>\n                            <TableHead className=\"text-xs\">Diagnostic Reason</TableHead>\n                          </TableRow>\n                        </TableHeader>\n                        <TableBody>\n                          {selectedAssertion.anomalies.map((anomaly) => (\n                            <TableRow key={anomaly.recordId}>\n                              <TableCell className=\"font-mono text-xs font-medium\">{anomaly.recordId}</TableCell>\n                              <TableCell className=\"font-mono text-xs\">{anomaly.column}</TableCell>\n                              <TableCell className=\"text-destructive font-mono text-xs font-semibold\">\n                                {anomaly.value}\n                              </TableCell>\n                              <TableCell className=\"text-muted-foreground text-xs\">{anomaly.reason}</TableCell>\n                            </TableRow>\n                          ))}\n                        </TableBody>\n                      </Table>\n                    </div>\n                  ) : (\n                    <div className=\"bg-muted/20 border-border/80 flex flex-col items-center justify-center gap-1.5 rounded-md border p-6 text-center\">\n                      <CheckCircle2 className=\"text-success size-6\" />\n                      <p className=\"text-foreground text-xs font-semibold\">Zero Anomalies Detected</p>\n                      <p className=\"text-muted-foreground text-xs\">\n                        All {selectedAssertion.totalEvaluated.toLocaleString()} audited records strictly satisfied the\n                        expectation rule.\n                      </p>\n                    </div>\n                  )}\n                </div>\n\n                {/* Quarantine SQL Script */}\n                <div className=\"space-y-2\">\n                  <div className=\"flex items-center justify-between gap-x-2\">\n                    <h3 className=\"text-muted-foreground text-xs font-semibold tracking-wider uppercase\">\n                      Quarantine & Remediation SQL\n                    </h3>\n                    <Button\n                      variant=\"ghost\"\n                      size=\"xs\"\n                      className=\"h-6 gap-1 px-2 text-xs\"\n                      onClick={() => copyCodeSnippet('sql', selectedAssertion.remediationQuery)}\n                    >\n                      {copiedSnippetKey === 'sql' ? (\n                        <Check className=\"text-success size-3\" />\n                      ) : (\n                        <Copy className=\"size-3\" />\n                      )}\n                      <span>{copiedSnippetKey === 'sql' ? 'Copied' : 'Copy SQL'}</span>\n                    </Button>\n                  </div>\n                  <div className=\"border-border bg-muted/60 rounded-md border p-3 font-mono text-xs leading-relaxed select-text\">\n                    <pre className=\"text-foreground overflow-x-auto whitespace-pre-wrap\">\n                      {selectedAssertion.remediationQuery}\n                    </pre>\n                  </div>\n                </div>\n              </div>\n\n              <SheetFooter className=\"border-border/80 flex flex-row items-center justify-end gap-2 border-t pt-4\">\n                <SheetClose asChild>\n                  <Button variant=\"outline\" size=\"sm\" className=\"text-xs\">\n                    Close\n                  </Button>\n                </SheetClose>\n\n                {selectedAssertion.anomalies.length > 0 && (\n                  <Button\n                    variant=\"default\"\n                    size=\"sm\"\n                    className=\"gap-1.5 text-xs font-medium shadow-xs\"\n                    onClick={exportAnomalyCsv}\n                  >\n                    {anomalyExportSuccess ? (\n                      <Check className=\"text-success size-3.5\" />\n                    ) : (\n                      <Download className=\"size-3.5\" />\n                    )}\n                    <span>{anomalyExportSuccess ? 'Anomalies Exported!' : 'Export Anomaly CSV'}</span>\n                  </Button>\n                )}\n              </SheetFooter>\n            </>\n          )}\n        </SheetContent>\n      </Sheet>\n    </div>\n  )\n}\n",
      "type": "registry:block",
      "target": "~/components/blocks/DataQualityMetrics.tsx"
    }
  ],
  "dependencies": [
    "lucide-react"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/react/badge.json",
    "https://uipkge.dev/r/react/button.json",
    "https://uipkge.dev/r/react/card.json",
    "https://uipkge.dev/r/react/progress.json",
    "https://uipkge.dev/r/react/separator.json",
    "https://uipkge.dev/r/react/sheet.json",
    "https://uipkge.dev/r/react/table.json"
  ],
  "description": "Great Expectations and Soda style automated data quality assertions, schema validation, and drift detector dashboard: top header with overall quality score and run triggers, 4 assertion metric cards, data quality assertions table with category filters, and an interactive anomaly inspector drawer with SQL quarantine remediation.",
  "categories": [
    "devops",
    "dashboard",
    "app",
    "data"
  ]
}