@memberjunction/ng-dashboards 5.38.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 (321) hide show
  1. package/README.md +14 -7
  2. package/dist/AI/components/agents/agent-configuration.component.js +199 -198
  3. package/dist/AI/components/agents/agent-configuration.component.js.map +1 -1
  4. package/dist/AI/components/analytics/ai-analytics-resource.component.d.ts.map +1 -1
  5. package/dist/AI/components/analytics/ai-analytics-resource.component.js +20 -17
  6. package/dist/AI/components/analytics/ai-analytics-resource.component.js.map +1 -1
  7. package/dist/AI/components/analytics/cost-budget/cost-budget.component.d.ts +15 -0
  8. package/dist/AI/components/analytics/cost-budget/cost-budget.component.d.ts.map +1 -1
  9. package/dist/AI/components/analytics/cost-budget/cost-budget.component.js +166 -58
  10. package/dist/AI/components/analytics/cost-budget/cost-budget.component.js.map +1 -1
  11. package/dist/AI/components/analytics/executive-summary/executive-summary.component.d.ts.map +1 -1
  12. package/dist/AI/components/analytics/executive-summary/executive-summary.component.js +2 -1
  13. package/dist/AI/components/analytics/executive-summary/executive-summary.component.js.map +1 -1
  14. package/dist/AI/components/analytics/model-performance/model-performance.component.d.ts +1 -0
  15. package/dist/AI/components/analytics/model-performance/model-performance.component.d.ts.map +1 -1
  16. package/dist/AI/components/analytics/model-performance/model-performance.component.js +55 -36
  17. package/dist/AI/components/analytics/model-performance/model-performance.component.js.map +1 -1
  18. package/dist/AI/components/analytics/prompt-runs/prompt-run-analysis.component.d.ts +9 -1
  19. package/dist/AI/components/analytics/prompt-runs/prompt-run-analysis.component.d.ts.map +1 -1
  20. package/dist/AI/components/analytics/prompt-runs/prompt-run-analysis.component.js +158 -117
  21. package/dist/AI/components/analytics/prompt-runs/prompt-run-analysis.component.js.map +1 -1
  22. package/dist/AI/components/analytics/usage-patterns/usage-patterns.component.d.ts +1 -0
  23. package/dist/AI/components/analytics/usage-patterns/usage-patterns.component.d.ts.map +1 -1
  24. package/dist/AI/components/analytics/usage-patterns/usage-patterns.component.js +22 -8
  25. package/dist/AI/components/analytics/usage-patterns/usage-patterns.component.js.map +1 -1
  26. package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.d.ts +217 -860
  27. package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.d.ts.map +1 -1
  28. package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.js +1717 -7802
  29. package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.js.map +1 -1
  30. package/dist/AI/components/autotagging/components/classify-item-drilldown.component.d.ts +56 -0
  31. package/dist/AI/components/autotagging/components/classify-item-drilldown.component.d.ts.map +1 -0
  32. package/dist/AI/components/autotagging/components/classify-item-drilldown.component.js +423 -0
  33. package/dist/AI/components/autotagging/components/classify-item-drilldown.component.js.map +1 -0
  34. package/dist/AI/components/autotagging/components/classify-item-grid.component.d.ts +70 -0
  35. package/dist/AI/components/autotagging/components/classify-item-grid.component.d.ts.map +1 -0
  36. package/dist/AI/components/autotagging/components/classify-item-grid.component.js +308 -0
  37. package/dist/AI/components/autotagging/components/classify-item-grid.component.js.map +1 -0
  38. package/dist/AI/components/autotagging/components/classify-org-context-editor.component.d.ts +29 -0
  39. package/dist/AI/components/autotagging/components/classify-org-context-editor.component.d.ts.map +1 -0
  40. package/dist/AI/components/autotagging/components/classify-org-context-editor.component.js +186 -0
  41. package/dist/AI/components/autotagging/components/classify-org-context-editor.component.js.map +1 -0
  42. package/dist/AI/components/autotagging/components/classify-overview-analytics.component.d.ts +69 -0
  43. package/dist/AI/components/autotagging/components/classify-overview-analytics.component.d.ts.map +1 -0
  44. package/dist/AI/components/autotagging/components/classify-overview-analytics.component.js +278 -0
  45. package/dist/AI/components/autotagging/components/classify-overview-analytics.component.js.map +1 -0
  46. package/dist/AI/components/autotagging/components/classify-seed-taxonomy.component.d.ts +73 -0
  47. package/dist/AI/components/autotagging/components/classify-seed-taxonomy.component.d.ts.map +1 -0
  48. package/dist/AI/components/autotagging/components/classify-seed-taxonomy.component.js +393 -0
  49. package/dist/AI/components/autotagging/components/classify-seed-taxonomy.component.js.map +1 -0
  50. package/dist/AI/components/autotagging/dialogs/classify-setup-wizard.component.d.ts +122 -0
  51. package/dist/AI/components/autotagging/dialogs/classify-setup-wizard.component.d.ts.map +1 -0
  52. package/dist/AI/components/autotagging/dialogs/classify-setup-wizard.component.js +908 -0
  53. package/dist/AI/components/autotagging/dialogs/classify-setup-wizard.component.js.map +1 -0
  54. package/dist/AI/components/autotagging/dialogs/dry-run-preview.dialog.component.d.ts +87 -0
  55. package/dist/AI/components/autotagging/dialogs/dry-run-preview.dialog.component.d.ts.map +1 -0
  56. package/dist/AI/components/autotagging/dialogs/dry-run-preview.dialog.component.js +475 -0
  57. package/dist/AI/components/autotagging/dialogs/dry-run-preview.dialog.component.js.map +1 -0
  58. package/dist/AI/components/autotagging/dialogs/item-detail.dialog.component.d.ts +29 -0
  59. package/dist/AI/components/autotagging/dialogs/item-detail.dialog.component.d.ts.map +1 -0
  60. package/dist/AI/components/autotagging/dialogs/item-detail.dialog.component.js +208 -0
  61. package/dist/AI/components/autotagging/dialogs/item-detail.dialog.component.js.map +1 -0
  62. package/dist/AI/components/autotagging/dialogs/no-content-type-warning.dialog.component.d.ts +21 -0
  63. package/dist/AI/components/autotagging/dialogs/no-content-type-warning.dialog.component.d.ts.map +1 -0
  64. package/dist/AI/components/autotagging/dialogs/no-content-type-warning.dialog.component.js +70 -0
  65. package/dist/AI/components/autotagging/dialogs/no-content-type-warning.dialog.component.js.map +1 -0
  66. package/dist/AI/components/autotagging/dialogs/source-type-form.dialog.component.d.ts +333 -0
  67. package/dist/AI/components/autotagging/dialogs/source-type-form.dialog.component.d.ts.map +1 -0
  68. package/dist/AI/components/autotagging/dialogs/source-type-form.dialog.component.js +2125 -0
  69. package/dist/AI/components/autotagging/dialogs/source-type-form.dialog.component.js.map +1 -0
  70. package/dist/AI/components/autotagging/shared/classify.dryrun.d.ts +61 -0
  71. package/dist/AI/components/autotagging/shared/classify.dryrun.d.ts.map +1 -0
  72. package/dist/AI/components/autotagging/shared/classify.dryrun.js +78 -0
  73. package/dist/AI/components/autotagging/shared/classify.dryrun.js.map +1 -0
  74. package/dist/AI/components/autotagging/shared/classify.format.d.ts +58 -0
  75. package/dist/AI/components/autotagging/shared/classify.format.d.ts.map +1 -0
  76. package/dist/AI/components/autotagging/shared/classify.format.js +260 -0
  77. package/dist/AI/components/autotagging/shared/classify.format.js.map +1 -0
  78. package/dist/AI/components/autotagging/shared/classify.types.d.ts +319 -0
  79. package/dist/AI/components/autotagging/shared/classify.types.d.ts.map +1 -0
  80. package/dist/AI/components/autotagging/shared/classify.types.js +6 -0
  81. package/dist/AI/components/autotagging/shared/classify.types.js.map +1 -0
  82. package/dist/AI/components/autotagging/tabs/health-tab.component.d.ts +103 -0
  83. package/dist/AI/components/autotagging/tabs/health-tab.component.d.ts.map +1 -0
  84. package/dist/AI/components/autotagging/tabs/health-tab.component.js +571 -0
  85. package/dist/AI/components/autotagging/tabs/health-tab.component.js.map +1 -0
  86. package/dist/AI/components/autotagging/tabs/history-tab.component.d.ts +77 -0
  87. package/dist/AI/components/autotagging/tabs/history-tab.component.d.ts.map +1 -0
  88. package/dist/AI/components/autotagging/tabs/history-tab.component.js +519 -0
  89. package/dist/AI/components/autotagging/tabs/history-tab.component.js.map +1 -0
  90. package/dist/AI/components/autotagging/tabs/inbox-tab.component.d.ts +107 -0
  91. package/dist/AI/components/autotagging/tabs/inbox-tab.component.d.ts.map +1 -0
  92. package/dist/AI/components/autotagging/tabs/inbox-tab.component.js +719 -0
  93. package/dist/AI/components/autotagging/tabs/inbox-tab.component.js.map +1 -0
  94. package/dist/AI/components/autotagging/tabs/pipeline-tab.component.d.ts +131 -0
  95. package/dist/AI/components/autotagging/tabs/pipeline-tab.component.d.ts.map +1 -0
  96. package/dist/AI/components/autotagging/tabs/pipeline-tab.component.js +813 -0
  97. package/dist/AI/components/autotagging/tabs/pipeline-tab.component.js.map +1 -0
  98. package/dist/AI/components/autotagging/tabs/sources-tab.component.d.ts +177 -0
  99. package/dist/AI/components/autotagging/tabs/sources-tab.component.d.ts.map +1 -0
  100. package/dist/AI/components/autotagging/tabs/sources-tab.component.js +1465 -0
  101. package/dist/AI/components/autotagging/tabs/sources-tab.component.js.map +1 -0
  102. package/dist/AI/components/autotagging/tabs/tags-tab.component.d.ts +78 -0
  103. package/dist/AI/components/autotagging/tabs/tags-tab.component.d.ts.map +1 -0
  104. package/dist/AI/components/autotagging/tabs/tags-tab.component.js +492 -0
  105. package/dist/AI/components/autotagging/tabs/tags-tab.component.js.map +1 -0
  106. package/dist/AI/components/autotagging/tabs/taxonomy-tab.component.d.ts +397 -0
  107. package/dist/AI/components/autotagging/tabs/taxonomy-tab.component.d.ts.map +1 -0
  108. package/dist/AI/components/autotagging/tabs/taxonomy-tab.component.js +3490 -0
  109. package/dist/AI/components/autotagging/tabs/taxonomy-tab.component.js.map +1 -0
  110. package/dist/AI/components/autotagging/tabs/types-tab.component.d.ts +56 -0
  111. package/dist/AI/components/autotagging/tabs/types-tab.component.d.ts.map +1 -0
  112. package/dist/AI/components/autotagging/tabs/types-tab.component.js +271 -0
  113. package/dist/AI/components/autotagging/tabs/types-tab.component.js.map +1 -0
  114. package/dist/AI/components/duplicates/duplicate-detection-resource.component.d.ts +3 -0
  115. package/dist/AI/components/duplicates/duplicate-detection-resource.component.d.ts.map +1 -1
  116. package/dist/AI/components/duplicates/duplicate-detection-resource.component.js +306 -290
  117. package/dist/AI/components/duplicates/duplicate-detection-resource.component.js.map +1 -1
  118. package/dist/AI/components/execution-monitoring.component.js +1 -1
  119. package/dist/AI/components/execution-monitoring.component.js.map +1 -1
  120. package/dist/AI/components/models/model-management.component.js +209 -208
  121. package/dist/AI/components/models/model-management.component.js.map +1 -1
  122. package/dist/AI/components/prompts/prompt-management.component.js +130 -128
  123. package/dist/AI/components/prompts/prompt-management.component.js.map +1 -1
  124. package/dist/AI/components/requests/agent-requests-resource.component.js +61 -61
  125. package/dist/AI/components/requests/agent-requests-resource.component.js.map +1 -1
  126. package/dist/AI/components/system/system-configuration.component.js +17 -17
  127. package/dist/AI/components/system/system-configuration.component.js.map +1 -1
  128. package/dist/AI/components/tags/tags-resource.component.d.ts +1 -0
  129. package/dist/AI/components/tags/tags-resource.component.d.ts.map +1 -1
  130. package/dist/AI/components/tags/tags-resource.component.js +578 -538
  131. package/dist/AI/components/tags/tags-resource.component.js.map +1 -1
  132. package/dist/AI/components/vectors/vector-management-resource.component.d.ts +3 -0
  133. package/dist/AI/components/vectors/vector-management-resource.component.d.ts.map +1 -1
  134. package/dist/AI/components/vectors/vector-management-resource.component.js +331 -303
  135. package/dist/AI/components/vectors/vector-management-resource.component.js.map +1 -1
  136. package/dist/AI/services/ai-instrumentation.service.d.ts +5 -0
  137. package/dist/AI/services/ai-instrumentation.service.d.ts.map +1 -1
  138. package/dist/AI/services/ai-instrumentation.service.js +14 -2
  139. package/dist/AI/services/ai-instrumentation.service.js.map +1 -1
  140. package/dist/AI/services/cache-metrics.d.ts +50 -0
  141. package/dist/AI/services/cache-metrics.d.ts.map +1 -0
  142. package/dist/AI/services/cache-metrics.js +43 -0
  143. package/dist/AI/services/cache-metrics.js.map +1 -0
  144. package/dist/APIKeys/api-applications-panel.component.js +2 -2
  145. package/dist/APIKeys/api-key-create-dialog.component.js +2 -2
  146. package/dist/APIKeys/api-key-edit-panel.component.js +2 -2
  147. package/dist/APIKeys/api-keys-resource.component.js +132 -131
  148. package/dist/APIKeys/api-keys-resource.component.js.map +1 -1
  149. package/dist/Actions/components/actions-overview.component.js +141 -141
  150. package/dist/Actions/components/actions-overview.component.js.map +1 -1
  151. package/dist/Actions/components/execution-monitoring.component.js +15 -15
  152. package/dist/Actions/components/execution-monitoring.component.js.map +1 -1
  153. package/dist/Actions/components/explorer/action-explorer.component.d.ts +0 -5
  154. package/dist/Actions/components/explorer/action-explorer.component.d.ts.map +1 -1
  155. package/dist/Actions/components/explorer/action-explorer.component.js +139 -212
  156. package/dist/Actions/components/explorer/action-explorer.component.js.map +1 -1
  157. package/dist/Admin/admin-data-schema.component.js +2 -2
  158. package/dist/Admin/admin-data-schema.component.js.map +1 -1
  159. package/dist/Admin/admin-dev-tools-resource.component.js +2 -2
  160. package/dist/Admin/admin-dev-tools-resource.component.js.map +1 -1
  161. package/dist/Admin/admin-identity-access.component.js +2 -2
  162. package/dist/Admin/admin-identity-access.component.js.map +1 -1
  163. package/dist/Admin/admin-monitoring.component.js +2 -2
  164. package/dist/Admin/admin-monitoring.component.js.map +1 -1
  165. package/dist/ApplicationRoles/application-roles-resource.component.js +54 -49
  166. package/dist/ApplicationRoles/application-roles-resource.component.js.map +1 -1
  167. package/dist/Communication/communication-logs-resource.component.d.ts +6 -0
  168. package/dist/Communication/communication-logs-resource.component.d.ts.map +1 -1
  169. package/dist/Communication/communication-logs-resource.component.js +72 -50
  170. package/dist/Communication/communication-logs-resource.component.js.map +1 -1
  171. package/dist/Communication/communication-monitor-resource.component.js +103 -102
  172. package/dist/Communication/communication-monitor-resource.component.js.map +1 -1
  173. package/dist/Communication/communication-providers-resource.component.js +52 -51
  174. package/dist/Communication/communication-providers-resource.component.js.map +1 -1
  175. package/dist/Communication/communication-runs-resource.component.js +39 -38
  176. package/dist/Communication/communication-runs-resource.component.js.map +1 -1
  177. package/dist/Communication/communication-templates-resource.component.d.ts +6 -0
  178. package/dist/Communication/communication-templates-resource.component.d.ts.map +1 -1
  179. package/dist/Communication/communication-templates-resource.component.js +92 -89
  180. package/dist/Communication/communication-templates-resource.component.js.map +1 -1
  181. package/dist/Credentials/components/credentials-audit-resource.component.js +136 -135
  182. package/dist/Credentials/components/credentials-audit-resource.component.js.map +1 -1
  183. package/dist/Credentials/components/credentials-categories-resource.component.js +155 -152
  184. package/dist/Credentials/components/credentials-categories-resource.component.js.map +1 -1
  185. package/dist/Credentials/components/credentials-list-resource.component.js +119 -118
  186. package/dist/Credentials/components/credentials-list-resource.component.js.map +1 -1
  187. package/dist/Credentials/components/credentials-overview-resource.component.js +129 -128
  188. package/dist/Credentials/components/credentials-overview-resource.component.js.map +1 -1
  189. package/dist/Credentials/components/credentials-types-resource.component.js +107 -106
  190. package/dist/Credentials/components/credentials-types-resource.component.js.map +1 -1
  191. package/dist/DataExplorer/data-explorer-dashboard.component.d.ts +31 -340
  192. package/dist/DataExplorer/data-explorer-dashboard.component.d.ts.map +1 -1
  193. package/dist/DataExplorer/data-explorer-dashboard.component.js +468 -1958
  194. package/dist/DataExplorer/data-explorer-dashboard.component.js.map +1 -1
  195. package/dist/DataExplorer/data-explorer-resource.component.d.ts.map +1 -1
  196. package/dist/DataExplorer/data-explorer-resource.component.js +10 -0
  197. package/dist/DataExplorer/data-explorer-resource.component.js.map +1 -1
  198. package/dist/DatabaseDesigner/components/database-designer-dashboard.component.js +1 -1
  199. package/dist/DatabaseDesigner/components/entity-list.component.js +115 -114
  200. package/dist/DatabaseDesigner/components/entity-list.component.js.map +1 -1
  201. package/dist/DatabaseDesigner/database-designer-dashboards.module.d.ts +5 -6
  202. package/dist/DatabaseDesigner/database-designer-dashboards.module.d.ts.map +1 -1
  203. package/dist/DatabaseDesigner/database-designer-dashboards.module.js +4 -5
  204. package/dist/DatabaseDesigner/database-designer-dashboards.module.js.map +1 -1
  205. package/dist/DevTools/app-state-inspector.component.js +18 -17
  206. package/dist/DevTools/app-state-inspector.component.js.map +1 -1
  207. package/dist/DevTools/class-registry.component.js +88 -85
  208. package/dist/DevTools/class-registry.component.js.map +1 -1
  209. package/dist/DevTools/event-monitor.component.js +155 -150
  210. package/dist/DevTools/event-monitor.component.js.map +1 -1
  211. package/dist/DevTools/graphql-console.component.js +245 -243
  212. package/dist/DevTools/graphql-console.component.js.map +1 -1
  213. package/dist/DevTools/layout-inspector.component.js +18 -17
  214. package/dist/DevTools/layout-inspector.component.js.map +1 -1
  215. package/dist/EntityAdmin/entity-admin-dashboard.component.js +20 -19
  216. package/dist/EntityAdmin/entity-admin-dashboard.component.js.map +1 -1
  217. package/dist/Home/home-dashboard.component.js +2 -2
  218. package/dist/Integration/components/activity/activity.component.d.ts.map +1 -1
  219. package/dist/Integration/components/activity/activity.component.js +236 -229
  220. package/dist/Integration/components/activity/activity.component.js.map +1 -1
  221. package/dist/Integration/components/connections/connections.component.js +390 -389
  222. package/dist/Integration/components/connections/connections.component.js.map +1 -1
  223. package/dist/Integration/components/overview/overview.component.js +2 -2
  224. package/dist/KnowledgeHub/components/analytics/analytics-resource.component.d.ts.map +1 -1
  225. package/dist/KnowledgeHub/components/analytics/analytics-resource.component.js +14 -11
  226. package/dist/KnowledgeHub/components/analytics/analytics-resource.component.js.map +1 -1
  227. package/dist/KnowledgeHub/components/clusters/cluster-visualization-resource.component.d.ts +27 -2
  228. package/dist/KnowledgeHub/components/clusters/cluster-visualization-resource.component.d.ts.map +1 -1
  229. package/dist/KnowledgeHub/components/clusters/cluster-visualization-resource.component.js +244 -119
  230. package/dist/KnowledgeHub/components/clusters/cluster-visualization-resource.component.js.map +1 -1
  231. package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.js +293 -291
  232. package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.js.map +1 -1
  233. package/dist/KnowledgeHub/components/scheduling/scheduling-resource.component.js +62 -61
  234. package/dist/KnowledgeHub/components/scheduling/scheduling-resource.component.js.map +1 -1
  235. package/dist/KnowledgeHub/components/visualize/record-drilldown/record-drilldown.component.d.ts +65 -0
  236. package/dist/KnowledgeHub/components/visualize/record-drilldown/record-drilldown.component.d.ts.map +1 -0
  237. package/dist/KnowledgeHub/components/visualize/record-drilldown/record-drilldown.component.js +176 -0
  238. package/dist/KnowledgeHub/components/visualize/record-drilldown/record-drilldown.component.js.map +1 -0
  239. package/dist/KnowledgeHub/components/visualize/tag-cloud/tag-cloud.component.d.ts +81 -0
  240. package/dist/KnowledgeHub/components/visualize/tag-cloud/tag-cloud.component.d.ts.map +1 -0
  241. package/dist/KnowledgeHub/components/visualize/tag-cloud/tag-cloud.component.js +308 -0
  242. package/dist/KnowledgeHub/components/visualize/tag-cloud/tag-cloud.component.js.map +1 -0
  243. package/dist/KnowledgeHub/components/visualize/visualize-resource.component.d.ts +85 -0
  244. package/dist/KnowledgeHub/components/visualize/visualize-resource.component.d.ts.map +1 -0
  245. package/dist/KnowledgeHub/components/visualize/visualize-resource.component.js +362 -0
  246. package/dist/KnowledgeHub/components/visualize/visualize-resource.component.js.map +1 -0
  247. package/dist/KnowledgeHub/index.d.ts +3 -0
  248. package/dist/KnowledgeHub/index.d.ts.map +1 -1
  249. package/dist/KnowledgeHub/index.js +3 -0
  250. package/dist/KnowledgeHub/index.js.map +1 -1
  251. package/dist/Lists/components/lists-browse-resource.component.d.ts +6 -2
  252. package/dist/Lists/components/lists-browse-resource.component.d.ts.map +1 -1
  253. package/dist/Lists/components/lists-browse-resource.component.js +525 -566
  254. package/dist/Lists/components/lists-browse-resource.component.js.map +1 -1
  255. package/dist/Lists/components/lists-categories-resource.component.js +135 -134
  256. package/dist/Lists/components/lists-categories-resource.component.js.map +1 -1
  257. package/dist/Lists/components/lists-my-lists-resource.component.js +199 -198
  258. package/dist/Lists/components/lists-my-lists-resource.component.js.map +1 -1
  259. package/dist/MCP/components/mcp-server-dialog.component.js +2 -2
  260. package/dist/MCP/mcp-dashboard.component.js +443 -438
  261. package/dist/MCP/mcp-dashboard.component.js.map +1 -1
  262. package/dist/QueryBrowser/query-browser-resource.component.js +1 -1
  263. package/dist/QueryBrowser/query-browser-resource.component.js.map +1 -1
  264. package/dist/Scheduling/components/scheduling-activity.component.d.ts.map +1 -1
  265. package/dist/Scheduling/components/scheduling-activity.component.js +146 -147
  266. package/dist/Scheduling/components/scheduling-activity.component.js.map +1 -1
  267. package/dist/Scheduling/components/scheduling-jobs.component.js +76 -75
  268. package/dist/Scheduling/components/scheduling-jobs.component.js.map +1 -1
  269. package/dist/Scheduling/components/scheduling-overview.component.js +97 -96
  270. package/dist/Scheduling/components/scheduling-overview.component.js.map +1 -1
  271. package/dist/Scheduling/scheduling-dashboard.component.js +24 -22
  272. package/dist/Scheduling/scheduling-dashboard.component.js.map +1 -1
  273. package/dist/Scheduling/services/scheduling-instrumentation.service.d.ts +2 -0
  274. package/dist/Scheduling/services/scheduling-instrumentation.service.d.ts.map +1 -1
  275. package/dist/Scheduling/services/scheduling-instrumentation.service.js +1 -0
  276. package/dist/Scheduling/services/scheduling-instrumentation.service.js.map +1 -1
  277. package/dist/Testing/components/testing-dashboard-tab-resource.component.js +1 -1
  278. package/dist/Testing/components/testing-explorer.component.d.ts +14 -4
  279. package/dist/Testing/components/testing-explorer.component.d.ts.map +1 -1
  280. package/dist/Testing/components/testing-explorer.component.js +436 -427
  281. package/dist/Testing/components/testing-explorer.component.js.map +1 -1
  282. package/dist/Testing/components/testing-runs-resource.component.js +1 -1
  283. package/dist/Testing/components/testing-runs.component.js +116 -115
  284. package/dist/Testing/components/testing-runs.component.js.map +1 -1
  285. package/dist/Testing/testing-dashboard.component.js +6 -7
  286. package/dist/Testing/testing-dashboard.component.js.map +1 -1
  287. package/dist/VersionHistory/components/labels-resource.component.js +173 -172
  288. package/dist/VersionHistory/components/labels-resource.component.js.map +1 -1
  289. package/dist/VersionHistory/components/restore-resource.component.d.ts +6 -0
  290. package/dist/VersionHistory/components/restore-resource.component.d.ts.map +1 -1
  291. package/dist/VersionHistory/components/restore-resource.component.js +116 -92
  292. package/dist/VersionHistory/components/restore-resource.component.js.map +1 -1
  293. package/dist/ai-dashboards.module.d.ts +57 -35
  294. package/dist/ai-dashboards.module.d.ts.map +1 -1
  295. package/dist/ai-dashboards.module.js +80 -1
  296. package/dist/ai-dashboards.module.js.map +1 -1
  297. package/dist/communication-dashboards.module.d.ts +1 -1
  298. package/dist/communication-dashboards.module.d.ts.map +1 -1
  299. package/dist/communication-dashboards.module.js +7 -1
  300. package/dist/communication-dashboards.module.js.map +1 -1
  301. package/dist/data-explorer-dashboards.module.d.ts +12 -14
  302. package/dist/data-explorer-dashboards.module.d.ts.map +1 -1
  303. package/dist/data-explorer-dashboards.module.js +5 -14
  304. package/dist/data-explorer-dashboards.module.js.map +1 -1
  305. package/dist/public-api.d.ts +3 -0
  306. package/dist/public-api.d.ts.map +1 -1
  307. package/dist/public-api.js +3 -0
  308. package/dist/public-api.js.map +1 -1
  309. package/dist/testing-dashboards.module.d.ts +4 -5
  310. package/dist/testing-dashboards.module.d.ts.map +1 -1
  311. package/dist/testing-dashboards.module.js +7 -5
  312. package/dist/testing-dashboards.module.js.map +1 -1
  313. package/package.json +57 -54
  314. package/dist/DataExplorer/components/filter-dialog/filter-dialog.component.d.ts +0 -79
  315. package/dist/DataExplorer/components/filter-dialog/filter-dialog.component.d.ts.map +0 -1
  316. package/dist/DataExplorer/components/filter-dialog/filter-dialog.component.js +0 -195
  317. package/dist/DataExplorer/components/filter-dialog/filter-dialog.component.js.map +0 -1
  318. package/dist/DataExplorer/components/view-selector/view-selector.component.d.ts +0 -226
  319. package/dist/DataExplorer/components/view-selector/view-selector.component.d.ts.map +0 -1
  320. package/dist/DataExplorer/components/view-selector/view-selector.component.js +0 -861
  321. package/dist/DataExplorer/components/view-selector/view-selector.component.js.map +0 -1
@@ -0,0 +1,492 @@
1
+ /**
2
+ * @fileoverview Classify · Tag Library tab.
3
+ *
4
+ * Self-contained sub-page: owns its header-interior (with the tag search box),
5
+ * the tag rows table, the word cloud, the tags-by-source breakdown, and the
6
+ * per-tag drill-down. Receives the shared raw tag + item rows from the host
7
+ * orchestrator via `[ContentTags]`/`[ContentItems]` and rebuilds its view
8
+ * models from them. Opening a content item from the drill-down is a cross-tab
9
+ * concern owned by the host's slide-in, so it bubbles up via @Output.
10
+ */
11
+ import { Component, ChangeDetectorRef, EventEmitter, Input, Output, inject } from '@angular/core';
12
+ import { NormalizeUUID } from '@memberjunction/global';
13
+ import { BaseAngularComponent } from '@memberjunction/ng-base-types';
14
+ import { formatWeight, tagFontSize, formatShortDate, deriveDisplayName } from '../shared/classify.format';
15
+ import * as i0 from "@angular/core";
16
+ import * as i1 from "@angular/forms";
17
+ import * as i2 from "@memberjunction/ng-shared-generic";
18
+ import * as i3 from "@memberjunction/ng-ui-components";
19
+ import * as i4 from "@memberjunction/ng-word-cloud";
20
+ const _forTrack0 = ($index, $item) => $item.Tag;
21
+ const _forTrack1 = ($index, $item) => $item.SourceName;
22
+ const _forTrack2 = ($index, $item) => $item.ID;
23
+ function ClassifyTagsTabComponent_Conditional_3_Template(rf, ctx) { if (rf & 1) {
24
+ i0.ɵɵelement(0, "i", 27);
25
+ i0.ɵɵelementStart(1, "span", 28);
26
+ i0.ɵɵtext(2, "Refreshing\u2026");
27
+ i0.ɵɵelementEnd();
28
+ } }
29
+ function ClassifyTagsTabComponent_Conditional_4_Template(rf, ctx) { if (rf & 1) {
30
+ i0.ɵɵelement(0, "i", 29);
31
+ i0.ɵɵelementStart(1, "span", 28);
32
+ i0.ɵɵtext(2, "Refresh");
33
+ i0.ɵɵelementEnd();
34
+ } }
35
+ function ClassifyTagsTabComponent_Conditional_9_Template(rf, ctx) { if (rf & 1) {
36
+ i0.ɵɵelementStart(0, "div", 7);
37
+ i0.ɵɵelement(1, "mj-loading", 30);
38
+ i0.ɵɵelementEnd();
39
+ } }
40
+ function ClassifyTagsTabComponent_For_32_Template(rf, ctx) { if (rf & 1) {
41
+ const _r1 = i0.ɵɵgetCurrentView();
42
+ i0.ɵɵelementStart(0, "tr", 31);
43
+ i0.ɵɵlistener("click", function ClassifyTagsTabComponent_For_32_Template_tr_click_0_listener() { const row_r2 = i0.ɵɵrestoreView(_r1).$implicit; const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.DrillDownTag(row_r2.Tag)); });
44
+ i0.ɵɵelementStart(1, "td", 32);
45
+ i0.ɵɵtext(2);
46
+ i0.ɵɵelementEnd();
47
+ i0.ɵɵelementStart(3, "td");
48
+ i0.ɵɵtext(4);
49
+ i0.ɵɵelementEnd();
50
+ i0.ɵɵelementStart(5, "td")(6, "div", 33)(7, "div", 34);
51
+ i0.ɵɵelement(8, "div", 35);
52
+ i0.ɵɵelementEnd();
53
+ i0.ɵɵelementStart(9, "span", 36);
54
+ i0.ɵɵtext(10);
55
+ i0.ɵɵelementEnd()()();
56
+ i0.ɵɵelementStart(11, "td")(12, "div", 37);
57
+ i0.ɵɵelement(13, "div", 38);
58
+ i0.ɵɵelementEnd()();
59
+ i0.ɵɵelementStart(14, "td");
60
+ i0.ɵɵtext(15);
61
+ i0.ɵɵelementEnd();
62
+ i0.ɵɵelementStart(16, "td");
63
+ i0.ɵɵtext(17);
64
+ i0.ɵɵelementEnd()();
65
+ } if (rf & 2) {
66
+ const row_r2 = ctx.$implicit;
67
+ const ctx_r2 = i0.ɵɵnextContext();
68
+ i0.ɵɵclassProp("at-tag-row-selected", ctx_r2.SelectedDrillDownTag === row_r2.Tag);
69
+ i0.ɵɵadvance(2);
70
+ i0.ɵɵtextInterpolate(row_r2.Tag);
71
+ i0.ɵɵadvance(2);
72
+ i0.ɵɵtextInterpolate(row_r2.UsageCount);
73
+ i0.ɵɵadvance(4);
74
+ i0.ɵɵstyleProp("width", row_r2.AvgWeight * 100, "%");
75
+ i0.ɵɵclassProp("at-weight-high", row_r2.AvgWeight >= 0.7)("at-weight-medium", row_r2.AvgWeight >= 0.4 && row_r2.AvgWeight < 0.7)("at-weight-low", row_r2.AvgWeight < 0.4);
76
+ i0.ɵɵadvance(2);
77
+ i0.ɵɵtextInterpolate(row_r2.AvgWeight.toFixed(2));
78
+ i0.ɵɵadvance(3);
79
+ i0.ɵɵstyleProp("width", row_r2.BarWidthPct, "%");
80
+ i0.ɵɵadvance(2);
81
+ i0.ɵɵtextInterpolate(row_r2.TopSource);
82
+ i0.ɵɵadvance(2);
83
+ i0.ɵɵtextInterpolate(row_r2.FirstSeen);
84
+ } }
85
+ function ClassifyTagsTabComponent_Conditional_33_Conditional_8_Template(rf, ctx) { if (rf & 1) {
86
+ i0.ɵɵelementStart(0, "div", 45)(1, "p");
87
+ i0.ɵɵtext(2, "No content items found for this tag.");
88
+ i0.ɵɵelementEnd()();
89
+ } }
90
+ function ClassifyTagsTabComponent_Conditional_33_Conditional_9_For_13_Template(rf, ctx) { if (rf & 1) {
91
+ const _r5 = i0.ɵɵgetCurrentView();
92
+ i0.ɵɵelementStart(0, "tr", 31);
93
+ i0.ɵɵlistener("click", function ClassifyTagsTabComponent_Conditional_33_Conditional_9_For_13_Template_tr_click_0_listener() { const di_r6 = i0.ɵɵrestoreView(_r5).$implicit; const ctx_r2 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r2.onOpenItemDetail(di_r6.ID)); });
94
+ i0.ɵɵelementStart(1, "td");
95
+ i0.ɵɵtext(2);
96
+ i0.ɵɵelementEnd();
97
+ i0.ɵɵelementStart(3, "td");
98
+ i0.ɵɵtext(4);
99
+ i0.ɵɵelementEnd();
100
+ i0.ɵɵelementStart(5, "td");
101
+ i0.ɵɵtext(6);
102
+ i0.ɵɵelementEnd();
103
+ i0.ɵɵelementStart(7, "td");
104
+ i0.ɵɵtext(8);
105
+ i0.ɵɵelementEnd()();
106
+ } if (rf & 2) {
107
+ const di_r6 = ctx.$implicit;
108
+ const ctx_r2 = i0.ɵɵnextContext(3);
109
+ i0.ɵɵadvance(2);
110
+ i0.ɵɵtextInterpolate(di_r6.Name);
111
+ i0.ɵɵadvance(2);
112
+ i0.ɵɵtextInterpolate(di_r6.SourceName);
113
+ i0.ɵɵadvance(2);
114
+ i0.ɵɵtextInterpolate(ctx_r2.FormatWeight(di_r6.Weight));
115
+ i0.ɵɵadvance(2);
116
+ i0.ɵɵtextInterpolate(di_r6.UpdatedAt);
117
+ } }
118
+ function ClassifyTagsTabComponent_Conditional_33_Conditional_9_Template(rf, ctx) { if (rf & 1) {
119
+ i0.ɵɵelementStart(0, "table", 13)(1, "thead")(2, "tr")(3, "th");
120
+ i0.ɵɵtext(4, "Name");
121
+ i0.ɵɵelementEnd();
122
+ i0.ɵɵelementStart(5, "th");
123
+ i0.ɵɵtext(6, "Source");
124
+ i0.ɵɵelementEnd();
125
+ i0.ɵɵelementStart(7, "th");
126
+ i0.ɵɵtext(8, "Weight");
127
+ i0.ɵɵelementEnd();
128
+ i0.ɵɵelementStart(9, "th");
129
+ i0.ɵɵtext(10, "Updated");
130
+ i0.ɵɵelementEnd()()();
131
+ i0.ɵɵelementStart(11, "tbody");
132
+ i0.ɵɵrepeaterCreate(12, ClassifyTagsTabComponent_Conditional_33_Conditional_9_For_13_Template, 9, 4, "tr", 46, _forTrack2);
133
+ i0.ɵɵelementEnd()();
134
+ } if (rf & 2) {
135
+ const ctx_r2 = i0.ɵɵnextContext(2);
136
+ i0.ɵɵadvance(12);
137
+ i0.ɵɵrepeater(ctx_r2.TagDrillDownItems);
138
+ } }
139
+ function ClassifyTagsTabComponent_Conditional_33_Template(rf, ctx) { if (rf & 1) {
140
+ const _r4 = i0.ɵɵgetCurrentView();
141
+ i0.ɵɵelementStart(0, "div", 15)(1, "div", 39)(2, "span", 40);
142
+ i0.ɵɵelement(3, "i", 41);
143
+ i0.ɵɵtext(4);
144
+ i0.ɵɵelementEnd();
145
+ i0.ɵɵelementStart(5, "button", 42);
146
+ i0.ɵɵlistener("click", function ClassifyTagsTabComponent_Conditional_33_Template_button_click_5_listener() { i0.ɵɵrestoreView(_r4); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.CloseDrillDownTag()); });
147
+ i0.ɵɵelement(6, "i", 43);
148
+ i0.ɵɵelementEnd()();
149
+ i0.ɵɵelementStart(7, "div", 44);
150
+ i0.ɵɵconditionalCreate(8, ClassifyTagsTabComponent_Conditional_33_Conditional_8_Template, 3, 0, "div", 45)(9, ClassifyTagsTabComponent_Conditional_33_Conditional_9_Template, 14, 0, "table", 13);
151
+ i0.ɵɵelementEnd()();
152
+ } if (rf & 2) {
153
+ const ctx_r2 = i0.ɵɵnextContext();
154
+ i0.ɵɵadvance(4);
155
+ i0.ɵɵtextInterpolate2(" Content items tagged \"", ctx_r2.SelectedDrillDownTag, "\" (", ctx_r2.TagDrillDownItems.length, ") ");
156
+ i0.ɵɵadvance(4);
157
+ i0.ɵɵconditional(ctx_r2.TagDrillDownItems.length === 0 ? 8 : 9);
158
+ } }
159
+ function ClassifyTagsTabComponent_Conditional_39_Template(rf, ctx) { if (rf & 1) {
160
+ i0.ɵɵelement(0, "mj-word-cloud", 20);
161
+ } if (rf & 2) {
162
+ const ctx_r2 = i0.ɵɵnextContext();
163
+ i0.ɵɵproperty("Items", ctx_r2.TagCloudWordItems)("MaxFontSize", 40)("MinFontSize", 12)("MaxItems", 20)("Interactive", true)("Animate", true);
164
+ } }
165
+ function ClassifyTagsTabComponent_Conditional_40_Template(rf, ctx) { if (rf & 1) {
166
+ i0.ɵɵelementStart(0, "div", 21);
167
+ i0.ɵɵtext(1, "No tags yet");
168
+ i0.ɵɵelementEnd();
169
+ } }
170
+ function ClassifyTagsTabComponent_For_47_Template(rf, ctx) { if (rf & 1) {
171
+ i0.ɵɵelementStart(0, "div", 26)(1, "span");
172
+ i0.ɵɵtext(2);
173
+ i0.ɵɵelementEnd();
174
+ i0.ɵɵelementStart(3, "strong");
175
+ i0.ɵɵtext(4);
176
+ i0.ɵɵelementEnd()();
177
+ } if (rf & 2) {
178
+ const s_r7 = ctx.$implicit;
179
+ i0.ɵɵadvance(2);
180
+ i0.ɵɵtextInterpolate(s_r7.SourceName);
181
+ i0.ɵɵadvance(2);
182
+ i0.ɵɵtextInterpolate(s_r7.Count);
183
+ } }
184
+ export class ClassifyTagsTabComponent extends BaseAngularComponent {
185
+ cdr = inject(ChangeDetectorRef);
186
+ /** Shared raw `MJ: Content Item Tags` rows, supplied by the host orchestrator. */
187
+ _contentTags = [];
188
+ set ContentTags(value) {
189
+ this._contentTags = value ?? [];
190
+ this.rebuild();
191
+ }
192
+ get ContentTags() {
193
+ return this._contentTags;
194
+ }
195
+ /** Shared raw `MJ: Content Items` rows — used for source mapping and drill-down. */
196
+ _contentItems = [];
197
+ set ContentItems(value) {
198
+ this._contentItems = value ?? [];
199
+ this.rebuild();
200
+ }
201
+ get ContentItems() {
202
+ return this._contentItems;
203
+ }
204
+ /** Shown while a manual Refresh() rebuilds the tag view models. */
205
+ IsLoading = false;
206
+ TagRows = [];
207
+ FilteredTagRows = [];
208
+ TagCloudWordItems = [];
209
+ TagsBySource = [];
210
+ TagSearchQuery = '';
211
+ SelectedDrillDownTag = null;
212
+ TagDrillDownItems = [];
213
+ /** Subtitle reflects the live tag count, mirroring the former host subtitle. */
214
+ get Subtitle() {
215
+ return `${this.TagRows.length} unique tags across all content sources`;
216
+ }
217
+ // Template-facing formatters (shared pure helpers exposed for the view).
218
+ TagFontSize = tagFontSize;
219
+ FormatWeight = formatWeight;
220
+ /** Bubble a request to open a content item's detail slide-in (host-owned). */
221
+ OpenItemDetailRequested = new EventEmitter();
222
+ onOpenItemDetail(contentItemID) {
223
+ this.OpenItemDetailRequested.emit(contentItemID);
224
+ }
225
+ /** Rebuild all tag-tab view models from the current inputs. */
226
+ rebuild() {
227
+ this.buildTagRows();
228
+ this.buildTagCloud();
229
+ this.buildTagsBySource();
230
+ this.FilterTags();
231
+ }
232
+ /**
233
+ * Rebuild the tag view models from the current host-supplied inputs. The tag
234
+ * data is host-owned (flows in via [ContentTags]/[ContentItems]); Refresh
235
+ * recomputes the rows/cloud/breakdown and surfaces a brief loading state.
236
+ */
237
+ async Refresh() {
238
+ this.IsLoading = true;
239
+ this.cdr.detectChanges();
240
+ this.rebuild();
241
+ this.IsLoading = false;
242
+ this.cdr.detectChanges();
243
+ }
244
+ // ── External control surface (host deep-link + agent tool) ──
245
+ /** Apply a search query programmatically (used by the agent tool + deep link). Returns the match count. */
246
+ ApplySearch(query) {
247
+ this.TagSearchQuery = query;
248
+ this.FilterTags();
249
+ return this.FilteredTagRows.length;
250
+ }
251
+ // ── View-model building ──
252
+ buildTagRows() {
253
+ const tagCounts = this.countAllTags();
254
+ const avgWeights = this.computeAvgWeights();
255
+ const tagSourceMap = this.getTopSourcePerTag();
256
+ const tagFirstSeen = this.getFirstSeenPerTag();
257
+ const sorted = Array.from(tagCounts.entries()).sort((a, b) => b[1] - a[1]);
258
+ const maxCount = sorted.length > 0 ? sorted[0][1] : 1;
259
+ this.TagRows = sorted.map(([tag, count]) => ({
260
+ Tag: tag,
261
+ UsageCount: count,
262
+ AvgWeight: avgWeights.get(tag) ?? 1.0,
263
+ BarWidthPct: Math.round((count / maxCount) * 100),
264
+ TopSource: tagSourceMap.get(tag) ?? 'Unknown',
265
+ FirstSeen: tagFirstSeen.get(tag) ?? ''
266
+ }));
267
+ }
268
+ buildTagCloud() {
269
+ const tagCounts = this.countAllTags();
270
+ const avgWeights = this.computeAvgWeights();
271
+ // Sort by a combined score: usage count * avg weight (so high-weight, high-count tags bubble up)
272
+ const scored = Array.from(tagCounts.entries()).map(([tag, count]) => {
273
+ const weight = avgWeights.get(tag) ?? 1.0;
274
+ return { tag, count, weight, score: count * weight };
275
+ }).sort((a, b) => b.score - a.score).slice(0, 20);
276
+ const maxScore = scored.length > 0 ? scored[0].score : 1;
277
+ // Build WordCloudItem[] for the mj-word-cloud component
278
+ this.TagCloudWordItems = scored.map(s => ({
279
+ Text: s.tag,
280
+ Weight: maxScore > 0 ? s.score / maxScore : 0,
281
+ Metadata: { Count: s.count, AvgWeight: s.weight }
282
+ }));
283
+ }
284
+ buildTagsBySource() {
285
+ const sourceTagCounts = new Map();
286
+ const itemSourceMap = new Map();
287
+ for (const item of this._contentItems) {
288
+ itemSourceMap.set(item['ID'], item['ContentSource'] ?? 'Unknown');
289
+ }
290
+ for (const tag of this._contentTags) {
291
+ const source = itemSourceMap.get(tag['ItemID']) ?? 'Unknown';
292
+ sourceTagCounts.set(source, (sourceTagCounts.get(source) ?? 0) + 1);
293
+ }
294
+ this.TagsBySource = Array.from(sourceTagCounts.entries())
295
+ .sort((a, b) => b[1] - a[1])
296
+ .map(([name, count]) => ({ SourceName: name, Count: count }));
297
+ }
298
+ FilterTags() {
299
+ const q = this.TagSearchQuery.toLowerCase().trim();
300
+ this.FilteredTagRows = q
301
+ ? this.TagRows.filter(r => r.Tag.toLowerCase().includes(q))
302
+ : this.TagRows;
303
+ this.cdr.detectChanges();
304
+ }
305
+ /** Drill down into content items matching a specific tag. */
306
+ DrillDownTag(tagName) {
307
+ if (this.SelectedDrillDownTag === tagName) {
308
+ this.CloseDrillDownTag();
309
+ return;
310
+ }
311
+ this.SelectedDrillDownTag = tagName;
312
+ // Find all content items that have this tag
313
+ const matchingItemIDs = new Map(); // itemID → weight
314
+ for (const tag of this._contentTags) {
315
+ if (tag['Tag'] === tagName) {
316
+ matchingItemIDs.set(NormalizeUUID(tag['ItemID']), Number(tag['Weight'] ?? 1));
317
+ }
318
+ }
319
+ this.TagDrillDownItems = [];
320
+ for (let i = 0; i < this._contentItems.length; i++) {
321
+ const item = this._contentItems[i];
322
+ const normalizedID = NormalizeUUID(item['ID']);
323
+ const weight = matchingItemIDs.get(normalizedID);
324
+ if (weight !== undefined) {
325
+ this.TagDrillDownItems.push({
326
+ ID: item['ID'],
327
+ Name: deriveDisplayName({ Name: item['Name'], Description: item['Description'] }),
328
+ SourceName: item['ContentSource'] ?? 'Unknown',
329
+ Weight: weight,
330
+ UpdatedAt: formatShortDate(item['__mj_UpdatedAt'] ?? ''),
331
+ FeedIndex: i,
332
+ });
333
+ }
334
+ }
335
+ // Sort by weight descending
336
+ this.TagDrillDownItems.sort((a, b) => b.Weight - a.Weight);
337
+ this.cdr.detectChanges();
338
+ }
339
+ CloseDrillDownTag() {
340
+ this.SelectedDrillDownTag = null;
341
+ this.TagDrillDownItems = [];
342
+ this.cdr.detectChanges();
343
+ }
344
+ // ── Aggregation utilities (read only the tag + item inputs) ──
345
+ countAllTags() {
346
+ const counts = new Map();
347
+ for (const tag of this._contentTags) {
348
+ const t = tag['Tag'];
349
+ if (t)
350
+ counts.set(t, (counts.get(t) ?? 0) + 1);
351
+ }
352
+ return counts;
353
+ }
354
+ /** Compute average weight per tag across all occurrences. */
355
+ computeAvgWeights() {
356
+ const sums = new Map();
357
+ const counts = new Map();
358
+ for (const tag of this._contentTags) {
359
+ const t = tag['Tag'];
360
+ const w = Number(tag['Weight'] ?? 0.5);
361
+ if (t) {
362
+ sums.set(t, (sums.get(t) ?? 0) + w);
363
+ counts.set(t, (counts.get(t) ?? 0) + 1);
364
+ }
365
+ }
366
+ const avgs = new Map();
367
+ for (const [t, sum] of sums) {
368
+ avgs.set(t, Math.round((sum / (counts.get(t) ?? 1)) * 100) / 100);
369
+ }
370
+ return avgs;
371
+ }
372
+ getTopSourcePerTag() {
373
+ const tagSourceCounts = new Map();
374
+ const itemSourceMap = new Map();
375
+ for (const item of this._contentItems) {
376
+ itemSourceMap.set(item['ID'], item['ContentSource'] ?? 'Unknown');
377
+ }
378
+ for (const tag of this._contentTags) {
379
+ const t = tag['Tag'];
380
+ const source = itemSourceMap.get(tag['ItemID']) ?? 'Unknown';
381
+ if (!tagSourceCounts.has(t))
382
+ tagSourceCounts.set(t, new Map());
383
+ const inner = tagSourceCounts.get(t);
384
+ inner.set(source, (inner.get(source) ?? 0) + 1);
385
+ }
386
+ const result = new Map();
387
+ for (const [tag, sourceCounts] of tagSourceCounts) {
388
+ let maxSource = 'Unknown';
389
+ let maxCount = 0;
390
+ for (const [source, count] of sourceCounts) {
391
+ if (count > maxCount) {
392
+ maxSource = source;
393
+ maxCount = count;
394
+ }
395
+ }
396
+ result.set(tag, maxSource);
397
+ }
398
+ return result;
399
+ }
400
+ getFirstSeenPerTag() {
401
+ const result = new Map();
402
+ for (const tag of this._contentTags) {
403
+ const t = tag['Tag'];
404
+ if (t && !result.has(t)) {
405
+ const date = tag['__mj_CreatedAt'];
406
+ result.set(t, date ? formatShortDate(date) : '');
407
+ }
408
+ }
409
+ return result;
410
+ }
411
+ static ɵfac = /*@__PURE__*/ (() => { let ɵClassifyTagsTabComponent_BaseFactory; return function ClassifyTagsTabComponent_Factory(__ngFactoryType__) { return (ɵClassifyTagsTabComponent_BaseFactory || (ɵClassifyTagsTabComponent_BaseFactory = i0.ɵɵgetInheritedFactory(ClassifyTagsTabComponent)))(__ngFactoryType__ || ClassifyTagsTabComponent); }; })();
412
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ClassifyTagsTabComponent, selectors: [["classify-tags-tab"]], inputs: { ContentTags: "ContentTags", ContentItems: "ContentItems" }, outputs: { OpenItemDetailRequested: "OpenItemDetailRequested" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 48, vars: 9, consts: [["Title", "Tag Library", 3, "Subtitle"], ["actions", ""], ["mjButton", "", "variant", "secondary", "size", "sm", 3, "click", "disabled"], ["toolbar", ""], ["type", "text", "placeholder", "Search tags...", 1, "at-search-input", 3, "ngModelChange", "input", "ngModel"], [3, "Padding", "Flex"], [1, "at-main-area"], [1, "at-loading-overlay"], [1, "at-page-body"], [1, "at-tag-lib-layout"], [1, "at-tag-lib-main"], [1, "at-card"], [1, "at-card-body", 2, "max-height", "500px", "overflow-y", "auto"], [1, "at-tag-table"], [1, "at-tag-row-clickable", 3, "at-tag-row-selected"], [1, "at-card", 2, "margin-top", "12px"], [1, "at-tag-lib-sidebar"], [1, "at-card", "at-tag-cloud-card"], [1, "at-card-title", 2, "margin-bottom", "12px"], [1, "fa-solid", "fa-cloud"], ["Layout", "spiral", "ColorMode", "weight-gradient", 3, "Items", "MaxFontSize", "MinFontSize", "MaxItems", "Interactive", "Animate"], [1, "at-tag-cloud-empty"], [1, "at-card", 2, "padding", "16px", "margin-top", "12px"], [1, "at-card-title", 2, "margin-bottom", "10px"], [1, "fa-solid", "fa-chart-pie"], [1, "at-tags-by-source"], [1, "at-tag-source-row"], [1, "fa-solid", "fa-spinner", "fa-spin"], [1, "mj-action-label"], [1, "fa-solid", "fa-arrows-rotate"], ["text", "Refreshing tags\u2026"], [1, "at-tag-row-clickable", 3, "click"], [1, "at-tag-name-cell"], [1, "at-weight-indicator"], [1, "at-weight-bar"], [1, "at-weight-bar-fill"], [1, "at-weight-value"], [1, "at-tag-bar"], [1, "at-tag-bar-fill"], [1, "at-card-header"], [1, "at-card-title"], [1, "fa-solid", "fa-tag"], ["aria-label", "Close", 1, "at-slide-close", 2, "background", "none", "border", "none", "cursor", "pointer", "color", "var(--mj-text-muted)", 3, "click"], [1, "fa-solid", "fa-times"], [1, "at-card-body", 2, "max-height", "300px", "overflow-y", "auto"], [1, "at-empty-state"], [1, "at-tag-row-clickable"]], template: function ClassifyTagsTabComponent_Template(rf, ctx) { if (rf & 1) {
413
+ i0.ɵɵelementStart(0, "mj-page-header-interior", 0)(1, "div", 1)(2, "button", 2);
414
+ i0.ɵɵlistener("click", function ClassifyTagsTabComponent_Template_button_click_2_listener() { return ctx.Refresh(); });
415
+ i0.ɵɵconditionalCreate(3, ClassifyTagsTabComponent_Conditional_3_Template, 3, 0)(4, ClassifyTagsTabComponent_Conditional_4_Template, 3, 0);
416
+ i0.ɵɵelementEnd()();
417
+ i0.ɵɵelementStart(5, "div", 3)(6, "input", 4);
418
+ i0.ɵɵtwoWayListener("ngModelChange", function ClassifyTagsTabComponent_Template_input_ngModelChange_6_listener($event) { i0.ɵɵtwoWayBindingSet(ctx.TagSearchQuery, $event) || (ctx.TagSearchQuery = $event); return $event; });
419
+ i0.ɵɵlistener("input", function ClassifyTagsTabComponent_Template_input_input_6_listener() { return ctx.FilterTags(); });
420
+ i0.ɵɵelementEnd()()();
421
+ i0.ɵɵelementStart(7, "mj-page-body-interior", 5)(8, "div", 6);
422
+ i0.ɵɵconditionalCreate(9, ClassifyTagsTabComponent_Conditional_9_Template, 2, 0, "div", 7);
423
+ i0.ɵɵelementStart(10, "div", 8)(11, "div", 9)(12, "div", 10)(13, "div", 11)(14, "div", 12)(15, "table", 13)(16, "thead")(17, "tr")(18, "th");
424
+ i0.ɵɵtext(19, "Tag");
425
+ i0.ɵɵelementEnd();
426
+ i0.ɵɵelementStart(20, "th");
427
+ i0.ɵɵtext(21, "Count");
428
+ i0.ɵɵelementEnd();
429
+ i0.ɵɵelementStart(22, "th");
430
+ i0.ɵɵtext(23, "Avg Weight");
431
+ i0.ɵɵelementEnd();
432
+ i0.ɵɵelementStart(24, "th");
433
+ i0.ɵɵtext(25, "Distribution");
434
+ i0.ɵɵelementEnd();
435
+ i0.ɵɵelementStart(26, "th");
436
+ i0.ɵɵtext(27, "Top Source");
437
+ i0.ɵɵelementEnd();
438
+ i0.ɵɵelementStart(28, "th");
439
+ i0.ɵɵtext(29, "First Seen");
440
+ i0.ɵɵelementEnd()()();
441
+ i0.ɵɵelementStart(30, "tbody");
442
+ i0.ɵɵrepeaterCreate(31, ClassifyTagsTabComponent_For_32_Template, 18, 17, "tr", 14, _forTrack0);
443
+ i0.ɵɵelementEnd()()()();
444
+ i0.ɵɵconditionalCreate(33, ClassifyTagsTabComponent_Conditional_33_Template, 10, 3, "div", 15);
445
+ i0.ɵɵelementEnd();
446
+ i0.ɵɵelementStart(34, "div", 16)(35, "div", 17)(36, "div", 18);
447
+ i0.ɵɵelement(37, "i", 19);
448
+ i0.ɵɵtext(38, " Tag Cloud");
449
+ i0.ɵɵelementEnd();
450
+ i0.ɵɵconditionalCreate(39, ClassifyTagsTabComponent_Conditional_39_Template, 1, 6, "mj-word-cloud", 20)(40, ClassifyTagsTabComponent_Conditional_40_Template, 2, 0, "div", 21);
451
+ i0.ɵɵelementEnd();
452
+ i0.ɵɵelementStart(41, "div", 22)(42, "div", 23);
453
+ i0.ɵɵelement(43, "i", 24);
454
+ i0.ɵɵtext(44, " By Source");
455
+ i0.ɵɵelementEnd();
456
+ i0.ɵɵelementStart(45, "div", 25);
457
+ i0.ɵɵrepeaterCreate(46, ClassifyTagsTabComponent_For_47_Template, 5, 2, "div", 26, _forTrack1);
458
+ i0.ɵɵelementEnd()()()()()()();
459
+ } if (rf & 2) {
460
+ i0.ɵɵproperty("Subtitle", ctx.Subtitle);
461
+ i0.ɵɵadvance(2);
462
+ i0.ɵɵproperty("disabled", ctx.IsLoading);
463
+ i0.ɵɵadvance();
464
+ i0.ɵɵconditional(ctx.IsLoading ? 3 : 4);
465
+ i0.ɵɵadvance(3);
466
+ i0.ɵɵtwoWayProperty("ngModel", ctx.TagSearchQuery);
467
+ i0.ɵɵadvance();
468
+ i0.ɵɵproperty("Padding", false)("Flex", true);
469
+ i0.ɵɵadvance(2);
470
+ i0.ɵɵconditional(ctx.IsLoading ? 9 : -1);
471
+ i0.ɵɵadvance(22);
472
+ i0.ɵɵrepeater(ctx.FilteredTagRows);
473
+ i0.ɵɵadvance(2);
474
+ i0.ɵɵconditional(ctx.SelectedDrillDownTag ? 33 : -1);
475
+ i0.ɵɵadvance(6);
476
+ i0.ɵɵconditional(ctx.TagCloudWordItems.length > 0 ? 39 : 40);
477
+ i0.ɵɵadvance(7);
478
+ i0.ɵɵrepeater(ctx.TagsBySource);
479
+ } }, dependencies: [i1.DefaultValueAccessor, i1.NgControlStatus, i1.NgModel, i2.LoadingComponent, i3.MJButtonDirective, i3.MJPageHeaderInteriorComponent, i3.MJPageBodyInteriorComponent, i4.MJWordCloudComponent], encapsulation: 2 });
480
+ }
481
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ClassifyTagsTabComponent, [{
482
+ type: Component,
483
+ args: [{ standalone: false, selector: 'classify-tags-tab', template: "<mj-page-header-interior\n Title=\"Tag Library\"\n [Subtitle]=\"Subtitle\">\n <div actions>\n <button mjButton variant=\"secondary\" size=\"sm\" (click)=\"Refresh()\" [disabled]=\"IsLoading\">\n @if (IsLoading) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i> <span class=\"mj-action-label\">Refreshing\u2026</span>\n } @else {\n <i class=\"fa-solid fa-arrows-rotate\"></i> <span class=\"mj-action-label\">Refresh</span>\n }\n </button>\n </div>\n <div toolbar>\n <input type=\"text\" class=\"at-search-input\" placeholder=\"Search tags...\"\n [(ngModel)]=\"TagSearchQuery\" (input)=\"FilterTags()\">\n </div>\n</mj-page-header-interior>\n\n<mj-page-body-interior [Padding]=\"false\" [Flex]=\"true\">\n <div class=\"at-main-area\">\n @if (IsLoading) {\n <div class=\"at-loading-overlay\">\n <mj-loading text=\"Refreshing tags\u2026\"></mj-loading>\n </div>\n }\n <div class=\"at-page-body\">\n <div class=\"at-tag-lib-layout\">\n <div class=\"at-tag-lib-main\">\n <div class=\"at-card\">\n <div class=\"at-card-body\" style=\"max-height: 500px; overflow-y: auto;\">\n <table class=\"at-tag-table\">\n <thead>\n <tr>\n <th>Tag</th>\n <th>Count</th>\n <th>Avg Weight</th>\n <th>Distribution</th>\n <th>Top Source</th>\n <th>First Seen</th>\n </tr>\n </thead>\n <tbody>\n @for (row of FilteredTagRows; track row.Tag) {\n <tr class=\"at-tag-row-clickable\" (click)=\"DrillDownTag(row.Tag)\"\n [class.at-tag-row-selected]=\"SelectedDrillDownTag === row.Tag\">\n <td class=\"at-tag-name-cell\">{{ row.Tag }}</td>\n <td>{{ row.UsageCount }}</td>\n <td>\n <div class=\"at-weight-indicator\">\n <div class=\"at-weight-bar\">\n <div class=\"at-weight-bar-fill\" [style.width.%]=\"row.AvgWeight * 100\"\n [class.at-weight-high]=\"row.AvgWeight >= 0.7\"\n [class.at-weight-medium]=\"row.AvgWeight >= 0.4 && row.AvgWeight < 0.7\"\n [class.at-weight-low]=\"row.AvgWeight < 0.4\"></div>\n </div>\n <span class=\"at-weight-value\">{{ row.AvgWeight.toFixed(2) }}</span>\n </div>\n </td>\n <td>\n <div class=\"at-tag-bar\">\n <div class=\"at-tag-bar-fill\" [style.width.%]=\"row.BarWidthPct\"></div>\n </div>\n </td>\n <td>{{ row.TopSource }}</td>\n <td>{{ row.FirstSeen }}</td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n </div>\n\n <!-- Tag drill-down: content items matching selected tag -->\n @if (SelectedDrillDownTag) {\n <div class=\"at-card\" style=\"margin-top: 12px;\">\n <div class=\"at-card-header\">\n <span class=\"at-card-title\">\n <i class=\"fa-solid fa-tag\"></i>\n Content items tagged \"{{ SelectedDrillDownTag }}\"\n ({{ TagDrillDownItems.length }})\n </span>\n <button class=\"at-slide-close\" (click)=\"CloseDrillDownTag()\" style=\"background:none;border:none;cursor:pointer;color:var(--mj-text-muted)\" aria-label=\"Close\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n <div class=\"at-card-body\" style=\"max-height: 300px; overflow-y: auto;\">\n @if (TagDrillDownItems.length === 0) {\n <div class=\"at-empty-state\"><p>No content items found for this tag.</p></div>\n } @else {\n <table class=\"at-tag-table\">\n <thead>\n <tr>\n <th>Name</th>\n <th>Source</th>\n <th>Weight</th>\n <th>Updated</th>\n </tr>\n </thead>\n <tbody>\n @for (di of TagDrillDownItems; track di.ID) {\n <tr class=\"at-tag-row-clickable\" (click)=\"onOpenItemDetail(di.ID)\">\n <td>{{ di.Name }}</td>\n <td>{{ di.SourceName }}</td>\n <td>{{ FormatWeight(di.Weight) }}</td>\n <td>{{ di.UpdatedAt }}</td>\n </tr>\n }\n </tbody>\n </table>\n }\n </div>\n </div>\n }\n </div>\n <div class=\"at-tag-lib-sidebar\">\n <div class=\"at-card at-tag-cloud-card\">\n <div class=\"at-card-title\" style=\"margin-bottom: 12px;\"><i class=\"fa-solid fa-cloud\"></i> Tag Cloud</div>\n @if (TagCloudWordItems.length > 0) {\n <mj-word-cloud\n [Items]=\"TagCloudWordItems\"\n [MaxFontSize]=\"40\"\n [MinFontSize]=\"12\"\n [MaxItems]=\"20\"\n Layout=\"spiral\"\n ColorMode=\"weight-gradient\"\n [Interactive]=\"true\"\n [Animate]=\"true\">\n </mj-word-cloud>\n } @else {\n <div class=\"at-tag-cloud-empty\">No tags yet</div>\n }\n </div>\n <div class=\"at-card\" style=\"padding: 16px; margin-top: 12px;\">\n <div class=\"at-card-title\" style=\"margin-bottom: 10px;\"><i class=\"fa-solid fa-chart-pie\"></i> By Source</div>\n <div class=\"at-tags-by-source\">\n @for (s of TagsBySource; track s.SourceName) {\n <div class=\"at-tag-source-row\">\n <span>{{ s.SourceName }}</span>\n <strong>{{ s.Count }}</strong>\n </div>\n }\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n</mj-page-body-interior>\n", styles: ["/*\n * Tag Library tab styles.\n *\n * The host (AutotaggingPipelineResourceComponent) uses ViewEncapsulation.None,\n * so its `.at-*` rules are global and already style this tab's markup while it\n * renders inside the host shell. Tab-specific rules live here as the shared CSS\n * is partitioned during the host-slim step.\n */\n"] }]
484
+ }], null, { ContentTags: [{
485
+ type: Input
486
+ }], ContentItems: [{
487
+ type: Input
488
+ }], OpenItemDetailRequested: [{
489
+ type: Output
490
+ }] }); })();
491
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ClassifyTagsTabComponent, { className: "ClassifyTagsTabComponent", filePath: "src/AI/components/autotagging/tabs/tags-tab.component.ts", lineNumber: 34 }); })();
492
+ //# sourceMappingURL=tags-tab.component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tags-tab.component.js","sourceRoot":"","sources":["../../../../../src/AI/components/autotagging/tabs/tags-tab.component.ts","../../../../../src/AI/components/autotagging/tabs/tags-tab.component.html"],"names":[],"mappings":"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","sourcesContent":["/**\n * @fileoverview Classify · Tag Library tab.\n *\n * Self-contained sub-page: owns its header-interior (with the tag search box),\n * the tag rows table, the word cloud, the tags-by-source breakdown, and the\n * per-tag drill-down. Receives the shared raw tag + item rows from the host\n * orchestrator via `[ContentTags]`/`[ContentItems]` and rebuilds its view\n * models from them. Opening a content item from the drill-down is a cross-tab\n * concern owned by the host's slide-in, so it bubbles up via @Output.\n */\nimport { Component, ChangeDetectorRef, EventEmitter, Input, Output, inject } from '@angular/core';\nimport { NormalizeUUID } from '@memberjunction/global';\nimport { BaseAngularComponent } from '@memberjunction/ng-base-types';\nimport { WordCloudItem } from '@memberjunction/ng-word-cloud';\nimport { TagRow, TagBySource } from '../shared/classify.types';\nimport { formatWeight, tagFontSize, formatShortDate, deriveDisplayName } from '../shared/classify.format';\n\n/** One row in the per-tag drill-down (content items carrying a given tag). */\ninterface TagDrillDownItem {\n ID: string;\n Name: string;\n SourceName: string;\n Weight: number;\n UpdatedAt: string;\n FeedIndex: number;\n}\n\n@Component({\n standalone: false,\n selector: 'classify-tags-tab',\n templateUrl: './tags-tab.component.html',\n styleUrls: ['./tags-tab.component.css']\n})\nexport class ClassifyTagsTabComponent extends BaseAngularComponent {\n private cdr = inject(ChangeDetectorRef);\n\n /** Shared raw `MJ: Content Item Tags` rows, supplied by the host orchestrator. */\n private _contentTags: Record<string, unknown>[] = [];\n @Input()\n set ContentTags(value: Record<string, unknown>[]) {\n this._contentTags = value ?? [];\n this.rebuild();\n }\n get ContentTags(): Record<string, unknown>[] {\n return this._contentTags;\n }\n\n /** Shared raw `MJ: Content Items` rows — used for source mapping and drill-down. */\n private _contentItems: Record<string, unknown>[] = [];\n @Input()\n set ContentItems(value: Record<string, unknown>[]) {\n this._contentItems = value ?? [];\n this.rebuild();\n }\n get ContentItems(): Record<string, unknown>[] {\n return this._contentItems;\n }\n\n /** Shown while a manual Refresh() rebuilds the tag view models. */\n public IsLoading = false;\n\n public TagRows: TagRow[] = [];\n public FilteredTagRows: TagRow[] = [];\n public TagCloudWordItems: WordCloudItem[] = [];\n public TagsBySource: TagBySource[] = [];\n public TagSearchQuery = '';\n public SelectedDrillDownTag: string | null = null;\n public TagDrillDownItems: TagDrillDownItem[] = [];\n\n /** Subtitle reflects the live tag count, mirroring the former host subtitle. */\n public get Subtitle(): string {\n return `${this.TagRows.length} unique tags across all content sources`;\n }\n\n // Template-facing formatters (shared pure helpers exposed for the view).\n public readonly TagFontSize = tagFontSize;\n public readonly FormatWeight = formatWeight;\n\n /** Bubble a request to open a content item's detail slide-in (host-owned). */\n @Output() OpenItemDetailRequested = new EventEmitter<string>();\n\n public onOpenItemDetail(contentItemID: string): void {\n this.OpenItemDetailRequested.emit(contentItemID);\n }\n\n /** Rebuild all tag-tab view models from the current inputs. */\n private rebuild(): void {\n this.buildTagRows();\n this.buildTagCloud();\n this.buildTagsBySource();\n this.FilterTags();\n }\n\n /**\n * Rebuild the tag view models from the current host-supplied inputs. The tag\n * data is host-owned (flows in via [ContentTags]/[ContentItems]); Refresh\n * recomputes the rows/cloud/breakdown and surfaces a brief loading state.\n */\n public async Refresh(): Promise<void> {\n this.IsLoading = true;\n this.cdr.detectChanges();\n this.rebuild();\n this.IsLoading = false;\n this.cdr.detectChanges();\n }\n\n // ── External control surface (host deep-link + agent tool) ──\n\n /** Apply a search query programmatically (used by the agent tool + deep link). Returns the match count. */\n public ApplySearch(query: string): number {\n this.TagSearchQuery = query;\n this.FilterTags();\n return this.FilteredTagRows.length;\n }\n\n // ── View-model building ──\n\n private buildTagRows(): void {\n const tagCounts = this.countAllTags();\n const avgWeights = this.computeAvgWeights();\n const tagSourceMap = this.getTopSourcePerTag();\n const tagFirstSeen = this.getFirstSeenPerTag();\n const sorted = Array.from(tagCounts.entries()).sort((a, b) => b[1] - a[1]);\n const maxCount = sorted.length > 0 ? sorted[0][1] : 1;\n\n this.TagRows = sorted.map(([tag, count]) => ({\n Tag: tag,\n UsageCount: count,\n AvgWeight: avgWeights.get(tag) ?? 1.0,\n BarWidthPct: Math.round((count / maxCount) * 100),\n TopSource: tagSourceMap.get(tag) ?? 'Unknown',\n FirstSeen: tagFirstSeen.get(tag) ?? ''\n }));\n }\n\n private buildTagCloud(): void {\n const tagCounts = this.countAllTags();\n const avgWeights = this.computeAvgWeights();\n // Sort by a combined score: usage count * avg weight (so high-weight, high-count tags bubble up)\n const scored = Array.from(tagCounts.entries()).map(([tag, count]) => {\n const weight = avgWeights.get(tag) ?? 1.0;\n return { tag, count, weight, score: count * weight };\n }).sort((a, b) => b.score - a.score).slice(0, 20);\n const maxScore = scored.length > 0 ? scored[0].score : 1;\n\n // Build WordCloudItem[] for the mj-word-cloud component\n this.TagCloudWordItems = scored.map(s => ({\n Text: s.tag,\n Weight: maxScore > 0 ? s.score / maxScore : 0,\n Metadata: { Count: s.count, AvgWeight: s.weight }\n }));\n }\n\n private buildTagsBySource(): void {\n const sourceTagCounts = new Map<string, number>();\n const itemSourceMap = new Map<string, string>();\n for (const item of this._contentItems) {\n itemSourceMap.set(item['ID'] as string, (item['ContentSource'] as string) ?? 'Unknown');\n }\n for (const tag of this._contentTags) {\n const source = itemSourceMap.get(tag['ItemID'] as string) ?? 'Unknown';\n sourceTagCounts.set(source, (sourceTagCounts.get(source) ?? 0) + 1);\n }\n this.TagsBySource = Array.from(sourceTagCounts.entries())\n .sort((a, b) => b[1] - a[1])\n .map(([name, count]) => ({ SourceName: name, Count: count }));\n }\n\n public FilterTags(): void {\n const q = this.TagSearchQuery.toLowerCase().trim();\n this.FilteredTagRows = q\n ? this.TagRows.filter(r => r.Tag.toLowerCase().includes(q))\n : this.TagRows;\n this.cdr.detectChanges();\n }\n\n /** Drill down into content items matching a specific tag. */\n public DrillDownTag(tagName: string): void {\n if (this.SelectedDrillDownTag === tagName) {\n this.CloseDrillDownTag();\n return;\n }\n this.SelectedDrillDownTag = tagName;\n\n // Find all content items that have this tag\n const matchingItemIDs = new Map<string, number>(); // itemID → weight\n for (const tag of this._contentTags) {\n if ((tag['Tag'] as string) === tagName) {\n matchingItemIDs.set(\n NormalizeUUID(tag['ItemID'] as string),\n Number(tag['Weight'] ?? 1)\n );\n }\n }\n\n this.TagDrillDownItems = [];\n for (let i = 0; i < this._contentItems.length; i++) {\n const item = this._contentItems[i];\n const normalizedID = NormalizeUUID(item['ID'] as string);\n const weight = matchingItemIDs.get(normalizedID);\n if (weight !== undefined) {\n this.TagDrillDownItems.push({\n ID: item['ID'] as string,\n Name: deriveDisplayName({ Name: item['Name'] as string | null, Description: item['Description'] as string | null }),\n SourceName: (item['ContentSource'] as string) ?? 'Unknown',\n Weight: weight,\n UpdatedAt: formatShortDate((item['__mj_UpdatedAt'] as string) ?? ''),\n FeedIndex: i,\n });\n }\n }\n\n // Sort by weight descending\n this.TagDrillDownItems.sort((a, b) => b.Weight - a.Weight);\n this.cdr.detectChanges();\n }\n\n public CloseDrillDownTag(): void {\n this.SelectedDrillDownTag = null;\n this.TagDrillDownItems = [];\n this.cdr.detectChanges();\n }\n\n // ── Aggregation utilities (read only the tag + item inputs) ──\n\n private countAllTags(): Map<string, number> {\n const counts = new Map<string, number>();\n for (const tag of this._contentTags) {\n const t = tag['Tag'] as string;\n if (t) counts.set(t, (counts.get(t) ?? 0) + 1);\n }\n return counts;\n }\n\n /** Compute average weight per tag across all occurrences. */\n private computeAvgWeights(): Map<string, number> {\n const sums = new Map<string, number>();\n const counts = new Map<string, number>();\n for (const tag of this._contentTags) {\n const t = tag['Tag'] as string;\n const w = Number(tag['Weight'] ?? 0.5);\n if (t) {\n sums.set(t, (sums.get(t) ?? 0) + w);\n counts.set(t, (counts.get(t) ?? 0) + 1);\n }\n }\n const avgs = new Map<string, number>();\n for (const [t, sum] of sums) {\n avgs.set(t, Math.round((sum / (counts.get(t) ?? 1)) * 100) / 100);\n }\n return avgs;\n }\n\n private getTopSourcePerTag(): Map<string, string> {\n const tagSourceCounts = new Map<string, Map<string, number>>();\n const itemSourceMap = new Map<string, string>();\n for (const item of this._contentItems) {\n itemSourceMap.set(item['ID'] as string, (item['ContentSource'] as string) ?? 'Unknown');\n }\n for (const tag of this._contentTags) {\n const t = tag['Tag'] as string;\n const source = itemSourceMap.get(tag['ItemID'] as string) ?? 'Unknown';\n if (!tagSourceCounts.has(t)) tagSourceCounts.set(t, new Map());\n const inner = tagSourceCounts.get(t)!;\n inner.set(source, (inner.get(source) ?? 0) + 1);\n }\n const result = new Map<string, string>();\n for (const [tag, sourceCounts] of tagSourceCounts) {\n let maxSource = 'Unknown';\n let maxCount = 0;\n for (const [source, count] of sourceCounts) {\n if (count > maxCount) { maxSource = source; maxCount = count; }\n }\n result.set(tag, maxSource);\n }\n return result;\n }\n\n private getFirstSeenPerTag(): Map<string, string> {\n const result = new Map<string, string>();\n for (const tag of this._contentTags) {\n const t = tag['Tag'] as string;\n if (t && !result.has(t)) {\n const date = tag['__mj_CreatedAt'] as string;\n result.set(t, date ? formatShortDate(date) : '');\n }\n }\n return result;\n }\n}\n","<mj-page-header-interior\n Title=\"Tag Library\"\n [Subtitle]=\"Subtitle\">\n <div actions>\n <button mjButton variant=\"secondary\" size=\"sm\" (click)=\"Refresh()\" [disabled]=\"IsLoading\">\n @if (IsLoading) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i> <span class=\"mj-action-label\">Refreshing…</span>\n } @else {\n <i class=\"fa-solid fa-arrows-rotate\"></i> <span class=\"mj-action-label\">Refresh</span>\n }\n </button>\n </div>\n <div toolbar>\n <input type=\"text\" class=\"at-search-input\" placeholder=\"Search tags...\"\n [(ngModel)]=\"TagSearchQuery\" (input)=\"FilterTags()\">\n </div>\n</mj-page-header-interior>\n\n<mj-page-body-interior [Padding]=\"false\" [Flex]=\"true\">\n <div class=\"at-main-area\">\n @if (IsLoading) {\n <div class=\"at-loading-overlay\">\n <mj-loading text=\"Refreshing tags…\"></mj-loading>\n </div>\n }\n <div class=\"at-page-body\">\n <div class=\"at-tag-lib-layout\">\n <div class=\"at-tag-lib-main\">\n <div class=\"at-card\">\n <div class=\"at-card-body\" style=\"max-height: 500px; overflow-y: auto;\">\n <table class=\"at-tag-table\">\n <thead>\n <tr>\n <th>Tag</th>\n <th>Count</th>\n <th>Avg Weight</th>\n <th>Distribution</th>\n <th>Top Source</th>\n <th>First Seen</th>\n </tr>\n </thead>\n <tbody>\n @for (row of FilteredTagRows; track row.Tag) {\n <tr class=\"at-tag-row-clickable\" (click)=\"DrillDownTag(row.Tag)\"\n [class.at-tag-row-selected]=\"SelectedDrillDownTag === row.Tag\">\n <td class=\"at-tag-name-cell\">{{ row.Tag }}</td>\n <td>{{ row.UsageCount }}</td>\n <td>\n <div class=\"at-weight-indicator\">\n <div class=\"at-weight-bar\">\n <div class=\"at-weight-bar-fill\" [style.width.%]=\"row.AvgWeight * 100\"\n [class.at-weight-high]=\"row.AvgWeight >= 0.7\"\n [class.at-weight-medium]=\"row.AvgWeight >= 0.4 && row.AvgWeight < 0.7\"\n [class.at-weight-low]=\"row.AvgWeight < 0.4\"></div>\n </div>\n <span class=\"at-weight-value\">{{ row.AvgWeight.toFixed(2) }}</span>\n </div>\n </td>\n <td>\n <div class=\"at-tag-bar\">\n <div class=\"at-tag-bar-fill\" [style.width.%]=\"row.BarWidthPct\"></div>\n </div>\n </td>\n <td>{{ row.TopSource }}</td>\n <td>{{ row.FirstSeen }}</td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n </div>\n\n <!-- Tag drill-down: content items matching selected tag -->\n @if (SelectedDrillDownTag) {\n <div class=\"at-card\" style=\"margin-top: 12px;\">\n <div class=\"at-card-header\">\n <span class=\"at-card-title\">\n <i class=\"fa-solid fa-tag\"></i>\n Content items tagged \"{{ SelectedDrillDownTag }}\"\n ({{ TagDrillDownItems.length }})\n </span>\n <button class=\"at-slide-close\" (click)=\"CloseDrillDownTag()\" style=\"background:none;border:none;cursor:pointer;color:var(--mj-text-muted)\" aria-label=\"Close\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n <div class=\"at-card-body\" style=\"max-height: 300px; overflow-y: auto;\">\n @if (TagDrillDownItems.length === 0) {\n <div class=\"at-empty-state\"><p>No content items found for this tag.</p></div>\n } @else {\n <table class=\"at-tag-table\">\n <thead>\n <tr>\n <th>Name</th>\n <th>Source</th>\n <th>Weight</th>\n <th>Updated</th>\n </tr>\n </thead>\n <tbody>\n @for (di of TagDrillDownItems; track di.ID) {\n <tr class=\"at-tag-row-clickable\" (click)=\"onOpenItemDetail(di.ID)\">\n <td>{{ di.Name }}</td>\n <td>{{ di.SourceName }}</td>\n <td>{{ FormatWeight(di.Weight) }}</td>\n <td>{{ di.UpdatedAt }}</td>\n </tr>\n }\n </tbody>\n </table>\n }\n </div>\n </div>\n }\n </div>\n <div class=\"at-tag-lib-sidebar\">\n <div class=\"at-card at-tag-cloud-card\">\n <div class=\"at-card-title\" style=\"margin-bottom: 12px;\"><i class=\"fa-solid fa-cloud\"></i> Tag Cloud</div>\n @if (TagCloudWordItems.length > 0) {\n <mj-word-cloud\n [Items]=\"TagCloudWordItems\"\n [MaxFontSize]=\"40\"\n [MinFontSize]=\"12\"\n [MaxItems]=\"20\"\n Layout=\"spiral\"\n ColorMode=\"weight-gradient\"\n [Interactive]=\"true\"\n [Animate]=\"true\">\n </mj-word-cloud>\n } @else {\n <div class=\"at-tag-cloud-empty\">No tags yet</div>\n }\n </div>\n <div class=\"at-card\" style=\"padding: 16px; margin-top: 12px;\">\n <div class=\"at-card-title\" style=\"margin-bottom: 10px;\"><i class=\"fa-solid fa-chart-pie\"></i> By Source</div>\n <div class=\"at-tags-by-source\">\n @for (s of TagsBySource; track s.SourceName) {\n <div class=\"at-tag-source-row\">\n <span>{{ s.SourceName }}</span>\n <strong>{{ s.Count }}</strong>\n </div>\n }\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n</mj-page-body-interior>\n"]}