{
  "$schema": "https://uipkge.dev/schema/registry-item.json",
  "name": "feature-store-registry",
  "title": "Feature Store Registry",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-angular/blocks/feature-store-registry/feature-store-registry.component.ts",
      "content": "import { Component, DestroyRef, Input, computed, inject, signal, ChangeDetectionStrategy } from '@angular/core'\nimport {\n  Activity,\n  Check,\n  CheckCircle2,\n  Clock,\n  Code2,\n  Copy,\n  Cpu,\n  Database,\n  Download,\n  Fingerprint,\n  Key,\n  Layers,\n  Loader2,\n  LucideAngularModule,\n  Search,\n  ShieldCheck,\n  Table2,\n  Workflow,\n  Zap,\n  type LucideIconData,\n} from 'lucide-angular'\nimport { cn } from '@/lib/utils'\nimport { UiBadgeComponent } from '@/ui/badge/badge.component'\nimport { UiButtonComponent } from '@/ui/button/button.component'\nimport { UiCardComponent, UiCardContentComponent } from '@/ui/card/card.component'\nimport { UiInputComponent } from '@/ui/input/input.component'\nimport {\n  UiTableBodyComponent,\n  UiTableCellComponent,\n  UiTableComponent,\n  UiTableHeadComponent,\n  UiTableHeaderComponent,\n  UiTableRowComponent,\n} from '@/ui/table/table.component'\nimport {\n  UiTabsComponent,\n  UiTabsContentComponent,\n  UiTabsListComponent,\n  UiTabsTriggerComponent,\n} from '@/ui/tabs/tabs.component'\n\nexport interface FeatureDefinition {\n  name: string\n  dtype: 'Float64' | 'Int32' | 'String'\n  description: string\n  aggregationWindow: string\n  onlineCacheKey: string\n  freshness: string\n  status: 'Online & Batch Ready'\n  sourceSql: string\n  sampleValue: string\n}\n\nexport interface MetricCard {\n  title: string\n  value: string\n  subtitle: string\n  badge: string\n  icon: LucideIconData\n}\n\nexport type FeatureStoreRegistryTab = 'features' | 'python-feast' | 'lineage'\nexport type FeatureStoreRegistryTypeFilter = 'all' | 'Float64' | 'Int32' | 'String'\n\nconst metrics: MetricCard[] = [\n  {\n    title: 'Total Features Registered',\n    value: '18 Active Features',\n    subtitle: '5 in this view · 4 views active',\n    badge: '18 in Registry',\n    icon: Layers,\n  },\n  {\n    title: 'Online Cache Hit Rate',\n    value: '99.8%',\n    subtitle: '1.4ms p95 latency · Redis Cluster',\n    badge: '< 2ms SLA',\n    icon: Zap,\n  },\n  {\n    title: 'Daily Ingestion Throughput',\n    value: '14.8M Updates / Day',\n    subtitle: '171.2 req/s avg · Stream + Batch',\n    badge: 'Real-time CDC',\n    icon: Activity,\n  },\n  {\n    title: 'Max Point-in-Time TTL',\n    value: '30 Days',\n    subtitle: 'Lookback window · Anti-leakage safe',\n    badge: 'AS-OF Safe',\n    icon: Clock,\n  },\n]\n\nconst features: FeatureDefinition[] = [\n  {\n    name: 'avg_transaction_value_30d',\n    dtype: 'Float64',\n    description: '30-day sliding average transaction amount in base USD currency',\n    aggregationWindow: '30-day sliding mean',\n    onlineCacheKey: 'user:ft:avg_tx_val_30d',\n    freshness: 'Synced 4m ago',\n    status: 'Online & Batch Ready',\n    sourceSql: 'AVG(amount_usd) OVER (PARTITION BY user_id ROWS BETWEEN 30 PRECEDING AND CURRENT ROW)',\n    sampleValue: '$342.80',\n  },\n  {\n    name: 'failed_logins_24h',\n    dtype: 'Int32',\n    description: 'Failed authentication attempts in rolling 24-hour security window',\n    aggregationWindow: '24-hour count',\n    onlineCacheKey: 'user:ft:fail_login_24h',\n    freshness: 'Synced 2m ago',\n    status: 'Online & Batch Ready',\n    sourceSql: 'SUM(CASE WHEN auth_success = FALSE THEN 1 ELSE 0 END)',\n    sampleValue: '0',\n  },\n  {\n    name: 'lifetime_chargeback_count',\n    dtype: 'Int32',\n    description: 'Total historical dispute and payment chargeback occurrences',\n    aggregationWindow: 'Cumulative lifetime',\n    onlineCacheKey: 'user:ft:cb_cnt_lt',\n    freshness: 'Synced 12m ago',\n    status: 'Online & Batch Ready',\n    sourceSql: 'COUNT(chargeback_id) OVER (PARTITION BY user_id)',\n    sampleValue: '0',\n  },\n  {\n    name: 'preferred_payment_method',\n    dtype: 'String',\n    description: 'Most frequently utilized payment method category across checkout sessions',\n    aggregationWindow: 'Mode category',\n    onlineCacheKey: 'user:ft:pref_pay_method',\n    freshness: 'Synced 18m ago',\n    status: 'Online & Batch Ready',\n    sourceSql: 'MODE(payment_method_code) OVER (PARTITION BY user_id)',\n    sampleValue: '\"apple_pay\"',\n  },\n  {\n    name: 'risk_score_ml_v3',\n    dtype: 'Float64',\n    description: 'Real-time XGBoost inference fraud risk score probability [0.0 - 1.0]',\n    aggregationWindow: 'Real-time inference',\n    onlineCacheKey: 'user:ft:risk_score_v3',\n    freshness: 'Synced 1m ago',\n    status: 'Online & Batch Ready',\n    sourceSql: 'MODEL_PREDICT_FRAUD_V3(features)',\n    sampleValue: '0.042',\n  },\n]\n\nconst pythonFeastSource = `from datetime import timedelta\nfrom feast import (\n    BatchSource,\n    Entity,\n    FeatureView,\n    Field,\n    SnowflakeSource,\n    ValueType,\n)\nfrom feast.types import Float64, Int32, String\n\n# 1. Define Primary Entity\nuser_entity = Entity(\n    name=\"user_id\",\n    value_type=ValueType.STRING,\n    join_keys=[\"user_id\"],\n    description=\"Global UUID representing verified consumer and business accounts\",\n)\n\n# 2. Snowflake Gold DW Batch Offline Source\ntransactions_batch_source = SnowflakeSource(\n    database=\"ANALYTICS_PROD\",\n    schema=\"GOLD_MARTS\",\n    table=\"fct_user_transactions_daily\",\n    timestamp_field=\"event_timestamp\",\n    created_timestamp_column=\"created_at\",\n)\n\n# 3. Dual-Store Feature View Definition (Redis Online + Snowflake Batch)\nuser_30d_transaction_aggregates = FeatureView(\n    name=\"user_30d_transaction_aggregates\",\n    entities=[user_entity],\n    ttl=timedelta(days=30),\n    schema=[\n        Field(\n            name=\"avg_transaction_value_30d\",\n            dtype=Float64,\n            description=\"30-day sliding average transaction amount in base USD currency\",\n        ),\n        Field(\n            name=\"failed_logins_24h\",\n            dtype=Int32,\n            description=\"Failed authentication attempts in rolling 24-hour security window\",\n        ),\n        Field(\n            name=\"lifetime_chargeback_count\",\n            dtype=Int32,\n            description=\"Total historical dispute and payment chargeback occurrences\",\n        ),\n        Field(\n            name=\"preferred_payment_method\",\n            dtype=String,\n            description=\"Most frequently utilized payment method category across checkout sessions\",\n        ),\n        Field(\n            name=\"risk_score_ml_v3\",\n            dtype=Float64,\n            description=\"Real-time XGBoost inference fraud risk score probability [0.0 - 1.0]\",\n        ),\n    ],\n    online=True,\n    source=transactions_batch_source,\n    tags={\n        \"team\": \"fraud-ml\",\n        \"tier\": \"tier-1-prod\",\n        \"online_store\": \"redis_cluster\",\n        \"batch_store\": \"snowflake_gold\",\n        \"sla\": \"sub-2ms\",\n    },\n)`\n\nfunction escapeHtml(str: string): string {\n  return str.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')\n}\n\n/** One source line as highlighted HTML (spans with Tailwind colour classes only). */\nexport function highlightPythonLine(line: string): string {\n  if (!line.trim()) return '&nbsp;'\n  const escaped = escapeHtml(line)\n\n  // Comments\n  if (/^\\s*#/.test(escaped)) {\n    return `<span class=\"text-neutral-500 italic\">${escaped}</span>`\n  }\n\n  // Each emitted <span> is parked behind a letter-only placeholder so a later\n  // pass cannot match inside markup an earlier pass produced.\n  const parked: string[] = []\n  const park = (html: string) => {\n    const key = String(parked.length)\n      .split('')\n      .map((d) => String.fromCharCode(97 + Number(d)))\n      .join('')\n    parked.push(html)\n    return `\\u0000${key}\\u0000`\n  }\n\n  let res = escaped\n\n  // Strings\n  res = res.replace(/([\"'])(?:(?=(\\\\?))\\2.)*?\\1/g, (match) =>\n    park(`<span class=\"text-success font-normal\">${match}</span>`),\n  )\n\n  // Keywords\n  res = res.replace(\n    /\\b(from|import|def|class|return|as|True|False|None|with|for|in|and|or|not|is|if|else|elif)\\b/g,\n    (m) => park(`<span class=\"text-chart-1 font-semibold\">${m}</span>`),\n  )\n\n  // Types / Feast Classes\n  res = res.replace(\n    /\\b(Entity|FeatureView|Field|SnowflakeSource|BatchSource|ValueType|Float64|Int32|String|timedelta)\\b/g,\n    (m) => park(`<span class=\"text-warning font-medium\">${m}</span>`),\n  )\n\n  // Arguments\n  res = res.replace(\n    /\\b(name|value_type|join_keys|description|database|schema|table|timestamp_field|created_timestamp_column|entities|ttl|dtype|online|source|tags|days)\\b(?=\\s*=)/g,\n    (m) => park(`<span class=\"text-info\">${m}</span>`),\n  )\n\n  // Numbers\n  res = res.replace(/\\b(\\d+)\\b/g, (m) => park(`<span class=\"text-warning font-medium\">${m}</span>`))\n\n  // Restore every parked span\n  return res.replace(/\\u0000([a-j]+)\\u0000/g, (_, key: string) => {\n    const idx = Number(\n      key\n        .split('')\n        .map((c: string) => String(c.charCodeAt(0) - 97))\n        .join(''),\n    )\n    return parked[idx] ?? ''\n  })\n}\n\n/**\n * FeatureStoreRegistry -- the React block, 1:1: a Feast / Tecton style feature view page with\n * entity + store pills, \"Generate Training Dataset\" / \"Materialize Online Features\" actions,\n * four metric cards, and three tabs: a searchable, type-filterable feature table (click a cache\n * key to copy it) with an online vector lookup strip, the highlighted Python Feast definition\n * (copyable), and the offline / online storage lineage cards. Edit the data consts above.\n */\n@Component({\n  changeDetection: ChangeDetectionStrategy.Eager,\n  selector: 'ui-feature-store-registry, [ui-feature-store-registry]',\n  standalone: true,\n  // React renders the root <div> itself: keep this wrapper out of the layout.\n  host: { class: 'contents' },\n  imports: [\n    LucideAngularModule,\n    UiBadgeComponent,\n    UiButtonComponent,\n    UiCardComponent,\n    UiCardContentComponent,\n    UiInputComponent,\n    UiTableComponent,\n    UiTableHeaderComponent,\n    UiTableBodyComponent,\n    UiTableRowComponent,\n    UiTableHeadComponent,\n    UiTableCellComponent,\n    UiTabsComponent,\n    UiTabsListComponent,\n    UiTabsTriggerComponent,\n    UiTabsContentComponent,\n  ],\n  template: `\n    <div data-slot=\"feature-store-registry\" [class]=\"rootClass\">\n      <!-- TOP FEATURE VIEW HEADER -->\n      <header class=\"border-border bg-card/70 border-b px-4 py-4 sm:px-6\">\n        <div class=\"flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between\">\n          <!-- Left: Title, Entity, Stores -->\n          <div class=\"flex flex-wrap items-center gap-3\">\n            <div class=\"bg-primary/10 text-primary flex size-10 items-center justify-center rounded-lg shadow-xs\">\n              <lucide-icon [img]=\"Cpu\" class=\"size-5\" />\n            </div>\n\n            <div class=\"flex flex-col gap-1\">\n              <div class=\"flex flex-wrap items-center gap-2\">\n                <span class=\"text-muted-foreground font-mono text-xs\">feature_view /</span>\n                <h1 class=\"text-foreground font-mono text-base font-bold tracking-tight break-all sm:text-lg\">\n                  user_30d_transaction_aggregates\n                </h1>\n                <span ui-badge wrap variant=\"outline\" class=\"font-mono text-xs font-normal\">v2.4.0</span>\n              </div>\n\n              <!-- Metadata Badges Strip -->\n              <div class=\"flex flex-wrap items-center gap-2 pt-0.5\">\n                <!-- Entity Pill -->\n                <div\n                  class=\"border-border bg-muted/40 text-foreground inline-flex items-center gap-1.5 rounded-md border px-2 py-0.5 font-mono text-xs\"\n                >\n                  <lucide-icon [img]=\"Key\" class=\"text-primary size-3\" />\n                  <span class=\"text-muted-foreground\">Entity:</span>\n                  <span class=\"font-semibold\">user_id</span>\n                  <span class=\"text-muted-foreground\">[UUID]</span>\n                </div>\n\n                <!-- Online Store Pill -->\n                <div\n                  class=\"border-success/30 bg-success/10 text-success inline-flex items-center gap-1.5 rounded-md border px-2 py-0.5 font-mono text-xs font-medium\"\n                >\n                  <span class=\"bg-success size-1.5 animate-pulse rounded-full\"></span>\n                  <span>Redis Cluster · &lt; 2ms latency</span>\n                </div>\n\n                <!-- Batch Store Pill -->\n                <div\n                  class=\"border-info/30 bg-info/10 text-info inline-flex items-center gap-1.5 rounded-md border px-2 py-0.5 font-mono text-xs font-medium\"\n                >\n                  <lucide-icon [img]=\"Database\" class=\"text-info size-3\" />\n                  <span>Snowflake Gold DW</span>\n                </div>\n              </div>\n            </div>\n          </div>\n\n          <!-- Right: Action Buttons -->\n          <div class=\"flex flex-wrap items-center gap-2\">\n            <!-- Generate Training Dataset Button -->\n            <button\n              ui-button\n              aria-label=\"Download attachment\"\n              variant=\"outline\"\n              size=\"sm\"\n              class=\"h-9 gap-1.5 text-xs font-medium shadow-none\"\n              [disabled]=\"isGeneratingDataset()\"\n              (click)=\"handleGenerateDataset()\"\n            >\n              @if (isGeneratingDataset()) {\n                <lucide-icon [img]=\"Loader2\" class=\"size-3.5 animate-spin\" />\n              } @else if (datasetSuccess()) {\n                <lucide-icon [img]=\"Check\" class=\"text-success size-3.5\" />\n              } @else {\n                <lucide-icon [img]=\"Download\" class=\"size-3.5\" />\n              }\n              <span>{{ datasetLabel() }}</span>\n            </button>\n\n            <!-- Materialize Online Features Button -->\n            <button\n              ui-button\n              variant=\"default\"\n              size=\"sm\"\n              class=\"bg-primary text-primary-foreground hover:bg-primary/90 h-9 gap-1.5 text-xs font-semibold shadow-xs\"\n              [disabled]=\"isMaterializing()\"\n              (click)=\"handleMaterialize()\"\n            >\n              @if (isMaterializing()) {\n                <lucide-icon [img]=\"Loader2\" class=\"size-3.5 animate-spin\" />\n              } @else if (materializeSuccess()) {\n                <lucide-icon [img]=\"Check\" class=\"text-success size-3.5\" />\n              } @else {\n                <lucide-icon [img]=\"Zap\" class=\"size-3.5 fill-current\" />\n              }\n              <span>{{ materializeLabel() }}</span>\n            </button>\n          </div>\n        </div>\n      </header>\n\n      <!-- 4 FEATURE STORE METRIC CARDS -->\n      <div class=\"border-border bg-muted/15 border-b p-4 sm:p-6\">\n        <div class=\"grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-4\">\n          @for (metric of metrics; track metric.title) {\n            <ui-card class=\"border-border bg-card hover:bg-muted/30 shadow-none transition-colors\">\n              <ui-card-content class=\"flex flex-col justify-between gap-3 p-4\">\n                <div class=\"flex items-center justify-between\">\n                  <span class=\"text-muted-foreground text-xs font-medium\">{{ metric.title }}</span>\n                  <div class=\"bg-primary/10 text-primary flex size-7 items-center justify-center rounded-md\">\n                    <lucide-icon [img]=\"metric.icon\" class=\"size-3.5\" />\n                  </div>\n                </div>\n\n                <div>\n                  <div class=\"text-foreground font-mono text-xl font-bold tracking-tight\">{{ metric.value }}</div>\n                  <div class=\"flex items-center justify-between pt-1 text-xs\">\n                    <span class=\"text-muted-foreground truncate\">{{ metric.subtitle }}</span>\n                    <span ui-badge wrap variant=\"secondary\" class=\"ml-1 shrink-0 font-mono text-xs font-normal\">{{\n                      metric.badge\n                    }}</span>\n                  </div>\n                </div>\n              </ui-card-content>\n            </ui-card>\n          }\n        </div>\n      </div>\n\n      <!-- MAIN TABS STUDIO -->\n      <div class=\"flex flex-1 flex-col\">\n        <ui-tabs [value]=\"activeTab()\" (valueChange)=\"setActiveTab($event)\" class=\"flex flex-1 flex-col\">\n          <!-- Tabs Bar -->\n          <div\n            class=\"border-border bg-card flex flex-wrap items-center justify-between gap-3 border-b px-4 py-2.5 sm:px-6\"\n          >\n            <div ui-tabs-list class=\"grid h-9 grid-cols-3\">\n              <button ui-tabs-trigger value=\"features\" class=\"gap-1.5 text-xs\">\n                <lucide-icon [img]=\"Table2\" class=\"text-primary size-3.5\" />\n                <span>Feature Definitions</span>\n                <span ui-badge wrap variant=\"secondary\" class=\"ml-1 h-4 px-1 font-mono text-xs\">{{\n                  features.length\n                }}</span>\n              </button>\n              <button ui-tabs-trigger value=\"python-feast\" class=\"gap-1.5 text-xs\">\n                <lucide-icon [img]=\"Code2\" class=\"text-warning size-3.5\" />\n                <span>Feast Definition</span>\n              </button>\n              <button ui-tabs-trigger value=\"lineage\" class=\"gap-1.5 text-xs\">\n                <lucide-icon [img]=\"Workflow\" class=\"text-info size-3.5\" />\n                <span>Lineage &amp; Architecture</span>\n              </button>\n            </div>\n\n            <div class=\"flex items-center gap-2\">\n              <span ui-badge wrap variant=\"outline\" class=\"text-success gap-1 font-mono text-xs\">\n                <lucide-icon [img]=\"ShieldCheck\" class=\"size-3\" />\n                <span>Redis Online Serving: ACTIVE</span>\n              </span>\n            </div>\n          </div>\n\n          <!-- TAB 1: FEATURE DEFINITIONS TABLE -->\n          <ui-tabs-content value=\"features\" class=\"m-0 flex flex-1 flex-col space-y-5 p-4 sm:p-6\">\n            <!-- Filter / Search Controls -->\n            <div class=\"flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n              <div class=\"flex flex-wrap items-center gap-2\">\n                <div class=\"relative w-full sm:w-72\">\n                  <!-- [class] (not class=) styles only the svg: the absolute offsets must not apply twice. -->\n                  <lucide-icon\n                    [img]=\"Search\"\n                    [class]=\"'text-muted-foreground absolute top-1/2 left-2.5 size-3.5 -translate-y-1/2'\"\n                  />\n                  <ui-input\n                    [value]=\"searchQuery()\"\n                    (valueChange)=\"searchQuery.set($event)\"\n                    placeholder=\"Filter by feature name, type, or cache key...\"\n                    class=\"h-8 pl-8 font-mono text-xs\"\n                  />\n                </div>\n\n                <!-- Type filter pills -->\n                <div class=\"flex items-center gap-1\">\n                  @for (t of typeFilters; track t) {\n                    <button type=\"button\" [class]=\"typePillClass(t)\" (click)=\"selectedType.set(t)\">\n                      {{ t === 'all' ? 'All Types' : t }}\n                    </button>\n                  }\n                </div>\n              </div>\n\n              <div class=\"text-muted-foreground flex items-center gap-2 font-mono text-xs\">\n                <span>Showing {{ filteredFeatures().length }} of {{ features.length }} features</span>\n              </div>\n            </div>\n\n            <!-- Feature Definitions Table -->\n            <ui-card class=\"border-border overflow-hidden border shadow-none\">\n              <div class=\"overflow-x-auto\">\n                <div ui-table>\n                  <thead ui-table-header>\n                    <tr ui-table-row class=\"bg-muted/40 hover:bg-muted/40\">\n                      <th ui-table-head class=\"text-xs font-semibold\">Feature Name &amp; Type</th>\n                      <th ui-table-head class=\"text-xs font-semibold\">Description &amp; Aggregation Window</th>\n                      <th ui-table-head class=\"text-xs font-semibold\">Online Cache Key (Redis)</th>\n                      <th ui-table-head class=\"text-xs font-semibold\">Freshness</th>\n                      <th ui-table-head class=\"text-xs font-semibold\">Status</th>\n                    </tr>\n                  </thead>\n                  <tbody ui-table-body>\n                    @for (feature of filteredFeatures(); track feature.name) {\n                      <tr ui-table-row class=\"text-xs\">\n                        <!-- Feature Name & Type -->\n                        <td ui-table-cell class=\"font-mono\">\n                          <div class=\"space-y-1\">\n                            <div class=\"text-foreground font-semibold tracking-tight\">{{ feature.name }}</div>\n                            <span ui-badge variant=\"secondary\" [class]=\"dtypeBadgeClass(feature.dtype)\">{{\n                              feature.dtype\n                            }}</span>\n                          </div>\n                        </td>\n\n                        <!-- Description & Aggregation Window -->\n                        <td ui-table-cell class=\"max-w-[280px]\">\n                          <div class=\"space-y-1\">\n                            <p class=\"text-muted-foreground text-xs leading-relaxed\">{{ feature.description }}</p>\n                            <span ui-badge wrap variant=\"outline\" class=\"gap-1 font-mono text-xs font-normal\">\n                              <lucide-icon [img]=\"Clock\" class=\"text-muted-foreground size-2.5\" />\n                              {{ feature.aggregationWindow }}\n                            </span>\n                          </div>\n                        </td>\n\n                        <!-- Online Cache Key -->\n                        <td ui-table-cell>\n                          <button\n                            type=\"button\"\n                            class=\"border-border/80 bg-muted/60 hover:bg-muted hover:border-primary/40 text-foreground group inline-flex items-center gap-1.5 rounded-md border px-2.5 py-1 font-mono text-xs transition-colors\"\n                            title=\"Click to copy Redis key\"\n                            (click)=\"copyToClipboard(feature.onlineCacheKey, 'key', feature.name)\"\n                          >\n                            <span class=\"text-primary font-semibold\">GET</span>\n                            <span>{{ feature.onlineCacheKey }}</span>\n                            @if (copiedKey() === feature.name) {\n                              <lucide-icon [img]=\"Check\" class=\"text-success size-3 transition-transform\" />\n                            } @else {\n                              <lucide-icon\n                                [img]=\"Copy\"\n                                class=\"text-muted-foreground size-3 opacity-60 group-hover:opacity-100\"\n                              />\n                            }\n                          </button>\n                        </td>\n\n                        <!-- Freshness / Last Synced -->\n                        <td ui-table-cell class=\"text-muted-foreground font-mono whitespace-nowrap\">\n                          <div class=\"flex items-center gap-1.5\">\n                            <lucide-icon [img]=\"Clock\" class=\"text-success size-3\" />\n                            <span>{{ feature.freshness }}</span>\n                          </div>\n                        </td>\n\n                        <!-- Feature Status -->\n                        <td ui-table-cell class=\"whitespace-nowrap\">\n                          <span\n                            ui-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 rounded-full\"></span>\n                            {{ feature.status }}\n                          </span>\n                        </td>\n                      </tr>\n                    }\n                  </tbody>\n                </div>\n              </div>\n            </ui-card>\n\n            <!-- Interactive Entity Live Feature Vector Inspector -->\n            <ui-card class=\"border-border bg-card/60 space-y-4 border p-4 shadow-none sm:p-5\">\n              <div\n                class=\"border-border/80 flex flex-col gap-2 border-b pb-3 sm:flex-row sm:items-center sm:justify-between\"\n              >\n                <div class=\"flex flex-wrap items-center gap-2\">\n                  <lucide-icon [img]=\"Fingerprint\" class=\"text-primary size-4 shrink-0\" />\n                  <span class=\"text-foreground text-xs font-semibold\">Live Online Feature Vector Lookup Simulator</span>\n                  <span ui-badge wrap variant=\"secondary\" class=\"font-mono text-xs\">feast.get_online_features()</span>\n                </div>\n                <div class=\"flex items-center gap-2\">\n                  <span class=\"text-muted-foreground font-mono text-xs\">Target Entity:</span>\n                  <span class=\"text-foreground font-mono text-xs font-semibold\">{{ selectedEntityId }}</span>\n                </div>\n              </div>\n\n              <div class=\"grid grid-cols-1 gap-2 sm:grid-cols-2 lg:grid-cols-5\">\n                @for (feature of features; track feature.name) {\n                  <div class=\"border-border/70 bg-muted/25 flex flex-col justify-between rounded-lg border p-3\">\n                    <div class=\"space-y-1\">\n                      <span class=\"text-muted-foreground block truncate font-mono text-xs font-medium\">{{\n                        feature.name\n                      }}</span>\n                      <span class=\"text-muted-foreground text-xs\">{{ feature.aggregationWindow }}</span>\n                    </div>\n                    <div\n                      class=\"border-border/40 mt-3 flex flex-wrap items-baseline justify-between gap-x-2 gap-y-0.5 border-t pt-2\"\n                    >\n                      <span class=\"text-foreground font-mono text-sm font-bold\">{{ feature.sampleValue }}</span>\n                      <span class=\"text-success font-mono text-xs\">&lt; 1.2ms</span>\n                    </div>\n                  </div>\n                }\n              </div>\n            </ui-card>\n          </ui-tabs-content>\n\n          <!-- TAB 2: PYTHON FEAST DEFINITION CODE BOX -->\n          <ui-tabs-content value=\"python-feast\" class=\"m-0 flex flex-1 flex-col space-y-4 p-4 sm:p-6\">\n            <div class=\"border-border bg-muted/40 overflow-hidden rounded-xl border\">\n              <!-- Code Box Toolbar Header -->\n              <div class=\"border-border bg-card flex items-center justify-between border-b px-4 py-2.5\">\n                <div class=\"flex items-center gap-2\">\n                  <div class=\"bg-warning/10 text-warning flex size-6 items-center justify-center rounded\">\n                    <lucide-icon [img]=\"Code2\" class=\"size-3.5\" />\n                  </div>\n                  <span class=\"text-foreground font-mono text-xs font-semibold\"\n                    >feature_definitions/user_aggregates.py</span\n                  >\n                  <span ui-badge wrap variant=\"secondary\" class=\"font-mono text-xs\">Python 3.11 · Feast 0.42+</span>\n                </div>\n\n                <button\n                  ui-button\n                  variant=\"outline\"\n                  size=\"sm\"\n                  class=\"h-7 gap-1.5 text-xs font-medium\"\n                  (click)=\"copyToClipboard(pythonFeastSource, 'code')\"\n                >\n                  @if (copiedFeast()) {\n                    <lucide-icon [img]=\"Check\" class=\"text-success size-3\" />\n                  } @else {\n                    <lucide-icon [img]=\"Copy\" class=\"size-3\" />\n                  }\n                  <span>{{ copiedFeast() ? 'Copied Feast Code!' : 'Copy Python Code' }}</span>\n                </button>\n              </div>\n\n              <!-- Code Gutter and Syntax Highlighter -->\n              <div\n                class=\"relative flex overflow-x-auto bg-neutral-950 font-mono text-xs leading-relaxed text-neutral-100 dark:bg-neutral-950\"\n              >\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 text-neutral-500 select-none\"\n                >\n                  @for (line of pythonLines; track $index) {\n                    <div>{{ $index + 1 }}</div>\n                  }\n                </div>\n\n                <!-- Python Code Content -->\n                <div class=\"flex-1 overflow-x-auto p-3 whitespace-pre select-text\">\n                  @for (html of highlightedLines; track $index) {\n                    <div class=\"h-5 font-mono leading-5\" [innerHTML]=\"html\"></div>\n                  }\n                </div>\n              </div>\n\n              <!-- Code Footer Meta -->\n              <div\n                class=\"border-border/60 bg-muted/20 text-muted-foreground flex items-center justify-between border-t px-4 py-1.5 font-mono text-xs\"\n              >\n                <div class=\"flex items-center gap-3\">\n                  <span>{{ pythonLines.length }} lines</span>\n                  <span>·</span>\n                  <span>UTF-8</span>\n                  <span>·</span>\n                  <span>Feast Entity &amp; FeatureView DSL</span>\n                </div>\n                <div class=\"text-success flex items-center gap-1.5\">\n                  <lucide-icon [img]=\"CheckCircle2\" class=\"size-3.5\" />\n                  <span>Valid Feast Schema Contract</span>\n                </div>\n              </div>\n            </div>\n          </ui-tabs-content>\n\n          <!-- TAB 3: STORAGE & LINEAGE ARCHITECTURE -->\n          <ui-tabs-content value=\"lineage\" class=\"m-0 flex flex-1 flex-col space-y-4 p-4 sm:p-6\">\n            <div class=\"grid grid-cols-1 gap-4 lg:grid-cols-2\">\n              <!-- Offline Batch Lineage Card -->\n              <ui-card class=\"border-border bg-card space-y-3 border p-5 shadow-none\">\n                <div class=\"border-border flex items-center justify-between border-b pb-2.5\">\n                  <div class=\"flex items-center gap-2\">\n                    <lucide-icon [img]=\"Database\" class=\"text-info size-4\" />\n                    <span class=\"text-foreground text-xs font-semibold\">Offline Batch Store Architecture</span>\n                  </div>\n                  <span ui-badge wrap variant=\"secondary\" class=\"font-mono text-xs\">Snowflake Gold</span>\n                </div>\n\n                <p class=\"text-muted-foreground text-xs leading-relaxed\">\n                  Immutable historical logs for time-travel queries, training set generation, and AS-OF joins without\n                  point-in-time data leakage.\n                </p>\n\n                <div class=\"border-border/60 bg-muted/20 space-y-2 rounded-lg border p-3 font-mono text-xs\">\n                  <div class=\"flex justify-between\">\n                    <span class=\"text-muted-foreground\">Database &amp; Schema:</span>\n                    <span class=\"text-foreground font-semibold\">ANALYTICS_PROD.GOLD_MARTS</span>\n                  </div>\n                  <div class=\"flex justify-between\">\n                    <span class=\"text-muted-foreground\">Source Table:</span>\n                    <span class=\"text-foreground font-semibold\">fct_user_transactions_daily</span>\n                  </div>\n                  <div class=\"flex justify-between\">\n                    <span class=\"text-muted-foreground\">Timestamp Partition:</span>\n                    <span class=\"text-foreground\">event_timestamp (UTC)</span>\n                  </div>\n                  <div class=\"flex justify-between\">\n                    <span class=\"text-muted-foreground\">Historical Depth:</span>\n                    <span class=\"text-foreground\">3 Years (Lookback TTL 30 Days)</span>\n                  </div>\n                </div>\n              </ui-card>\n\n              <!-- Online Low-Latency Cache Card -->\n              <ui-card class=\"border-border bg-card space-y-3 border p-5 shadow-none\">\n                <div class=\"border-border flex items-center justify-between border-b pb-2.5\">\n                  <div class=\"flex items-center gap-2\">\n                    <lucide-icon [img]=\"Zap\" class=\"text-success size-4\" />\n                    <span class=\"text-foreground text-xs font-semibold\">Online Key-Value Cache Architecture</span>\n                  </div>\n                  <span ui-badge wrap variant=\"outline\" class=\"border-success/30 text-success font-mono text-xs\">\n                    Redis 7.2 Cluster\n                  </span>\n                </div>\n\n                <p class=\"text-muted-foreground text-xs leading-relaxed\">\n                  Ultra-low latency memory tier providing sub-2 millisecond retrieval for online model inference\n                  microservices and fraud scoring.\n                </p>\n\n                <div class=\"border-border/60 bg-muted/20 space-y-2 rounded-lg border p-3 font-mono text-xs\">\n                  <div class=\"flex justify-between\">\n                    <span class=\"text-muted-foreground\">Cluster Topology:</span>\n                    <span class=\"text-foreground font-semibold\">3 Master Shards + 3 Replicas</span>\n                  </div>\n                  <div class=\"flex justify-between\">\n                    <span class=\"text-muted-foreground\">Key Prefix Pattern:</span>\n                    <span class=\"text-foreground font-semibold\">user:ft:{{ '{' }}feature_name{{ '}' }}</span>\n                  </div>\n                  <div class=\"flex justify-between\">\n                    <span class=\"text-muted-foreground\">Read SLA (p95):</span>\n                    <span class=\"text-success font-semibold\">&lt; 1.4ms Latency</span>\n                  </div>\n                  <div class=\"flex justify-between\">\n                    <span class=\"text-muted-foreground\">Materialization Schedule:</span>\n                    <span class=\"text-foreground\">Every 15 mins via Feast Job</span>\n                  </div>\n                </div>\n              </ui-card>\n            </div>\n          </ui-tabs-content>\n        </ui-tabs>\n      </div>\n    </div>\n  `,\n})\nexport class UiFeatureStoreRegistryComponent {\n  @Input('class') className?: string\n\n  protected readonly metrics = metrics\n  protected readonly features = features\n  protected readonly pythonFeastSource = pythonFeastSource\n  protected readonly pythonLines = pythonFeastSource.split('\\n')\n  protected readonly highlightedLines = this.pythonLines.map(highlightPythonLine)\n  protected readonly typeFilters: readonly FeatureStoreRegistryTypeFilter[] = ['all', 'Float64', 'Int32', 'String']\n  protected readonly selectedEntityId = 'usr_9a4f201d-7e2b-4d68'\n\n  readonly activeTab = signal<FeatureStoreRegistryTab>('features')\n  readonly searchQuery = signal('')\n  readonly selectedType = signal<FeatureStoreRegistryTypeFilter>('all')\n  readonly isMaterializing = signal(false)\n  readonly materializeSuccess = signal(false)\n  readonly isGeneratingDataset = signal(false)\n  readonly datasetSuccess = signal(false)\n  readonly copiedFeast = signal(false)\n  readonly copiedKey = signal<string | null>(null)\n\n  readonly filteredFeatures = computed(() => {\n    const query = this.searchQuery().trim().toLowerCase()\n    const type = this.selectedType()\n    return features.filter((f) => {\n      const matchesSearch =\n        !query ||\n        f.name.toLowerCase().includes(query) ||\n        f.description.toLowerCase().includes(query) ||\n        f.onlineCacheKey.toLowerCase().includes(query) ||\n        f.dtype.toLowerCase().includes(query)\n      const matchesType = type === 'all' || f.dtype === type\n      return matchesSearch && matchesType\n    })\n  })\n\n  protected get rootClass(): string {\n    return cn(\n      'bg-background text-foreground border-border flex w-full flex-col overflow-hidden rounded-xl border shadow-xs',\n      this.className,\n    )\n  }\n\n  protected readonly datasetLabel = computed(() =>\n    this.isGeneratingDataset()\n      ? 'Building Parquet...'\n      : this.datasetSuccess()\n        ? 'Dataset Exported (14.2 MB)'\n        : 'Generate Training Dataset',\n  )\n\n  protected readonly materializeLabel = computed(() =>\n    this.isMaterializing()\n      ? 'Syncing to Redis...'\n      : this.materializeSuccess()\n        ? 'Materialized 18.4k Keys!'\n        : 'Materialize Online Features',\n  )\n\n  protected readonly Activity = Activity\n  protected readonly Check = Check\n  protected readonly CheckCircle2 = CheckCircle2\n  protected readonly Clock = Clock\n  protected readonly Code2 = Code2\n  protected readonly Copy = Copy\n  protected readonly Cpu = Cpu\n  protected readonly Database = Database\n  protected readonly Download = Download\n  protected readonly Fingerprint = Fingerprint\n  protected readonly Key = Key\n  protected readonly Loader2 = Loader2\n  protected readonly Search = Search\n  protected readonly ShieldCheck = ShieldCheck\n  protected readonly Table2 = Table2\n  protected readonly Workflow = Workflow\n  protected readonly Zap = Zap\n\n  private readonly timers = new Set<ReturnType<typeof setTimeout>>()\n\n  constructor() {\n    inject(DestroyRef).onDestroy(() => this.timers.forEach((t) => clearTimeout(t)))\n  }\n\n  setActiveTab(value: string): void {\n    if (value === 'features' || value === 'python-feast' || value === 'lineage') this.activeTab.set(value)\n  }\n\n  typePillClass(t: FeatureStoreRegistryTypeFilter): string {\n    return cn(\n      'cursor-pointer rounded-md px-2 py-1 font-mono text-xs transition-colors',\n      this.selectedType() === t\n        ? 'bg-primary text-primary-foreground font-medium shadow-xs'\n        : 'bg-muted/50 text-muted-foreground hover:bg-muted hover:text-foreground',\n    )\n  }\n\n  dtypeBadgeClass(dtype: FeatureDefinition['dtype']): string {\n    return cn(\n      'font-mono text-xs font-normal',\n      dtype === 'Float64' && 'border-warning/20 bg-warning/10 text-warning border',\n      dtype === 'Int32' && 'border-info/20 bg-info/10 text-info border',\n      dtype === 'String' && 'border-chart-1/20 bg-chart-1/10 text-chart-1 border',\n    )\n  }\n\n  copyToClipboard(text: string, type: 'code' | 'key', keyName?: string): void {\n    if (typeof navigator !== 'undefined' && navigator.clipboard) {\n      navigator.clipboard.writeText(text).catch(() => {})\n      if (type === 'code') {\n        this.copiedFeast.set(true)\n        this.later(2000, () => this.copiedFeast.set(false))\n      } else if (type === 'key' && keyName) {\n        this.copiedKey.set(keyName)\n        this.later(2000, () => this.copiedKey.set(null))\n      }\n    }\n  }\n\n  handleMaterialize(): void {\n    if (this.isMaterializing()) return\n    this.isMaterializing.set(true)\n    this.materializeSuccess.set(false)\n    this.later(1200, () => {\n      this.isMaterializing.set(false)\n      this.materializeSuccess.set(true)\n      this.later(3000, () => this.materializeSuccess.set(false))\n    })\n  }\n\n  handleGenerateDataset(): void {\n    if (this.isGeneratingDataset()) return\n    this.isGeneratingDataset.set(true)\n    this.datasetSuccess.set(false)\n    this.later(1000, () => {\n      this.isGeneratingDataset.set(false)\n      this.datasetSuccess.set(true)\n      this.later(3000, () => this.datasetSuccess.set(false))\n    })\n  }\n\n  private later(ms: number, fn: () => void): void {\n    const t = setTimeout(() => {\n      this.timers.delete(t)\n      fn()\n    }, ms)\n    this.timers.add(t)\n  }\n}\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/feature-store-registry/feature-store-registry.component.ts"
    },
    {
      "path": "packages/registry-angular/blocks/feature-store-registry/index.ts",
      "content": "export {\n  UiFeatureStoreRegistryComponent,\n  highlightPythonLine,\n  type FeatureDefinition,\n  type MetricCard,\n  type FeatureStoreRegistryTab,\n  type FeatureStoreRegistryTypeFilter,\n} from './feature-store-registry.component'\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/feature-store-registry/index.ts"
    }
  ],
  "dependencies": [
    "lucide-angular"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/angular/badge.json",
    "https://uipkge.dev/r/angular/button.json",
    "https://uipkge.dev/r/angular/card.json",
    "https://uipkge.dev/r/angular/input.json",
    "https://uipkge.dev/r/angular/table.json",
    "https://uipkge.dev/r/angular/tabs.json"
  ],
  "description": "Feast and Tecton style machine learning feature store registry with entity definitions, low-latency Redis online cache status, Snowflake batch source lineage, feature schema inspection table, throughput metrics, and Python Feast feature view code generator.",
  "categories": [
    "ai",
    "app",
    "devops"
  ]
}