@memberjunction/ng-dashboards 5.37.0 → 5.39.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 (328) hide show
  1. package/README.md +46 -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 +89 -842
  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 +1353 -7683
  29. package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.js.map +1 -1
  30. package/dist/AI/components/autotagging/dialogs/dry-run-preview.dialog.component.d.ts +87 -0
  31. package/dist/AI/components/autotagging/dialogs/dry-run-preview.dialog.component.d.ts.map +1 -0
  32. package/dist/AI/components/autotagging/dialogs/dry-run-preview.dialog.component.js +475 -0
  33. package/dist/AI/components/autotagging/dialogs/dry-run-preview.dialog.component.js.map +1 -0
  34. package/dist/AI/components/autotagging/dialogs/item-detail.dialog.component.d.ts +29 -0
  35. package/dist/AI/components/autotagging/dialogs/item-detail.dialog.component.d.ts.map +1 -0
  36. package/dist/AI/components/autotagging/dialogs/item-detail.dialog.component.js +208 -0
  37. package/dist/AI/components/autotagging/dialogs/item-detail.dialog.component.js.map +1 -0
  38. package/dist/AI/components/autotagging/dialogs/no-content-type-warning.dialog.component.d.ts +21 -0
  39. package/dist/AI/components/autotagging/dialogs/no-content-type-warning.dialog.component.d.ts.map +1 -0
  40. package/dist/AI/components/autotagging/dialogs/no-content-type-warning.dialog.component.js +70 -0
  41. package/dist/AI/components/autotagging/dialogs/no-content-type-warning.dialog.component.js.map +1 -0
  42. package/dist/AI/components/autotagging/dialogs/source-type-form.dialog.component.d.ts +235 -0
  43. package/dist/AI/components/autotagging/dialogs/source-type-form.dialog.component.d.ts.map +1 -0
  44. package/dist/AI/components/autotagging/dialogs/source-type-form.dialog.component.js +1735 -0
  45. package/dist/AI/components/autotagging/dialogs/source-type-form.dialog.component.js.map +1 -0
  46. package/dist/AI/components/autotagging/shared/classify.dryrun.d.ts +61 -0
  47. package/dist/AI/components/autotagging/shared/classify.dryrun.d.ts.map +1 -0
  48. package/dist/AI/components/autotagging/shared/classify.dryrun.js +78 -0
  49. package/dist/AI/components/autotagging/shared/classify.dryrun.js.map +1 -0
  50. package/dist/AI/components/autotagging/shared/classify.format.d.ts +43 -0
  51. package/dist/AI/components/autotagging/shared/classify.format.d.ts.map +1 -0
  52. package/dist/AI/components/autotagging/shared/classify.format.js +209 -0
  53. package/dist/AI/components/autotagging/shared/classify.format.js.map +1 -0
  54. package/dist/AI/components/autotagging/shared/classify.types.d.ts +276 -0
  55. package/dist/AI/components/autotagging/shared/classify.types.d.ts.map +1 -0
  56. package/dist/AI/components/autotagging/shared/classify.types.js +6 -0
  57. package/dist/AI/components/autotagging/shared/classify.types.js.map +1 -0
  58. package/dist/AI/components/autotagging/tabs/health-tab.component.d.ts +103 -0
  59. package/dist/AI/components/autotagging/tabs/health-tab.component.d.ts.map +1 -0
  60. package/dist/AI/components/autotagging/tabs/health-tab.component.js +571 -0
  61. package/dist/AI/components/autotagging/tabs/health-tab.component.js.map +1 -0
  62. package/dist/AI/components/autotagging/tabs/history-tab.component.d.ts +40 -0
  63. package/dist/AI/components/autotagging/tabs/history-tab.component.d.ts.map +1 -0
  64. package/dist/AI/components/autotagging/tabs/history-tab.component.js +402 -0
  65. package/dist/AI/components/autotagging/tabs/history-tab.component.js.map +1 -0
  66. package/dist/AI/components/autotagging/tabs/inbox-tab.component.d.ts +107 -0
  67. package/dist/AI/components/autotagging/tabs/inbox-tab.component.d.ts.map +1 -0
  68. package/dist/AI/components/autotagging/tabs/inbox-tab.component.js +719 -0
  69. package/dist/AI/components/autotagging/tabs/inbox-tab.component.js.map +1 -0
  70. package/dist/AI/components/autotagging/tabs/pipeline-tab.component.d.ts +122 -0
  71. package/dist/AI/components/autotagging/tabs/pipeline-tab.component.d.ts.map +1 -0
  72. package/dist/AI/components/autotagging/tabs/pipeline-tab.component.js +752 -0
  73. package/dist/AI/components/autotagging/tabs/pipeline-tab.component.js.map +1 -0
  74. package/dist/AI/components/autotagging/tabs/sources-tab.component.d.ts +166 -0
  75. package/dist/AI/components/autotagging/tabs/sources-tab.component.d.ts.map +1 -0
  76. package/dist/AI/components/autotagging/tabs/sources-tab.component.js +1384 -0
  77. package/dist/AI/components/autotagging/tabs/sources-tab.component.js.map +1 -0
  78. package/dist/AI/components/autotagging/tabs/tags-tab.component.d.ts +70 -0
  79. package/dist/AI/components/autotagging/tabs/tags-tab.component.d.ts.map +1 -0
  80. package/dist/AI/components/autotagging/tabs/tags-tab.component.js +448 -0
  81. package/dist/AI/components/autotagging/tabs/tags-tab.component.js.map +1 -0
  82. package/dist/AI/components/autotagging/tabs/taxonomy-tab.component.d.ts +397 -0
  83. package/dist/AI/components/autotagging/tabs/taxonomy-tab.component.d.ts.map +1 -0
  84. package/dist/AI/components/autotagging/tabs/taxonomy-tab.component.js +3490 -0
  85. package/dist/AI/components/autotagging/tabs/taxonomy-tab.component.js.map +1 -0
  86. package/dist/AI/components/autotagging/tabs/types-tab.component.d.ts +47 -0
  87. package/dist/AI/components/autotagging/tabs/types-tab.component.d.ts.map +1 -0
  88. package/dist/AI/components/autotagging/tabs/types-tab.component.js +220 -0
  89. package/dist/AI/components/autotagging/tabs/types-tab.component.js.map +1 -0
  90. package/dist/AI/components/duplicates/duplicate-detection-resource.component.js +293 -289
  91. package/dist/AI/components/duplicates/duplicate-detection-resource.component.js.map +1 -1
  92. package/dist/AI/components/models/model-management.component.js +209 -208
  93. package/dist/AI/components/models/model-management.component.js.map +1 -1
  94. package/dist/AI/components/prompts/prompt-management.component.js +130 -128
  95. package/dist/AI/components/prompts/prompt-management.component.js.map +1 -1
  96. package/dist/AI/components/requests/agent-requests-resource.component.js +61 -61
  97. package/dist/AI/components/requests/agent-requests-resource.component.js.map +1 -1
  98. package/dist/AI/components/system/system-configuration.component.js +17 -17
  99. package/dist/AI/components/system/system-configuration.component.js.map +1 -1
  100. package/dist/AI/components/tags/tags-resource.component.js +550 -532
  101. package/dist/AI/components/tags/tags-resource.component.js.map +1 -1
  102. package/dist/AI/components/vectors/vector-management-resource.component.js +1 -1
  103. package/dist/AI/components/vectors/vector-management-resource.component.js.map +1 -1
  104. package/dist/AI/services/ai-instrumentation.service.d.ts +5 -0
  105. package/dist/AI/services/ai-instrumentation.service.d.ts.map +1 -1
  106. package/dist/AI/services/ai-instrumentation.service.js +14 -2
  107. package/dist/AI/services/ai-instrumentation.service.js.map +1 -1
  108. package/dist/AI/services/cache-metrics.d.ts +50 -0
  109. package/dist/AI/services/cache-metrics.d.ts.map +1 -0
  110. package/dist/AI/services/cache-metrics.js +43 -0
  111. package/dist/AI/services/cache-metrics.js.map +1 -0
  112. package/dist/APIKeys/api-key-edit-panel.component.js +2 -2
  113. package/dist/APIKeys/api-keys-resource.component.js +132 -131
  114. package/dist/APIKeys/api-keys-resource.component.js.map +1 -1
  115. package/dist/Actions/components/actions-overview.component.js +141 -141
  116. package/dist/Actions/components/actions-overview.component.js.map +1 -1
  117. package/dist/Actions/components/execution-monitoring.component.js +15 -15
  118. package/dist/Actions/components/execution-monitoring.component.js.map +1 -1
  119. package/dist/Actions/components/explorer/action-explorer.component.d.ts +0 -5
  120. package/dist/Actions/components/explorer/action-explorer.component.d.ts.map +1 -1
  121. package/dist/Actions/components/explorer/action-explorer.component.js +139 -212
  122. package/dist/Actions/components/explorer/action-explorer.component.js.map +1 -1
  123. package/dist/Admin/admin-data-schema.component.js +2 -2
  124. package/dist/Admin/admin-data-schema.component.js.map +1 -1
  125. package/dist/Admin/admin-dev-tools-resource.component.js +2 -2
  126. package/dist/Admin/admin-dev-tools-resource.component.js.map +1 -1
  127. package/dist/Admin/admin-identity-access.component.js +2 -2
  128. package/dist/Admin/admin-identity-access.component.js.map +1 -1
  129. package/dist/Admin/admin-monitoring.component.js +2 -2
  130. package/dist/Admin/admin-monitoring.component.js.map +1 -1
  131. package/dist/ApplicationRoles/application-roles-resource.component.js +54 -49
  132. package/dist/ApplicationRoles/application-roles-resource.component.js.map +1 -1
  133. package/dist/Communication/communication-logs-resource.component.d.ts +6 -0
  134. package/dist/Communication/communication-logs-resource.component.d.ts.map +1 -1
  135. package/dist/Communication/communication-logs-resource.component.js +72 -50
  136. package/dist/Communication/communication-logs-resource.component.js.map +1 -1
  137. package/dist/Communication/communication-monitor-resource.component.js +103 -102
  138. package/dist/Communication/communication-monitor-resource.component.js.map +1 -1
  139. package/dist/Communication/communication-providers-resource.component.js +52 -51
  140. package/dist/Communication/communication-providers-resource.component.js.map +1 -1
  141. package/dist/Communication/communication-runs-resource.component.js +39 -38
  142. package/dist/Communication/communication-runs-resource.component.js.map +1 -1
  143. package/dist/Communication/communication-templates-resource.component.d.ts +6 -0
  144. package/dist/Communication/communication-templates-resource.component.d.ts.map +1 -1
  145. package/dist/Communication/communication-templates-resource.component.js +92 -89
  146. package/dist/Communication/communication-templates-resource.component.js.map +1 -1
  147. package/dist/ComponentStudio/component-studio-dashboard.component.d.ts +73 -1
  148. package/dist/ComponentStudio/component-studio-dashboard.component.d.ts.map +1 -1
  149. package/dist/ComponentStudio/component-studio-dashboard.component.js +512 -127
  150. package/dist/ComponentStudio/component-studio-dashboard.component.js.map +1 -1
  151. package/dist/ComponentStudio/component-studio-resource.component.d.ts +22 -0
  152. package/dist/ComponentStudio/component-studio-resource.component.d.ts.map +1 -0
  153. package/dist/ComponentStudio/component-studio-resource.component.js +55 -0
  154. package/dist/ComponentStudio/component-studio-resource.component.js.map +1 -0
  155. package/dist/ComponentStudio/components/ai-assistant/ai-assistant-panel.component.d.ts +104 -45
  156. package/dist/ComponentStudio/components/ai-assistant/ai-assistant-panel.component.d.ts.map +1 -1
  157. package/dist/ComponentStudio/components/ai-assistant/ai-assistant-panel.component.js +234 -331
  158. package/dist/ComponentStudio/components/ai-assistant/ai-assistant-panel.component.js.map +1 -1
  159. package/dist/ComponentStudio/components/form-builder/form-builder-canvas.component.d.ts +54 -0
  160. package/dist/ComponentStudio/components/form-builder/form-builder-canvas.component.d.ts.map +1 -0
  161. package/dist/ComponentStudio/components/form-builder/form-builder-canvas.component.js +339 -0
  162. package/dist/ComponentStudio/components/form-builder/form-builder-canvas.component.js.map +1 -0
  163. package/dist/ComponentStudio/components/form-builder/form-builder-right-panel.component.d.ts +65 -0
  164. package/dist/ComponentStudio/components/form-builder/form-builder-right-panel.component.d.ts.map +1 -0
  165. package/dist/ComponentStudio/components/form-builder/form-builder-right-panel.component.js +492 -0
  166. package/dist/ComponentStudio/components/form-builder/form-builder-right-panel.component.js.map +1 -0
  167. package/dist/ComponentStudio/components/form-builder/form-builder-tab.component.d.ts +88 -0
  168. package/dist/ComponentStudio/components/form-builder/form-builder-tab.component.d.ts.map +1 -0
  169. package/dist/ComponentStudio/components/form-builder/form-builder-tab.component.js +457 -0
  170. package/dist/ComponentStudio/components/form-builder/form-builder-tab.component.js.map +1 -0
  171. package/dist/ComponentStudio/components/form-override-dialog.component.d.ts +106 -0
  172. package/dist/ComponentStudio/components/form-override-dialog.component.d.ts.map +1 -0
  173. package/dist/ComponentStudio/components/form-override-dialog.component.js +478 -0
  174. package/dist/ComponentStudio/components/form-override-dialog.component.js.map +1 -0
  175. package/dist/ComponentStudio/components/workspace/component-preview.component.d.ts +54 -0
  176. package/dist/ComponentStudio/components/workspace/component-preview.component.d.ts.map +1 -1
  177. package/dist/ComponentStudio/components/workspace/component-preview.component.js +361 -50
  178. package/dist/ComponentStudio/components/workspace/component-preview.component.js.map +1 -1
  179. package/dist/ComponentStudio/components/workspace/editor-tabs.component.d.ts +10 -0
  180. package/dist/ComponentStudio/components/workspace/editor-tabs.component.d.ts.map +1 -1
  181. package/dist/ComponentStudio/components/workspace/editor-tabs.component.js +114 -45
  182. package/dist/ComponentStudio/components/workspace/editor-tabs.component.js.map +1 -1
  183. package/dist/ComponentStudio/services/canvas-to-code.d.ts +32 -0
  184. package/dist/ComponentStudio/services/canvas-to-code.d.ts.map +1 -0
  185. package/dist/ComponentStudio/services/canvas-to-code.js +347 -0
  186. package/dist/ComponentStudio/services/canvas-to-code.js.map +1 -0
  187. package/dist/ComponentStudio/services/code-to-canvas.d.ts +32 -0
  188. package/dist/ComponentStudio/services/code-to-canvas.d.ts.map +1 -0
  189. package/dist/ComponentStudio/services/code-to-canvas.js +92 -0
  190. package/dist/ComponentStudio/services/code-to-canvas.js.map +1 -0
  191. package/dist/ComponentStudio/services/component-studio-state.service.d.ts +29 -0
  192. package/dist/ComponentStudio/services/component-studio-state.service.d.ts.map +1 -1
  193. package/dist/ComponentStudio/services/component-studio-state.service.js +76 -0
  194. package/dist/ComponentStudio/services/component-studio-state.service.js.map +1 -1
  195. package/dist/ComponentStudio/services/entity-form-override.service.d.ts +86 -0
  196. package/dist/ComponentStudio/services/entity-form-override.service.d.ts.map +1 -0
  197. package/dist/ComponentStudio/services/entity-form-override.service.js +246 -0
  198. package/dist/ComponentStudio/services/entity-form-override.service.js.map +1 -0
  199. package/dist/ComponentStudio/services/field-binding-scanner.d.ts +29 -0
  200. package/dist/ComponentStudio/services/field-binding-scanner.d.ts.map +1 -0
  201. package/dist/ComponentStudio/services/field-binding-scanner.js +110 -0
  202. package/dist/ComponentStudio/services/field-binding-scanner.js.map +1 -0
  203. package/dist/ComponentStudio/services/form-canvas-model.d.ts +56 -0
  204. package/dist/ComponentStudio/services/form-canvas-model.d.ts.map +1 -0
  205. package/dist/ComponentStudio/services/form-canvas-model.js +35 -0
  206. package/dist/ComponentStudio/services/form-canvas-model.js.map +1 -0
  207. package/dist/ComponentStudio/services/form-host-props-fixture.d.ts +10 -0
  208. package/dist/ComponentStudio/services/form-host-props-fixture.d.ts.map +1 -0
  209. package/dist/ComponentStudio/services/form-host-props-fixture.js +10 -0
  210. package/dist/ComponentStudio/services/form-host-props-fixture.js.map +1 -0
  211. package/dist/Credentials/components/credentials-audit-resource.component.js +136 -135
  212. package/dist/Credentials/components/credentials-audit-resource.component.js.map +1 -1
  213. package/dist/Credentials/components/credentials-categories-resource.component.js +155 -152
  214. package/dist/Credentials/components/credentials-categories-resource.component.js.map +1 -1
  215. package/dist/Credentials/components/credentials-list-resource.component.js +119 -118
  216. package/dist/Credentials/components/credentials-list-resource.component.js.map +1 -1
  217. package/dist/Credentials/components/credentials-overview-resource.component.js +129 -128
  218. package/dist/Credentials/components/credentials-overview-resource.component.js.map +1 -1
  219. package/dist/Credentials/components/credentials-types-resource.component.js +107 -106
  220. package/dist/Credentials/components/credentials-types-resource.component.js.map +1 -1
  221. package/dist/DataExplorer/data-explorer-dashboard.component.js +2 -2
  222. package/dist/DataExplorer/data-explorer-dashboard.component.js.map +1 -1
  223. package/dist/DatabaseDesigner/components/database-designer-dashboard.component.js +1 -1
  224. package/dist/DatabaseDesigner/components/entity-list.component.js +115 -114
  225. package/dist/DatabaseDesigner/components/entity-list.component.js.map +1 -1
  226. package/dist/DatabaseDesigner/database-designer-dashboards.module.d.ts +5 -6
  227. package/dist/DatabaseDesigner/database-designer-dashboards.module.d.ts.map +1 -1
  228. package/dist/DatabaseDesigner/database-designer-dashboards.module.js +4 -5
  229. package/dist/DatabaseDesigner/database-designer-dashboards.module.js.map +1 -1
  230. package/dist/DevTools/app-state-inspector.component.js +18 -17
  231. package/dist/DevTools/app-state-inspector.component.js.map +1 -1
  232. package/dist/DevTools/class-registry.component.js +88 -85
  233. package/dist/DevTools/class-registry.component.js.map +1 -1
  234. package/dist/DevTools/event-monitor.component.js +155 -150
  235. package/dist/DevTools/event-monitor.component.js.map +1 -1
  236. package/dist/DevTools/graphql-console.component.js +245 -243
  237. package/dist/DevTools/graphql-console.component.js.map +1 -1
  238. package/dist/DevTools/layout-inspector.component.js +18 -17
  239. package/dist/DevTools/layout-inspector.component.js.map +1 -1
  240. package/dist/EntityAdmin/entity-admin-dashboard.component.js +20 -19
  241. package/dist/EntityAdmin/entity-admin-dashboard.component.js.map +1 -1
  242. package/dist/FormBuilder/form-builder-resource.component.d.ts +964 -0
  243. package/dist/FormBuilder/form-builder-resource.component.d.ts.map +1 -0
  244. package/dist/FormBuilder/form-builder-resource.component.js +4487 -0
  245. package/dist/FormBuilder/form-builder-resource.component.js.map +1 -0
  246. package/dist/FormBuilder/form-builder-version-rail.helpers.d.ts +55 -0
  247. package/dist/FormBuilder/form-builder-version-rail.helpers.d.ts.map +1 -0
  248. package/dist/FormBuilder/form-builder-version-rail.helpers.js +73 -0
  249. package/dist/FormBuilder/form-builder-version-rail.helpers.js.map +1 -0
  250. package/dist/Home/home-application.d.ts +21 -1
  251. package/dist/Home/home-application.d.ts.map +1 -1
  252. package/dist/Home/home-application.js +60 -8
  253. package/dist/Home/home-application.js.map +1 -1
  254. package/dist/Home/home-dashboard.component.js +2 -2
  255. package/dist/Integration/components/activity/activity.component.d.ts.map +1 -1
  256. package/dist/Integration/components/activity/activity.component.js +236 -229
  257. package/dist/Integration/components/activity/activity.component.js.map +1 -1
  258. package/dist/Integration/components/connections/connections.component.js +390 -389
  259. package/dist/Integration/components/connections/connections.component.js.map +1 -1
  260. package/dist/Integration/components/overview/overview.component.js +2 -2
  261. package/dist/KnowledgeHub/components/analytics/analytics-resource.component.js +2 -2
  262. package/dist/KnowledgeHub/components/analytics/analytics-resource.component.js.map +1 -1
  263. package/dist/KnowledgeHub/components/clusters/cluster-visualization-resource.component.js +45 -44
  264. package/dist/KnowledgeHub/components/clusters/cluster-visualization-resource.component.js.map +1 -1
  265. package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.js +293 -291
  266. package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.js.map +1 -1
  267. package/dist/KnowledgeHub/components/scheduling/scheduling-resource.component.js +62 -61
  268. package/dist/KnowledgeHub/components/scheduling/scheduling-resource.component.js.map +1 -1
  269. package/dist/Lists/components/lists-browse-resource.component.d.ts +6 -2
  270. package/dist/Lists/components/lists-browse-resource.component.d.ts.map +1 -1
  271. package/dist/Lists/components/lists-browse-resource.component.js +525 -566
  272. package/dist/Lists/components/lists-browse-resource.component.js.map +1 -1
  273. package/dist/Lists/components/lists-categories-resource.component.js +135 -134
  274. package/dist/Lists/components/lists-categories-resource.component.js.map +1 -1
  275. package/dist/Lists/components/lists-my-lists-resource.component.js +199 -198
  276. package/dist/Lists/components/lists-my-lists-resource.component.js.map +1 -1
  277. package/dist/MCP/mcp-dashboard.component.js +443 -438
  278. package/dist/MCP/mcp-dashboard.component.js.map +1 -1
  279. package/dist/QueryBrowser/query-browser-resource.component.d.ts +14 -14
  280. package/dist/QueryBrowser/query-browser-resource.component.d.ts.map +1 -1
  281. package/dist/QueryBrowser/query-browser-resource.component.js +11 -10
  282. package/dist/QueryBrowser/query-browser-resource.component.js.map +1 -1
  283. package/dist/Scheduling/components/scheduling-activity.component.d.ts.map +1 -1
  284. package/dist/Scheduling/components/scheduling-activity.component.js +146 -147
  285. package/dist/Scheduling/components/scheduling-activity.component.js.map +1 -1
  286. package/dist/Scheduling/components/scheduling-jobs.component.js +76 -75
  287. package/dist/Scheduling/components/scheduling-jobs.component.js.map +1 -1
  288. package/dist/Scheduling/components/scheduling-overview.component.js +97 -96
  289. package/dist/Scheduling/components/scheduling-overview.component.js.map +1 -1
  290. package/dist/Scheduling/scheduling-dashboard.component.js +24 -22
  291. package/dist/Scheduling/scheduling-dashboard.component.js.map +1 -1
  292. package/dist/Scheduling/services/scheduling-instrumentation.service.d.ts +2 -0
  293. package/dist/Scheduling/services/scheduling-instrumentation.service.d.ts.map +1 -1
  294. package/dist/Scheduling/services/scheduling-instrumentation.service.js +1 -0
  295. package/dist/Scheduling/services/scheduling-instrumentation.service.js.map +1 -1
  296. package/dist/Testing/components/testing-dashboard-tab-resource.component.js +1 -1
  297. package/dist/Testing/components/testing-explorer.component.d.ts +14 -4
  298. package/dist/Testing/components/testing-explorer.component.d.ts.map +1 -1
  299. package/dist/Testing/components/testing-explorer.component.js +436 -427
  300. package/dist/Testing/components/testing-explorer.component.js.map +1 -1
  301. package/dist/Testing/components/testing-runs-resource.component.js +1 -1
  302. package/dist/Testing/components/testing-runs.component.js +116 -115
  303. package/dist/Testing/components/testing-runs.component.js.map +1 -1
  304. package/dist/Testing/testing-dashboard.component.js +6 -7
  305. package/dist/Testing/testing-dashboard.component.js.map +1 -1
  306. package/dist/VersionHistory/components/labels-resource.component.js +173 -172
  307. package/dist/VersionHistory/components/labels-resource.component.js.map +1 -1
  308. package/dist/VersionHistory/components/restore-resource.component.d.ts +6 -0
  309. package/dist/VersionHistory/components/restore-resource.component.d.ts.map +1 -1
  310. package/dist/VersionHistory/components/restore-resource.component.js +116 -92
  311. package/dist/VersionHistory/components/restore-resource.component.js.map +1 -1
  312. package/dist/ai-dashboards.module.d.ts +47 -35
  313. package/dist/ai-dashboards.module.d.ts.map +1 -1
  314. package/dist/ai-dashboards.module.js +40 -1
  315. package/dist/ai-dashboards.module.js.map +1 -1
  316. package/dist/communication-dashboards.module.d.ts +1 -1
  317. package/dist/communication-dashboards.module.d.ts.map +1 -1
  318. package/dist/communication-dashboards.module.js +7 -1
  319. package/dist/communication-dashboards.module.js.map +1 -1
  320. package/dist/component-studio-dashboards.module.d.ts +34 -22
  321. package/dist/component-studio-dashboards.module.d.ts.map +1 -1
  322. package/dist/component-studio-dashboards.module.js +65 -9
  323. package/dist/component-studio-dashboards.module.js.map +1 -1
  324. package/dist/testing-dashboards.module.d.ts +4 -5
  325. package/dist/testing-dashboards.module.d.ts.map +1 -1
  326. package/dist/testing-dashboards.module.js +7 -5
  327. package/dist/testing-dashboards.module.js.map +1 -1
  328. package/package.json +55 -53
@@ -0,0 +1,571 @@
1
+ /**
2
+ * @fileoverview Classify · Tag Health tab.
3
+ *
4
+ * Self-contained sub-page that surfaces the REAL taxonomy-quality signals the
5
+ * server-side TagHealthJob produces as `MJ: Tag Suggestions` rows with
6
+ * `Reason ∈ {MergeCandidate, LowUsage, WideNode}`. The Suggestions Inbox tab
7
+ * deliberately EXCLUDES these 3 reasons; the Health tab OWNS them.
8
+ *
9
+ * NOTE: the underlying signals (which tags are merge candidates, which are
10
+ * low-usage, which are wide nodes) are computed SERVER-SIDE by the TagHealthJob
11
+ * — this tab does not recompute them. It triages the resulting suggestion rows:
12
+ * grouping them into the 3 signal buckets and applying human decisions
13
+ * (Merge / Deprecate / Review-in-Taxonomy / Dismiss) as client-side entity
14
+ * mutations on the suggestion (and, for Deprecate, on the subject Tag).
15
+ *
16
+ * Data is TRANSACTIONAL and grows over time — loaded via RunView (NOT cached),
17
+ * grouped into the 3 buckets in memory. Loads lazily on first activation.
18
+ */
19
+ import { Component, ChangeDetectorRef, EventEmitter, Output, inject } from '@angular/core';
20
+ import { RunView } from '@memberjunction/core';
21
+ import { UUIDsEqual } from '@memberjunction/global';
22
+ import { BaseAngularComponent } from '@memberjunction/ng-base-types';
23
+ import { MJNotificationService } from '@memberjunction/ng-notifications';
24
+ import { TagEngineBase } from '@memberjunction/tag-engine-base';
25
+ import * as i0 from "@angular/core";
26
+ import * as i1 from "@memberjunction/ng-shared-generic";
27
+ import * as i2 from "@memberjunction/ng-ui-components";
28
+ import * as i3 from "@angular/common";
29
+ const _forTrack0 = ($index, $item) => $item.Meta.Reason;
30
+ const _forTrack1 = ($index, $item) => $item.ID;
31
+ function ClassifyHealthTabComponent_Conditional_3_Template(rf, ctx) { if (rf & 1) {
32
+ i0.ɵɵelement(0, "i", 7);
33
+ i0.ɵɵelementStart(1, "span", 8);
34
+ i0.ɵɵtext(2, "Refreshing\u2026");
35
+ i0.ɵɵelementEnd();
36
+ } }
37
+ function ClassifyHealthTabComponent_Conditional_4_Template(rf, ctx) { if (rf & 1) {
38
+ i0.ɵɵelement(0, "i", 9);
39
+ i0.ɵɵelementStart(1, "span", 8);
40
+ i0.ɵɵtext(2, "Refresh");
41
+ i0.ɵɵelementEnd();
42
+ } }
43
+ function ClassifyHealthTabComponent_Conditional_7_Template(rf, ctx) { if (rf & 1) {
44
+ i0.ɵɵelementStart(0, "div", 5);
45
+ i0.ɵɵelement(1, "mj-loading", 10);
46
+ i0.ɵɵelementEnd();
47
+ } }
48
+ function ClassifyHealthTabComponent_Conditional_8_For_2_Conditional_11_Template(rf, ctx) { if (rf & 1) {
49
+ i0.ɵɵelementStart(0, "div", 17);
50
+ i0.ɵɵelement(1, "i", 18);
51
+ i0.ɵɵelementStart(2, "span");
52
+ i0.ɵɵtext(3);
53
+ i0.ɵɵpipe(4, "lowercase");
54
+ i0.ɵɵelementEnd()();
55
+ } if (rf & 2) {
56
+ const card_r1 = i0.ɵɵnextContext().$implicit;
57
+ i0.ɵɵadvance(3);
58
+ i0.ɵɵtextInterpolate1("No ", i0.ɵɵpipeBind1(4, 1, card_r1.Meta.Title), " right now.");
59
+ } }
60
+ function ClassifyHealthTabComponent_Conditional_8_For_2_Conditional_12_For_2_Conditional_4_Template(rf, ctx) { if (rf & 1) {
61
+ i0.ɵɵelementStart(0, "span", 29);
62
+ i0.ɵɵelement(1, "i", 30);
63
+ i0.ɵɵelementEnd();
64
+ i0.ɵɵelementStart(2, "span", 31);
65
+ i0.ɵɵtext(3);
66
+ i0.ɵɵelementEnd();
67
+ } if (rf & 2) {
68
+ const s_r2 = i0.ɵɵnextContext().$implicit;
69
+ i0.ɵɵadvance(3);
70
+ i0.ɵɵtextInterpolate(s_r2.BestMatchTag);
71
+ } }
72
+ function ClassifyHealthTabComponent_Conditional_8_For_2_Conditional_12_For_2_Case_8_Template(rf, ctx) { if (rf & 1) {
73
+ const _r3 = i0.ɵɵgetCurrentView();
74
+ i0.ɵɵelementStart(0, "button", 32);
75
+ i0.ɵɵlistener("click", function ClassifyHealthTabComponent_Conditional_8_For_2_Conditional_12_For_2_Case_8_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r3); const s_r2 = i0.ɵɵnextContext().$implicit; const ctx_r3 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r3.Merge(s_r2)); });
76
+ i0.ɵɵelement(1, "i", 33);
77
+ i0.ɵɵtext(2, " Merge ");
78
+ i0.ɵɵelementEnd();
79
+ i0.ɵɵelementStart(3, "button", 2);
80
+ i0.ɵɵlistener("click", function ClassifyHealthTabComponent_Conditional_8_For_2_Conditional_12_For_2_Case_8_Template_button_click_3_listener() { i0.ɵɵrestoreView(_r3); const s_r2 = i0.ɵɵnextContext().$implicit; const ctx_r3 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r3.Dismiss(s_r2)); });
81
+ i0.ɵɵtext(4, " Dismiss ");
82
+ i0.ɵɵelementEnd();
83
+ } if (rf & 2) {
84
+ const s_r2 = i0.ɵɵnextContext().$implicit;
85
+ const ctx_r3 = i0.ɵɵnextContext(4);
86
+ i0.ɵɵproperty("disabled", ctx_r3.IsRowBusy(s_r2) || !s_r2.BestMatchTagID);
87
+ i0.ɵɵadvance(3);
88
+ i0.ɵɵproperty("disabled", ctx_r3.IsRowBusy(s_r2));
89
+ } }
90
+ function ClassifyHealthTabComponent_Conditional_8_For_2_Conditional_12_For_2_Case_9_Template(rf, ctx) { if (rf & 1) {
91
+ const _r5 = i0.ɵɵgetCurrentView();
92
+ i0.ɵɵelementStart(0, "button", 34);
93
+ i0.ɵɵlistener("click", function ClassifyHealthTabComponent_Conditional_8_For_2_Conditional_12_For_2_Case_9_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r5); const s_r2 = i0.ɵɵnextContext().$implicit; const ctx_r3 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r3.Deprecate(s_r2)); });
94
+ i0.ɵɵelement(1, "i", 35);
95
+ i0.ɵɵtext(2, " Deprecate ");
96
+ i0.ɵɵelementEnd();
97
+ i0.ɵɵelementStart(3, "button", 2);
98
+ i0.ɵɵlistener("click", function ClassifyHealthTabComponent_Conditional_8_For_2_Conditional_12_For_2_Case_9_Template_button_click_3_listener() { i0.ɵɵrestoreView(_r5); const s_r2 = i0.ɵɵnextContext().$implicit; const ctx_r3 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r3.Dismiss(s_r2)); });
99
+ i0.ɵɵtext(4, " Dismiss ");
100
+ i0.ɵɵelementEnd();
101
+ } if (rf & 2) {
102
+ const s_r2 = i0.ɵɵnextContext().$implicit;
103
+ const ctx_r3 = i0.ɵɵnextContext(4);
104
+ i0.ɵɵproperty("disabled", ctx_r3.IsRowBusy(s_r2));
105
+ i0.ɵɵadvance(3);
106
+ i0.ɵɵproperty("disabled", ctx_r3.IsRowBusy(s_r2));
107
+ } }
108
+ function ClassifyHealthTabComponent_Conditional_8_For_2_Conditional_12_For_2_Case_10_Template(rf, ctx) { if (rf & 1) {
109
+ const _r6 = i0.ɵɵgetCurrentView();
110
+ i0.ɵɵelementStart(0, "button", 32);
111
+ i0.ɵɵlistener("click", function ClassifyHealthTabComponent_Conditional_8_For_2_Conditional_12_For_2_Case_10_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r6); const s_r2 = i0.ɵɵnextContext().$implicit; const ctx_r3 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r3.ReviewInTaxonomy(s_r2)); });
112
+ i0.ɵɵelement(1, "i", 36);
113
+ i0.ɵɵtext(2, " Review ");
114
+ i0.ɵɵelementEnd();
115
+ i0.ɵɵelementStart(3, "button", 2);
116
+ i0.ɵɵlistener("click", function ClassifyHealthTabComponent_Conditional_8_For_2_Conditional_12_For_2_Case_10_Template_button_click_3_listener() { i0.ɵɵrestoreView(_r6); const s_r2 = i0.ɵɵnextContext().$implicit; const ctx_r3 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r3.Dismiss(s_r2)); });
117
+ i0.ɵɵtext(4, " Dismiss ");
118
+ i0.ɵɵelementEnd();
119
+ } if (rf & 2) {
120
+ const s_r2 = i0.ɵɵnextContext().$implicit;
121
+ const ctx_r3 = i0.ɵɵnextContext(4);
122
+ i0.ɵɵproperty("disabled", ctx_r3.IsRowBusy(s_r2));
123
+ i0.ɵɵadvance(3);
124
+ i0.ɵɵproperty("disabled", ctx_r3.IsRowBusy(s_r2));
125
+ } }
126
+ function ClassifyHealthTabComponent_Conditional_8_For_2_Conditional_12_For_2_Template(rf, ctx) { if (rf & 1) {
127
+ i0.ɵɵelementStart(0, "div", 24)(1, "div", 25)(2, "span", 26);
128
+ i0.ɵɵtext(3);
129
+ i0.ɵɵelementEnd();
130
+ i0.ɵɵconditionalCreate(4, ClassifyHealthTabComponent_Conditional_8_For_2_Conditional_12_For_2_Conditional_4_Template, 4, 1);
131
+ i0.ɵɵelementEnd();
132
+ i0.ɵɵelementStart(5, "div", 27)(6, "span", 28);
133
+ i0.ɵɵtext(7);
134
+ i0.ɵɵelementEnd();
135
+ i0.ɵɵconditionalCreate(8, ClassifyHealthTabComponent_Conditional_8_For_2_Conditional_12_For_2_Case_8_Template, 5, 2)(9, ClassifyHealthTabComponent_Conditional_8_For_2_Conditional_12_For_2_Case_9_Template, 5, 2)(10, ClassifyHealthTabComponent_Conditional_8_For_2_Conditional_12_For_2_Case_10_Template, 5, 2);
136
+ i0.ɵɵelementEnd()();
137
+ } if (rf & 2) {
138
+ let tmp_26_0;
139
+ const s_r2 = ctx.$implicit;
140
+ const card_r1 = i0.ɵɵnextContext(2).$implicit;
141
+ const ctx_r3 = i0.ɵɵnextContext(2);
142
+ i0.ɵɵclassProp("ch-item-busy", ctx_r3.IsRowBusy(s_r2));
143
+ i0.ɵɵadvance(3);
144
+ i0.ɵɵtextInterpolate(s_r2.ProposedName);
145
+ i0.ɵɵadvance();
146
+ i0.ɵɵconditional(card_r1.Meta.Reason === "MergeCandidate" && s_r2.BestMatchTag ? 4 : -1);
147
+ i0.ɵɵadvance(3);
148
+ i0.ɵɵtextInterpolate(ctx_r3.FormatScore(s_r2.BestMatchScore));
149
+ i0.ɵɵadvance();
150
+ i0.ɵɵconditional((tmp_26_0 = card_r1.Meta.Reason) === "MergeCandidate" ? 8 : tmp_26_0 === "LowUsage" ? 9 : tmp_26_0 === "WideNode" ? 10 : -1);
151
+ } }
152
+ function ClassifyHealthTabComponent_Conditional_8_For_2_Conditional_12_Conditional_4_Template(rf, ctx) { if (rf & 1) {
153
+ i0.ɵɵelementStart(0, "span", 22);
154
+ i0.ɵɵtext(1);
155
+ i0.ɵɵelementEnd();
156
+ } if (rf & 2) {
157
+ const card_r1 = i0.ɵɵnextContext(2).$implicit;
158
+ const ctx_r3 = i0.ɵɵnextContext(2);
159
+ i0.ɵɵadvance();
160
+ i0.ɵɵtextInterpolate1("+", card_r1.Items.length - ctx_r3.PreviewLimit, " more");
161
+ } }
162
+ function ClassifyHealthTabComponent_Conditional_8_For_2_Conditional_12_Conditional_5_Template(rf, ctx) { if (rf & 1) {
163
+ i0.ɵɵelement(0, "span", 22);
164
+ } }
165
+ function ClassifyHealthTabComponent_Conditional_8_For_2_Conditional_12_Conditional_6_Conditional_1_Template(rf, ctx) { if (rf & 1) {
166
+ i0.ɵɵelement(0, "i", 7);
167
+ i0.ɵɵtext(1, " Merging\u2026 ");
168
+ } }
169
+ function ClassifyHealthTabComponent_Conditional_8_For_2_Conditional_12_Conditional_6_Conditional_2_Template(rf, ctx) { if (rf & 1) {
170
+ i0.ɵɵelement(0, "i", 37);
171
+ i0.ɵɵtext(1);
172
+ } if (rf & 2) {
173
+ const card_r1 = i0.ɵɵnextContext(3).$implicit;
174
+ const ctx_r3 = i0.ɵɵnextContext(2);
175
+ i0.ɵɵadvance();
176
+ i0.ɵɵtextInterpolate1(" Merge all high-confidence (", ctx_r3.HighConfidenceCount(card_r1), ") ");
177
+ } }
178
+ function ClassifyHealthTabComponent_Conditional_8_For_2_Conditional_12_Conditional_6_Template(rf, ctx) { if (rf & 1) {
179
+ const _r7 = i0.ɵɵgetCurrentView();
180
+ i0.ɵɵelementStart(0, "button", 32);
181
+ i0.ɵɵlistener("click", function ClassifyHealthTabComponent_Conditional_8_For_2_Conditional_12_Conditional_6_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r7); const card_r1 = i0.ɵɵnextContext(2).$implicit; const ctx_r3 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r3.MergeAllHighConfidence(card_r1)); });
182
+ i0.ɵɵconditionalCreate(1, ClassifyHealthTabComponent_Conditional_8_For_2_Conditional_12_Conditional_6_Conditional_1_Template, 2, 0)(2, ClassifyHealthTabComponent_Conditional_8_For_2_Conditional_12_Conditional_6_Conditional_2_Template, 2, 1);
183
+ i0.ɵɵelementEnd();
184
+ } if (rf & 2) {
185
+ const ctx_r3 = i0.ɵɵnextContext(4);
186
+ i0.ɵɵproperty("disabled", ctx_r3.IsBulkActing);
187
+ i0.ɵɵadvance();
188
+ i0.ɵɵconditional(ctx_r3.IsBulkActing ? 1 : 2);
189
+ } }
190
+ function ClassifyHealthTabComponent_Conditional_8_For_2_Conditional_12_Template(rf, ctx) { if (rf & 1) {
191
+ i0.ɵɵelementStart(0, "div", 19);
192
+ i0.ɵɵrepeaterCreate(1, ClassifyHealthTabComponent_Conditional_8_For_2_Conditional_12_For_2_Template, 11, 6, "div", 20, _forTrack1);
193
+ i0.ɵɵelementEnd();
194
+ i0.ɵɵelementStart(3, "div", 21);
195
+ i0.ɵɵconditionalCreate(4, ClassifyHealthTabComponent_Conditional_8_For_2_Conditional_12_Conditional_4_Template, 2, 1, "span", 22)(5, ClassifyHealthTabComponent_Conditional_8_For_2_Conditional_12_Conditional_5_Template, 1, 0, "span", 22);
196
+ i0.ɵɵconditionalCreate(6, ClassifyHealthTabComponent_Conditional_8_For_2_Conditional_12_Conditional_6_Template, 3, 2, "button", 23);
197
+ i0.ɵɵelementEnd();
198
+ } if (rf & 2) {
199
+ const card_r1 = i0.ɵɵnextContext().$implicit;
200
+ const ctx_r3 = i0.ɵɵnextContext(2);
201
+ i0.ɵɵadvance();
202
+ i0.ɵɵrepeater(card_r1.Items.slice(0, ctx_r3.PreviewLimit));
203
+ i0.ɵɵadvance(3);
204
+ i0.ɵɵconditional(card_r1.Items.length > ctx_r3.PreviewLimit ? 4 : 5);
205
+ i0.ɵɵadvance(2);
206
+ i0.ɵɵconditional(card_r1.Meta.Reason === "MergeCandidate" && ctx_r3.HighConfidenceCount(card_r1) > 0 ? 6 : -1);
207
+ } }
208
+ function ClassifyHealthTabComponent_Conditional_8_For_2_Template(rf, ctx) { if (rf & 1) {
209
+ i0.ɵɵelementStart(0, "div", 12)(1, "div", 13)(2, "div", 14);
210
+ i0.ɵɵtext(3);
211
+ i0.ɵɵelementStart(4, "small");
212
+ i0.ɵɵtext(5);
213
+ i0.ɵɵelementEnd()();
214
+ i0.ɵɵelementStart(6, "h5", 15);
215
+ i0.ɵɵelement(7, "i");
216
+ i0.ɵɵtext(8);
217
+ i0.ɵɵelementEnd();
218
+ i0.ɵɵelementStart(9, "p", 16);
219
+ i0.ɵɵtext(10);
220
+ i0.ɵɵelementEnd()();
221
+ i0.ɵɵconditionalCreate(11, ClassifyHealthTabComponent_Conditional_8_For_2_Conditional_11_Template, 5, 3, "div", 17)(12, ClassifyHealthTabComponent_Conditional_8_For_2_Conditional_12_Template, 7, 2);
222
+ i0.ɵɵelementEnd();
223
+ } if (rf & 2) {
224
+ const card_r1 = ctx.$implicit;
225
+ i0.ɵɵclassMap("ch-" + card_r1.Meta.Variant);
226
+ i0.ɵɵadvance(3);
227
+ i0.ɵɵtextInterpolate1(" ", card_r1.Items.length, " ");
228
+ i0.ɵɵadvance(2);
229
+ i0.ɵɵtextInterpolate(card_r1.Meta.CountNoun);
230
+ i0.ɵɵadvance(2);
231
+ i0.ɵɵclassMap(card_r1.Meta.Icon);
232
+ i0.ɵɵadvance();
233
+ i0.ɵɵtextInterpolate1(" ", card_r1.Meta.Title, " ");
234
+ i0.ɵɵadvance(2);
235
+ i0.ɵɵtextInterpolate(card_r1.Meta.Explanation);
236
+ i0.ɵɵadvance();
237
+ i0.ɵɵconditional(card_r1.Items.length === 0 ? 11 : 12);
238
+ } }
239
+ function ClassifyHealthTabComponent_Conditional_8_Template(rf, ctx) { if (rf & 1) {
240
+ i0.ɵɵelementStart(0, "div", 6);
241
+ i0.ɵɵrepeaterCreate(1, ClassifyHealthTabComponent_Conditional_8_For_2_Template, 13, 9, "div", 11, _forTrack0);
242
+ i0.ɵɵelementEnd();
243
+ } if (rf & 2) {
244
+ const ctx_r3 = i0.ɵɵnextContext();
245
+ i0.ɵɵadvance();
246
+ i0.ɵɵrepeater(ctx_r3.Cards);
247
+ } }
248
+ /** Confidence floor for the "merge all high-confidence" bulk action. */
249
+ const HIGH_CONFIDENCE_THRESHOLD = 0.9;
250
+ /** Card descriptors in display order (merge → low-usage → wide-node). */
251
+ const SIGNAL_CARDS = [
252
+ {
253
+ Reason: 'MergeCandidate',
254
+ Title: 'Merge candidates',
255
+ Icon: 'fa-solid fa-code-merge',
256
+ Variant: 'info',
257
+ Explanation: 'Near-duplicate tags with high embedding similarity — likely the same concept under two names.',
258
+ CountNoun: 'pairs',
259
+ },
260
+ {
261
+ Reason: 'LowUsage',
262
+ Title: 'Low usage',
263
+ Icon: 'fa-solid fa-arrow-trend-down',
264
+ Variant: 'warning',
265
+ Explanation: 'Tags applied to very few items recently — candidates to deprecate and keep the taxonomy lean.',
266
+ CountNoun: 'tags',
267
+ },
268
+ {
269
+ Reason: 'WideNode',
270
+ Title: 'Wide nodes',
271
+ Icon: 'fa-solid fa-arrows-left-right-to-line',
272
+ Variant: 'error',
273
+ Explanation: 'Tags with too many direct children — likely need splitting into sub-categories.',
274
+ CountNoun: 'nodes',
275
+ },
276
+ ];
277
+ /** How many example items to surface per card before "show all". */
278
+ const PREVIEW_LIMIT = 5;
279
+ export class ClassifyHealthTabComponent extends BaseAngularComponent {
280
+ cdr = inject(ChangeDetectorRef);
281
+ PreviewLimit = PREVIEW_LIMIT;
282
+ HighConfidenceThreshold = HIGH_CONFIDENCE_THRESHOLD;
283
+ // ── Loaded data (NOT cached — transactional) ──
284
+ allSuggestions = [];
285
+ Cards = [];
286
+ IsLoading = false;
287
+ hasLoaded = false;
288
+ /** ID of the suggestion currently being acted on (disables its row controls). */
289
+ ActingID = null;
290
+ /** True while a bulk action is in flight. */
291
+ IsBulkActing = false;
292
+ /** Emitted after any action so the host can refresh its pending/health badge. */
293
+ Resolved = new EventEmitter();
294
+ /** Emitted with a tag ID so the host can switch to the Taxonomy tab for review. */
295
+ OpenInTaxonomyRequested = new EventEmitter();
296
+ // ════════════════════════════════════════════
297
+ // ACTIVATION + LOAD
298
+ // ════════════════════════════════════════════
299
+ /** Lazy-load on first activation (host calls this when the tab becomes active). */
300
+ async EnsureLoaded() {
301
+ if (this.hasLoaded)
302
+ return;
303
+ this.hasLoaded = true;
304
+ await Promise.all([this.loadSuggestions(), this.ensureTagEngine()]);
305
+ }
306
+ /** Public refresh — re-pull the health suggestions and rebuild buckets. */
307
+ async Refresh() {
308
+ await this.loadSuggestions();
309
+ }
310
+ async ensureTagEngine() {
311
+ await TagEngineBase.Instance.Config(false, this.ProviderToUse.CurrentUser, this.ProviderToUse);
312
+ }
313
+ async loadSuggestions() {
314
+ this.IsLoading = true;
315
+ this.cdr.detectChanges();
316
+ const rv = RunView.FromMetadataProvider(this.ProviderToUse);
317
+ const result = await rv.RunView({
318
+ EntityName: 'MJ: Tag Suggestions',
319
+ ExtraFilter: `Status='Pending' AND Reason IN ('MergeCandidate','LowUsage','WideNode')`,
320
+ OrderBy: 'BestMatchScore DESC',
321
+ ResultType: 'entity_object',
322
+ }, this.ProviderToUse.CurrentUser);
323
+ this.allSuggestions = result.Success ? result.Results : [];
324
+ this.buildCards();
325
+ this.IsLoading = false;
326
+ this.cdr.detectChanges();
327
+ }
328
+ /** Group the loaded suggestions into the 3 signal buckets, preserving card order. */
329
+ buildCards() {
330
+ this.Cards = SIGNAL_CARDS.map(meta => ({
331
+ Meta: meta,
332
+ Items: this.allSuggestions.filter(s => s.Reason === meta.Reason),
333
+ }));
334
+ }
335
+ // ════════════════════════════════════════════
336
+ // DISPLAY HELPERS
337
+ // ════════════════════════════════════════════
338
+ FormatScore(score) {
339
+ return score == null ? '—' : score.toFixed(2);
340
+ }
341
+ /** Count of high-confidence merge candidates eligible for the bulk merge. */
342
+ HighConfidenceCount(card) {
343
+ if (card.Meta.Reason !== 'MergeCandidate')
344
+ return 0;
345
+ return card.Items.filter(s => (s.BestMatchScore ?? 0) >= HIGH_CONFIDENCE_THRESHOLD).length;
346
+ }
347
+ /** Whether a given suggestion's row controls should be disabled. */
348
+ IsRowBusy(suggestion) {
349
+ return this.IsBulkActing || (this.ActingID != null && UUIDsEqual(this.ActingID, suggestion.ID));
350
+ }
351
+ // ════════════════════════════════════════════
352
+ // ACTIONS — entity-level mutations on the client
353
+ // ════════════════════════════════════════════
354
+ //
355
+ // NOTE: the health signals themselves are computed server-side by the
356
+ // TagHealthJob. These handlers triage the resulting suggestion rows by
357
+ // stamping reviewer fields + resolving status (and, for Deprecate, flipping
358
+ // the subject Tag's Status). Full downstream re-pointing of content-item
359
+ // tags onto the resolved tag is handled by the server-side promotion job.
360
+ stampReviewFields(suggestion) {
361
+ suggestion.ReviewedByUserID = this.ProviderToUse.CurrentUser.ID;
362
+ suggestion.ReviewedAt = new Date();
363
+ }
364
+ /** Merge candidate → Merge: resolve the suggestion onto its best-match tag. */
365
+ async Merge(suggestion) {
366
+ if (this.IsRowBusy(suggestion))
367
+ return;
368
+ if (!suggestion.BestMatchTagID) {
369
+ MJNotificationService.Instance.CreateSimpleNotification('No best-match tag to merge into', 'warning', 3000);
370
+ return;
371
+ }
372
+ this.ActingID = suggestion.ID;
373
+ this.cdr.detectChanges();
374
+ try {
375
+ const saved = await this.resolveMerge(suggestion);
376
+ if (saved) {
377
+ MJNotificationService.Instance.CreateSimpleNotification(`Merged "${suggestion.ProposedName}" into "${suggestion.BestMatchTag ?? 'best match'}"`, 'success', 3000);
378
+ this.finishAction(suggestion);
379
+ }
380
+ }
381
+ catch (error) {
382
+ this.notifyError(error);
383
+ }
384
+ finally {
385
+ this.ActingID = null;
386
+ this.cdr.detectChanges();
387
+ }
388
+ }
389
+ /** Bulk: merge every high-confidence (score ≥ 0.9) merge candidate at once. */
390
+ async MergeAllHighConfidence(card) {
391
+ if (card.Meta.Reason !== 'MergeCandidate' || this.IsBulkActing)
392
+ return;
393
+ const targets = card.Items.filter(s => (s.BestMatchScore ?? 0) >= HIGH_CONFIDENCE_THRESHOLD && s.BestMatchTagID);
394
+ if (targets.length === 0)
395
+ return;
396
+ this.IsBulkActing = true;
397
+ this.cdr.detectChanges();
398
+ let succeeded = 0;
399
+ try {
400
+ for (const suggestion of targets) {
401
+ const saved = await this.resolveMerge(suggestion);
402
+ if (saved) {
403
+ this.allSuggestions = this.allSuggestions.filter(s => !UUIDsEqual(s.ID, suggestion.ID));
404
+ succeeded++;
405
+ }
406
+ }
407
+ this.buildCards();
408
+ MJNotificationService.Instance.CreateSimpleNotification(`Merged ${succeeded} high-confidence candidate${succeeded === 1 ? '' : 's'}`, 'success', 3000);
409
+ if (succeeded > 0)
410
+ this.Resolved.emit();
411
+ }
412
+ catch (error) {
413
+ this.notifyError(error);
414
+ }
415
+ finally {
416
+ this.IsBulkActing = false;
417
+ this.cdr.detectChanges();
418
+ }
419
+ }
420
+ /** Stamp + resolve a single merge suggestion. Returns Save() success. */
421
+ async resolveMerge(suggestion) {
422
+ this.stampReviewFields(suggestion);
423
+ suggestion.Status = 'Merged';
424
+ suggestion.ResolvedTagID = suggestion.BestMatchTagID;
425
+ const saved = await suggestion.Save();
426
+ if (!saved) {
427
+ this.notifyFailure('Failed to merge suggestion', suggestion.LatestResult?.CompleteMessage);
428
+ }
429
+ return saved;
430
+ }
431
+ /** Low usage → Deprecate: flip the subject Tag to Deprecated, then resolve. */
432
+ async Deprecate(suggestion) {
433
+ if (this.IsRowBusy(suggestion))
434
+ return;
435
+ this.ActingID = suggestion.ID;
436
+ this.cdr.detectChanges();
437
+ try {
438
+ const tag = await this.resolveSubjectTag(suggestion);
439
+ if (!tag) {
440
+ this.notifyFailure('Could not find the tag to deprecate', 'no matching MJ: Tags record');
441
+ return;
442
+ }
443
+ tag.Status = 'Deprecated';
444
+ const tagSaved = await tag.Save();
445
+ if (!tagSaved) {
446
+ this.notifyFailure('Failed to deprecate tag', tag.LatestResult?.CompleteMessage);
447
+ return;
448
+ }
449
+ this.stampReviewFields(suggestion);
450
+ suggestion.Status = 'Approved';
451
+ suggestion.ResolvedTagID = tag.ID;
452
+ const sugSaved = await suggestion.Save();
453
+ if (!sugSaved) {
454
+ this.notifyFailure('Tag deprecated but failed to resolve suggestion', suggestion.LatestResult?.CompleteMessage);
455
+ return;
456
+ }
457
+ MJNotificationService.Instance.CreateSimpleNotification(`Deprecated "${tag.DisplayName || tag.Name}"`, 'success', 3000);
458
+ this.finishAction(suggestion);
459
+ }
460
+ catch (error) {
461
+ this.notifyError(error);
462
+ }
463
+ finally {
464
+ this.ActingID = null;
465
+ this.cdr.detectChanges();
466
+ }
467
+ }
468
+ /**
469
+ * Resolve the subject Tag for a low-usage suggestion: prefer the best-match
470
+ * tag (that IS the low-usage tag here), else fall back to the already-resolved
471
+ * tag, else look up by proposed name via the cached TagEngineBase tags.
472
+ */
473
+ async resolveSubjectTag(suggestion) {
474
+ const tagID = suggestion.BestMatchTagID ?? suggestion.ResolvedTagID ?? this.lookupTagIDByName(suggestion.ProposedName);
475
+ if (!tagID)
476
+ return null;
477
+ const p = this.ProviderToUse;
478
+ const tag = await p.GetEntityObject('MJ: Tags', p.CurrentUser);
479
+ const loaded = await tag.Load(tagID);
480
+ return loaded ? tag : null;
481
+ }
482
+ /** Case-insensitive name → tag ID lookup against the cached tag set. */
483
+ lookupTagIDByName(name) {
484
+ const lower = name.trim().toLowerCase();
485
+ const match = TagEngineBase.Instance.Tags.find(t => (t.DisplayName || t.Name).trim().toLowerCase() === lower ||
486
+ t.Name.trim().toLowerCase() === lower);
487
+ return match?.ID ?? null;
488
+ }
489
+ /**
490
+ * Wide node → Review in Taxonomy: bubble the tag ID up so the host can switch
491
+ * to the Taxonomy tab. The suggestion stays Pending — review happens there.
492
+ */
493
+ ReviewInTaxonomy(suggestion) {
494
+ const tagID = suggestion.BestMatchTagID ?? suggestion.ResolvedTagID ?? this.lookupTagIDByName(suggestion.ProposedName);
495
+ if (tagID) {
496
+ this.OpenInTaxonomyRequested.emit(tagID);
497
+ }
498
+ else {
499
+ // No resolvable tag — still let the host open the taxonomy surface.
500
+ this.OpenInTaxonomyRequested.emit('');
501
+ }
502
+ }
503
+ /** Dismiss any signal: mark the suggestion Rejected. */
504
+ async Dismiss(suggestion) {
505
+ if (this.IsRowBusy(suggestion))
506
+ return;
507
+ this.ActingID = suggestion.ID;
508
+ this.cdr.detectChanges();
509
+ try {
510
+ this.stampReviewFields(suggestion);
511
+ suggestion.Status = 'Rejected';
512
+ const saved = await suggestion.Save();
513
+ if (!saved) {
514
+ this.notifyFailure('Failed to dismiss suggestion', suggestion.LatestResult?.CompleteMessage);
515
+ return;
516
+ }
517
+ MJNotificationService.Instance.CreateSimpleNotification(`Dismissed "${suggestion.ProposedName}"`, 'success', 2500);
518
+ this.finishAction(suggestion);
519
+ }
520
+ catch (error) {
521
+ this.notifyError(error);
522
+ }
523
+ finally {
524
+ this.ActingID = null;
525
+ this.cdr.detectChanges();
526
+ }
527
+ }
528
+ /** Remove a resolved suggestion, rebuild buckets, notify the host. */
529
+ finishAction(resolved) {
530
+ this.allSuggestions = this.allSuggestions.filter(s => !UUIDsEqual(s.ID, resolved.ID));
531
+ this.buildCards();
532
+ this.Resolved.emit();
533
+ this.cdr.detectChanges();
534
+ }
535
+ notifyFailure(prefix, detail) {
536
+ MJNotificationService.Instance.CreateSimpleNotification(`${prefix}: ${detail ?? 'unknown error'}`, 'error', 5000);
537
+ }
538
+ notifyError(error) {
539
+ const msg = error instanceof Error ? error.message : String(error);
540
+ MJNotificationService.Instance.CreateSimpleNotification(`Error: ${msg}`, 'error', 5000);
541
+ }
542
+ static ɵfac = /*@__PURE__*/ (() => { let ɵClassifyHealthTabComponent_BaseFactory; return function ClassifyHealthTabComponent_Factory(__ngFactoryType__) { return (ɵClassifyHealthTabComponent_BaseFactory || (ɵClassifyHealthTabComponent_BaseFactory = i0.ɵɵgetInheritedFactory(ClassifyHealthTabComponent)))(__ngFactoryType__ || ClassifyHealthTabComponent); }; })();
543
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ClassifyHealthTabComponent, selectors: [["classify-health-tab"]], outputs: { Resolved: "Resolved", OpenInTaxonomyRequested: "OpenInTaxonomyRequested" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 9, vars: 5, consts: [["Title", "Tag Health", "Subtitle", "Automated taxonomy-quality signals from the latest classification runs"], ["actions", ""], ["mjButton", "", "variant", "secondary", "size", "sm", 3, "click", "disabled"], [3, "Padding", "Flex"], [1, "at-main-area"], [1, "at-page-body"], [1, "ch-grid"], [1, "fa-solid", "fa-spinner", "fa-spin"], [1, "mj-action-label"], [1, "fa-solid", "fa-arrows-rotate"], ["text", "Loading tag-health signals\u2026"], [1, "ch-card", 3, "class"], [1, "ch-card"], [1, "ch-top"], [1, "ch-big"], [1, "ch-title"], [1, "ch-explain"], [1, "ch-empty"], [1, "fa-solid", "fa-circle-check"], [1, "ch-list"], [1, "ch-item", 3, "ch-item-busy"], [1, "ch-foot"], [1, "ch-more"], ["mjButton", "", "variant", "primary", "size", "sm", 3, "disabled"], [1, "ch-item"], [1, "ch-item-main"], [1, "ch-item-name"], [1, "ch-item-side"], [1, "ch-score"], [1, "ch-item-arrow"], [1, "fa-solid", "fa-arrow-right-long"], [1, "ch-item-target"], ["mjButton", "", "variant", "primary", "size", "sm", 3, "click", "disabled"], [1, "fa-solid", "fa-code-merge"], ["mjButton", "", "variant", "warning", "size", "sm", 3, "click", "disabled"], [1, "fa-solid", "fa-arrow-trend-down"], [1, "fa-solid", "fa-sitemap"], [1, "fa-solid", "fa-layer-group"]], template: function ClassifyHealthTabComponent_Template(rf, ctx) { if (rf & 1) {
544
+ i0.ɵɵelementStart(0, "mj-page-header-interior", 0)(1, "div", 1)(2, "button", 2);
545
+ i0.ɵɵlistener("click", function ClassifyHealthTabComponent_Template_button_click_2_listener() { return ctx.Refresh(); });
546
+ i0.ɵɵconditionalCreate(3, ClassifyHealthTabComponent_Conditional_3_Template, 3, 0)(4, ClassifyHealthTabComponent_Conditional_4_Template, 3, 0);
547
+ i0.ɵɵelementEnd()()();
548
+ i0.ɵɵelementStart(5, "mj-page-body-interior", 3)(6, "div", 4);
549
+ i0.ɵɵconditionalCreate(7, ClassifyHealthTabComponent_Conditional_7_Template, 2, 0, "div", 5)(8, ClassifyHealthTabComponent_Conditional_8_Template, 3, 0, "div", 6);
550
+ i0.ɵɵelementEnd()();
551
+ } if (rf & 2) {
552
+ i0.ɵɵadvance(2);
553
+ i0.ɵɵproperty("disabled", ctx.IsLoading);
554
+ i0.ɵɵadvance();
555
+ i0.ɵɵconditional(ctx.IsLoading ? 3 : 4);
556
+ i0.ɵɵadvance(2);
557
+ i0.ɵɵproperty("Padding", false)("Flex", true);
558
+ i0.ɵɵadvance(2);
559
+ i0.ɵɵconditional(ctx.IsLoading ? 7 : 8);
560
+ } }, dependencies: [i1.LoadingComponent, i2.MJButtonDirective, i2.MJPageHeaderInteriorComponent, i2.MJPageBodyInteriorComponent, i3.LowerCasePipe], styles: ["\n\n\n\n\n\n\n\n\n\n\n\n\n\n.ch-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));\n gap: 16px;\n padding: 16px;\n align-items: start;\n}\n\n\n\n.ch-card[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n overflow: hidden;\n}\n\n\n\n.ch-card[_ngcontent-%COMP%] .ch-top[_ngcontent-%COMP%] {\n border-top: 3px solid var(--mj-border-default);\n}\n.ch-info[_ngcontent-%COMP%] .ch-top[_ngcontent-%COMP%] {\n border-top-color: var(--mj-status-info);\n}\n.ch-warning[_ngcontent-%COMP%] .ch-top[_ngcontent-%COMP%] {\n border-top-color: var(--mj-status-warning);\n}\n.ch-error[_ngcontent-%COMP%] .ch-top[_ngcontent-%COMP%] {\n border-top-color: var(--mj-status-error);\n}\n\n\n\n.ch-top[_ngcontent-%COMP%] {\n padding: 16px 18px 14px;\n background: var(--mj-bg-surface-card);\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n.ch-big[_ngcontent-%COMP%] {\n font-size: 30px;\n font-weight: 800;\n line-height: 1;\n color: var(--mj-text-primary);\n}\n.ch-big[_ngcontent-%COMP%] small[_ngcontent-%COMP%] {\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-text-muted);\n margin-left: 4px;\n}\n.ch-title[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n margin: 12px 0 4px;\n font-size: 14px;\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n.ch-info[_ngcontent-%COMP%] .ch-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-status-info);\n}\n.ch-warning[_ngcontent-%COMP%] .ch-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-status-warning);\n}\n.ch-error[_ngcontent-%COMP%] .ch-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n}\n.ch-explain[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 12px;\n line-height: 1.45;\n color: var(--mj-text-secondary);\n}\n\n\n\n.ch-list[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n}\n.ch-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 10px;\n padding: 10px 16px;\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n.ch-item[_ngcontent-%COMP%]:last-child {\n border-bottom: 0;\n}\n.ch-item-busy[_ngcontent-%COMP%] {\n opacity: 0.55;\n}\n.ch-item-main[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 7px;\n min-width: 0;\n flex: 1;\n flex-wrap: wrap;\n font-size: 12.5px;\n}\n.ch-item-name[_ngcontent-%COMP%] {\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n.ch-item-arrow[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n font-size: 11px;\n}\n.ch-item-target[_ngcontent-%COMP%] {\n font-weight: 600;\n color: var(--mj-text-secondary);\n}\n.ch-item-side[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 7px;\n white-space: nowrap;\n}\n.ch-score[_ngcontent-%COMP%] {\n font-size: 11px;\n font-weight: 700;\n color: var(--mj-text-muted);\n font-variant-numeric: tabular-nums;\n}\n\n\n\n.ch-empty[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 9px;\n padding: 18px 16px;\n font-size: 12.5px;\n color: var(--mj-text-muted);\n}\n.ch-empty[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-status-success);\n}\n\n\n\n.ch-foot[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 10px;\n padding: 12px 16px;\n border-top: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-card);\n}\n.ch-more[_ngcontent-%COMP%] {\n font-size: 11.5px;\n font-weight: 600;\n color: var(--mj-text-muted);\n}"] });
561
+ }
562
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ClassifyHealthTabComponent, [{
563
+ type: Component,
564
+ args: [{ standalone: false, selector: 'classify-health-tab', template: "<mj-page-header-interior\n Title=\"Tag Health\"\n Subtitle=\"Automated taxonomy-quality signals from the latest classification runs\">\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</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-page-body\">\n <mj-loading text=\"Loading tag-health signals\u2026\"></mj-loading>\n </div>\n } @else {\n <div class=\"ch-grid\">\n @for (card of Cards; track card.Meta.Reason) {\n <div class=\"ch-card\" [class]=\"'ch-' + card.Meta.Variant\">\n\n <!-- Card head: big count + signal title + explanation -->\n <div class=\"ch-top\">\n <div class=\"ch-big\">\n {{ card.Items.length }} <small>{{ card.Meta.CountNoun }}</small>\n </div>\n <h5 class=\"ch-title\">\n <i [class]=\"card.Meta.Icon\"></i> {{ card.Meta.Title }}\n </h5>\n <p class=\"ch-explain\">{{ card.Meta.Explanation }}</p>\n </div>\n\n @if (card.Items.length === 0) {\n <div class=\"ch-empty\">\n <i class=\"fa-solid fa-circle-check\"></i>\n <span>No {{ card.Meta.Title | lowercase }} right now.</span>\n </div>\n } @else {\n <!-- Top examples (capped at PreviewLimit) -->\n <div class=\"ch-list\">\n @for (s of card.Items.slice(0, PreviewLimit); track s.ID) {\n <div class=\"ch-item\" [class.ch-item-busy]=\"IsRowBusy(s)\">\n <div class=\"ch-item-main\">\n <span class=\"ch-item-name\">{{ s.ProposedName }}</span>\n @if (card.Meta.Reason === 'MergeCandidate' && s.BestMatchTag) {\n <span class=\"ch-item-arrow\"><i class=\"fa-solid fa-arrow-right-long\"></i></span>\n <span class=\"ch-item-target\">{{ s.BestMatchTag }}</span>\n }\n </div>\n <div class=\"ch-item-side\">\n <span class=\"ch-score\">{{ FormatScore(s.BestMatchScore) }}</span>\n\n @switch (card.Meta.Reason) {\n @case ('MergeCandidate') {\n <button mjButton variant=\"primary\" size=\"sm\"\n (click)=\"Merge(s)\" [disabled]=\"IsRowBusy(s) || !s.BestMatchTagID\">\n <i class=\"fa-solid fa-code-merge\"></i> Merge\n </button>\n <button mjButton variant=\"secondary\" size=\"sm\"\n (click)=\"Dismiss(s)\" [disabled]=\"IsRowBusy(s)\">\n Dismiss\n </button>\n }\n @case ('LowUsage') {\n <button mjButton variant=\"warning\" size=\"sm\"\n (click)=\"Deprecate(s)\" [disabled]=\"IsRowBusy(s)\">\n <i class=\"fa-solid fa-arrow-trend-down\"></i> Deprecate\n </button>\n <button mjButton variant=\"secondary\" size=\"sm\"\n (click)=\"Dismiss(s)\" [disabled]=\"IsRowBusy(s)\">\n Dismiss\n </button>\n }\n @case ('WideNode') {\n <button mjButton variant=\"primary\" size=\"sm\"\n (click)=\"ReviewInTaxonomy(s)\" [disabled]=\"IsRowBusy(s)\">\n <i class=\"fa-solid fa-sitemap\"></i> Review\n </button>\n <button mjButton variant=\"secondary\" size=\"sm\"\n (click)=\"Dismiss(s)\" [disabled]=\"IsRowBusy(s)\">\n Dismiss\n </button>\n }\n }\n </div>\n </div>\n }\n </div>\n\n <!-- Card footer: overflow hint + bulk action -->\n <div class=\"ch-foot\">\n @if (card.Items.length > PreviewLimit) {\n <span class=\"ch-more\">+{{ card.Items.length - PreviewLimit }} more</span>\n } @else {\n <span class=\"ch-more\"></span>\n }\n\n @if (card.Meta.Reason === 'MergeCandidate' && HighConfidenceCount(card) > 0) {\n <button mjButton variant=\"primary\" size=\"sm\"\n (click)=\"MergeAllHighConfidence(card)\" [disabled]=\"IsBulkActing\">\n @if (IsBulkActing) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i> Merging\u2026\n } @else {\n <i class=\"fa-solid fa-layer-group\"></i>\n Merge all high-confidence ({{ HighConfidenceCount(card) }})\n }\n </button>\n }\n </div>\n }\n </div>\n }\n </div>\n }\n </div>\n</mj-page-body-interior>\n", styles: ["/*\n * Tag Health tab styles.\n *\n * The host (AutotaggingPipelineResourceComponent) uses ViewEncapsulation.None,\n * so its `.at-*` utilities (.at-main-area, .at-page-body) style the shell. The\n * health-specific `.ch-*` classes below are scoped to this component.\n *\n * Design tokens only \u2014 no hardcoded hex. The 3 signal cards key off semantic\n * status tokens: info = merge, warning = low-usage, error = wide-node.\n */\n\n/* \u2500\u2500 3-card responsive grid \u2500\u2500 */\n.ch-grid {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));\n gap: 16px;\n padding: 16px;\n align-items: start;\n}\n\n/* \u2500\u2500 Card shell \u2500\u2500 */\n.ch-card {\n display: flex;\n flex-direction: column;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n overflow: hidden;\n}\n\n/* Top accent stripe driven by the signal variant */\n.ch-card .ch-top {\n border-top: 3px solid var(--mj-border-default);\n}\n.ch-info .ch-top {\n border-top-color: var(--mj-status-info);\n}\n.ch-warning .ch-top {\n border-top-color: var(--mj-status-warning);\n}\n.ch-error .ch-top {\n border-top-color: var(--mj-status-error);\n}\n\n/* \u2500\u2500 Card head \u2500\u2500 */\n.ch-top {\n padding: 16px 18px 14px;\n background: var(--mj-bg-surface-card);\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n.ch-big {\n font-size: 30px;\n font-weight: 800;\n line-height: 1;\n color: var(--mj-text-primary);\n}\n.ch-big small {\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-text-muted);\n margin-left: 4px;\n}\n.ch-title {\n display: flex;\n align-items: center;\n gap: 8px;\n margin: 12px 0 4px;\n font-size: 14px;\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n.ch-info .ch-title i {\n color: var(--mj-status-info);\n}\n.ch-warning .ch-title i {\n color: var(--mj-status-warning);\n}\n.ch-error .ch-title i {\n color: var(--mj-status-error);\n}\n.ch-explain {\n margin: 0;\n font-size: 12px;\n line-height: 1.45;\n color: var(--mj-text-secondary);\n}\n\n/* \u2500\u2500 Example list \u2500\u2500 */\n.ch-list {\n display: flex;\n flex-direction: column;\n}\n.ch-item {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 10px;\n padding: 10px 16px;\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n.ch-item:last-child {\n border-bottom: 0;\n}\n.ch-item-busy {\n opacity: 0.55;\n}\n.ch-item-main {\n display: flex;\n align-items: center;\n gap: 7px;\n min-width: 0;\n flex: 1;\n flex-wrap: wrap;\n font-size: 12.5px;\n}\n.ch-item-name {\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n.ch-item-arrow {\n color: var(--mj-text-muted);\n font-size: 11px;\n}\n.ch-item-target {\n font-weight: 600;\n color: var(--mj-text-secondary);\n}\n.ch-item-side {\n display: flex;\n align-items: center;\n gap: 7px;\n white-space: nowrap;\n}\n.ch-score {\n font-size: 11px;\n font-weight: 700;\n color: var(--mj-text-muted);\n font-variant-numeric: tabular-nums;\n}\n\n/* \u2500\u2500 Empty state \u2500\u2500 */\n.ch-empty {\n display: flex;\n align-items: center;\n gap: 9px;\n padding: 18px 16px;\n font-size: 12.5px;\n color: var(--mj-text-muted);\n}\n.ch-empty i {\n color: var(--mj-status-success);\n}\n\n/* \u2500\u2500 Footer \u2500\u2500 */\n.ch-foot {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 10px;\n padding: 12px 16px;\n border-top: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-card);\n}\n.ch-more {\n font-size: 11.5px;\n font-weight: 600;\n color: var(--mj-text-muted);\n}\n"] }]
565
+ }], null, { Resolved: [{
566
+ type: Output
567
+ }], OpenInTaxonomyRequested: [{
568
+ type: Output
569
+ }] }); })();
570
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ClassifyHealthTabComponent, { className: "ClassifyHealthTabComponent", filePath: "src/AI/components/autotagging/tabs/health-tab.component.ts", lineNumber: 89 }); })();
571
+ //# sourceMappingURL=health-tab.component.js.map