@memberjunction/ng-dashboards 5.39.0 → 5.40.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (129) hide show
  1. package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.d.ts +128 -4
  2. package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.d.ts.map +1 -1
  3. package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.js +548 -145
  4. package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.js.map +1 -1
  5. package/dist/AI/components/autotagging/components/classify-item-drilldown.component.d.ts +56 -0
  6. package/dist/AI/components/autotagging/components/classify-item-drilldown.component.d.ts.map +1 -0
  7. package/dist/AI/components/autotagging/components/classify-item-drilldown.component.js +423 -0
  8. package/dist/AI/components/autotagging/components/classify-item-drilldown.component.js.map +1 -0
  9. package/dist/AI/components/autotagging/components/classify-item-grid.component.d.ts +70 -0
  10. package/dist/AI/components/autotagging/components/classify-item-grid.component.d.ts.map +1 -0
  11. package/dist/AI/components/autotagging/components/classify-item-grid.component.js +308 -0
  12. package/dist/AI/components/autotagging/components/classify-item-grid.component.js.map +1 -0
  13. package/dist/AI/components/autotagging/components/classify-org-context-editor.component.d.ts +29 -0
  14. package/dist/AI/components/autotagging/components/classify-org-context-editor.component.d.ts.map +1 -0
  15. package/dist/AI/components/autotagging/components/classify-org-context-editor.component.js +186 -0
  16. package/dist/AI/components/autotagging/components/classify-org-context-editor.component.js.map +1 -0
  17. package/dist/AI/components/autotagging/components/classify-overview-analytics.component.d.ts +69 -0
  18. package/dist/AI/components/autotagging/components/classify-overview-analytics.component.d.ts.map +1 -0
  19. package/dist/AI/components/autotagging/components/classify-overview-analytics.component.js +278 -0
  20. package/dist/AI/components/autotagging/components/classify-overview-analytics.component.js.map +1 -0
  21. package/dist/AI/components/autotagging/components/classify-seed-taxonomy.component.d.ts +73 -0
  22. package/dist/AI/components/autotagging/components/classify-seed-taxonomy.component.d.ts.map +1 -0
  23. package/dist/AI/components/autotagging/components/classify-seed-taxonomy.component.js +393 -0
  24. package/dist/AI/components/autotagging/components/classify-seed-taxonomy.component.js.map +1 -0
  25. package/dist/AI/components/autotagging/dialogs/classify-setup-wizard.component.d.ts +122 -0
  26. package/dist/AI/components/autotagging/dialogs/classify-setup-wizard.component.d.ts.map +1 -0
  27. package/dist/AI/components/autotagging/dialogs/classify-setup-wizard.component.js +908 -0
  28. package/dist/AI/components/autotagging/dialogs/classify-setup-wizard.component.js.map +1 -0
  29. package/dist/AI/components/autotagging/dialogs/source-type-form.dialog.component.d.ts +100 -2
  30. package/dist/AI/components/autotagging/dialogs/source-type-form.dialog.component.d.ts.map +1 -1
  31. package/dist/AI/components/autotagging/dialogs/source-type-form.dialog.component.js +603 -213
  32. package/dist/AI/components/autotagging/dialogs/source-type-form.dialog.component.js.map +1 -1
  33. package/dist/AI/components/autotagging/shared/classify.format.d.ts +15 -0
  34. package/dist/AI/components/autotagging/shared/classify.format.d.ts.map +1 -1
  35. package/dist/AI/components/autotagging/shared/classify.format.js +51 -0
  36. package/dist/AI/components/autotagging/shared/classify.format.js.map +1 -1
  37. package/dist/AI/components/autotagging/shared/classify.types.d.ts +43 -0
  38. package/dist/AI/components/autotagging/shared/classify.types.d.ts.map +1 -1
  39. package/dist/AI/components/autotagging/shared/classify.types.js.map +1 -1
  40. package/dist/AI/components/autotagging/tabs/history-tab.component.d.ts +38 -1
  41. package/dist/AI/components/autotagging/tabs/history-tab.component.d.ts.map +1 -1
  42. package/dist/AI/components/autotagging/tabs/history-tab.component.js +185 -68
  43. package/dist/AI/components/autotagging/tabs/history-tab.component.js.map +1 -1
  44. package/dist/AI/components/autotagging/tabs/pipeline-tab.component.d.ts +10 -1
  45. package/dist/AI/components/autotagging/tabs/pipeline-tab.component.d.ts.map +1 -1
  46. package/dist/AI/components/autotagging/tabs/pipeline-tab.component.js +249 -188
  47. package/dist/AI/components/autotagging/tabs/pipeline-tab.component.js.map +1 -1
  48. package/dist/AI/components/autotagging/tabs/sources-tab.component.d.ts +12 -1
  49. package/dist/AI/components/autotagging/tabs/sources-tab.component.d.ts.map +1 -1
  50. package/dist/AI/components/autotagging/tabs/sources-tab.component.js +377 -296
  51. package/dist/AI/components/autotagging/tabs/sources-tab.component.js.map +1 -1
  52. package/dist/AI/components/autotagging/tabs/tags-tab.component.d.ts +8 -0
  53. package/dist/AI/components/autotagging/tabs/tags-tab.component.d.ts.map +1 -1
  54. package/dist/AI/components/autotagging/tabs/tags-tab.component.js +112 -68
  55. package/dist/AI/components/autotagging/tabs/tags-tab.component.js.map +1 -1
  56. package/dist/AI/components/autotagging/tabs/types-tab.component.d.ts +9 -0
  57. package/dist/AI/components/autotagging/tabs/types-tab.component.d.ts.map +1 -1
  58. package/dist/AI/components/autotagging/tabs/types-tab.component.js +87 -36
  59. package/dist/AI/components/autotagging/tabs/types-tab.component.js.map +1 -1
  60. package/dist/AI/components/duplicates/duplicate-detection-resource.component.d.ts +3 -0
  61. package/dist/AI/components/duplicates/duplicate-detection-resource.component.d.ts.map +1 -1
  62. package/dist/AI/components/duplicates/duplicate-detection-resource.component.js +15 -3
  63. package/dist/AI/components/duplicates/duplicate-detection-resource.component.js.map +1 -1
  64. package/dist/AI/components/execution-monitoring.component.js +1 -1
  65. package/dist/AI/components/execution-monitoring.component.js.map +1 -1
  66. package/dist/AI/components/tags/tags-resource.component.d.ts +1 -0
  67. package/dist/AI/components/tags/tags-resource.component.d.ts.map +1 -1
  68. package/dist/AI/components/tags/tags-resource.component.js +28 -6
  69. package/dist/AI/components/tags/tags-resource.component.js.map +1 -1
  70. package/dist/AI/components/vectors/vector-management-resource.component.d.ts +3 -0
  71. package/dist/AI/components/vectors/vector-management-resource.component.d.ts.map +1 -1
  72. package/dist/AI/components/vectors/vector-management-resource.component.js +330 -302
  73. package/dist/AI/components/vectors/vector-management-resource.component.js.map +1 -1
  74. package/dist/APIKeys/api-applications-panel.component.js +2 -2
  75. package/dist/APIKeys/api-key-create-dialog.component.js +2 -2
  76. package/dist/DataExplorer/data-explorer-dashboard.component.d.ts +31 -340
  77. package/dist/DataExplorer/data-explorer-dashboard.component.d.ts.map +1 -1
  78. package/dist/DataExplorer/data-explorer-dashboard.component.js +468 -1958
  79. package/dist/DataExplorer/data-explorer-dashboard.component.js.map +1 -1
  80. package/dist/DataExplorer/data-explorer-resource.component.d.ts.map +1 -1
  81. package/dist/DataExplorer/data-explorer-resource.component.js +10 -0
  82. package/dist/DataExplorer/data-explorer-resource.component.js.map +1 -1
  83. package/dist/KnowledgeHub/components/analytics/analytics-resource.component.d.ts.map +1 -1
  84. package/dist/KnowledgeHub/components/analytics/analytics-resource.component.js +12 -9
  85. package/dist/KnowledgeHub/components/analytics/analytics-resource.component.js.map +1 -1
  86. package/dist/KnowledgeHub/components/clusters/cluster-visualization-resource.component.d.ts +27 -2
  87. package/dist/KnowledgeHub/components/clusters/cluster-visualization-resource.component.d.ts.map +1 -1
  88. package/dist/KnowledgeHub/components/clusters/cluster-visualization-resource.component.js +244 -120
  89. package/dist/KnowledgeHub/components/clusters/cluster-visualization-resource.component.js.map +1 -1
  90. package/dist/KnowledgeHub/components/visualize/record-drilldown/record-drilldown.component.d.ts +65 -0
  91. package/dist/KnowledgeHub/components/visualize/record-drilldown/record-drilldown.component.d.ts.map +1 -0
  92. package/dist/KnowledgeHub/components/visualize/record-drilldown/record-drilldown.component.js +176 -0
  93. package/dist/KnowledgeHub/components/visualize/record-drilldown/record-drilldown.component.js.map +1 -0
  94. package/dist/KnowledgeHub/components/visualize/tag-cloud/tag-cloud.component.d.ts +81 -0
  95. package/dist/KnowledgeHub/components/visualize/tag-cloud/tag-cloud.component.d.ts.map +1 -0
  96. package/dist/KnowledgeHub/components/visualize/tag-cloud/tag-cloud.component.js +308 -0
  97. package/dist/KnowledgeHub/components/visualize/tag-cloud/tag-cloud.component.js.map +1 -0
  98. package/dist/KnowledgeHub/components/visualize/visualize-resource.component.d.ts +85 -0
  99. package/dist/KnowledgeHub/components/visualize/visualize-resource.component.d.ts.map +1 -0
  100. package/dist/KnowledgeHub/components/visualize/visualize-resource.component.js +362 -0
  101. package/dist/KnowledgeHub/components/visualize/visualize-resource.component.js.map +1 -0
  102. package/dist/KnowledgeHub/index.d.ts +3 -0
  103. package/dist/KnowledgeHub/index.d.ts.map +1 -1
  104. package/dist/KnowledgeHub/index.js +3 -0
  105. package/dist/KnowledgeHub/index.js.map +1 -1
  106. package/dist/MCP/components/mcp-server-dialog.component.js +2 -2
  107. package/dist/QueryBrowser/query-browser-resource.component.js +1 -1
  108. package/dist/QueryBrowser/query-browser-resource.component.js.map +1 -1
  109. package/dist/ai-dashboards.module.d.ts +48 -38
  110. package/dist/ai-dashboards.module.d.ts.map +1 -1
  111. package/dist/ai-dashboards.module.js +41 -1
  112. package/dist/ai-dashboards.module.js.map +1 -1
  113. package/dist/data-explorer-dashboards.module.d.ts +12 -14
  114. package/dist/data-explorer-dashboards.module.d.ts.map +1 -1
  115. package/dist/data-explorer-dashboards.module.js +5 -14
  116. package/dist/data-explorer-dashboards.module.js.map +1 -1
  117. package/dist/public-api.d.ts +3 -0
  118. package/dist/public-api.d.ts.map +1 -1
  119. package/dist/public-api.js +3 -0
  120. package/dist/public-api.js.map +1 -1
  121. package/package.json +57 -55
  122. package/dist/DataExplorer/components/filter-dialog/filter-dialog.component.d.ts +0 -79
  123. package/dist/DataExplorer/components/filter-dialog/filter-dialog.component.d.ts.map +0 -1
  124. package/dist/DataExplorer/components/filter-dialog/filter-dialog.component.js +0 -195
  125. package/dist/DataExplorer/components/filter-dialog/filter-dialog.component.js.map +0 -1
  126. package/dist/DataExplorer/components/view-selector/view-selector.component.d.ts +0 -226
  127. package/dist/DataExplorer/components/view-selector/view-selector.component.d.ts.map +0 -1
  128. package/dist/DataExplorer/components/view-selector/view-selector.component.js +0 -861
  129. package/dist/DataExplorer/components/view-selector/view-selector.component.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"cluster-visualization-resource.component.js","sourceRoot":"","sources":["../../../../src/KnowledgeHub/components/clusters/cluster-visualization-resource.component.ts","../../../../src/KnowledgeHub/components/clusters/cluster-visualization-resource.component.html"],"names":[],"mappings":"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","sourcesContent":["/**\n * @fileoverview Knowledge Hub Clusters Dashboard Tab\n *\n * Full-page cluster visualization with:\n * - Left sidebar: saved cluster visualizations (persisted via UserInfoEngine)\n * - Main area: SVG scatter plot (mj-cluster-scatter)\n * - Floating config panel (mj-cluster-config-panel)\n * - Top metrics bar\n *\n * Registered as BaseResourceComponent for the Knowledge Hub application.\n */\n\nimport { Component, ChangeDetectorRef, OnDestroy, AfterViewInit, inject, ViewChild } from '@angular/core';\nimport { Subject } from 'rxjs';\nimport { CompositeKey, Metadata, EntityFieldInfo } from '@memberjunction/core';\nimport { ResourceData, UserInfoEngine, MJUserSettingEntity, KnowledgeHubMetadataEngine } from '@memberjunction/core-entities';\nimport { RegisterClass } from '@memberjunction/global';\nimport { BaseResourceComponent, NavigationService } from '@memberjunction/ng-shared';\nimport { GraphQLDataProvider, GraphQLAIClient } from '@memberjunction/graphql-dataprovider';\nimport { AIEngineBase } from '@memberjunction/ai-engine-base';\nimport {\n ClusterConfig,\n ClusterConfigPanelEntityOption,\n ClusterConfigPanelEntityDocOption,\n ClusterInputVector,\n ClusterVisualizationResult,\n ClusterMetrics,\n ClusterPoint,\n ClusterLabel,\n SavedClusterVisualization,\n DefaultClusterConfig,\n ViewportTransform,\n} from '@memberjunction/ng-clustering';\nimport { ClusteringService, ClusterScatterComponent } from '@memberjunction/ng-clustering';\n\n/**\n * Build an environment-scoped storage key so cluster data does not bleed\n * across different database environments that share the same browser.\n * Uses the GraphQL endpoint origin as the environment fingerprint.\n */\nfunction buildEnvScopedKey(base: string): string {\n try {\n const origin = (Metadata.Provider as GraphQLDataProvider).ConfigData?.URL; // global-provider-ok: free helper function — no component context\n if (origin) {\n // Use just the origin portion (protocol + host) so path differences don't fragment keys\n const url = new URL(origin);\n return `${base}_${url.origin}`;\n }\n } catch { /* fall through */ }\n return base;\n}\n\nconst SAVED_CLUSTERS_BASE_KEY = 'KnowledgeHub_SavedClusters';\nconst LAST_SESSION_BASE_KEY = 'KnowledgeHub_LastClusterSession';\n\n@RegisterClass(BaseResourceComponent, 'ClusterVisualizationResource')\n@Component({\n standalone: false,\n selector: 'app-cluster-visualization-resource',\n templateUrl: './cluster-visualization-resource.component.html',\n styleUrls: ['./cluster-visualization-resource.component.css'],\n})\nexport class ClusterVisualizationResourceComponent extends BaseResourceComponent implements AfterViewInit, OnDestroy {\n @ViewChild('scatterPlot') scatterPlot?: ClusterScatterComponent;\n\n private cdr = inject(ChangeDetectorRef);\n private clusteringService = inject(ClusteringService);\n protected override navigationService = inject(NavigationService);\n protected override destroy$ = new Subject<void>();\n\n /** LLM-generated cluster labels for the current result */\n public ClusterLabels: ClusterLabel[] = [];\n\n // ================================================================\n // Resource overrides\n // ================================================================\n\n async GetResourceDisplayName(_data: ResourceData): Promise<string> {\n return 'Clusters';\n }\n\n async GetResourceIconClass(_data: ResourceData): Promise<string> {\n return 'fa-solid fa-circle-nodes';\n }\n\n // ================================================================\n // State\n // ================================================================\n\n /** Current visualization result */\n public Result: ClusterVisualizationResult | null = null;\n /** Whether a clustering run is in progress */\n public IsRunning = false;\n /** The active cluster config */\n public ActiveConfig: ClusterConfig = DefaultClusterConfig();\n /** Title for the top bar */\n public VisualizationTitle = 'New Cluster Analysis';\n /** Entity options for the config panel dropdown */\n public EntityOptions: ClusterConfigPanelEntityOption[] = [];\n /** Entity document options for the selected entity (shown when 2+) */\n public EntityDocOptions: ClusterConfigPanelEntityDocOption[] = [];\n /** Ordered field keys for prioritized display in scatter tooltip/detail */\n public FieldPriority: string[] = [];\n /** Map of field names to human-readable display names */\n public FieldDisplayNames: Record<string, string> = {};\n\n // Saved visualizations\n public SavedVisualizations: SavedClusterVisualization[] = [];\n public ActiveSavedId: string | null = null;\n\n // User setting entity for persistence\n private userSettingEntity: MJUserSettingEntity | null = null;\n\n // ================================================================\n // Lifecycle\n // ================================================================\n\n async ngAfterViewInit(): Promise<void> {\n await this.loadEntityOptions();\n this.loadSavedVisualizations();\n this.restoreLastSession();\n this.navigationService.SetAgentContext(this, {\n IsVisualizationLoaded: !!this.Result,\n VisualizationTitle: this.VisualizationTitle || null,\n ClusterCount: this.Result?.Clusters?.length ?? 0,\n TotalPoints: this.Result?.Points?.length ?? 0,\n });\n this.NotifyLoadComplete();\n }\n\n ngOnDestroy(): void {\n super.ngOnDestroy();\n this.destroy$.next();\n this.destroy$.complete();\n }\n\n // ================================================================\n // Getters\n // ================================================================\n\n public get Metrics(): ClusterMetrics | null {\n return this.Result?.Metrics ?? null;\n }\n\n public get HasResult(): boolean {\n return this.Result != null && this.Result.Points.length > 0;\n }\n\n public get SilhouetteScoreFormatted(): string {\n return this.Result?.Metrics?.SilhouetteScore?.toFixed(2) ?? '--';\n }\n\n public get IsSilhouetteGood(): boolean {\n return (this.Result?.Metrics?.SilhouetteScore ?? 0) >= 0.5;\n }\n\n public get ComputationTimeFormatted(): string {\n const ms = this.Result?.Metrics?.ComputationTimeMs ?? 0;\n return ms >= 1000 ? `${(ms / 1000).toFixed(1)}s` : `${ms}ms`;\n }\n\n // ================================================================\n // Public Methods\n // ================================================================\n\n /** Handle \"Run Clustering\" from the config panel */\n public async OnRunClustering(config: ClusterConfig): Promise<void> {\n this.IsRunning = true;\n this.ActiveConfig = config;\n this.ClusterLabels = [];\n\n // Auto-hide detail panel from previous visualization\n this.scatterPlot?.CloseDetailPanel();\n\n // Update entity doc options if entity changed\n this.updateEntityDocOptions(config.EntityName);\n\n this.cdr.detectChanges();\n\n try {\n // Fetch vectors from the vector database\n const vectors = await this.fetchVectorsForEntity(config);\n\n // Run clustering (client-side UMAP + K-Means/DBSCAN)\n this.Result = await this.clusteringService.RunClustering(vectors, config);\n this.VisualizationTitle = `${config.EntityName} — ${config.Algorithm === 'kmeans' ? 'K-Means' : 'DBSCAN'}`;\n this.FieldPriority = this.ComputeFieldPriority(config.EntityName);\n\n // Fire LLM cluster naming in the background (non-blocking).\n // Clusters render immediately; labels appear when LLM responds.\n this.requestClusterLabelsFromLLM().catch(err =>\n console.warn('[ClusterVisualization] Background naming failed:', err)\n );\n // Auto-save session state so it can be restored after navigation\n this.saveLastSession();\n } catch (error) {\n console.error('[ClusterVisualization] Pipeline error:', error);\n this.Result = null;\n } finally {\n this.IsRunning = false;\n this.cdr.detectChanges();\n }\n }\n\n /** Handle point click — log for now */\n public OnPointClicked(_point: ClusterPoint): void {\n // Detail panel is handled by the scatter component internally\n }\n\n /** Handle point hover */\n public OnPointHovered(_point: ClusterPoint | null): void {\n // Tooltip display handled by scatter component\n }\n\n /** Navigate to the entity record when \"Open Record\" is clicked in the detail panel */\n public OnOpenRecord(point: ClusterPoint): void {\n const entityName = point.Metadata?.['Entity'] as string;\n const recordID = point.Metadata?.['RecordID'] as string;\n if (!entityName || !recordID) return;\n\n const compositeKey = new CompositeKey();\n compositeKey.SimpleLoadFromURLSegment(recordID);\n this.navigationService.OpenEntityRecord(entityName, compositeKey);\n }\n\n /** Save the current visualization */\n public async OnSaveVisualization(): Promise<void> {\n if (!this.Result) return;\n\n const id = crypto.randomUUID();\n const saved: SavedClusterVisualization = {\n Id: id,\n Name: this.VisualizationTitle,\n EntityName: this.ActiveConfig.EntityName,\n Algorithm: this.ActiveConfig.Algorithm,\n Params: { ...this.ActiveConfig },\n CreatedAt: new Date().toISOString(),\n Result: this.stripVectorsFromResult(this.Result),\n Viewport: this.scatterPlot?.GetViewportTransform(),\n ClusterLabels: this.ClusterLabels.length > 0 ? [...this.ClusterLabels] : undefined,\n };\n\n this.SavedVisualizations = [saved, ...this.SavedVisualizations];\n this.ActiveSavedId = id;\n await this.persistSavedVisualizations();\n this.cdr.detectChanges();\n }\n\n /** Select a saved visualization — restore from cache if available, otherwise re-run */\n public async OnSelectSaved(saved: SavedClusterVisualization): Promise<void> {\n this.scatterPlot?.CloseDetailPanel();\n this.ActiveSavedId = saved.Id;\n this.VisualizationTitle = saved.Name;\n\n // Reconstruct config\n const config: ClusterConfig = {\n ...DefaultClusterConfig(),\n ...saved.Params,\n EntityName: saved.EntityName,\n Algorithm: saved.Algorithm,\n };\n this.ActiveConfig = config;\n\n // If we have cached results, restore instantly without re-running\n if (saved.Result) {\n this.Result = saved.Result;\n this.ClusterLabels = saved.ClusterLabels ?? [];\n this.applyLabelsToResult();\n this.cdr.detectChanges();\n\n // Restore viewport after a tick (scatter needs to render first)\n if (saved.Viewport) {\n setTimeout(() => {\n this.scatterPlot?.SetViewportTransform(saved.Viewport!);\n this.cdr.detectChanges();\n }, 50);\n }\n return;\n }\n\n // No cached results — re-run from scratch\n await this.OnRunClustering(config);\n }\n\n /** Delete a saved visualization */\n public async OnDeleteSaved(saved: SavedClusterVisualization, event: MouseEvent): Promise<void> {\n event.stopPropagation();\n this.SavedVisualizations = this.SavedVisualizations.filter(s => s.Id !== saved.Id);\n if (this.ActiveSavedId === saved.Id) {\n this.ActiveSavedId = null;\n }\n await this.persistSavedVisualizations();\n this.cdr.detectChanges();\n }\n\n /** Start a new analysis (clear current) */\n public OnNewAnalysis(): void {\n this.scatterPlot?.CloseDetailPanel();\n this.ActiveSavedId = null;\n this.Result = null;\n this.ClusterLabels = [];\n this.VisualizationTitle = 'New Cluster Analysis';\n this.ActiveConfig = DefaultClusterConfig();\n this.cdr.detectChanges();\n }\n\n public IsActiveSaved(saved: SavedClusterVisualization): boolean {\n return this.ActiveSavedId === saved.Id;\n }\n\n public TrackSavedBy(_index: number, saved: SavedClusterVisualization): string {\n return saved.Id;\n }\n\n public FormatDate(iso: string): string {\n try {\n return new Date(iso).toLocaleDateString();\n } catch {\n return iso;\n }\n }\n\n // ================================================================\n // Private Methods\n // ================================================================\n\n /** Populate the entity options for the config panel dropdown */\n private async loadEntityOptions(): Promise<void> {\n try {\n // Use KnowledgeHubMetadataEngine for cached entity document data\n const engine = KnowledgeHubMetadataEngine.Instance;\n await engine.Config(false);\n\n const entityNames = engine.GetEntitiesWithDocuments();\n if (entityNames.length > 0) {\n this.EntityOptions = entityNames.map(name => ({ Name: name }));\n }\n\n // Set default entity if config is blank\n if (this.EntityOptions.length > 0 && !this.ActiveConfig.EntityName) {\n this.ActiveConfig.EntityName = this.EntityOptions[0].Name;\n }\n\n // Populate entity doc options for the default entity\n this.updateEntityDocOptions(this.ActiveConfig.EntityName);\n } catch (error) {\n console.warn('[ClusterVisualization] Error loading entity options:', error);\n }\n this.cdr.detectChanges();\n }\n\n /** Update entity document options when the selected entity changes */\n private updateEntityDocOptions(entityName: string): void {\n if (!entityName) {\n this.EntityDocOptions = [];\n return;\n }\n\n const engine = KnowledgeHubMetadataEngine.Instance;\n const docs = engine.GetEntityDocumentsForEntity(entityName)\n .filter(d => d.Status === 'Active');\n\n this.EntityDocOptions = docs.map(d => ({ ID: d.ID, Name: d.Name }));\n\n // Auto-select the first doc (or clear if none)\n if (docs.length > 0 && !this.ActiveConfig.EntityDocumentID) {\n this.ActiveConfig.EntityDocumentID = docs[0].ID;\n } else if (docs.length === 0) {\n this.ActiveConfig.EntityDocumentID = '';\n }\n }\n\n /**\n * Fetch vectors from Entity Document Runs via RunView.\n * Entity Documents store vectorized entity data; we query for runs\n * that match the requested entity.\n */\n private async fetchVectorsForEntity(config: ClusterConfig): Promise<ClusterInputVector[]> {\n // Use the selected entity document, or fall back to first active one\n let entityDocID = config.EntityDocumentID;\n if (!entityDocID) {\n const engine = KnowledgeHubMetadataEngine.Instance;\n const entityDocs = engine.GetEntityDocumentsForEntity(config.EntityName)\n .filter(d => d.Status === 'Active');\n if (entityDocs.length === 0) {\n return [];\n }\n entityDocID = entityDocs[0].ID;\n }\n\n // Fetch vectors + metadata directly from the vector database (Pinecone)\n const provider = this.ProviderToUse as GraphQLDataProvider;\n const aiClient = new GraphQLAIClient(provider);\n const result = await aiClient.FetchEntityVectors({\n entityDocumentID: entityDocID,\n maxRecords: config.MaxRecords,\n filter: config.Filter || undefined,\n });\n\n if (!result.Success || result.Results.length === 0) {\n return [];\n }\n\n // Convert vector DB results to ClusterInputVector format\n const vectors: ClusterInputVector[] = [];\n for (const item of result.Results) {\n if (!item.Values || item.Values.length === 0) continue;\n\n const metadata = this.parseVectorMetadata(item.Metadata);\n const label = this.buildLabel(metadata);\n\n vectors.push({\n Key: item.ID,\n Label: label,\n Vector: item.Values,\n Metadata: metadata,\n });\n }\n\n return vectors;\n }\n\n /** Parse the JSON metadata string from the vector DB into a record */\n private parseVectorMetadata(metadataJson: string): Record<string, string> {\n try {\n return JSON.parse(metadataJson) as Record<string, string>;\n } catch {\n return {};\n }\n }\n\n /**\n * Build a human-readable label from vector metadata using entity field metadata.\n * Combines all IsNameField fields in Sequence order (e.g., \"Sarah Chen\" from FirstName + LastName).\n * Falls back to heuristic field detection when entity metadata isn't available.\n */\n private buildLabel(metadata: Record<string, string>): string {\n const entityName = metadata['Entity'];\n if (entityName) {\n try {\n const md = this.ProviderToUse;\n const entityInfo = md.Entities.find(e => e.Name === entityName);\n if (entityInfo) {\n // Combine all IsNameField fields in Sequence order\n const nameFields = entityInfo.Fields\n .filter(f => f.IsNameField)\n .sort((a, b) => (a.Sequence ?? 9999) - (b.Sequence ?? 9999));\n if (nameFields.length > 0) {\n const parts = nameFields\n .map(f => metadata[f.Name])\n .filter(v => v != null && v.trim() !== '');\n if (parts.length > 0) return parts.join(' ');\n }\n // Single NameField fallback\n if (entityInfo.NameField && metadata[entityInfo.NameField.Name]) {\n return metadata[entityInfo.NameField.Name];\n }\n }\n } catch { /* metadata not available, fall through */ }\n }\n // Heuristic fallbacks\n return metadata['Name']\n || metadata['Title']\n || metadata['Description']?.substring(0, 60)\n || metadata['RecordID']\n || 'Unknown';\n }\n\n // ================================================================\n // LLM Cluster Naming\n // ================================================================\n\n /**\n * After clustering completes, send sample records per cluster to an LLM for naming.\n * Updates ClusterLabels and refreshes the view.\n */\n private async requestClusterLabelsFromLLM(): Promise<void> {\n if (!this.Result || this.Result.Clusters.length === 0) return;\n\n try {\n const clusterData = this.buildClusterDataForPrompt(this.Result);\n if (!clusterData) return;\n\n // AIEngineBase is deferred at startup; ensure it's loaded before reading .Prompts.\n await AIEngineBase.Instance.EnsureLoaded();\n // Look up the \"Cluster Naming\" prompt from AIEngineBase cached metadata\n const promptEntity = AIEngineBase.Instance.Prompts.find(p => p.Name === 'Cluster Naming');\n if (!promptEntity) {\n console.warn('[ClusterVisualization] \"Cluster Naming\" prompt not found — run metadata sync');\n return;\n }\n\n const provider = this.ProviderToUse as GraphQLDataProvider;\n const aiClient = new GraphQLAIClient(provider);\n const result = await aiClient.RunAIPrompt({\n promptId: promptEntity.ID,\n data: { clusterData },\n });\n\n if (result.success && result.parsedResult) {\n const labels = result.parsedResult as Array<{ clusterId: number; label: string }>;\n this.ClusterLabels = labels.map(l => ({\n ClusterId: l.clusterId,\n Label: l.label,\n IsUserEdited: false,\n }));\n this.applyLabelsToResult();\n this.cdr.detectChanges();\n }\n } catch (error) {\n console.warn('[ClusterVisualization] LLM cluster naming failed:', error);\n }\n }\n\n /** Build a text block describing sample records per cluster for the LLM prompt */\n private buildClusterDataForPrompt(result: ClusterVisualizationResult): string | null {\n if (!result.Clusters || result.Clusters.length === 0) return null;\n\n const lines: string[] = [];\n for (const cluster of result.Clusters) {\n // Get points in this cluster, take up to 5 samples\n const clusterPoints = result.Points.filter(p => p.ClusterId === cluster.Id);\n const samples = clusterPoints.slice(0, 5);\n if (samples.length === 0) continue;\n\n lines.push(`### Cluster ${cluster.Id} (${clusterPoints.length} records)`);\n for (const point of samples) {\n const meta = point.Metadata || {};\n // Include the most informative metadata fields\n const fields = ['Name', 'Title', 'Description', 'Entity', 'Status', 'Type']\n .filter(f => meta[f])\n .map(f => `${f}: ${meta[f]}`)\n .join(', ');\n lines.push(`- ${fields || point.Label}`);\n }\n lines.push('');\n }\n\n return lines.join('\\n');\n }\n\n /**\n * Handle inline label edits from the scatter component legend.\n * Updates the ClusterLabels cache and marks the label as user-edited.\n */\n public OnLabelEdited(event: { ClusterId: number; OldLabel: string; NewLabel: string }): void {\n const existing = this.ClusterLabels.find(l => l.ClusterId === event.ClusterId);\n if (existing) {\n existing.Label = event.NewLabel;\n existing.IsUserEdited = true;\n } else {\n this.ClusterLabels.push({\n ClusterId: event.ClusterId,\n Label: event.NewLabel,\n IsUserEdited: true,\n });\n }\n this.cdr.detectChanges();\n }\n\n /**\n * Compute the prioritized field order and display names from entity metadata.\n * Sets both FieldPriority and FieldDisplayNames.\n * Returns field names sorted: IsNameField first, then DefaultInView by Sequence,\n * then remaining fields by Sequence.\n */\n private ComputeFieldPriority(entityName: string): string[] {\n try {\n const md = this.ProviderToUse;\n const entityInfo = md.Entities.find(e => e.Name === entityName);\n if (!entityInfo) return [];\n\n const internalKeys = new Set([\n 'ID', 'Entity', 'EntityIcon', 'RecordID', 'TemplateID',\n '__mj_UpdatedAt', '__mj_CreatedAt',\n ]);\n\n // Build display names map\n const displayNames: Record<string, string> = {};\n for (const f of entityInfo.Fields) {\n displayNames[f.Name] = f.DisplayNameOrName;\n }\n this.FieldDisplayNames = displayNames;\n\n return entityInfo.Fields\n .filter(f => !internalKeys.has(f.Name) && !f.IsVirtual && !f.IsPrimaryKey)\n .sort((a, b) => {\n if (a.IsNameField !== b.IsNameField) return a.IsNameField ? -1 : 1;\n if (a.DefaultInView !== b.DefaultInView) return a.DefaultInView ? -1 : 1;\n return (a.Sequence ?? 9999) - (b.Sequence ?? 9999);\n })\n .map(f => f.Name);\n } catch {\n return [];\n }\n }\n\n /** Apply cluster labels to the result's Clusters array (sets the Label property) */\n private applyLabelsToResult(): void {\n if (!this.Result || this.ClusterLabels.length === 0) return;\n\n for (const label of this.ClusterLabels) {\n const cluster = this.Result.Clusters.find(c => c.Id === label.ClusterId);\n if (cluster) {\n cluster.Label = label.Label;\n }\n }\n }\n\n /**\n * Strip full vector arrays from the result before saving (they're large and not needed for display).\n * Keeps points with 2D coordinates and metadata but removes the original high-dimensional vectors.\n */\n private stripVectorsFromResult(result: ClusterVisualizationResult): ClusterVisualizationResult {\n return {\n ...result,\n Points: result.Points.map(p => ({\n ...p,\n Vector: [], // Strip the high-dimensional vector — only 2D coords (X, Y) matter for display\n })),\n };\n }\n\n /** Load saved visualizations from UserInfoEngine settings */\n private loadSavedVisualizations(): void {\n try {\n const key = buildEnvScopedKey(SAVED_CLUSTERS_BASE_KEY);\n const engine = UserInfoEngine.Instance;\n const setting = engine.UserSettings.find(s => s.Setting === key);\n if (setting?.Value) {\n this.userSettingEntity = setting;\n this.SavedVisualizations = JSON.parse(setting.Value) as SavedClusterVisualization[];\n }\n } catch (error) {\n console.warn('[ClusterVisualization] Error loading saved visualizations:', error);\n this.SavedVisualizations = [];\n }\n this.cdr.detectChanges();\n }\n\n /**\n * Auto-save the current session to localStorage so it can be restored\n * when the user navigates away and comes back.\n */\n private saveLastSession(): void {\n if (!this.Result) return;\n try {\n const session = {\n Result: this.stripVectorsFromResult(this.Result),\n ClusterLabels: this.ClusterLabels,\n Config: this.ActiveConfig,\n Title: this.VisualizationTitle,\n Viewport: this.scatterPlot?.GetViewportTransform() ?? null,\n };\n localStorage.setItem(buildEnvScopedKey(LAST_SESSION_BASE_KEY), JSON.stringify(session));\n } catch {\n // localStorage quota exceeded or not available — non-critical\n }\n }\n\n /**\n * Restore the last session from localStorage if no saved visualization is active.\n * This handles the \"navigate away and come back\" case.\n */\n private restoreLastSession(): void {\n if (this.Result || this.ActiveSavedId) return; // Already showing something\n try {\n const raw = localStorage.getItem(buildEnvScopedKey(LAST_SESSION_BASE_KEY));\n if (!raw) return;\n const session = JSON.parse(raw) as {\n Result: ClusterVisualizationResult;\n ClusterLabels: ClusterLabel[];\n Config: ClusterConfig;\n Title: string;\n Viewport: ViewportTransform | null;\n };\n this.Result = session.Result;\n this.ClusterLabels = session.ClusterLabels ?? [];\n this.ActiveConfig = session.Config;\n this.VisualizationTitle = session.Title ?? 'Restored Session';\n this.FieldPriority = this.ComputeFieldPriority(session.Config.EntityName);\n this.applyLabelsToResult();\n this.cdr.detectChanges();\n\n // Restore viewport after a tick to let the scatter component render\n if (session.Viewport) {\n setTimeout(() => {\n this.scatterPlot?.SetViewportTransform(session.Viewport!);\n }, 50);\n }\n } catch {\n localStorage.removeItem(buildEnvScopedKey(LAST_SESSION_BASE_KEY));\n }\n }\n\n /** Persist saved visualizations to UserInfoEngine settings */\n private async persistSavedVisualizations(): Promise<void> {\n try {\n const md = this.ProviderToUse;\n const userId = md.CurrentUser?.ID;\n if (!userId) return;\n\n if (!this.userSettingEntity) {\n const key = buildEnvScopedKey(SAVED_CLUSTERS_BASE_KEY);\n const engine = UserInfoEngine.Instance;\n const existing = engine.UserSettings.find(s => s.Setting === key);\n if (existing) {\n this.userSettingEntity = existing;\n } else {\n this.userSettingEntity = await md.GetEntityObject<MJUserSettingEntity>('MJ: User Settings');\n this.userSettingEntity.UserID = userId;\n this.userSettingEntity.Setting = buildEnvScopedKey(SAVED_CLUSTERS_BASE_KEY);\n }\n }\n\n this.userSettingEntity.Value = JSON.stringify(this.SavedVisualizations);\n await this.userSettingEntity.Save();\n } catch (error) {\n console.warn('[ClusterVisualization] Error saving visualizations:', error);\n }\n }\n}\n\n/** Tree-shaking prevention */\nexport function LoadClusterVisualizationResource(): void {\n // Prevents tree-shaking of the component\n}\n","<mj-page-layout>\n <mj-page-header\n Title=\"Cluster Visualization\"\n Icon=\"fa-solid fa-circle-nodes\"\n Subtitle=\"Explore semantic clusters in your knowledge base\">\n <div actions>\n <button mjButton variant=\"primary\" size=\"sm\" (click)=\"OnNewAnalysis()\">\n <i class=\"fa-solid fa-plus\"></i> <span class=\"action-btn-label\">New Analysis</span>\n </button>\n </div>\n </mj-page-header>\n\n <mj-page-body [Flex]=\"true\" [Padding]=\"false\">\n<div class=\"cluster-viz-container\">\n <!-- Left Sidebar: Saved Visualizations -->\n <div class=\"sidebar\">\n <div class=\"sidebar-header\">\n <h2><i class=\"fa-solid fa-circle-nodes\"></i> Saved Clusters</h2>\n </div>\n <div class=\"saved-list\">\n @for (saved of SavedVisualizations; track TrackSavedBy($index, saved)) {\n <div class=\"saved-item\"\n [class.active]=\"IsActiveSaved(saved)\"\n (click)=\"OnSelectSaved(saved)\">\n <div class=\"saved-name\">{{ saved.Name }}</div>\n <div class=\"saved-meta\">\n <span>{{ saved.EntityName }}</span>\n <span>{{ FormatDate(saved.CreatedAt) }}</span>\n </div>\n <button class=\"delete-btn\"\n title=\"Delete\"\n (click)=\"OnDeleteSaved(saved, $event)\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n }\n\n @if (SavedVisualizations.length === 0) {\n <div class=\"no-saved\">\n <i class=\"fa-solid fa-bookmark\"></i>\n <p>No saved visualizations yet</p>\n </div>\n }\n </div>\n </div>\n\n <!-- Main Area -->\n <div class=\"main-area\">\n <!-- Top metrics bar -->\n <div class=\"topbar\">\n <div class=\"topbar-title\">{{ VisualizationTitle }}</div>\n @if (HasResult) {\n <div class=\"metric\">\n <i class=\"fa-solid fa-circle-dot\"></i>\n Records: <span class=\"metric-value\">{{ Result!.Metrics.RecordCount }}</span>\n </div>\n <div class=\"metric\">\n <i class=\"fa-solid fa-layer-group\"></i>\n Clusters: <span class=\"metric-value\">{{ Result!.Metrics.ClusterCount }}</span>\n </div>\n <div class=\"metric\">\n <i class=\"fa-solid fa-chart-line\"></i>\n Silhouette:\n <span class=\"metric-value\" [class.good]=\"IsSilhouetteGood\">\n {{ SilhouetteScoreFormatted }}\n </span>\n </div>\n <div class=\"metric\">\n <i class=\"fa-solid fa-clock\"></i>\n Computed: <span class=\"metric-value\">{{ ComputationTimeFormatted }}</span>\n </div>\n }\n </div>\n\n <!-- Scatter plot area -->\n <div class=\"scatter-area\">\n <mj-cluster-scatter\n #scatterPlot\n [Points]=\"Result?.Points ?? []\"\n [Clusters]=\"Result?.Clusters ?? []\"\n [IsLoading]=\"IsRunning\"\n [EntityName]=\"ActiveConfig.EntityName\"\n (PointClicked)=\"OnPointClicked($event)\"\n (PointHovered)=\"OnPointHovered($event)\"\n (OpenRecordRequested)=\"OnOpenRecord($event)\"\n (LabelEdited)=\"OnLabelEdited($event)\">\n </mj-cluster-scatter>\n\n <!-- Floating config panel -->\n <mj-cluster-config-panel\n [IsRunning]=\"IsRunning\"\n [Metrics]=\"Metrics\"\n [EntityOptions]=\"EntityOptions\"\n [EntityDocOptions]=\"EntityDocOptions\"\n (RunClustering)=\"OnRunClustering($event)\"\n (SaveVisualization)=\"OnSaveVisualization()\">\n </mj-cluster-config-panel>\n </div>\n </div>\n</div>\n </mj-page-body>\n</mj-page-layout>\n"]}
1
+ {"version":3,"file":"cluster-visualization-resource.component.js","sourceRoot":"","sources":["../../../../src/KnowledgeHub/components/clusters/cluster-visualization-resource.component.ts","../../../../src/KnowledgeHub/components/clusters/cluster-visualization-resource.component.html"],"names":[],"mappings":"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","sourcesContent":["/**\n * @fileoverview Knowledge Hub Clusters Dashboard Tab\n *\n * Full-page cluster visualization with:\n * - Left sidebar: saved cluster visualizations (persisted via UserInfoEngine)\n * - Main area: SVG scatter plot (mj-cluster-scatter)\n * - Floating config panel (mj-cluster-config-panel)\n * - Top metrics bar\n *\n * Registered as BaseResourceComponent for the Knowledge Hub application.\n */\n\nimport { Component, ChangeDetectorRef, OnDestroy, AfterViewInit, inject, ViewChild, Input, Output, EventEmitter } from '@angular/core';\nimport { Subject } from 'rxjs';\nimport { CompositeKey, Metadata, EntityFieldInfo } from '@memberjunction/core';\nimport { ResourceData, UserInfoEngine, MJUserSettingEntity, KnowledgeHubMetadataEngine } from '@memberjunction/core-entities';\nimport { RegisterClass } from '@memberjunction/global';\nimport { BaseResourceComponent, NavigationService, ActivityService } from '@memberjunction/ng-shared';\nimport { GraphQLDataProvider, GraphQLAIClient } from '@memberjunction/graphql-dataprovider';\nimport { AIEngineBase } from '@memberjunction/ai-engine-base';\nimport {\n ClusterConfig,\n ClusterConfigPanelEntityOption,\n ClusterConfigPanelEntityDocOption,\n ClusterInputVector,\n ClusterVisualizationResult,\n ClusterMetrics,\n ClusterPoint,\n ClusterLabel,\n SavedClusterVisualization,\n DefaultClusterConfig,\n ViewportTransform,\n} from '@memberjunction/ng-clustering';\nimport { ClusteringService, ClusterScatterComponent } from '@memberjunction/ng-clustering';\n\n/**\n * Build an environment-scoped storage key so cluster data does not bleed\n * across different database environments that share the same browser.\n * Uses the GraphQL endpoint origin as the environment fingerprint.\n */\nfunction buildEnvScopedKey(base: string): string {\n try {\n const origin = (Metadata.Provider as GraphQLDataProvider).ConfigData?.URL; // global-provider-ok: free helper function — no component context\n if (origin) {\n // Use just the origin portion (protocol + host) so path differences don't fragment keys\n const url = new URL(origin);\n return `${base}_${url.origin}`;\n }\n } catch { /* fall through */ }\n return base;\n}\n\nconst SAVED_CLUSTERS_BASE_KEY = 'KnowledgeHub_SavedClusters';\nconst LAST_SESSION_BASE_KEY = 'KnowledgeHub_LastClusterSession';\n\n@RegisterClass(BaseResourceComponent, 'ClusterVisualizationResource')\n@Component({\n standalone: false,\n selector: 'app-cluster-visualization-resource',\n templateUrl: './cluster-visualization-resource.component.html',\n styleUrls: ['./cluster-visualization-resource.component.css'],\n})\nexport class ClusterVisualizationResourceComponent extends BaseResourceComponent implements AfterViewInit, OnDestroy {\n @ViewChild('scatterPlot') scatterPlot?: ClusterScatterComponent;\n\n private cdr = inject(ChangeDetectorRef);\n private clusteringService = inject(ClusteringService);\n private activityService = inject(ActivityService);\n protected override navigationService = inject(NavigationService);\n protected override destroy$ = new Subject<void>();\n\n /** LLM-generated cluster labels for the current result */\n public ClusterLabels: ClusterLabel[] = [];\n\n /**\n * When true, this component is embedded inside the Visualize host surface.\n * In that case the host owns the resource lifecycle (NotifyLoadComplete,\n * agent context) and record navigation, so this component suppresses those\n * and instead emits open-record intents via {@link OpenRecordRequested}.\n */\n @Input() Embedded = false;\n\n /** Emitted (only when Embedded) to ask the host to open an entity record. */\n @Output() OpenRecordRequested = new EventEmitter<{ EntityName: string; RecordID: string }>();\n\n // ================================================================\n // Resource overrides\n // ================================================================\n\n async GetResourceDisplayName(_data: ResourceData): Promise<string> {\n return 'Clusters';\n }\n\n async GetResourceIconClass(_data: ResourceData): Promise<string> {\n return 'fa-solid fa-circle-nodes';\n }\n\n // ================================================================\n // State\n // ================================================================\n\n /** Current visualization result */\n public Result: ClusterVisualizationResult | null = null;\n /** Whether a clustering run is in progress */\n public IsRunning = false;\n /** The active cluster config */\n public ActiveConfig: ClusterConfig = DefaultClusterConfig();\n /** Title for the top bar */\n public VisualizationTitle = 'New Cluster Analysis';\n /** Entity options for the config panel dropdown */\n public EntityOptions: ClusterConfigPanelEntityOption[] = [];\n /** Entity document options for the selected entity (shown when 2+) */\n public EntityDocOptions: ClusterConfigPanelEntityDocOption[] = [];\n /** All entity documents across entities (for the multi-entity source selector) */\n public AllEntityDocOptions: ClusterConfigPanelEntityDocOption[] = [];\n /** User-facing error from the last run (e.g. multi-entity embedding mismatch) */\n public RunError: string | null = null;\n /** Ordered field keys for prioritized display in scatter tooltip/detail */\n public FieldPriority: string[] = [];\n /** Map of field names to human-readable display names */\n public FieldDisplayNames: Record<string, string> = {};\n\n // Saved visualizations\n public SavedVisualizations: SavedClusterVisualization[] = [];\n public ActiveSavedId: string | null = null;\n\n // User setting entity for persistence\n private userSettingEntity: MJUserSettingEntity | null = null;\n\n // ================================================================\n // Lifecycle\n // ================================================================\n\n async ngAfterViewInit(): Promise<void> {\n await this.loadEntityOptions();\n this.loadSavedVisualizations();\n this.restoreLastSession();\n // When embedded in the Visualize host, the host owns agent context +\n // the resource load lifecycle; skip them here to avoid double-reporting.\n if (!this.Embedded) {\n this.navigationService.SetAgentContext(this, {\n IsVisualizationLoaded: !!this.Result,\n VisualizationTitle: this.VisualizationTitle || null,\n ClusterCount: this.Result?.Clusters?.length ?? 0,\n TotalPoints: this.Result?.Points?.length ?? 0,\n });\n this.NotifyLoadComplete();\n }\n }\n\n ngOnDestroy(): void {\n super.ngOnDestroy();\n this.destroy$.next();\n this.destroy$.complete();\n }\n\n // ================================================================\n // Getters\n // ================================================================\n\n public get Metrics(): ClusterMetrics | null {\n return this.Result?.Metrics ?? null;\n }\n\n public get HasResult(): boolean {\n return this.Result != null && this.Result.Points.length > 0;\n }\n\n public get SilhouetteScoreFormatted(): string {\n return this.Result?.Metrics?.SilhouetteScore?.toFixed(2) ?? '--';\n }\n\n public get IsSilhouetteGood(): boolean {\n return (this.Result?.Metrics?.SilhouetteScore ?? 0) >= 0.5;\n }\n\n public get ComputationTimeFormatted(): string {\n const ms = this.Result?.Metrics?.ComputationTimeMs ?? 0;\n return ms >= 1000 ? `${(ms / 1000).toFixed(1)}s` : `${ms}ms`;\n }\n\n // ================================================================\n // Public Methods\n // ================================================================\n\n /** Handle \"Run Clustering\" from the config panel */\n public async OnRunClustering(config: ClusterConfig): Promise<void> {\n this.IsRunning = true;\n this.ActiveConfig = config;\n this.ClusterLabels = [];\n this.RunError = null;\n\n // Auto-hide detail panel from previous visualization\n this.scatterPlot?.CloseDetailPanel();\n\n // Update entity doc options if entity changed\n this.updateEntityDocOptions(config.EntityName);\n\n this.cdr.detectChanges();\n\n const activityID = this.activityService.Start('Cluster analysis', {\n icon: 'fa-solid fa-circle-nodes',\n detail: `${config.EntityName || 'Multiple sources'} · ${config.Algorithm === 'kmeans' ? 'K-Means' : 'DBSCAN'}`,\n });\n try {\n // Fetch vectors from the vector database\n const vectors = await this.fetchVectorsForEntity(config);\n\n // Run clustering (client-side UMAP + K-Means/DBSCAN)\n this.Result = await this.clusteringService.RunClustering(vectors, config);\n this.activityService.Complete(activityID, 'success', `${this.Result.Points.length} points · ${this.Result.Clusters.length} clusters`);\n this.VisualizationTitle = `${config.EntityName} — ${config.Algorithm === 'kmeans' ? 'K-Means' : 'DBSCAN'}`;\n this.FieldPriority = this.ComputeFieldPriority(config.EntityName);\n\n // Fire LLM cluster naming in the background (non-blocking).\n // Clusters render immediately; labels appear when LLM responds.\n this.requestClusterLabelsFromLLM().catch(err =>\n console.warn('[ClusterVisualization] Background naming failed:', err)\n );\n // Auto-save session state so it can be restored after navigation\n this.saveLastSession();\n } catch (error) {\n console.error('[ClusterVisualization] Pipeline error:', error);\n this.Result = null;\n this.RunError = error instanceof Error ? error.message : String(error);\n this.activityService.Complete(activityID, 'error', this.RunError);\n } finally {\n this.IsRunning = false;\n this.cdr.detectChanges();\n }\n }\n\n /**\n * Re-run when the user flips 2D⇄3D so the projection updates immediately.\n * A 3D layout needs a Z coordinate that only a fresh projection produces, so\n * toggling alone wouldn't change the existing plot.\n */\n public OnDimensionsChanged(dims: 2 | 3): void {\n this.ActiveConfig = { ...this.ActiveConfig, Dimensions: dims };\n if (this.Result && this.Result.Points.length > 0 && !this.IsRunning) {\n void this.OnRunClustering(this.ActiveConfig);\n }\n }\n\n /** Handle point click — log for now */\n public OnPointClicked(_point: ClusterPoint): void {\n // Detail panel is handled by the scatter component internally\n }\n\n /** Handle point hover */\n public OnPointHovered(_point: ClusterPoint | null): void {\n // Tooltip display handled by scatter component\n }\n\n /** Navigate to the entity record when \"Open Record\" is clicked in the detail panel */\n public OnOpenRecord(point: ClusterPoint): void {\n const entityName = point.Metadata?.['Entity'] as string;\n const recordID = point.Metadata?.['RecordID'] as string;\n if (!entityName || !recordID) return;\n\n // When embedded, defer navigation to the host (shared drilldown owner).\n if (this.Embedded) {\n this.OpenRecordRequested.emit({ EntityName: entityName, RecordID: recordID });\n return;\n }\n\n const compositeKey = new CompositeKey();\n compositeKey.SimpleLoadFromURLSegment(recordID);\n this.navigationService.OpenEntityRecord(entityName, compositeKey);\n }\n\n /** Save the current visualization */\n public async OnSaveVisualization(): Promise<void> {\n if (!this.Result) return;\n\n const id = crypto.randomUUID();\n const saved: SavedClusterVisualization = {\n Id: id,\n Name: this.VisualizationTitle,\n EntityName: this.ActiveConfig.EntityName,\n Algorithm: this.ActiveConfig.Algorithm,\n Params: { ...this.ActiveConfig },\n CreatedAt: new Date().toISOString(),\n Result: this.stripVectorsFromResult(this.Result),\n Viewport: this.scatterPlot?.GetViewportTransform(),\n ClusterLabels: this.ClusterLabels.length > 0 ? [...this.ClusterLabels] : undefined,\n };\n\n this.SavedVisualizations = [saved, ...this.SavedVisualizations];\n this.ActiveSavedId = id;\n await this.persistSavedVisualizations();\n this.cdr.detectChanges();\n }\n\n /** Select a saved visualization — restore from cache if available, otherwise re-run */\n public async OnSelectSaved(saved: SavedClusterVisualization): Promise<void> {\n this.scatterPlot?.CloseDetailPanel();\n this.ActiveSavedId = saved.Id;\n this.VisualizationTitle = saved.Name;\n\n // Reconstruct config\n const config: ClusterConfig = {\n ...DefaultClusterConfig(),\n ...saved.Params,\n EntityName: saved.EntityName,\n Algorithm: saved.Algorithm,\n };\n this.ActiveConfig = config;\n\n // If we have cached results, restore instantly without re-running\n if (saved.Result) {\n this.Result = saved.Result;\n this.ClusterLabels = saved.ClusterLabels ?? [];\n this.applyLabelsToResult();\n this.cdr.detectChanges();\n\n // Restore viewport after a tick (scatter needs to render first)\n if (saved.Viewport) {\n setTimeout(() => {\n this.scatterPlot?.SetViewportTransform(saved.Viewport!);\n this.cdr.detectChanges();\n }, 50);\n }\n return;\n }\n\n // No cached results — re-run from scratch\n await this.OnRunClustering(config);\n }\n\n /** Delete a saved visualization */\n public async OnDeleteSaved(saved: SavedClusterVisualization, event: MouseEvent): Promise<void> {\n event.stopPropagation();\n this.SavedVisualizations = this.SavedVisualizations.filter(s => s.Id !== saved.Id);\n if (this.ActiveSavedId === saved.Id) {\n this.ActiveSavedId = null;\n }\n await this.persistSavedVisualizations();\n this.cdr.detectChanges();\n }\n\n /** Start a new analysis (clear current) */\n public OnNewAnalysis(): void {\n this.scatterPlot?.CloseDetailPanel();\n this.ActiveSavedId = null;\n this.Result = null;\n this.ClusterLabels = [];\n this.VisualizationTitle = 'New Cluster Analysis';\n this.ActiveConfig = DefaultClusterConfig();\n this.cdr.detectChanges();\n }\n\n public IsActiveSaved(saved: SavedClusterVisualization): boolean {\n return this.ActiveSavedId === saved.Id;\n }\n\n public TrackSavedBy(_index: number, saved: SavedClusterVisualization): string {\n return saved.Id;\n }\n\n public FormatDate(iso: string): string {\n try {\n return new Date(iso).toLocaleDateString();\n } catch {\n return iso;\n }\n }\n\n // ================================================================\n // Private Methods\n // ================================================================\n\n /** Populate the entity options for the config panel dropdown */\n private async loadEntityOptions(): Promise<void> {\n try {\n // Use KnowledgeHubMetadataEngine for cached entity document data\n const engine = KnowledgeHubMetadataEngine.Instance;\n await engine.Config(false);\n\n const entityNames = engine.GetEntitiesWithDocuments();\n if (entityNames.length > 0) {\n this.EntityOptions = entityNames.map(name => ({ Name: name }));\n }\n\n // Build the cross-entity document list that powers the multi-entity\n // source selector (each option tagged with its owning entity).\n const allDocs: ClusterConfigPanelEntityDocOption[] = [];\n for (const name of entityNames) {\n const docs = engine.GetEntityDocumentsForEntity(name).filter(d => d.Status === 'Active');\n for (const d of docs) {\n allDocs.push({ ID: d.ID, Name: d.Name, EntityName: name });\n }\n }\n this.AllEntityDocOptions = allDocs;\n\n // Set default entity if config is blank\n if (this.EntityOptions.length > 0 && !this.ActiveConfig.EntityName) {\n this.ActiveConfig.EntityName = this.EntityOptions[0].Name;\n }\n\n // Populate entity doc options for the default entity\n this.updateEntityDocOptions(this.ActiveConfig.EntityName);\n } catch (error) {\n console.warn('[ClusterVisualization] Error loading entity options:', error);\n }\n this.cdr.detectChanges();\n }\n\n /** Update entity document options when the selected entity changes */\n private updateEntityDocOptions(entityName: string): void {\n if (!entityName) {\n this.EntityDocOptions = [];\n return;\n }\n\n const engine = KnowledgeHubMetadataEngine.Instance;\n const docs = engine.GetEntityDocumentsForEntity(entityName)\n .filter(d => d.Status === 'Active');\n\n this.EntityDocOptions = docs.map(d => ({ ID: d.ID, Name: d.Name }));\n\n // Auto-select the first doc (or clear if none)\n if (docs.length > 0 && !this.ActiveConfig.EntityDocumentID) {\n this.ActiveConfig.EntityDocumentID = docs[0].ID;\n } else if (docs.length === 0) {\n this.ActiveConfig.EntityDocumentID = '';\n }\n }\n\n /**\n * Fetch vectors from Entity Document Runs via RunView.\n * Entity Documents store vectorized entity data; we query for runs\n * that match the requested entity.\n */\n private async fetchVectorsForEntity(config: ClusterConfig): Promise<ClusterInputVector[]> {\n const docIDs = this.resolveDocIDs(config);\n if (docIDs.length === 0) {\n return [];\n }\n\n const isMulti = docIDs.length > 1;\n const docEntityMap = new Map(this.AllEntityDocOptions.map(d => [d.ID, d.EntityName ?? '']));\n const provider = this.ProviderToUse as GraphQLDataProvider;\n const aiClient = new GraphQLAIClient(provider);\n\n const vectors: ClusterInputVector[] = [];\n let expectedLen = -1;\n\n for (const docID of docIDs) {\n const result = await aiClient.FetchEntityVectors({\n entityDocumentID: docID,\n maxRecords: config.MaxRecords,\n filter: config.Filter || undefined,\n });\n if (!result.Success || result.Results.length === 0) continue;\n\n for (const item of result.Results) {\n if (!item.Values || item.Values.length === 0) continue;\n\n // Hard-block multi-entity embedding mismatches: vectors of different\n // dimensionalities live in different spaces and aren't co-clusterable.\n if (isMulti) {\n if (expectedLen === -1) {\n expectedLen = item.Values.length;\n } else if (item.Values.length !== expectedLen) {\n throw new Error(\n 'The selected documents use different embedding models (vector sizes differ), ' +\n 'so their points are not comparable. Pick documents that share the same embedding model.',\n );\n }\n }\n\n const metadata = this.parseVectorMetadata(item.Metadata);\n // Ensure each point knows its source entity for color-by-entity.\n if (isMulti && !metadata['EntityName']) {\n metadata['EntityName'] = docEntityMap.get(docID) ?? metadata['Entity'] ?? '';\n }\n const label = this.buildLabel(metadata);\n\n vectors.push({\n Key: item.ID,\n Label: label,\n Vector: item.Values,\n Metadata: metadata,\n });\n }\n }\n\n return vectors;\n }\n\n /** Resolve which entity-document IDs to source vectors from for a run. */\n private resolveDocIDs(config: ClusterConfig): string[] {\n if (config.EntityDocumentIDs && config.EntityDocumentIDs.length > 0) {\n return config.EntityDocumentIDs;\n }\n if (config.EntityDocumentID) {\n return [config.EntityDocumentID];\n }\n const engine = KnowledgeHubMetadataEngine.Instance;\n const docs = engine.GetEntityDocumentsForEntity(config.EntityName).filter(d => d.Status === 'Active');\n return docs.length > 0 ? [docs[0].ID] : [];\n }\n\n /** Parse the JSON metadata string from the vector DB into a record */\n private parseVectorMetadata(metadataJson: string): Record<string, string> {\n try {\n return JSON.parse(metadataJson) as Record<string, string>;\n } catch {\n return {};\n }\n }\n\n /**\n * Build a human-readable label from vector metadata using entity field metadata.\n * Combines all IsNameField fields in Sequence order (e.g., \"Sarah Chen\" from FirstName + LastName).\n * Falls back to heuristic field detection when entity metadata isn't available.\n */\n private buildLabel(metadata: Record<string, string>): string {\n const entityName = metadata['Entity'];\n if (entityName) {\n try {\n const md = this.ProviderToUse;\n const entityInfo = md.Entities.find(e => e.Name === entityName);\n if (entityInfo) {\n // Combine all IsNameField fields in Sequence order\n const nameFields = entityInfo.Fields\n .filter(f => f.IsNameField)\n .sort((a, b) => (a.Sequence ?? 9999) - (b.Sequence ?? 9999));\n if (nameFields.length > 0) {\n const parts = nameFields\n .map(f => metadata[f.Name])\n .filter(v => v != null && v.trim() !== '');\n if (parts.length > 0) return parts.join(' ');\n }\n // Single NameField fallback\n if (entityInfo.NameField && metadata[entityInfo.NameField.Name]) {\n return metadata[entityInfo.NameField.Name];\n }\n }\n } catch { /* metadata not available, fall through */ }\n }\n // Heuristic fallbacks\n return metadata['Name']\n || metadata['Title']\n || metadata['Description']?.substring(0, 60)\n || metadata['RecordID']\n || 'Unknown';\n }\n\n // ================================================================\n // LLM Cluster Naming\n // ================================================================\n\n /**\n * After clustering completes, send sample records per cluster to an LLM for naming.\n * Updates ClusterLabels and refreshes the view.\n */\n private async requestClusterLabelsFromLLM(): Promise<void> {\n if (!this.Result || this.Result.Clusters.length === 0) return;\n\n try {\n const clusterData = this.buildClusterDataForPrompt(this.Result);\n if (!clusterData) return;\n\n // AIEngineBase is deferred at startup; ensure it's loaded before reading .Prompts.\n await AIEngineBase.Instance.EnsureLoaded();\n // Look up the \"Cluster Naming\" prompt from AIEngineBase cached metadata\n const promptEntity = AIEngineBase.Instance.Prompts.find(p => p.Name === 'Cluster Naming');\n if (!promptEntity) {\n console.warn('[ClusterVisualization] \"Cluster Naming\" prompt not found — run metadata sync');\n return;\n }\n\n const provider = this.ProviderToUse as GraphQLDataProvider;\n const aiClient = new GraphQLAIClient(provider);\n const result = await aiClient.RunAIPrompt({\n promptId: promptEntity.ID,\n data: { clusterData },\n });\n\n if (result.success && result.parsedResult) {\n const labels = result.parsedResult as Array<{ clusterId: number; label: string }>;\n this.ClusterLabels = labels.map(l => ({\n ClusterId: l.clusterId,\n Label: l.label,\n IsUserEdited: false,\n }));\n this.applyLabelsToResult();\n this.cdr.detectChanges();\n }\n } catch (error) {\n console.warn('[ClusterVisualization] LLM cluster naming failed:', error);\n }\n }\n\n /** Build a text block describing sample records per cluster for the LLM prompt */\n private buildClusterDataForPrompt(result: ClusterVisualizationResult): string | null {\n if (!result.Clusters || result.Clusters.length === 0) return null;\n\n const lines: string[] = [];\n for (const cluster of result.Clusters) {\n // Get points in this cluster, take up to 5 samples\n const clusterPoints = result.Points.filter(p => p.ClusterId === cluster.Id);\n const samples = clusterPoints.slice(0, 5);\n if (samples.length === 0) continue;\n\n lines.push(`### Cluster ${cluster.Id} (${clusterPoints.length} records)`);\n for (const point of samples) {\n const meta = point.Metadata || {};\n // Include the most informative metadata fields\n const fields = ['Name', 'Title', 'Description', 'Entity', 'Status', 'Type']\n .filter(f => meta[f])\n .map(f => `${f}: ${meta[f]}`)\n .join(', ');\n lines.push(`- ${fields || point.Label}`);\n }\n lines.push('');\n }\n\n return lines.join('\\n');\n }\n\n /**\n * Handle inline label edits from the scatter component legend.\n * Updates the ClusterLabels cache and marks the label as user-edited.\n */\n public OnLabelEdited(event: { ClusterId: number; OldLabel: string; NewLabel: string }): void {\n const existing = this.ClusterLabels.find(l => l.ClusterId === event.ClusterId);\n if (existing) {\n existing.Label = event.NewLabel;\n existing.IsUserEdited = true;\n } else {\n this.ClusterLabels.push({\n ClusterId: event.ClusterId,\n Label: event.NewLabel,\n IsUserEdited: true,\n });\n }\n this.cdr.detectChanges();\n }\n\n /**\n * Compute the prioritized field order and display names from entity metadata.\n * Sets both FieldPriority and FieldDisplayNames.\n * Returns field names sorted: IsNameField first, then DefaultInView by Sequence,\n * then remaining fields by Sequence.\n */\n private ComputeFieldPriority(entityName: string): string[] {\n try {\n const md = this.ProviderToUse;\n const entityInfo = md.Entities.find(e => e.Name === entityName);\n if (!entityInfo) return [];\n\n const internalKeys = new Set([\n 'ID', 'Entity', 'EntityIcon', 'RecordID', 'TemplateID',\n '__mj_UpdatedAt', '__mj_CreatedAt',\n ]);\n\n // Build display names map\n const displayNames: Record<string, string> = {};\n for (const f of entityInfo.Fields) {\n displayNames[f.Name] = f.DisplayNameOrName;\n }\n this.FieldDisplayNames = displayNames;\n\n return entityInfo.Fields\n .filter(f => !internalKeys.has(f.Name) && !f.IsVirtual && !f.IsPrimaryKey)\n .sort((a, b) => {\n if (a.IsNameField !== b.IsNameField) return a.IsNameField ? -1 : 1;\n if (a.DefaultInView !== b.DefaultInView) return a.DefaultInView ? -1 : 1;\n return (a.Sequence ?? 9999) - (b.Sequence ?? 9999);\n })\n .map(f => f.Name);\n } catch {\n return [];\n }\n }\n\n /** Apply cluster labels to the result's Clusters array (sets the Label property) */\n private applyLabelsToResult(): void {\n if (!this.Result || this.ClusterLabels.length === 0) return;\n\n for (const label of this.ClusterLabels) {\n const cluster = this.Result.Clusters.find(c => c.Id === label.ClusterId);\n if (cluster) {\n cluster.Label = label.Label;\n }\n }\n }\n\n /**\n * Strip full vector arrays from the result before saving (they're large and not needed for display).\n * Keeps points with 2D coordinates and metadata but removes the original high-dimensional vectors.\n */\n private stripVectorsFromResult(result: ClusterVisualizationResult): ClusterVisualizationResult {\n return {\n ...result,\n Points: result.Points.map(p => ({\n ...p,\n Vector: [], // Strip the high-dimensional vector — only 2D coords (X, Y) matter for display\n })),\n };\n }\n\n /** Load saved visualizations from UserInfoEngine settings */\n private loadSavedVisualizations(): void {\n try {\n const key = buildEnvScopedKey(SAVED_CLUSTERS_BASE_KEY);\n const engine = UserInfoEngine.Instance;\n const setting = engine.UserSettings.find(s => s.Setting === key);\n if (setting?.Value) {\n this.userSettingEntity = setting;\n this.SavedVisualizations = JSON.parse(setting.Value) as SavedClusterVisualization[];\n }\n } catch (error) {\n console.warn('[ClusterVisualization] Error loading saved visualizations:', error);\n this.SavedVisualizations = [];\n }\n this.cdr.detectChanges();\n }\n\n /**\n * Auto-save the current session to localStorage so it can be restored\n * when the user navigates away and comes back.\n */\n private saveLastSession(): void {\n if (!this.Result) return;\n try {\n const session = {\n Result: this.stripVectorsFromResult(this.Result),\n ClusterLabels: this.ClusterLabels,\n Config: this.ActiveConfig,\n Title: this.VisualizationTitle,\n Viewport: this.scatterPlot?.GetViewportTransform() ?? null,\n };\n localStorage.setItem(buildEnvScopedKey(LAST_SESSION_BASE_KEY), JSON.stringify(session));\n } catch {\n // localStorage quota exceeded or not available — non-critical\n }\n }\n\n /**\n * Restore the last session from localStorage if no saved visualization is active.\n * This handles the \"navigate away and come back\" case.\n */\n private restoreLastSession(): void {\n if (this.Result || this.ActiveSavedId) return; // Already showing something\n try {\n const raw = localStorage.getItem(buildEnvScopedKey(LAST_SESSION_BASE_KEY));\n if (!raw) return;\n const session = JSON.parse(raw) as {\n Result: ClusterVisualizationResult;\n ClusterLabels: ClusterLabel[];\n Config: ClusterConfig;\n Title: string;\n Viewport: ViewportTransform | null;\n };\n this.Result = session.Result;\n this.ClusterLabels = session.ClusterLabels ?? [];\n this.ActiveConfig = session.Config;\n this.VisualizationTitle = session.Title ?? 'Restored Session';\n this.FieldPriority = this.ComputeFieldPriority(session.Config.EntityName);\n this.applyLabelsToResult();\n this.cdr.detectChanges();\n\n // Restore viewport after a tick to let the scatter component render\n if (session.Viewport) {\n setTimeout(() => {\n this.scatterPlot?.SetViewportTransform(session.Viewport!);\n }, 50);\n }\n } catch {\n localStorage.removeItem(buildEnvScopedKey(LAST_SESSION_BASE_KEY));\n }\n }\n\n /** Persist saved visualizations to UserInfoEngine settings */\n private async persistSavedVisualizations(): Promise<void> {\n try {\n const md = this.ProviderToUse;\n const userId = md.CurrentUser?.ID;\n if (!userId) return;\n\n if (!this.userSettingEntity) {\n const key = buildEnvScopedKey(SAVED_CLUSTERS_BASE_KEY);\n const engine = UserInfoEngine.Instance;\n const existing = engine.UserSettings.find(s => s.Setting === key);\n if (existing) {\n this.userSettingEntity = existing;\n } else {\n this.userSettingEntity = await md.GetEntityObject<MJUserSettingEntity>('MJ: User Settings');\n this.userSettingEntity.UserID = userId;\n this.userSettingEntity.Setting = buildEnvScopedKey(SAVED_CLUSTERS_BASE_KEY);\n }\n }\n\n this.userSettingEntity.Value = JSON.stringify(this.SavedVisualizations);\n await this.userSettingEntity.Save();\n } catch (error) {\n console.warn('[ClusterVisualization] Error saving visualizations:', error);\n }\n }\n}\n\n/** Tree-shaking prevention */\nexport function LoadClusterVisualizationResource(): void {\n // Prevents tree-shaking of the component\n}\n","@if (Embedded) {\n <ng-container *ngTemplateOutlet=\"clusterBody\"></ng-container>\n} @else {\n<mj-page-layout>\n <mj-page-header\n Title=\"Cluster Visualization\"\n Icon=\"fa-solid fa-circle-nodes\"\n Subtitle=\"Explore semantic clusters in your knowledge base\">\n <div actions>\n <button mjButton variant=\"primary\" size=\"sm\" (click)=\"OnNewAnalysis()\">\n <i class=\"fa-solid fa-plus\"></i> <span class=\"action-btn-label\">New Analysis</span>\n </button>\n </div>\n </mj-page-header>\n\n <mj-page-body [Flex]=\"true\" [Padding]=\"false\">\n <ng-container *ngTemplateOutlet=\"clusterBody\"></ng-container>\n </mj-page-body>\n</mj-page-layout>\n}\n\n<ng-template #clusterBody>\n<div class=\"cluster-viz-container\">\n <!-- Left Sidebar: Saved Visualizations -->\n <div class=\"sidebar\">\n <div class=\"sidebar-header\">\n <h2><i class=\"fa-solid fa-circle-nodes\"></i> Saved Visualizations</h2>\n </div>\n <div class=\"saved-list\">\n @for (saved of SavedVisualizations; track TrackSavedBy($index, saved)) {\n <div class=\"saved-item\"\n [class.active]=\"IsActiveSaved(saved)\"\n (click)=\"OnSelectSaved(saved)\">\n <div class=\"saved-name\">{{ saved.Name }}</div>\n <div class=\"saved-meta\">\n <span>{{ saved.EntityName }}</span>\n <span>{{ FormatDate(saved.CreatedAt) }}</span>\n </div>\n <button class=\"delete-btn\"\n title=\"Delete\"\n (click)=\"OnDeleteSaved(saved, $event)\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n }\n\n @if (SavedVisualizations.length === 0) {\n <div class=\"no-saved\">\n <i class=\"fa-solid fa-bookmark\"></i>\n <p>No saved visualizations yet</p>\n </div>\n }\n </div>\n </div>\n\n <!-- Main Area -->\n <div class=\"main-area\">\n <!-- Top metrics bar -->\n <div class=\"topbar\">\n <div class=\"topbar-title\">{{ VisualizationTitle }}</div>\n @if (HasResult) {\n <div class=\"metric\">\n <i class=\"fa-solid fa-circle-dot\"></i>\n Records: <span class=\"metric-value\">{{ Result!.Metrics.RecordCount }}</span>\n </div>\n <div class=\"metric\">\n <i class=\"fa-solid fa-layer-group\"></i>\n Clusters: <span class=\"metric-value\">{{ Result!.Metrics.ClusterCount }}</span>\n </div>\n <div class=\"metric\">\n <i class=\"fa-solid fa-chart-line\"></i>\n Silhouette:\n <span class=\"metric-value\" [class.good]=\"IsSilhouetteGood\">\n {{ SilhouetteScoreFormatted }}\n </span>\n </div>\n <div class=\"metric\">\n <i class=\"fa-solid fa-clock\"></i>\n Computed: <span class=\"metric-value\">{{ ComputationTimeFormatted }}</span>\n </div>\n }\n </div>\n\n <!-- Scatter plot area -->\n <div class=\"scatter-area\">\n <mj-cluster-scatter\n #scatterPlot\n [Points]=\"Result?.Points ?? []\"\n [Clusters]=\"Result?.Clusters ?? []\"\n [IsLoading]=\"IsRunning\"\n [ColorBy]=\"ActiveConfig.ColorBy ?? 'cluster'\"\n [EntityName]=\"ActiveConfig.EntityName\"\n (PointClicked)=\"OnPointClicked($event)\"\n (PointHovered)=\"OnPointHovered($event)\"\n (OpenRecordRequested)=\"OnOpenRecord($event)\"\n (LabelEdited)=\"OnLabelEdited($event)\">\n </mj-cluster-scatter>\n\n <!-- Run error banner (e.g. multi-entity embedding mismatch) -->\n @if (RunError) {\n <div class=\"cluster-run-error\">\n <i class=\"fa-solid fa-triangle-exclamation\"></i>\n <span>{{ RunError }}</span>\n </div>\n }\n\n <!-- Floating config panel -->\n <mj-cluster-config-panel\n [IsRunning]=\"IsRunning\"\n [Metrics]=\"Metrics\"\n [EntityOptions]=\"EntityOptions\"\n [EntityDocOptions]=\"EntityDocOptions\"\n [AllEntityDocOptions]=\"AllEntityDocOptions\"\n (RunClustering)=\"OnRunClustering($event)\"\n (DimensionsChanged)=\"OnDimensionsChanged($event)\"\n (SaveVisualization)=\"OnSaveVisualization()\">\n </mj-cluster-config-panel>\n </div>\n </div>\n</div>\n</ng-template>\n"]}
@@ -0,0 +1,65 @@
1
+ /**
2
+ * @fileoverview Shared Record Drilldown Panel
3
+ *
4
+ * A single, reusable side panel that lists records behind a selection on the
5
+ * Knowledge Hub "Visualize" surface. It is driven entirely by inputs and emits
6
+ * record-open intents up to the host — it never imports NavigationService, so it
7
+ * stays a generic child that the KH resource host wires to navigation.
8
+ *
9
+ * Consumed by BOTH:
10
+ * - Cluster-point selection: the host passes a single record row.
11
+ * - Tag-cloud word selection: the host passes the records carrying that tag.
12
+ */
13
+ import { EventEmitter } from '@angular/core';
14
+ import * as i0 from "@angular/core";
15
+ /**
16
+ * A single record row shown in the drilldown panel. `EntityName` + `RecordID`
17
+ * are the open-intent payload; `Title`/`Subtitle`/`Weight` are display-only.
18
+ */
19
+ export interface DrilldownRecord {
20
+ /** Entity the record belongs to (e.g. 'MJ: Content Items' or a business entity). */
21
+ EntityName: string;
22
+ /** Primary-key URL segment used to open the record. */
23
+ RecordID: string;
24
+ /** Primary display label. */
25
+ Title: string;
26
+ /** Optional secondary line (source, content type, etc.). */
27
+ Subtitle?: string;
28
+ /** Optional weight/relevance shown as a chip (0.0 - 1.0). */
29
+ Weight?: number;
30
+ }
31
+ /**
32
+ * Emitted when the user asks to open one of the listed records. The host
33
+ * translates this into a NavigationService call.
34
+ */
35
+ export interface DrilldownOpenRequest {
36
+ EntityName: string;
37
+ RecordID: string;
38
+ }
39
+ export declare class RecordDrilldownComponent {
40
+ /** Panel heading (e.g. the tag text or the selected record's label). */
41
+ Title: string;
42
+ /** Optional sub-heading under the title (e.g. "12 records"). */
43
+ Subtitle: string;
44
+ /** Icon class shown next to the title. */
45
+ Icon: string;
46
+ /** Whether the panel is visible. */
47
+ Visible: boolean;
48
+ /** Whether records are currently loading. */
49
+ IsLoading: boolean;
50
+ /** The records to list. */
51
+ Records: DrilldownRecord[];
52
+ /** Emitted when the user closes the panel. */
53
+ Closed: EventEmitter<void>;
54
+ /** Emitted when the user clicks a record to open it. */
55
+ OpenRecord: EventEmitter<DrilldownOpenRequest>;
56
+ OnClose(): void;
57
+ OnOpen(record: DrilldownRecord): void;
58
+ TrackByRecord(_index: number, record: DrilldownRecord): string;
59
+ WeightPercent(weight: number | undefined): number;
60
+ static ɵfac: i0.ɵɵFactoryDeclaration<RecordDrilldownComponent, never>;
61
+ static ɵcmp: i0.ɵɵComponentDeclaration<RecordDrilldownComponent, "app-kh-record-drilldown", never, { "Title": { "alias": "Title"; "required": false; }; "Subtitle": { "alias": "Subtitle"; "required": false; }; "Icon": { "alias": "Icon"; "required": false; }; "Visible": { "alias": "Visible"; "required": false; }; "IsLoading": { "alias": "IsLoading"; "required": false; }; "Records": { "alias": "Records"; "required": false; }; }, { "Closed": "Closed"; "OpenRecord": "OpenRecord"; }, never, never, false, never>;
62
+ }
63
+ /** Tree-shaking prevention */
64
+ export declare function LoadRecordDrilldownComponent(): void;
65
+ //# sourceMappingURL=record-drilldown.component.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"record-drilldown.component.d.ts","sourceRoot":"","sources":["../../../../../src/KnowledgeHub/components/visualize/record-drilldown/record-drilldown.component.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAA4B,YAAY,EAA2B,MAAM,eAAe,CAAC;;AAEhG;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC5B,oFAAoF;IACpF,UAAU,EAAE,MAAM,CAAC;IACnB,uDAAuD;IACvD,QAAQ,EAAE,MAAM,CAAC;IACjB,6BAA6B;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,6DAA6D;IAC7D,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,MAAM,WAAW,oBAAoB;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CACpB;AAED,qBAOa,wBAAwB;IACjC,wEAAwE;IAC/D,KAAK,SAAM;IACpB,gEAAgE;IACvD,QAAQ,SAAM;IACvB,0CAA0C;IACjC,IAAI,SAAsB;IACnC,oCAAoC;IAC3B,OAAO,UAAS;IACzB,6CAA6C;IACpC,SAAS,UAAS;IAC3B,2BAA2B;IAClB,OAAO,EAAE,eAAe,EAAE,CAAM;IAEzC,8CAA8C;IACpC,MAAM,qBAA4B;IAC5C,wDAAwD;IAC9C,UAAU,qCAA4C;IAEzD,OAAO,IAAI,IAAI;IAIf,MAAM,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI;IAOrC,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,GAAG,MAAM;IAI9D,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM;yCAlC/C,wBAAwB;2CAAxB,wBAAwB;CAwCpC;AAED,8BAA8B;AAC9B,wBAAgB,4BAA4B,IAAI,IAAI,CAEnD"}
@@ -0,0 +1,176 @@
1
+ /**
2
+ * @fileoverview Shared Record Drilldown Panel
3
+ *
4
+ * A single, reusable side panel that lists records behind a selection on the
5
+ * Knowledge Hub "Visualize" surface. It is driven entirely by inputs and emits
6
+ * record-open intents up to the host — it never imports NavigationService, so it
7
+ * stays a generic child that the KH resource host wires to navigation.
8
+ *
9
+ * Consumed by BOTH:
10
+ * - Cluster-point selection: the host passes a single record row.
11
+ * - Tag-cloud word selection: the host passes the records carrying that tag.
12
+ */
13
+ import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy } from '@angular/core';
14
+ import * as i0 from "@angular/core";
15
+ import * as i1 from "@memberjunction/ng-shared-generic";
16
+ import * as i2 from "@memberjunction/ng-ui-components";
17
+ function RecordDrilldownComponent_Conditional_0_Conditional_7_Template(rf, ctx) { if (rf & 1) {
18
+ i0.ɵɵelementStart(0, "span", 5);
19
+ i0.ɵɵtext(1);
20
+ i0.ɵɵelementEnd();
21
+ } if (rf & 2) {
22
+ const ctx_r1 = i0.ɵɵnextContext(2);
23
+ i0.ɵɵadvance();
24
+ i0.ɵɵtextInterpolate(ctx_r1.Subtitle);
25
+ } }
26
+ function RecordDrilldownComponent_Conditional_0_Conditional_11_Template(rf, ctx) { if (rf & 1) {
27
+ i0.ɵɵelement(0, "mj-loading", 9);
28
+ } }
29
+ function RecordDrilldownComponent_Conditional_0_Conditional_12_Template(rf, ctx) { if (rf & 1) {
30
+ i0.ɵɵelementStart(0, "div", 10);
31
+ i0.ɵɵelement(1, "i", 11);
32
+ i0.ɵɵelementStart(2, "p");
33
+ i0.ɵɵtext(3, "No records found");
34
+ i0.ɵɵelementEnd()();
35
+ } }
36
+ function RecordDrilldownComponent_Conditional_0_Conditional_13_For_1_Conditional_4_Template(rf, ctx) { if (rf & 1) {
37
+ i0.ɵɵelementStart(0, "span", 16);
38
+ i0.ɵɵtext(1);
39
+ i0.ɵɵelementEnd();
40
+ } if (rf & 2) {
41
+ const record_r4 = i0.ɵɵnextContext().$implicit;
42
+ i0.ɵɵadvance();
43
+ i0.ɵɵtextInterpolate(record_r4.Subtitle);
44
+ } }
45
+ function RecordDrilldownComponent_Conditional_0_Conditional_13_For_1_Conditional_5_Template(rf, ctx) { if (rf & 1) {
46
+ i0.ɵɵelementStart(0, "span", 17);
47
+ i0.ɵɵtext(1);
48
+ i0.ɵɵelementEnd();
49
+ } if (rf & 2) {
50
+ const record_r4 = i0.ɵɵnextContext().$implicit;
51
+ const ctx_r1 = i0.ɵɵnextContext(3);
52
+ i0.ɵɵadvance();
53
+ i0.ɵɵtextInterpolate1("", ctx_r1.WeightPercent(record_r4.Weight), "%");
54
+ } }
55
+ function RecordDrilldownComponent_Conditional_0_Conditional_13_For_1_Template(rf, ctx) { if (rf & 1) {
56
+ const _r3 = i0.ɵɵgetCurrentView();
57
+ i0.ɵɵelementStart(0, "div", 13);
58
+ i0.ɵɵlistener("click", function RecordDrilldownComponent_Conditional_0_Conditional_13_For_1_Template_div_click_0_listener() { const record_r4 = i0.ɵɵrestoreView(_r3).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.OnOpen(record_r4)); });
59
+ i0.ɵɵelementStart(1, "div", 14)(2, "span", 15);
60
+ i0.ɵɵtext(3);
61
+ i0.ɵɵelementEnd();
62
+ i0.ɵɵconditionalCreate(4, RecordDrilldownComponent_Conditional_0_Conditional_13_For_1_Conditional_4_Template, 2, 1, "span", 16);
63
+ i0.ɵɵelementEnd();
64
+ i0.ɵɵconditionalCreate(5, RecordDrilldownComponent_Conditional_0_Conditional_13_For_1_Conditional_5_Template, 2, 1, "span", 17);
65
+ i0.ɵɵelement(6, "i", 18);
66
+ i0.ɵɵelementEnd();
67
+ } if (rf & 2) {
68
+ const record_r4 = ctx.$implicit;
69
+ i0.ɵɵadvance(3);
70
+ i0.ɵɵtextInterpolate(record_r4.Title);
71
+ i0.ɵɵadvance();
72
+ i0.ɵɵconditional(record_r4.Subtitle ? 4 : -1);
73
+ i0.ɵɵadvance();
74
+ i0.ɵɵconditional(record_r4.Weight != null ? 5 : -1);
75
+ } }
76
+ function RecordDrilldownComponent_Conditional_0_Conditional_13_Template(rf, ctx) { if (rf & 1) {
77
+ i0.ɵɵrepeaterCreate(0, RecordDrilldownComponent_Conditional_0_Conditional_13_For_1_Template, 7, 3, "div", 12, i0.ɵɵcomponentInstance().TrackByRecord, true);
78
+ } if (rf & 2) {
79
+ const ctx_r1 = i0.ɵɵnextContext(2);
80
+ i0.ɵɵrepeater(ctx_r1.Records);
81
+ } }
82
+ function RecordDrilldownComponent_Conditional_0_Template(rf, ctx) { if (rf & 1) {
83
+ const _r1 = i0.ɵɵgetCurrentView();
84
+ i0.ɵɵelementStart(0, "div", 0)(1, "div", 1)(2, "div", 2);
85
+ i0.ɵɵelement(3, "i");
86
+ i0.ɵɵelementStart(4, "div", 3)(5, "span", 4);
87
+ i0.ɵɵtext(6);
88
+ i0.ɵɵelementEnd();
89
+ i0.ɵɵconditionalCreate(7, RecordDrilldownComponent_Conditional_0_Conditional_7_Template, 2, 1, "span", 5);
90
+ i0.ɵɵelementEnd()();
91
+ i0.ɵɵelementStart(8, "button", 6);
92
+ i0.ɵɵlistener("click", function RecordDrilldownComponent_Conditional_0_Template_button_click_8_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnClose()); });
93
+ i0.ɵɵelement(9, "i", 7);
94
+ i0.ɵɵelementEnd()();
95
+ i0.ɵɵelementStart(10, "div", 8);
96
+ i0.ɵɵconditionalCreate(11, RecordDrilldownComponent_Conditional_0_Conditional_11_Template, 1, 0, "mj-loading", 9)(12, RecordDrilldownComponent_Conditional_0_Conditional_12_Template, 4, 0, "div", 10)(13, RecordDrilldownComponent_Conditional_0_Conditional_13_Template, 2, 0);
97
+ i0.ɵɵelementEnd()();
98
+ } if (rf & 2) {
99
+ const ctx_r1 = i0.ɵɵnextContext();
100
+ i0.ɵɵadvance(3);
101
+ i0.ɵɵclassMap(ctx_r1.Icon);
102
+ i0.ɵɵadvance(3);
103
+ i0.ɵɵtextInterpolate(ctx_r1.Title);
104
+ i0.ɵɵadvance();
105
+ i0.ɵɵconditional(ctx_r1.Subtitle ? 7 : -1);
106
+ i0.ɵɵadvance(4);
107
+ i0.ɵɵconditional(ctx_r1.IsLoading ? 11 : ctx_r1.Records.length === 0 ? 12 : 13);
108
+ } }
109
+ export class RecordDrilldownComponent {
110
+ /** Panel heading (e.g. the tag text or the selected record's label). */
111
+ Title = '';
112
+ /** Optional sub-heading under the title (e.g. "12 records"). */
113
+ Subtitle = '';
114
+ /** Icon class shown next to the title. */
115
+ Icon = 'fa-solid fa-list';
116
+ /** Whether the panel is visible. */
117
+ Visible = false;
118
+ /** Whether records are currently loading. */
119
+ IsLoading = false;
120
+ /** The records to list. */
121
+ Records = [];
122
+ /** Emitted when the user closes the panel. */
123
+ Closed = new EventEmitter();
124
+ /** Emitted when the user clicks a record to open it. */
125
+ OpenRecord = new EventEmitter();
126
+ OnClose() {
127
+ this.Closed.emit();
128
+ }
129
+ OnOpen(record) {
130
+ if (!record.EntityName || !record.RecordID) {
131
+ return;
132
+ }
133
+ this.OpenRecord.emit({ EntityName: record.EntityName, RecordID: record.RecordID });
134
+ }
135
+ TrackByRecord(_index, record) {
136
+ return `${record.EntityName}|${record.RecordID}`;
137
+ }
138
+ WeightPercent(weight) {
139
+ if (weight == null) {
140
+ return 0;
141
+ }
142
+ return Math.round(Math.max(0, Math.min(1, weight)) * 100);
143
+ }
144
+ static ɵfac = function RecordDrilldownComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || RecordDrilldownComponent)(); };
145
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: RecordDrilldownComponent, selectors: [["app-kh-record-drilldown"]], inputs: { Title: "Title", Subtitle: "Subtitle", Icon: "Icon", Visible: "Visible", IsLoading: "IsLoading", Records: "Records" }, outputs: { Closed: "Closed", OpenRecord: "OpenRecord" }, standalone: false, decls: 1, vars: 1, consts: [[1, "drilldown-panel"], [1, "drilldown-header"], [1, "drilldown-title"], [1, "drilldown-title-text"], [1, "drilldown-title-main"], [1, "drilldown-title-sub"], ["mjButton", "", "variant", "icon", "size", "sm", "title", "Close", 3, "click"], [1, "fa-solid", "fa-times"], [1, "drilldown-body"], ["text", "Loading records..."], [1, "drilldown-empty"], [1, "fa-solid", "fa-inbox"], [1, "drilldown-item"], [1, "drilldown-item", 3, "click"], [1, "drilldown-item-main"], [1, "drilldown-item-title"], [1, "drilldown-item-subtitle"], [1, "drilldown-item-weight"], [1, "fa-solid", "fa-chevron-right", "drilldown-item-chevron"]], template: function RecordDrilldownComponent_Template(rf, ctx) { if (rf & 1) {
146
+ i0.ɵɵconditionalCreate(0, RecordDrilldownComponent_Conditional_0_Template, 14, 5, "div", 0);
147
+ } if (rf & 2) {
148
+ i0.ɵɵconditional(ctx.Visible ? 0 : -1);
149
+ } }, dependencies: [i1.LoadingComponent, i2.MJButtonDirective], styles: ["[_nghost-%COMP%] {\n display: block;\n height: 100%;\n}\n\n.drilldown-panel[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n width: 340px;\n max-width: 100%;\n background: var(--mj-bg-surface);\n border-left: 1px solid var(--mj-border-default);\n}\n\n.drilldown-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n padding: 12px 16px;\n border-bottom: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-card);\n}\n\n.drilldown-title[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n min-width: 0;\n}\n\n.drilldown-title[_ngcontent-%COMP%] > i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n font-size: 16px;\n}\n\n.drilldown-title-text[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n min-width: 0;\n}\n\n.drilldown-title-main[_ngcontent-%COMP%] {\n font-weight: 600;\n color: var(--mj-text-primary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.drilldown-title-sub[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-muted);\n}\n\n.drilldown-body[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n padding: 8px;\n}\n\n.drilldown-empty[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 8px;\n padding: 32px 16px;\n color: var(--mj-text-muted);\n text-align: center;\n}\n\n.drilldown-empty[_ngcontent-%COMP%] > i[_ngcontent-%COMP%] {\n font-size: 28px;\n opacity: 0.6;\n}\n\n.drilldown-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 10px 12px;\n border-radius: 6px;\n cursor: pointer;\n transition: background 0.15s ease;\n}\n\n.drilldown-item[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.drilldown-item-main[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n min-width: 0;\n flex: 1;\n}\n\n.drilldown-item-title[_ngcontent-%COMP%] {\n font-weight: 500;\n color: var(--mj-text-primary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.drilldown-item-subtitle[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.drilldown-item-weight[_ngcontent-%COMP%] {\n font-size: 12px;\n font-weight: 600;\n color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, transparent);\n border-radius: 10px;\n padding: 2px 8px;\n flex-shrink: 0;\n}\n\n.drilldown-item-chevron[_ngcontent-%COMP%] {\n color: var(--mj-text-disabled);\n font-size: 12px;\n flex-shrink: 0;\n}"], changeDetection: 0 });
150
+ }
151
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(RecordDrilldownComponent, [{
152
+ type: Component,
153
+ args: [{ selector: 'app-kh-record-drilldown', standalone: false, changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (Visible) {\n <div class=\"drilldown-panel\">\n <div class=\"drilldown-header\">\n <div class=\"drilldown-title\">\n <i [class]=\"Icon\"></i>\n <div class=\"drilldown-title-text\">\n <span class=\"drilldown-title-main\">{{ Title }}</span>\n @if (Subtitle) {\n <span class=\"drilldown-title-sub\">{{ Subtitle }}</span>\n }\n </div>\n </div>\n <button mjButton variant=\"icon\" size=\"sm\" (click)=\"OnClose()\" title=\"Close\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n\n <div class=\"drilldown-body\">\n @if (IsLoading) {\n <mj-loading text=\"Loading records...\"></mj-loading>\n } @else if (Records.length === 0) {\n <div class=\"drilldown-empty\">\n <i class=\"fa-solid fa-inbox\"></i>\n <p>No records found</p>\n </div>\n } @else {\n @for (record of Records; track TrackByRecord($index, record)) {\n <div class=\"drilldown-item\" (click)=\"OnOpen(record)\">\n <div class=\"drilldown-item-main\">\n <span class=\"drilldown-item-title\">{{ record.Title }}</span>\n @if (record.Subtitle) {\n <span class=\"drilldown-item-subtitle\">{{ record.Subtitle }}</span>\n }\n </div>\n @if (record.Weight != null) {\n <span class=\"drilldown-item-weight\">{{ WeightPercent(record.Weight) }}%</span>\n }\n <i class=\"fa-solid fa-chevron-right drilldown-item-chevron\"></i>\n </div>\n }\n }\n </div>\n </div>\n}\n", styles: [":host {\n display: block;\n height: 100%;\n}\n\n.drilldown-panel {\n display: flex;\n flex-direction: column;\n height: 100%;\n width: 340px;\n max-width: 100%;\n background: var(--mj-bg-surface);\n border-left: 1px solid var(--mj-border-default);\n}\n\n.drilldown-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n padding: 12px 16px;\n border-bottom: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-card);\n}\n\n.drilldown-title {\n display: flex;\n align-items: center;\n gap: 10px;\n min-width: 0;\n}\n\n.drilldown-title > i {\n color: var(--mj-brand-primary);\n font-size: 16px;\n}\n\n.drilldown-title-text {\n display: flex;\n flex-direction: column;\n min-width: 0;\n}\n\n.drilldown-title-main {\n font-weight: 600;\n color: var(--mj-text-primary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.drilldown-title-sub {\n font-size: 12px;\n color: var(--mj-text-muted);\n}\n\n.drilldown-body {\n flex: 1;\n overflow-y: auto;\n padding: 8px;\n}\n\n.drilldown-empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 8px;\n padding: 32px 16px;\n color: var(--mj-text-muted);\n text-align: center;\n}\n\n.drilldown-empty > i {\n font-size: 28px;\n opacity: 0.6;\n}\n\n.drilldown-item {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 10px 12px;\n border-radius: 6px;\n cursor: pointer;\n transition: background 0.15s ease;\n}\n\n.drilldown-item:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.drilldown-item-main {\n display: flex;\n flex-direction: column;\n min-width: 0;\n flex: 1;\n}\n\n.drilldown-item-title {\n font-weight: 500;\n color: var(--mj-text-primary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.drilldown-item-subtitle {\n font-size: 12px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.drilldown-item-weight {\n font-size: 12px;\n font-weight: 600;\n color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, transparent);\n border-radius: 10px;\n padding: 2px 8px;\n flex-shrink: 0;\n}\n\n.drilldown-item-chevron {\n color: var(--mj-text-disabled);\n font-size: 12px;\n flex-shrink: 0;\n}\n"] }]
154
+ }], null, { Title: [{
155
+ type: Input
156
+ }], Subtitle: [{
157
+ type: Input
158
+ }], Icon: [{
159
+ type: Input
160
+ }], Visible: [{
161
+ type: Input
162
+ }], IsLoading: [{
163
+ type: Input
164
+ }], Records: [{
165
+ type: Input
166
+ }], Closed: [{
167
+ type: Output
168
+ }], OpenRecord: [{
169
+ type: Output
170
+ }] }); })();
171
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(RecordDrilldownComponent, { className: "RecordDrilldownComponent", filePath: "src/KnowledgeHub/components/visualize/record-drilldown/record-drilldown.component.ts", lineNumber: 49 }); })();
172
+ /** Tree-shaking prevention */
173
+ export function LoadRecordDrilldownComponent() {
174
+ // Prevents tree-shaking of the component
175
+ }
176
+ //# sourceMappingURL=record-drilldown.component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"record-drilldown.component.js","sourceRoot":"","sources":["../../../../../src/KnowledgeHub/components/visualize/record-drilldown/record-drilldown.component.ts","../../../../../src/KnowledgeHub/components/visualize/record-drilldown/record-drilldown.component.html"],"names":[],"mappings":"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","sourcesContent":["/**\n * @fileoverview Shared Record Drilldown Panel\n *\n * A single, reusable side panel that lists records behind a selection on the\n * Knowledge Hub \"Visualize\" surface. It is driven entirely by inputs and emits\n * record-open intents up to the host — it never imports NavigationService, so it\n * stays a generic child that the KH resource host wires to navigation.\n *\n * Consumed by BOTH:\n * - Cluster-point selection: the host passes a single record row.\n * - Tag-cloud word selection: the host passes the records carrying that tag.\n */\n\nimport { Component, Input, Output, EventEmitter, ChangeDetectionStrategy } from '@angular/core';\n\n/**\n * A single record row shown in the drilldown panel. `EntityName` + `RecordID`\n * are the open-intent payload; `Title`/`Subtitle`/`Weight` are display-only.\n */\nexport interface DrilldownRecord {\n /** Entity the record belongs to (e.g. 'MJ: Content Items' or a business entity). */\n EntityName: string;\n /** Primary-key URL segment used to open the record. */\n RecordID: string;\n /** Primary display label. */\n Title: string;\n /** Optional secondary line (source, content type, etc.). */\n Subtitle?: string;\n /** Optional weight/relevance shown as a chip (0.0 - 1.0). */\n Weight?: number;\n}\n\n/**\n * Emitted when the user asks to open one of the listed records. The host\n * translates this into a NavigationService call.\n */\nexport interface DrilldownOpenRequest {\n EntityName: string;\n RecordID: string;\n}\n\n@Component({\n selector: 'app-kh-record-drilldown',\n standalone: false,\n changeDetection: ChangeDetectionStrategy.OnPush,\n templateUrl: './record-drilldown.component.html',\n styleUrls: ['./record-drilldown.component.css'],\n})\nexport class RecordDrilldownComponent {\n /** Panel heading (e.g. the tag text or the selected record's label). */\n @Input() Title = '';\n /** Optional sub-heading under the title (e.g. \"12 records\"). */\n @Input() Subtitle = '';\n /** Icon class shown next to the title. */\n @Input() Icon = 'fa-solid fa-list';\n /** Whether the panel is visible. */\n @Input() Visible = false;\n /** Whether records are currently loading. */\n @Input() IsLoading = false;\n /** The records to list. */\n @Input() Records: DrilldownRecord[] = [];\n\n /** Emitted when the user closes the panel. */\n @Output() Closed = new EventEmitter<void>();\n /** Emitted when the user clicks a record to open it. */\n @Output() OpenRecord = new EventEmitter<DrilldownOpenRequest>();\n\n public OnClose(): void {\n this.Closed.emit();\n }\n\n public OnOpen(record: DrilldownRecord): void {\n if (!record.EntityName || !record.RecordID) {\n return;\n }\n this.OpenRecord.emit({ EntityName: record.EntityName, RecordID: record.RecordID });\n }\n\n public TrackByRecord(_index: number, record: DrilldownRecord): string {\n return `${record.EntityName}|${record.RecordID}`;\n }\n\n public WeightPercent(weight: number | undefined): number {\n if (weight == null) {\n return 0;\n }\n return Math.round(Math.max(0, Math.min(1, weight)) * 100);\n }\n}\n\n/** Tree-shaking prevention */\nexport function LoadRecordDrilldownComponent(): void {\n // Prevents tree-shaking of the component\n}\n","@if (Visible) {\n <div class=\"drilldown-panel\">\n <div class=\"drilldown-header\">\n <div class=\"drilldown-title\">\n <i [class]=\"Icon\"></i>\n <div class=\"drilldown-title-text\">\n <span class=\"drilldown-title-main\">{{ Title }}</span>\n @if (Subtitle) {\n <span class=\"drilldown-title-sub\">{{ Subtitle }}</span>\n }\n </div>\n </div>\n <button mjButton variant=\"icon\" size=\"sm\" (click)=\"OnClose()\" title=\"Close\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n\n <div class=\"drilldown-body\">\n @if (IsLoading) {\n <mj-loading text=\"Loading records...\"></mj-loading>\n } @else if (Records.length === 0) {\n <div class=\"drilldown-empty\">\n <i class=\"fa-solid fa-inbox\"></i>\n <p>No records found</p>\n </div>\n } @else {\n @for (record of Records; track TrackByRecord($index, record)) {\n <div class=\"drilldown-item\" (click)=\"OnOpen(record)\">\n <div class=\"drilldown-item-main\">\n <span class=\"drilldown-item-title\">{{ record.Title }}</span>\n @if (record.Subtitle) {\n <span class=\"drilldown-item-subtitle\">{{ record.Subtitle }}</span>\n }\n </div>\n @if (record.Weight != null) {\n <span class=\"drilldown-item-weight\">{{ WeightPercent(record.Weight) }}%</span>\n }\n <i class=\"fa-solid fa-chevron-right drilldown-item-chevron\"></i>\n </div>\n }\n }\n </div>\n </div>\n}\n"]}