@memberjunction/ng-dashboards 5.30.0 → 5.31.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 (424) hide show
  1. package/dist/AI/components/agents/agent-configuration.component.d.ts.map +1 -1
  2. package/dist/AI/components/agents/agent-configuration.component.js +4 -4
  3. package/dist/AI/components/agents/agent-configuration.component.js.map +1 -1
  4. package/dist/AI/components/agents/agent-editor.component.d.ts +2 -1
  5. package/dist/AI/components/agents/agent-editor.component.d.ts.map +1 -1
  6. package/dist/AI/components/agents/agent-editor.component.js +8 -6
  7. package/dist/AI/components/agents/agent-editor.component.js.map +1 -1
  8. package/dist/AI/components/analytics/agent-runs/agent-run-analysis.component.d.ts +2 -1
  9. package/dist/AI/components/analytics/agent-runs/agent-run-analysis.component.d.ts.map +1 -1
  10. package/dist/AI/components/analytics/agent-runs/agent-run-analysis.component.js +6 -5
  11. package/dist/AI/components/analytics/agent-runs/agent-run-analysis.component.js.map +1 -1
  12. package/dist/AI/components/analytics/cost-budget/cost-budget.component.d.ts +2 -1
  13. package/dist/AI/components/analytics/cost-budget/cost-budget.component.d.ts.map +1 -1
  14. package/dist/AI/components/analytics/cost-budget/cost-budget.component.js +6 -5
  15. package/dist/AI/components/analytics/cost-budget/cost-budget.component.js.map +1 -1
  16. package/dist/AI/components/analytics/error-analysis/error-analysis.component.d.ts +2 -1
  17. package/dist/AI/components/analytics/error-analysis/error-analysis.component.d.ts.map +1 -1
  18. package/dist/AI/components/analytics/error-analysis/error-analysis.component.js +6 -5
  19. package/dist/AI/components/analytics/error-analysis/error-analysis.component.js.map +1 -1
  20. package/dist/AI/components/analytics/executive-summary/executive-summary.component.d.ts +2 -1
  21. package/dist/AI/components/analytics/executive-summary/executive-summary.component.d.ts.map +1 -1
  22. package/dist/AI/components/analytics/executive-summary/executive-summary.component.js +7 -4
  23. package/dist/AI/components/analytics/executive-summary/executive-summary.component.js.map +1 -1
  24. package/dist/AI/components/analytics/model-performance/model-performance.component.d.ts +3 -2
  25. package/dist/AI/components/analytics/model-performance/model-performance.component.d.ts.map +1 -1
  26. package/dist/AI/components/analytics/model-performance/model-performance.component.js +10 -6
  27. package/dist/AI/components/analytics/model-performance/model-performance.component.js.map +1 -1
  28. package/dist/AI/components/analytics/prompt-runs/prompt-run-analysis.component.d.ts +2 -1
  29. package/dist/AI/components/analytics/prompt-runs/prompt-run-analysis.component.d.ts.map +1 -1
  30. package/dist/AI/components/analytics/prompt-runs/prompt-run-analysis.component.js +6 -5
  31. package/dist/AI/components/analytics/prompt-runs/prompt-run-analysis.component.js.map +1 -1
  32. package/dist/AI/components/analytics/usage-patterns/usage-patterns.component.d.ts +2 -1
  33. package/dist/AI/components/analytics/usage-patterns/usage-patterns.component.d.ts.map +1 -1
  34. package/dist/AI/components/analytics/usage-patterns/usage-patterns.component.js +6 -5
  35. package/dist/AI/components/analytics/usage-patterns/usage-patterns.component.js.map +1 -1
  36. package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.d.ts.map +1 -1
  37. package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.js +55 -52
  38. package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.js.map +1 -1
  39. package/dist/AI/components/duplicates/duplicate-detection-resource.component.js +15 -15
  40. package/dist/AI/components/duplicates/duplicate-detection-resource.component.js.map +1 -1
  41. package/dist/AI/components/execution-monitoring.component.d.ts.map +1 -1
  42. package/dist/AI/components/execution-monitoring.component.js +4 -3
  43. package/dist/AI/components/execution-monitoring.component.js.map +1 -1
  44. package/dist/AI/components/models/model-management.component.js +2 -2
  45. package/dist/AI/components/models/model-management.component.js.map +1 -1
  46. package/dist/AI/components/prompts/model-prompt-priority-matrix.component.d.ts +2 -1
  47. package/dist/AI/components/prompts/model-prompt-priority-matrix.component.d.ts.map +1 -1
  48. package/dist/AI/components/prompts/model-prompt-priority-matrix.component.js +10 -8
  49. package/dist/AI/components/prompts/model-prompt-priority-matrix.component.js.map +1 -1
  50. package/dist/AI/components/prompts/prompt-management.component.d.ts.map +1 -1
  51. package/dist/AI/components/prompts/prompt-management.component.js +2 -2
  52. package/dist/AI/components/prompts/prompt-management.component.js.map +1 -1
  53. package/dist/AI/components/prompts/prompt-version-control.component.d.ts +2 -1
  54. package/dist/AI/components/prompts/prompt-version-control.component.d.ts.map +1 -1
  55. package/dist/AI/components/prompts/prompt-version-control.component.js +13 -10
  56. package/dist/AI/components/prompts/prompt-version-control.component.js.map +1 -1
  57. package/dist/AI/components/requests/agent-requests-resource.component.js +1 -1
  58. package/dist/AI/components/requests/agent-requests-resource.component.js.map +1 -1
  59. package/dist/AI/components/tags/tags-resource.component.d.ts +1181 -0
  60. package/dist/AI/components/tags/tags-resource.component.d.ts.map +1 -0
  61. package/dist/AI/components/tags/tags-resource.component.js +7487 -0
  62. package/dist/AI/components/tags/tags-resource.component.js.map +1 -0
  63. package/dist/AI/components/vectors/vector-management-resource.component.d.ts.map +1 -1
  64. package/dist/AI/components/vectors/vector-management-resource.component.js +25 -21
  65. package/dist/AI/components/vectors/vector-management-resource.component.js.map +1 -1
  66. package/dist/AI/index.d.ts +1 -0
  67. package/dist/AI/index.d.ts.map +1 -1
  68. package/dist/AI/index.js +5 -0
  69. package/dist/AI/index.js.map +1 -1
  70. package/dist/AI/services/ai-instrumentation.service.d.ts +5 -0
  71. package/dist/AI/services/ai-instrumentation.service.d.ts.map +1 -1
  72. package/dist/AI/services/ai-instrumentation.service.js +12 -4
  73. package/dist/AI/services/ai-instrumentation.service.js.map +1 -1
  74. package/dist/APIKeys/api-applications-panel.component.d.ts +3 -2
  75. package/dist/APIKeys/api-applications-panel.component.d.ts.map +1 -1
  76. package/dist/APIKeys/api-applications-panel.component.js +5 -4
  77. package/dist/APIKeys/api-applications-panel.component.js.map +1 -1
  78. package/dist/APIKeys/api-key-create-dialog.component.d.ts +2 -1
  79. package/dist/APIKeys/api-key-create-dialog.component.d.ts.map +1 -1
  80. package/dist/APIKeys/api-key-create-dialog.component.js +5 -5
  81. package/dist/APIKeys/api-key-create-dialog.component.js.map +1 -1
  82. package/dist/APIKeys/api-key-edit-panel.component.d.ts +3 -2
  83. package/dist/APIKeys/api-key-edit-panel.component.d.ts.map +1 -1
  84. package/dist/APIKeys/api-key-edit-panel.component.js +11 -10
  85. package/dist/APIKeys/api-key-edit-panel.component.js.map +1 -1
  86. package/dist/APIKeys/api-key-list.component.d.ts +2 -1
  87. package/dist/APIKeys/api-key-list.component.d.ts.map +1 -1
  88. package/dist/APIKeys/api-key-list.component.js +6 -5
  89. package/dist/APIKeys/api-key-list.component.js.map +1 -1
  90. package/dist/APIKeys/api-keys-resource.component.d.ts.map +1 -1
  91. package/dist/APIKeys/api-keys-resource.component.js +4 -4
  92. package/dist/APIKeys/api-keys-resource.component.js.map +1 -1
  93. package/dist/APIKeys/api-scopes-panel.component.d.ts +3 -2
  94. package/dist/APIKeys/api-scopes-panel.component.d.ts.map +1 -1
  95. package/dist/APIKeys/api-scopes-panel.component.js +8 -6
  96. package/dist/APIKeys/api-scopes-panel.component.js.map +1 -1
  97. package/dist/APIKeys/api-usage-panel.component.d.ts +3 -2
  98. package/dist/APIKeys/api-usage-panel.component.d.ts.map +1 -1
  99. package/dist/APIKeys/api-usage-panel.component.js +10 -8
  100. package/dist/APIKeys/api-usage-panel.component.js.map +1 -1
  101. package/dist/Actions/components/actions-list-view.component.d.ts +2 -1
  102. package/dist/Actions/components/actions-list-view.component.d.ts.map +1 -1
  103. package/dist/Actions/components/actions-list-view.component.js +6 -5
  104. package/dist/Actions/components/actions-list-view.component.js.map +1 -1
  105. package/dist/Actions/components/actions-overview.component.js +2 -2
  106. package/dist/Actions/components/actions-overview.component.js.map +1 -1
  107. package/dist/Actions/components/categories-list-view.component.d.ts +2 -1
  108. package/dist/Actions/components/categories-list-view.component.d.ts.map +1 -1
  109. package/dist/Actions/components/categories-list-view.component.js +6 -5
  110. package/dist/Actions/components/categories-list-view.component.js.map +1 -1
  111. package/dist/Actions/components/execution-monitoring.component.js +1 -1
  112. package/dist/Actions/components/execution-monitoring.component.js.map +1 -1
  113. package/dist/Actions/components/explorer/action-card.component.d.ts +2 -1
  114. package/dist/Actions/components/explorer/action-card.component.d.ts.map +1 -1
  115. package/dist/Actions/components/explorer/action-card.component.js +6 -4
  116. package/dist/Actions/components/explorer/action-card.component.js.map +1 -1
  117. package/dist/Actions/components/explorer/action-explorer.component.js +1 -1
  118. package/dist/Actions/components/explorer/action-explorer.component.js.map +1 -1
  119. package/dist/Actions/components/explorer/new-action-panel.component.d.ts +2 -1
  120. package/dist/Actions/components/explorer/new-action-panel.component.d.ts.map +1 -1
  121. package/dist/Actions/components/explorer/new-action-panel.component.js +7 -5
  122. package/dist/Actions/components/explorer/new-action-panel.component.js.map +1 -1
  123. package/dist/Actions/components/explorer/new-category-panel.component.d.ts +2 -1
  124. package/dist/Actions/components/explorer/new-category-panel.component.d.ts.map +1 -1
  125. package/dist/Actions/components/explorer/new-category-panel.component.js +7 -5
  126. package/dist/Actions/components/explorer/new-category-panel.component.js.map +1 -1
  127. package/dist/ApplicationRoles/application-roles-resource.component.js +4 -4
  128. package/dist/ApplicationRoles/application-roles-resource.component.js.map +1 -1
  129. package/dist/Communication/communication-logs-resource.component.js +1 -1
  130. package/dist/Communication/communication-logs-resource.component.js.map +1 -1
  131. package/dist/Communication/communication-monitor-resource.component.js +1 -1
  132. package/dist/Communication/communication-monitor-resource.component.js.map +1 -1
  133. package/dist/Communication/communication-providers-resource.component.js +3 -3
  134. package/dist/Communication/communication-providers-resource.component.js.map +1 -1
  135. package/dist/Communication/communication-runs-resource.component.js +1 -1
  136. package/dist/Communication/communication-runs-resource.component.js.map +1 -1
  137. package/dist/Communication/communication-templates-resource.component.js +3 -3
  138. package/dist/Communication/communication-templates-resource.component.js.map +1 -1
  139. package/dist/ComponentStudio/component-studio-dashboard.component.d.ts +1 -1
  140. package/dist/ComponentStudio/component-studio-dashboard.component.d.ts.map +1 -1
  141. package/dist/ComponentStudio/component-studio-dashboard.component.js +5 -4
  142. package/dist/ComponentStudio/component-studio-dashboard.component.js.map +1 -1
  143. package/dist/ComponentStudio/components/ai-assistant/ai-assistant-panel.component.d.ts +2 -1
  144. package/dist/ComponentStudio/components/ai-assistant/ai-assistant-panel.component.d.ts.map +1 -1
  145. package/dist/ComponentStudio/components/ai-assistant/ai-assistant-panel.component.js +6 -4
  146. package/dist/ComponentStudio/components/ai-assistant/ai-assistant-panel.component.js.map +1 -1
  147. package/dist/ComponentStudio/components/artifact-load-dialog.component.d.ts +11 -2
  148. package/dist/ComponentStudio/components/artifact-load-dialog.component.d.ts.map +1 -1
  149. package/dist/ComponentStudio/components/artifact-load-dialog.component.js +61 -27
  150. package/dist/ComponentStudio/components/artifact-load-dialog.component.js.map +1 -1
  151. package/dist/ComponentStudio/components/artifact-selection-dialog.component.d.ts +4 -2
  152. package/dist/ComponentStudio/components/artifact-selection-dialog.component.d.ts.map +1 -1
  153. package/dist/ComponentStudio/components/artifact-selection-dialog.component.js +19 -11
  154. package/dist/ComponentStudio/components/artifact-selection-dialog.component.js.map +1 -1
  155. package/dist/ComponentStudio/components/editors/data-requirements-editor.component.d.ts +4 -2
  156. package/dist/ComponentStudio/components/editors/data-requirements-editor.component.d.ts.map +1 -1
  157. package/dist/ComponentStudio/components/editors/data-requirements-editor.component.js +11 -3
  158. package/dist/ComponentStudio/components/editors/data-requirements-editor.component.js.map +1 -1
  159. package/dist/ComponentStudio/components/workspace/component-preview.component.d.ts +10 -1
  160. package/dist/ComponentStudio/components/workspace/component-preview.component.d.ts.map +1 -1
  161. package/dist/ComponentStudio/components/workspace/component-preview.component.js +18 -9
  162. package/dist/ComponentStudio/components/workspace/component-preview.component.js.map +1 -1
  163. package/dist/ComponentStudio/services/component-studio-state.service.d.ts +11 -1
  164. package/dist/ComponentStudio/services/component-studio-state.service.d.ts.map +1 -1
  165. package/dist/ComponentStudio/services/component-studio-state.service.js +23 -3
  166. package/dist/ComponentStudio/services/component-studio-state.service.js.map +1 -1
  167. package/dist/ComponentStudio/services/component-version.service.d.ts +6 -1
  168. package/dist/ComponentStudio/services/component-version.service.d.ts.map +1 -1
  169. package/dist/ComponentStudio/services/component-version.service.js +16 -6
  170. package/dist/ComponentStudio/services/component-version.service.js.map +1 -1
  171. package/dist/Credentials/components/credentials-audit-resource.component.js +1 -1
  172. package/dist/Credentials/components/credentials-audit-resource.component.js.map +1 -1
  173. package/dist/Credentials/components/credentials-categories-resource.component.d.ts.map +1 -1
  174. package/dist/Credentials/components/credentials-categories-resource.component.js +3 -3
  175. package/dist/Credentials/components/credentials-categories-resource.component.js.map +1 -1
  176. package/dist/Credentials/components/credentials-list-resource.component.d.ts.map +1 -1
  177. package/dist/Credentials/components/credentials-list-resource.component.js +3 -3
  178. package/dist/Credentials/components/credentials-list-resource.component.js.map +1 -1
  179. package/dist/Credentials/components/credentials-overview-resource.component.d.ts.map +1 -1
  180. package/dist/Credentials/components/credentials-overview-resource.component.js +3 -3
  181. package/dist/Credentials/components/credentials-overview-resource.component.js.map +1 -1
  182. package/dist/Credentials/components/credentials-types-resource.component.d.ts.map +1 -1
  183. package/dist/Credentials/components/credentials-types-resource.component.js +3 -3
  184. package/dist/Credentials/components/credentials-types-resource.component.js.map +1 -1
  185. package/dist/Credentials/credentials-dashboard.component.js +1 -1
  186. package/dist/Credentials/credentials-dashboard.component.js.map +1 -1
  187. package/dist/DashboardBrowser/dashboard-browser-resource.component.js +13 -13
  188. package/dist/DashboardBrowser/dashboard-browser-resource.component.js.map +1 -1
  189. package/dist/DashboardBrowser/dashboard-share-adapter.d.ts +4 -0
  190. package/dist/DashboardBrowser/dashboard-share-adapter.d.ts.map +1 -1
  191. package/dist/DashboardBrowser/dashboard-share-adapter.js +5 -2
  192. package/dist/DashboardBrowser/dashboard-share-adapter.js.map +1 -1
  193. package/dist/DashboardBrowser/dashboard-share-dialog.component.d.ts +3 -1
  194. package/dist/DashboardBrowser/dashboard-share-dialog.component.d.ts.map +1 -1
  195. package/dist/DashboardBrowser/dashboard-share-dialog.component.js +9 -4
  196. package/dist/DashboardBrowser/dashboard-share-dialog.component.js.map +1 -1
  197. package/dist/DataExplorer/components/navigation-panel/navigation-panel.component.d.ts +3 -2
  198. package/dist/DataExplorer/components/navigation-panel/navigation-panel.component.d.ts.map +1 -1
  199. package/dist/DataExplorer/components/navigation-panel/navigation-panel.component.js +7 -6
  200. package/dist/DataExplorer/components/navigation-panel/navigation-panel.component.js.map +1 -1
  201. package/dist/DataExplorer/components/view-selector/view-selector.component.d.ts +3 -2
  202. package/dist/DataExplorer/components/view-selector/view-selector.component.d.ts.map +1 -1
  203. package/dist/DataExplorer/components/view-selector/view-selector.component.js +6 -5
  204. package/dist/DataExplorer/components/view-selector/view-selector.component.js.map +1 -1
  205. package/dist/DataExplorer/data-explorer-dashboard.component.d.ts.map +1 -1
  206. package/dist/DataExplorer/data-explorer-dashboard.component.js +10 -9
  207. package/dist/DataExplorer/data-explorer-dashboard.component.js.map +1 -1
  208. package/dist/DataExplorer/services/explorer-state.service.d.ts +6 -1
  209. package/dist/DataExplorer/services/explorer-state.service.d.ts.map +1 -1
  210. package/dist/DataExplorer/services/explorer-state.service.js +15 -5
  211. package/dist/DataExplorer/services/explorer-state.service.js.map +1 -1
  212. package/dist/DatabaseDesigner/components/create-wizard/database-create-wizard.component.d.ts +64 -0
  213. package/dist/DatabaseDesigner/components/create-wizard/database-create-wizard.component.d.ts.map +1 -0
  214. package/dist/DatabaseDesigner/components/create-wizard/database-create-wizard.component.js +400 -0
  215. package/dist/DatabaseDesigner/components/create-wizard/database-create-wizard.component.js.map +1 -0
  216. package/dist/DatabaseDesigner/components/create-wizard/steps/step-basics.component.d.ts +42 -0
  217. package/dist/DatabaseDesigner/components/create-wizard/steps/step-basics.component.d.ts.map +1 -0
  218. package/dist/DatabaseDesigner/components/create-wizard/steps/step-basics.component.js +232 -0
  219. package/dist/DatabaseDesigner/components/create-wizard/steps/step-basics.component.js.map +1 -0
  220. package/dist/DatabaseDesigner/components/create-wizard/steps/step-fields.component.d.ts +14 -0
  221. package/dist/DatabaseDesigner/components/create-wizard/steps/step-fields.component.d.ts.map +1 -0
  222. package/dist/DatabaseDesigner/components/create-wizard/steps/step-fields.component.js +38 -0
  223. package/dist/DatabaseDesigner/components/create-wizard/steps/step-fields.component.js.map +1 -0
  224. package/dist/DatabaseDesigner/components/create-wizard/steps/step-pipeline.component.d.ts +24 -0
  225. package/dist/DatabaseDesigner/components/create-wizard/steps/step-pipeline.component.d.ts.map +1 -0
  226. package/dist/DatabaseDesigner/components/create-wizard/steps/step-pipeline.component.js +77 -0
  227. package/dist/DatabaseDesigner/components/create-wizard/steps/step-pipeline.component.js.map +1 -0
  228. package/dist/DatabaseDesigner/components/create-wizard/steps/step-relationships.component.d.ts +88 -0
  229. package/dist/DatabaseDesigner/components/create-wizard/steps/step-relationships.component.d.ts.map +1 -0
  230. package/dist/DatabaseDesigner/components/create-wizard/steps/step-relationships.component.js +404 -0
  231. package/dist/DatabaseDesigner/components/create-wizard/steps/step-relationships.component.js.map +1 -0
  232. package/dist/DatabaseDesigner/components/create-wizard/steps/step-review.component.d.ts +12 -0
  233. package/dist/DatabaseDesigner/components/create-wizard/steps/step-review.component.d.ts.map +1 -0
  234. package/dist/DatabaseDesigner/components/create-wizard/steps/step-review.component.js +116 -0
  235. package/dist/DatabaseDesigner/components/create-wizard/steps/step-review.component.js.map +1 -0
  236. package/dist/DatabaseDesigner/components/database-designer-dashboard.component.d.ts +55 -0
  237. package/dist/DatabaseDesigner/components/database-designer-dashboard.component.d.ts.map +1 -0
  238. package/dist/DatabaseDesigner/components/database-designer-dashboard.component.js +204 -0
  239. package/dist/DatabaseDesigner/components/database-designer-dashboard.component.js.map +1 -0
  240. package/dist/DatabaseDesigner/components/entity-list.component.d.ts +61 -0
  241. package/dist/DatabaseDesigner/components/entity-list.component.d.ts.map +1 -0
  242. package/dist/DatabaseDesigner/components/entity-list.component.js +485 -0
  243. package/dist/DatabaseDesigner/components/entity-list.component.js.map +1 -0
  244. package/dist/DatabaseDesigner/components/modify/database-modify.component.d.ts +52 -0
  245. package/dist/DatabaseDesigner/components/modify/database-modify.component.d.ts.map +1 -0
  246. package/dist/DatabaseDesigner/components/modify/database-modify.component.js +320 -0
  247. package/dist/DatabaseDesigner/components/modify/database-modify.component.js.map +1 -0
  248. package/dist/DatabaseDesigner/components/shared/database-preview-pane.component.d.ts +79 -0
  249. package/dist/DatabaseDesigner/components/shared/database-preview-pane.component.d.ts.map +1 -0
  250. package/dist/DatabaseDesigner/components/shared/database-preview-pane.component.js +378 -0
  251. package/dist/DatabaseDesigner/components/shared/database-preview-pane.component.js.map +1 -0
  252. package/dist/DatabaseDesigner/components/shared/entity-fields-grid.component.d.ts +85 -0
  253. package/dist/DatabaseDesigner/components/shared/entity-fields-grid.component.d.ts.map +1 -0
  254. package/dist/DatabaseDesigner/components/shared/entity-fields-grid.component.js +429 -0
  255. package/dist/DatabaseDesigner/components/shared/entity-fields-grid.component.js.map +1 -0
  256. package/dist/DatabaseDesigner/components/shared/entity-pipeline-panel.component.d.ts +58 -0
  257. package/dist/DatabaseDesigner/components/shared/entity-pipeline-panel.component.d.ts.map +1 -0
  258. package/dist/DatabaseDesigner/components/shared/entity-pipeline-panel.component.js +333 -0
  259. package/dist/DatabaseDesigner/components/shared/entity-pipeline-panel.component.js.map +1 -0
  260. package/dist/DatabaseDesigner/components/shared/entity-review-panel.component.d.ts +36 -0
  261. package/dist/DatabaseDesigner/components/shared/entity-review-panel.component.d.ts.map +1 -0
  262. package/dist/DatabaseDesigner/components/shared/entity-review-panel.component.js +345 -0
  263. package/dist/DatabaseDesigner/components/shared/entity-review-panel.component.js.map +1 -0
  264. package/dist/DatabaseDesigner/components/shared/wizard-step-indicator.component.d.ts +13 -0
  265. package/dist/DatabaseDesigner/components/shared/wizard-step-indicator.component.d.ts.map +1 -0
  266. package/dist/DatabaseDesigner/components/shared/wizard-step-indicator.component.js +81 -0
  267. package/dist/DatabaseDesigner/components/shared/wizard-step-indicator.component.js.map +1 -0
  268. package/dist/DatabaseDesigner/database-designer-dashboards.module.d.ts +30 -0
  269. package/dist/DatabaseDesigner/database-designer-dashboards.module.d.ts.map +1 -0
  270. package/dist/DatabaseDesigner/database-designer-dashboards.module.js +131 -0
  271. package/dist/DatabaseDesigner/database-designer-dashboards.module.js.map +1 -0
  272. package/dist/DatabaseDesigner/database-designer-erd.d.ts +19 -0
  273. package/dist/DatabaseDesigner/database-designer-erd.d.ts.map +1 -0
  274. package/dist/DatabaseDesigner/database-designer-erd.js +84 -0
  275. package/dist/DatabaseDesigner/database-designer-erd.js.map +1 -0
  276. package/dist/DatabaseDesigner/database-designer.types.d.ts +167 -0
  277. package/dist/DatabaseDesigner/database-designer.types.d.ts.map +1 -0
  278. package/dist/DatabaseDesigner/database-designer.types.js +26 -0
  279. package/dist/DatabaseDesigner/database-designer.types.js.map +1 -0
  280. package/dist/DatabaseDesigner/services/database-designer.engine.d.ts +94 -0
  281. package/dist/DatabaseDesigner/services/database-designer.engine.d.ts.map +1 -0
  282. package/dist/DatabaseDesigner/services/database-designer.engine.js +392 -0
  283. package/dist/DatabaseDesigner/services/database-designer.engine.js.map +1 -0
  284. package/dist/DatabaseDesigner/services/database-designer.service.d.ts +78 -0
  285. package/dist/DatabaseDesigner/services/database-designer.service.d.ts.map +1 -0
  286. package/dist/DatabaseDesigner/services/database-designer.service.js +273 -0
  287. package/dist/DatabaseDesigner/services/database-designer.service.js.map +1 -0
  288. package/dist/DatabaseDesigner/services/entity-wizard-state.service.d.ts +79 -0
  289. package/dist/DatabaseDesigner/services/entity-wizard-state.service.d.ts.map +1 -0
  290. package/dist/DatabaseDesigner/services/entity-wizard-state.service.js +204 -0
  291. package/dist/DatabaseDesigner/services/entity-wizard-state.service.js.map +1 -0
  292. package/dist/EntityAdmin/entity-admin-dashboard.component.d.ts.map +1 -1
  293. package/dist/EntityAdmin/entity-admin-dashboard.component.js +2 -2
  294. package/dist/EntityAdmin/entity-admin-dashboard.component.js.map +1 -1
  295. package/dist/Home/action-pin-config-dialog.component.d.ts +2 -1
  296. package/dist/Home/action-pin-config-dialog.component.d.ts.map +1 -1
  297. package/dist/Home/action-pin-config-dialog.component.js +6 -4
  298. package/dist/Home/action-pin-config-dialog.component.js.map +1 -1
  299. package/dist/Home/action-pin-runner-dialog.component.d.ts +2 -1
  300. package/dist/Home/action-pin-runner-dialog.component.d.ts.map +1 -1
  301. package/dist/Home/action-pin-runner-dialog.component.js +5 -4
  302. package/dist/Home/action-pin-runner-dialog.component.js.map +1 -1
  303. package/dist/Home/home-application.d.ts.map +1 -1
  304. package/dist/Home/home-application.js +10 -12
  305. package/dist/Home/home-application.js.map +1 -1
  306. package/dist/Home/home-dashboard.component.d.ts.map +1 -1
  307. package/dist/Home/home-dashboard.component.js +3 -3
  308. package/dist/Home/home-dashboard.component.js.map +1 -1
  309. package/dist/Integration/components/activity/activity.component.d.ts.map +1 -1
  310. package/dist/Integration/components/activity/activity.component.js +1 -0
  311. package/dist/Integration/components/activity/activity.component.js.map +1 -1
  312. package/dist/Integration/components/connections/connections.component.d.ts.map +1 -1
  313. package/dist/Integration/components/connections/connections.component.js +11 -10
  314. package/dist/Integration/components/connections/connections.component.js.map +1 -1
  315. package/dist/Integration/components/mapping-workspace/mapping-workspace.component.d.ts.map +1 -1
  316. package/dist/Integration/components/mapping-workspace/mapping-workspace.component.js +2 -2
  317. package/dist/Integration/components/mapping-workspace/mapping-workspace.component.js.map +1 -1
  318. package/dist/Integration/components/overview/overview.component.d.ts.map +1 -1
  319. package/dist/Integration/components/overview/overview.component.js +1 -0
  320. package/dist/Integration/components/overview/overview.component.js.map +1 -1
  321. package/dist/Integration/components/pipelines/pipelines.component.d.ts.map +1 -1
  322. package/dist/Integration/components/pipelines/pipelines.component.js +1 -0
  323. package/dist/Integration/components/pipelines/pipelines.component.js.map +1 -1
  324. package/dist/Integration/components/schedules/schedules.component.d.ts.map +1 -1
  325. package/dist/Integration/components/schedules/schedules.component.js +5 -4
  326. package/dist/Integration/components/schedules/schedules.component.js.map +1 -1
  327. package/dist/Integration/services/integration-data.service.d.ts +5 -1
  328. package/dist/Integration/services/integration-data.service.d.ts.map +1 -1
  329. package/dist/Integration/services/integration-data.service.js +27 -19
  330. package/dist/Integration/services/integration-data.service.js.map +1 -1
  331. package/dist/KnowledgeHub/components/analytics/analytics-resource.component.js +6 -6
  332. package/dist/KnowledgeHub/components/analytics/analytics-resource.component.js.map +1 -1
  333. package/dist/KnowledgeHub/components/clusters/cluster-visualization-resource.component.d.ts.map +1 -1
  334. package/dist/KnowledgeHub/components/clusters/cluster-visualization-resource.component.js +8 -6
  335. package/dist/KnowledgeHub/components/clusters/cluster-visualization-resource.component.js.map +1 -1
  336. package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.js +6 -6
  337. package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.js.map +1 -1
  338. package/dist/KnowledgeHub/components/scheduling/scheduling-resource.component.js +3 -3
  339. package/dist/KnowledgeHub/components/scheduling/scheduling-resource.component.js.map +1 -1
  340. package/dist/Lists/components/lists-browse-resource.component.js +6 -6
  341. package/dist/Lists/components/lists-browse-resource.component.js.map +1 -1
  342. package/dist/Lists/components/lists-categories-resource.component.js +4 -4
  343. package/dist/Lists/components/lists-categories-resource.component.js.map +1 -1
  344. package/dist/Lists/components/lists-my-lists-resource.component.js +6 -6
  345. package/dist/Lists/components/lists-my-lists-resource.component.js.map +1 -1
  346. package/dist/Lists/components/lists-operations-resource.component.d.ts.map +1 -1
  347. package/dist/Lists/components/lists-operations-resource.component.js +11 -10
  348. package/dist/Lists/components/lists-operations-resource.component.js.map +1 -1
  349. package/dist/Lists/services/list-set-operations.service.d.ts +5 -0
  350. package/dist/Lists/services/list-set-operations.service.d.ts.map +1 -1
  351. package/dist/Lists/services/list-set-operations.service.js +11 -3
  352. package/dist/Lists/services/list-set-operations.service.js.map +1 -1
  353. package/dist/MCP/components/mcp-connection-dialog.component.d.ts +2 -1
  354. package/dist/MCP/components/mcp-connection-dialog.component.d.ts.map +1 -1
  355. package/dist/MCP/components/mcp-connection-dialog.component.js +8 -6
  356. package/dist/MCP/components/mcp-connection-dialog.component.js.map +1 -1
  357. package/dist/MCP/components/mcp-server-dialog.component.d.ts +2 -1
  358. package/dist/MCP/components/mcp-server-dialog.component.d.ts.map +1 -1
  359. package/dist/MCP/components/mcp-server-dialog.component.js +7 -5
  360. package/dist/MCP/components/mcp-server-dialog.component.js.map +1 -1
  361. package/dist/MCP/mcp-dashboard.component.d.ts.map +1 -1
  362. package/dist/MCP/mcp-dashboard.component.js +12 -12
  363. package/dist/MCP/mcp-dashboard.component.js.map +1 -1
  364. package/dist/Permissions/permissions-shared.d.ts +3 -3
  365. package/dist/Permissions/permissions-shared.d.ts.map +1 -1
  366. package/dist/Permissions/permissions-shared.js +5 -5
  367. package/dist/Permissions/permissions-shared.js.map +1 -1
  368. package/dist/Permissions/resource-access-resource.component.js +1 -1
  369. package/dist/Permissions/resource-access-resource.component.js.map +1 -1
  370. package/dist/Permissions/user-access-resource.component.js +1 -2
  371. package/dist/Permissions/user-access-resource.component.js.map +1 -1
  372. package/dist/QueryBrowser/query-browser-resource.component.d.ts.map +1 -1
  373. package/dist/QueryBrowser/query-browser-resource.component.js +2 -2
  374. package/dist/QueryBrowser/query-browser-resource.component.js.map +1 -1
  375. package/dist/Scheduling/scheduling-dashboard.component.d.ts.map +1 -1
  376. package/dist/Scheduling/scheduling-dashboard.component.js +1 -0
  377. package/dist/Scheduling/scheduling-dashboard.component.js.map +1 -1
  378. package/dist/Scheduling/services/scheduling-instrumentation.service.d.ts +5 -0
  379. package/dist/Scheduling/services/scheduling-instrumentation.service.d.ts.map +1 -1
  380. package/dist/Scheduling/services/scheduling-instrumentation.service.js +21 -13
  381. package/dist/Scheduling/services/scheduling-instrumentation.service.js.map +1 -1
  382. package/dist/SystemDiagnostics/system-diagnostics.component.d.ts.map +1 -1
  383. package/dist/SystemDiagnostics/system-diagnostics.component.js +2 -2
  384. package/dist/SystemDiagnostics/system-diagnostics.component.js.map +1 -1
  385. package/dist/Testing/components/testing-explorer.component.d.ts +2 -1
  386. package/dist/Testing/components/testing-explorer.component.d.ts.map +1 -1
  387. package/dist/Testing/components/testing-explorer.component.js +9 -7
  388. package/dist/Testing/components/testing-explorer.component.js.map +1 -1
  389. package/dist/Testing/services/testing-instrumentation.service.d.ts +6 -1
  390. package/dist/Testing/services/testing-instrumentation.service.d.ts.map +1 -1
  391. package/dist/Testing/services/testing-instrumentation.service.js +21 -11
  392. package/dist/Testing/services/testing-instrumentation.service.js.map +1 -1
  393. package/dist/Testing/testing-dashboard.component.d.ts +3 -1
  394. package/dist/Testing/testing-dashboard.component.d.ts.map +1 -1
  395. package/dist/Testing/testing-dashboard.component.js +15 -11
  396. package/dist/Testing/testing-dashboard.component.js.map +1 -1
  397. package/dist/VersionHistory/components/diff-resource.component.d.ts.map +1 -1
  398. package/dist/VersionHistory/components/diff-resource.component.js +5 -5
  399. package/dist/VersionHistory/components/diff-resource.component.js.map +1 -1
  400. package/dist/VersionHistory/components/graph-resource.component.d.ts.map +1 -1
  401. package/dist/VersionHistory/components/graph-resource.component.js +1 -2
  402. package/dist/VersionHistory/components/graph-resource.component.js.map +1 -1
  403. package/dist/VersionHistory/components/labels-resource.component.d.ts.map +1 -1
  404. package/dist/VersionHistory/components/labels-resource.component.js +3 -3
  405. package/dist/VersionHistory/components/labels-resource.component.js.map +1 -1
  406. package/dist/VersionHistory/components/restore-resource.component.js +1 -1
  407. package/dist/VersionHistory/components/restore-resource.component.js.map +1 -1
  408. package/dist/ai-dashboards.module.d.ts +35 -34
  409. package/dist/ai-dashboards.module.d.ts.map +1 -1
  410. package/dist/ai-dashboards.module.js +6 -0
  411. package/dist/ai-dashboards.module.js.map +1 -1
  412. package/dist/module.d.ts +13 -12
  413. package/dist/module.d.ts.map +1 -1
  414. package/dist/module.js +7 -0
  415. package/dist/module.js.map +1 -1
  416. package/dist/public-api.d.ts +3 -1
  417. package/dist/public-api.d.ts.map +1 -1
  418. package/dist/public-api.js +3 -1
  419. package/dist/public-api.js.map +1 -1
  420. package/dist/shared/entity-field-display.d.ts +4 -3
  421. package/dist/shared/entity-field-display.d.ts.map +1 -1
  422. package/dist/shared/entity-field-display.js +9 -9
  423. package/dist/shared/entity-field-display.js.map +1 -1
  424. package/package.json +52 -51
@@ -2,6 +2,7 @@ import { Component, Input, Output, EventEmitter, ChangeDetectorRef, inject } fro
2
2
  import { Subject } from 'rxjs';
3
3
  import { takeUntil } from 'rxjs/operators';
4
4
  import { AIInstrumentationService } from '../../../services/ai-instrumentation.service';
5
+ import { BaseAngularComponent } from '@memberjunction/ng-base-types';
5
6
  import * as i0 from "@angular/core";
6
7
  import * as i1 from "@memberjunction/ng-shared-generic";
7
8
  import * as i2 from "../../charts/time-series-chart.component";
@@ -148,7 +149,7 @@ function AnalyticsExecutiveSummaryComponent_Conditional_30_Template(rf, ctx) { i
148
149
  i0.ɵɵelementEnd();
149
150
  } }
150
151
  // ─── Component ─────────────────────────────────────────────────────
151
- export class AnalyticsExecutiveSummaryComponent {
152
+ export class AnalyticsExecutiveSummaryComponent extends BaseAngularComponent {
152
153
  // ─── Inputs / Outputs ────────────────────────────────────────────
153
154
  _timeRange = '24h';
154
155
  set TimeRange(value) {
@@ -187,6 +188,7 @@ export class AnalyticsExecutiveSummaryComponent {
187
188
  previousKpis = null;
188
189
  // ─── Lifecycle ───────────────────────────────────────────────────
189
190
  ngOnInit() {
191
+ this.instrumentationService.Provider = this.ProviderToUse;
190
192
  this.subscribeToStreams();
191
193
  this.applyDateRange();
192
194
  this.isInitialized = true;
@@ -313,6 +315,7 @@ export class AnalyticsExecutiveSummaryComponent {
313
315
  const prevStart = new Date(prevEnd.getTime() - durationMs);
314
316
  // Temporarily set date range to previous period, capture KPIs, then restore
315
317
  const previousService = new AIInstrumentationService();
318
+ previousService.Provider = this.ProviderToUse;
316
319
  previousService.setDateRange(prevStart, prevEnd);
317
320
  // We subscribe to the previousService's kpis$ once
318
321
  const sub = previousService.kpis$
@@ -460,8 +463,8 @@ export class AnalyticsExecutiveSummaryComponent {
460
463
  return (ms / 1_000).toFixed(1) + 's';
461
464
  return Math.round(ms) + 'ms';
462
465
  }
463
- static ɵfac = function AnalyticsExecutiveSummaryComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || AnalyticsExecutiveSummaryComponent)(); };
464
- static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: AnalyticsExecutiveSummaryComponent, selectors: [["app-analytics-executive-summary"]], inputs: { TimeRange: "TimeRange", Filters: "Filters" }, outputs: { TimeRangeChange: "TimeRangeChange", FiltersChange: "FiltersChange", SectionNavigate: "SectionNavigate" }, standalone: false, decls: 31, vars: 15, consts: [[3, "TimeRangeChange", "FiltersChange", "CompareToggled", "TimeRange", "Filters", "ShowCompareToggle", "ShowModelFilter", "ShowAgentFilter", "ShowPromptFilter", "ShowStatusFilter"], [1, "loading-container"], [1, "kpi-row"], [1, "kpi-card", 3, "border-left-color"], [1, "trends-panel"], ["title", "Execution Trends", 3, "data", "config"], [1, "panels-grid"], [1, "panel"], [1, "panel-header"], [1, "panel-header__title"], [1, "fa-solid", "fa-ranking-star", "panel-header__icon"], [1, "panel-header__subtitle"], [1, "panel-body"], [1, "panel-empty"], ["role", "button", "tabindex", "0", 1, "consumer-item"], [1, "fa-solid", "fa-triangle-exclamation", "panel-header__icon", "panel-header__icon--error"], [1, "error-item"], [1, "view-all-link"], ["text", "Loading executive summary...", "size", "medium"], [1, "kpi-card"], [1, "kpi-label"], [1, "kpi-value"], [1, "kpi-sparkline"], [1, "spark-bar", 3, "height", "background"], [1, "kpi-delta", 3, "kpi-delta--good", "kpi-delta--bad"], [1, "spark-bar"], [1, "kpi-delta"], [1, "kpi-delta__period"], ["role", "button", "tabindex", "0", 1, "consumer-item", 3, "click", "keydown.enter"], [1, "consumer-rank"], [1, "consumer-type-pill"], [1, "consumer-name", 3, "title"], [1, "consumer-cost"], [1, "consumer-bar-container"], [1, "consumer-bar"], [1, "error-icon"], [1, "fa-solid", "fa-circle-exclamation"], [1, "error-info"], [1, "error-source"], [1, "error-message", 3, "title"], [1, "error-count"], [1, "view-all-link", 3, "click"], [1, "fa-solid", "fa-arrow-right"]], template: function AnalyticsExecutiveSummaryComponent_Template(rf, ctx) { if (rf & 1) {
466
+ static ɵfac = /*@__PURE__*/ (() => { let ɵAnalyticsExecutiveSummaryComponent_BaseFactory; return function AnalyticsExecutiveSummaryComponent_Factory(__ngFactoryType__) { return (ɵAnalyticsExecutiveSummaryComponent_BaseFactory || (ɵAnalyticsExecutiveSummaryComponent_BaseFactory = i0.ɵɵgetInheritedFactory(AnalyticsExecutiveSummaryComponent)))(__ngFactoryType__ || AnalyticsExecutiveSummaryComponent); }; })();
467
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: AnalyticsExecutiveSummaryComponent, selectors: [["app-analytics-executive-summary"]], inputs: { TimeRange: "TimeRange", Filters: "Filters" }, outputs: { TimeRangeChange: "TimeRangeChange", FiltersChange: "FiltersChange", SectionNavigate: "SectionNavigate" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 31, vars: 15, consts: [[3, "TimeRangeChange", "FiltersChange", "CompareToggled", "TimeRange", "Filters", "ShowCompareToggle", "ShowModelFilter", "ShowAgentFilter", "ShowPromptFilter", "ShowStatusFilter"], [1, "loading-container"], [1, "kpi-row"], [1, "kpi-card", 3, "border-left-color"], [1, "trends-panel"], ["title", "Execution Trends", 3, "data", "config"], [1, "panels-grid"], [1, "panel"], [1, "panel-header"], [1, "panel-header__title"], [1, "fa-solid", "fa-ranking-star", "panel-header__icon"], [1, "panel-header__subtitle"], [1, "panel-body"], [1, "panel-empty"], ["role", "button", "tabindex", "0", 1, "consumer-item"], [1, "fa-solid", "fa-triangle-exclamation", "panel-header__icon", "panel-header__icon--error"], [1, "error-item"], [1, "view-all-link"], ["text", "Loading executive summary...", "size", "medium"], [1, "kpi-card"], [1, "kpi-label"], [1, "kpi-value"], [1, "kpi-sparkline"], [1, "spark-bar", 3, "height", "background"], [1, "kpi-delta", 3, "kpi-delta--good", "kpi-delta--bad"], [1, "spark-bar"], [1, "kpi-delta"], [1, "kpi-delta__period"], ["role", "button", "tabindex", "0", 1, "consumer-item", 3, "click", "keydown.enter"], [1, "consumer-rank"], [1, "consumer-type-pill"], [1, "consumer-name", 3, "title"], [1, "consumer-cost"], [1, "consumer-bar-container"], [1, "consumer-bar"], [1, "error-icon"], [1, "fa-solid", "fa-circle-exclamation"], [1, "error-info"], [1, "error-source"], [1, "error-message", 3, "title"], [1, "error-count"], [1, "view-all-link", 3, "click"], [1, "fa-solid", "fa-arrow-right"]], template: function AnalyticsExecutiveSummaryComponent_Template(rf, ctx) { if (rf & 1) {
465
468
  i0.ɵɵelementStart(0, "app-analytics-filter-bar", 0);
466
469
  i0.ɵɵlistener("TimeRangeChange", function AnalyticsExecutiveSummaryComponent_Template_app_analytics_filter_bar_TimeRangeChange_0_listener($event) { return ctx.OnTimeRangeChange($event); })("FiltersChange", function AnalyticsExecutiveSummaryComponent_Template_app_analytics_filter_bar_FiltersChange_0_listener($event) { return ctx.OnFiltersChange($event); })("CompareToggled", function AnalyticsExecutiveSummaryComponent_Template_app_analytics_filter_bar_CompareToggled_0_listener($event) { return ctx.OnCompareToggled($event); });
467
470
  i0.ɵɵelementEnd();
@@ -666,7 +669,7 @@ export class AnalyticsExecutiveSummaryComponent {
666
669
  }], SectionNavigate: [{
667
670
  type: Output
668
671
  }] }); })();
669
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(AnalyticsExecutiveSummaryComponent, { className: "AnalyticsExecutiveSummaryComponent", filePath: "src/AI/components/analytics/executive-summary/executive-summary.component.ts", lineNumber: 481 }); })();
672
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(AnalyticsExecutiveSummaryComponent, { className: "AnalyticsExecutiveSummaryComponent", filePath: "src/AI/components/analytics/executive-summary/executive-summary.component.ts", lineNumber: 482 }); })();
670
673
  export function LoadAnalyticsExecutiveSummary() {
671
674
  // Prevents tree-shaking
672
675
  }
@@ -1 +1 @@
1
- {"version":3,"file":"executive-summary.component.js","sourceRoot":"","sources":["../../../../../src/AI/components/analytics/executive-summary/executive-summary.component.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Component, Input, Output, EventEmitter, OnInit, OnDestroy,\n ChangeDetectorRef, inject\n} from '@angular/core';\nimport { Subject, Subscription } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport {\n AIInstrumentationService,\n DashboardKPIs,\n TrendData,\n ChartData\n} from '../../../services/ai-instrumentation.service';\nimport { GlobalFilterState } from '../../../interfaces/analytics-preferences.interface';\nimport { TimeSeriesConfig } from '../../charts/time-series-chart.component';\n\n// ─── Local Interfaces ──────────────────────────────────────────────\n\ninterface KpiDisplayCard {\n Label: string;\n Value: string;\n SparklineData: number[];\n DeltaPercent: number;\n DeltaDirection: 'up' | 'down' | 'stable';\n IsImprovement: boolean;\n BorderColor: string;\n}\n\ninterface TopConsumer {\n Rank: number;\n Type: 'agent' | 'prompt';\n Name: string;\n Cost: number;\n Proportion: number;\n}\n\ninterface ErrorHotspot {\n Source: string;\n ErrorMessage: string;\n Count: number;\n}\n\n// ─── Component ─────────────────────────────────────────────────────\n\n@Component({\n standalone: false,\n selector: 'app-analytics-executive-summary',\n template: `\n <!-- Filter Bar -->\n <app-analytics-filter-bar\n [TimeRange]=\"TimeRange\"\n [Filters]=\"Filters\"\n [ShowCompareToggle]=\"true\"\n [ShowModelFilter]=\"false\"\n [ShowAgentFilter]=\"false\"\n [ShowPromptFilter]=\"false\"\n [ShowStatusFilter]=\"false\"\n (TimeRangeChange)=\"OnTimeRangeChange($event)\"\n (FiltersChange)=\"OnFiltersChange($event)\"\n (CompareToggled)=\"OnCompareToggled($event)\"\n ></app-analytics-filter-bar>\n\n @if (IsLoading && KpiCards.length === 0) {\n <div class=\"loading-container\">\n <mj-loading text=\"Loading executive summary...\" size=\"medium\"></mj-loading>\n </div>\n }\n\n <!-- KPI Row -->\n <div class=\"kpi-row\">\n @for (card of KpiCards; track card.Label) {\n <div class=\"kpi-card\" [style.border-left-color]=\"card.BorderColor\">\n <div class=\"kpi-label\">{{ card.Label }}</div>\n <div class=\"kpi-value\">{{ card.Value }}</div>\n <div class=\"kpi-sparkline\">\n @for (bar of card.SparklineData; track $index) {\n <div\n class=\"spark-bar\"\n [style.height.%]=\"bar\"\n [style.background]=\"card.BorderColor\"\n ></div>\n }\n </div>\n @if (ComparisonEnabled && card.DeltaDirection !== 'stable') {\n <div class=\"kpi-delta\" [class.kpi-delta--good]=\"card.IsImprovement\" [class.kpi-delta--bad]=\"!card.IsImprovement\">\n <i [class]=\"card.DeltaDirection === 'up' ? 'fa-solid fa-arrow-up' : 'fa-solid fa-arrow-down'\"></i>\n {{ card.DeltaPercent | number:'1.1-1' }}%\n <span class=\"kpi-delta__period\">vs prev {{ PeriodLabel }}</span>\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Execution Trends Chart -->\n <div class=\"trends-panel\">\n <app-time-series-chart\n [data]=\"TrendsData\"\n title=\"Execution Trends\"\n [config]=\"TimeSeriesConfig\"\n ></app-time-series-chart>\n </div>\n\n <!-- Two-Column Panels -->\n <div class=\"panels-grid\">\n <!-- Top Consumers -->\n <div class=\"panel\">\n <div class=\"panel-header\">\n <div class=\"panel-header__title\">\n <i class=\"fa-solid fa-ranking-star panel-header__icon\"></i>\n Top Consumers\n </div>\n <span class=\"panel-header__subtitle\">by cost</span>\n </div>\n <div class=\"panel-body\">\n @if (TopConsumers.length === 0) {\n <div class=\"panel-empty\">No data for selected period</div>\n }\n @for (item of TopConsumers; track item.Name) {\n <div\n class=\"consumer-item\"\n (click)=\"OnConsumerClick(item)\"\n role=\"button\"\n tabindex=\"0\"\n (keydown.enter)=\"OnConsumerClick(item)\"\n >\n <div\n class=\"consumer-rank\"\n [class.consumer-rank--top]=\"item.Rank <= 3\"\n >{{ item.Rank }}</div>\n <div\n class=\"consumer-type-pill\"\n [class.consumer-type-pill--agent]=\"item.Type === 'agent'\"\n >{{ item.Type }}</div>\n <div class=\"consumer-name\" [title]=\"item.Name\">{{ item.Name }}</div>\n <div class=\"consumer-cost\">\\${{ FormatCost(item.Cost) }}</div>\n <div class=\"consumer-bar-container\">\n <div\n class=\"consumer-bar\"\n [style.width.%]=\"item.Proportion * 100\"\n ></div>\n </div>\n </div>\n }\n </div>\n </div>\n\n <!-- Error Hotspots -->\n <div class=\"panel\">\n <div class=\"panel-header\">\n <div class=\"panel-header__title\">\n <i class=\"fa-solid fa-triangle-exclamation panel-header__icon panel-header__icon--error\"></i>\n Error Hotspots\n </div>\n <span class=\"panel-header__subtitle\">\n {{ ErrorHotspots.length }} source{{ ErrorHotspots.length !== 1 ? 's' : '' }}\n </span>\n </div>\n <div class=\"panel-body\">\n @if (ErrorHotspots.length === 0) {\n <div class=\"panel-empty\">No errors in selected period</div>\n }\n @for (item of ErrorHotspots; track item.Source) {\n <div class=\"error-item\">\n <div class=\"error-icon\">\n <i class=\"fa-solid fa-circle-exclamation\"></i>\n </div>\n <div class=\"error-info\">\n <div class=\"error-source\">{{ item.Source }}</div>\n <div class=\"error-message\" [title]=\"item.ErrorMessage\">{{ item.ErrorMessage }}</div>\n </div>\n <div class=\"error-count\">{{ item.Count }}</div>\n </div>\n }\n @if (ErrorHotspots.length > 0) {\n <button class=\"view-all-link\" (click)=\"SectionNavigate.emit('error-analysis')\">\n View All Errors <i class=\"fa-solid fa-arrow-right\"></i>\n </button>\n }\n </div>\n </div>\n </div>\n `,\n styles: [`\n /* ─── Host ────────────────────────────────────────────────── */\n :host {\n display: flex;\n flex-direction: column;\n gap: 20px;\n padding: 4px;\n }\n\n /* ─── Loading ─────────────────────────────────────────────── */\n .loading-container {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 60px 20px;\n }\n\n /* ─── KPI Row ─────────────────────────────────────────────── */\n .kpi-row {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));\n gap: 14px;\n }\n .kpi-card {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-left: 4px solid var(--mj-brand-primary);\n border-radius: 12px;\n padding: 16px 18px;\n display: flex;\n flex-direction: column;\n gap: 6px;\n transition: all 0.25s ease;\n }\n .kpi-card:hover {\n transform: translateY(-2px);\n box-shadow: 0 6px 20px color-mix(in srgb, var(--mj-text-primary) 8%, transparent);\n }\n .kpi-label {\n font-size: 10px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.6px;\n color: var(--mj-text-muted);\n }\n .kpi-value {\n font-size: 24px;\n font-weight: 700;\n color: var(--mj-text-primary);\n line-height: 1.1;\n letter-spacing: -0.02em;\n }\n\n /* ─── Sparkline ───────────────────────────────────────────── */\n .kpi-sparkline {\n display: flex;\n align-items: flex-end;\n gap: 2px;\n height: 24px;\n margin-top: 4px;\n }\n .spark-bar {\n flex: 1;\n min-width: 4px;\n max-width: 8px;\n border-radius: 1px;\n opacity: 0.35;\n transition: opacity 0.15s ease;\n }\n .kpi-card:hover .spark-bar {\n opacity: 0.55;\n }\n\n /* ─── Delta Badge ─────────────────────────────────────────── */\n .kpi-delta {\n display: flex;\n align-items: center;\n gap: 4px;\n font-size: 11px;\n font-weight: 600;\n margin-top: 2px;\n }\n .kpi-delta--good {\n color: var(--mj-status-success);\n }\n .kpi-delta--bad {\n color: var(--mj-status-error);\n }\n .kpi-delta__period {\n font-weight: 400;\n color: var(--mj-text-disabled);\n }\n\n /* ─── Trends Panel ────────────────────────────────────────── */\n .trends-panel {\n height: 320px;\n border-radius: 12px;\n overflow: hidden;\n }\n\n /* ─── Panels Grid ─────────────────────────────────────────── */\n .panels-grid {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 16px;\n }\n .panel {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n overflow: hidden;\n }\n .panel-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 14px 18px;\n border-bottom: 1px solid var(--mj-border-subtle);\n }\n .panel-header__title {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n }\n .panel-header__icon {\n color: var(--mj-brand-primary);\n font-size: 14px;\n }\n .panel-header__icon--error {\n color: var(--mj-status-warning);\n }\n .panel-header__subtitle {\n font-size: 12px;\n color: var(--mj-text-muted);\n }\n .panel-body {\n padding: 8px 0;\n }\n .panel-empty {\n padding: 24px 18px;\n text-align: center;\n font-size: 13px;\n color: var(--mj-text-disabled);\n }\n\n /* ─── Consumer Item ───────────────────────────────────────── */\n .consumer-item {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 10px 18px;\n cursor: pointer;\n transition: background 0.15s ease;\n }\n .consumer-item:hover {\n background: var(--mj-bg-surface-hover);\n }\n .consumer-rank {\n width: 22px;\n height: 22px;\n border-radius: 6px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 11px;\n font-weight: 700;\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-muted);\n flex-shrink: 0;\n }\n .consumer-rank--top {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n }\n .consumer-type-pill {\n font-size: 10px;\n font-weight: 600;\n text-transform: uppercase;\n padding: 2px 8px;\n border-radius: 4px;\n background: color-mix(in srgb, var(--mj-status-info) 12%, var(--mj-bg-surface));\n color: var(--mj-status-info);\n flex-shrink: 0;\n }\n .consumer-type-pill--agent {\n background: color-mix(in srgb, var(--mj-status-success) 12%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n }\n .consumer-name {\n flex: 1;\n font-size: 13px;\n font-weight: 500;\n color: var(--mj-text-primary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n .consumer-cost {\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n flex-shrink: 0;\n }\n .consumer-bar-container {\n width: 60px;\n height: 6px;\n border-radius: 3px;\n background: var(--mj-bg-surface-sunken);\n overflow: hidden;\n flex-shrink: 0;\n }\n .consumer-bar {\n height: 100%;\n border-radius: 3px;\n background: var(--mj-brand-primary);\n transition: width 0.3s ease;\n }\n\n /* ─── Error Item ──────────────────────────────────────────── */\n .error-item {\n display: flex;\n align-items: flex-start;\n gap: 10px;\n padding: 10px 18px;\n }\n .error-icon {\n color: var(--mj-status-error);\n font-size: 14px;\n margin-top: 2px;\n flex-shrink: 0;\n }\n .error-info {\n flex: 1;\n min-width: 0;\n }\n .error-source {\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin-bottom: 2px;\n }\n .error-message {\n font-size: 12px;\n color: var(--mj-text-muted);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n .error-count {\n font-size: 13px;\n font-weight: 700;\n color: var(--mj-status-error);\n flex-shrink: 0;\n min-width: 28px;\n height: 28px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 8px;\n background: color-mix(in srgb, var(--mj-status-error) 10%, var(--mj-bg-surface));\n }\n .view-all-link {\n display: flex;\n align-items: center;\n gap: 6px;\n margin: 8px 18px 10px;\n padding: 0;\n border: none;\n background: none;\n font-size: 12px;\n font-weight: 600;\n color: var(--mj-brand-primary);\n cursor: pointer;\n transition: color 0.15s ease;\n }\n .view-all-link:hover {\n color: var(--mj-brand-primary-hover);\n }\n\n /* ─── Responsive ──────────────────────────────────────────── */\n @media (max-width: 1200px) {\n .panels-grid {\n grid-template-columns: 1fr;\n }\n }\n @media (max-width: 768px) {\n .kpi-row {\n grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));\n }\n .trends-panel {\n height: 260px;\n }\n }\n `]\n})\nexport class AnalyticsExecutiveSummaryComponent implements OnInit, OnDestroy {\n // ─── Inputs / Outputs ────────────────────────────────────────────\n\n private _timeRange = '24h';\n @Input()\n set TimeRange(value: string) {\n if (value !== this._timeRange) {\n this._timeRange = value;\n if (this.isInitialized) {\n this.applyDateRange();\n }\n }\n }\n get TimeRange(): string { return this._timeRange; }\n\n @Input() Filters: GlobalFilterState = { Models: [], Agents: [], Prompts: [], Statuses: [] };\n\n @Output() TimeRangeChange = new EventEmitter<string>();\n @Output() FiltersChange = new EventEmitter<GlobalFilterState>();\n @Output() SectionNavigate = new EventEmitter<string>();\n\n // ─── DI ──────────────────────────────────────────────────────────\n\n private instrumentationService = inject(AIInstrumentationService);\n private cdr = inject(ChangeDetectorRef);\n\n // ─── Public State ────────────────────────────────────────────────\n\n KpiCards: KpiDisplayCard[] = [];\n TrendsData: TrendData[] = [];\n TopConsumers: TopConsumer[] = [];\n ErrorHotspots: ErrorHotspot[] = [];\n IsLoading = false;\n ComparisonEnabled = false;\n PeriodLabel = 'period';\n\n TimeSeriesConfig: TimeSeriesConfig = {\n showGrid: true,\n showTooltip: true,\n animationDuration: 300,\n useDualAxis: true\n };\n\n // ─── Private State ───────────────────────────────────────────────\n\n private destroy$ = new Subject<void>();\n private isInitialized = false;\n private previousKpis: DashboardKPIs | null = null;\n\n // ─── Lifecycle ───────────────────────────────────────────────────\n\n ngOnInit(): void {\n this.subscribeToStreams();\n this.applyDateRange();\n this.isInitialized = true;\n }\n\n ngOnDestroy(): void {\n this.destroy$.next();\n this.destroy$.complete();\n }\n\n // ─── Event Handlers ──────────────────────────────────────────────\n\n OnTimeRangeChange(range: string): void {\n this.TimeRange = range;\n this.TimeRangeChange.emit(range);\n }\n\n OnFiltersChange(filters: GlobalFilterState): void {\n this.Filters = filters;\n this.FiltersChange.emit(filters);\n }\n\n OnCompareToggled(active: boolean): void {\n this.ComparisonEnabled = active;\n if (this.ComparisonEnabled) {\n this.loadComparisonData();\n } else {\n this.previousKpis = null;\n this.rebuildKpiCards(this.latestKpis);\n }\n }\n\n OnRefresh(): void {\n this.instrumentationService.refresh();\n if (this.ComparisonEnabled) {\n this.loadComparisonData();\n }\n }\n\n OnConsumerClick(item: TopConsumer): void {\n this.SectionNavigate.emit(item.Type === 'agent' ? 'agent-runs' : 'prompt-runs');\n }\n\n // ─── Formatting Helpers ──────────────────────────────────────────\n\n FormatCost(cost: number): string {\n if (cost >= 1000) {\n return (cost / 1000).toFixed(1) + 'K';\n }\n if (cost >= 1) {\n return cost.toFixed(2);\n }\n return cost.toFixed(4);\n }\n\n // ─── Private: Subscriptions ──────────────────────────────────────\n\n private latestKpis: DashboardKPIs | null = null;\n\n private subscribeToStreams(): void {\n this.instrumentationService.isLoading$\n .pipe(takeUntil(this.destroy$))\n .subscribe(loading => {\n this.IsLoading = loading;\n this.cdr.markForCheck();\n });\n\n this.instrumentationService.kpis$\n .pipe(takeUntil(this.destroy$))\n .subscribe(kpis => {\n this.latestKpis = kpis;\n this.rebuildKpiCards(kpis);\n this.cdr.markForCheck();\n });\n\n this.instrumentationService.trends$\n .pipe(takeUntil(this.destroy$))\n .subscribe(trends => {\n this.TrendsData = trends;\n this.cdr.markForCheck();\n });\n\n this.instrumentationService.chartData$\n .pipe(takeUntil(this.destroy$))\n .subscribe(chartData => {\n this.TopConsumers = this.buildTopConsumers(chartData);\n this.ErrorHotspots = this.buildErrorHotspots(chartData);\n this.cdr.markForCheck();\n });\n }\n\n // ─── Private: Date Range ─────────────────────────────────────────\n\n private applyDateRange(): void {\n const { start, end } = this.computeDateRange(this.TimeRange);\n this.PeriodLabel = this.getPeriodLabel(this.TimeRange);\n this.instrumentationService.setDateRange(start, end);\n // Explicitly refresh to ensure data loads on first visit\n this.instrumentationService.refresh();\n }\n\n private computeDateRange(range: string): { start: Date; end: Date } {\n const end = new Date();\n const start = new Date();\n switch (range) {\n case '1h':\n start.setHours(start.getHours() - 1);\n break;\n case '24h':\n start.setDate(start.getDate() - 1);\n break;\n case '7d':\n start.setDate(start.getDate() - 7);\n break;\n case '30d':\n start.setDate(start.getDate() - 30);\n break;\n case '90d':\n start.setDate(start.getDate() - 90);\n break;\n default:\n start.setDate(start.getDate() - 1);\n }\n return { start, end };\n }\n\n private getPeriodLabel(range: string): string {\n switch (range) {\n case '1h': return 'hour';\n case '24h': return 'day';\n case '7d': return 'week';\n case '30d': return 'month';\n case '90d': return 'quarter';\n default: return 'period';\n }\n }\n\n // ─── Private: Comparison Data ────────────────────────────────────\n\n private async loadComparisonData(): Promise<void> {\n const { start: currentStart, end: currentEnd } = this.computeDateRange(this.TimeRange);\n const durationMs = currentEnd.getTime() - currentStart.getTime();\n const prevEnd = new Date(currentStart.getTime());\n const prevStart = new Date(prevEnd.getTime() - durationMs);\n\n // Temporarily set date range to previous period, capture KPIs, then restore\n const previousService = new AIInstrumentationService();\n previousService.setDateRange(prevStart, prevEnd);\n\n // We subscribe to the previousService's kpis$ once\n const sub: Subscription = previousService.kpis$\n .pipe(takeUntil(this.destroy$))\n .subscribe(kpis => {\n this.previousKpis = kpis;\n this.rebuildKpiCards(this.latestKpis);\n this.cdr.markForCheck();\n sub.unsubscribe();\n });\n }\n\n // ─── Private: KPI Card Builder ───────────────────────────────────\n\n private rebuildKpiCards(kpis: DashboardKPIs | null): void {\n if (!kpis) {\n this.KpiCards = [];\n return;\n }\n\n const trends = this.TrendsData;\n this.KpiCards = [\n this.buildKpiCard(\n 'Total Executions', this.formatNumber(kpis.totalExecutions),\n this.extractSparkline(trends, 'executions'),\n kpis.totalExecutions, this.previousKpis?.totalExecutions ?? null,\n 'up-is-neutral', 'var(--mj-brand-primary)'\n ),\n this.buildKpiCard(\n 'Total Cost', '$' + this.FormatCost(kpis.totalCost),\n this.extractSparkline(trends, 'cost'),\n kpis.totalCost, this.previousKpis?.totalCost ?? null,\n 'down-is-good', 'var(--mj-status-warning)'\n ),\n this.buildKpiCard(\n 'Success Rate', (kpis.successRate * 100).toFixed(1) + '%',\n this.extractSparkline(trends, 'executions'),\n kpis.successRate, this.previousKpis?.successRate ?? null,\n 'up-is-good', 'var(--mj-status-success)'\n ),\n this.buildKpiCard(\n 'Avg Latency', this.formatLatency(kpis.avgExecutionTime),\n this.extractSparkline(trends, 'avgTime'),\n kpis.avgExecutionTime, this.previousKpis?.avgExecutionTime ?? null,\n 'down-is-good', 'var(--mj-status-info)'\n ),\n this.buildKpiCard(\n 'Token Usage', this.formatNumber(kpis.totalTokens),\n this.extractSparkline(trends, 'tokens'),\n kpis.totalTokens, this.previousKpis?.totalTokens ?? null,\n 'up-is-neutral', 'var(--mj-brand-accent, var(--mj-brand-primary))'\n ),\n this.buildKpiCard(\n 'Errors', this.formatNumber(Math.round(kpis.errorRate * kpis.totalExecutions)),\n this.extractSparkline(trends, 'errors'),\n kpis.errorRate, this.previousKpis?.errorRate ?? null,\n 'down-is-good', 'var(--mj-status-error)'\n )\n ];\n }\n\n private buildKpiCard(\n label: string,\n value: string,\n sparkline: number[],\n current: number,\n previous: number | null,\n goodDirection: 'up-is-good' | 'down-is-good' | 'up-is-neutral',\n borderColor: string\n ): KpiDisplayCard {\n const { percent, direction } = this.computeDelta(current, previous);\n const isImprovement = this.isDirectionGood(direction, goodDirection);\n\n return {\n Label: label,\n Value: value,\n SparklineData: sparkline,\n DeltaPercent: percent,\n DeltaDirection: direction,\n IsImprovement: isImprovement,\n BorderColor: borderColor\n };\n }\n\n private computeDelta(current: number, previous: number | null): { percent: number; direction: 'up' | 'down' | 'stable' } {\n if (previous == null || previous === 0) {\n return { percent: 0, direction: 'stable' };\n }\n const change = ((current - previous) / previous) * 100;\n if (Math.abs(change) < 0.5) {\n return { percent: 0, direction: 'stable' };\n }\n return {\n percent: Math.abs(change),\n direction: change > 0 ? 'up' : 'down'\n };\n }\n\n private isDirectionGood(direction: 'up' | 'down' | 'stable', rule: 'up-is-good' | 'down-is-good' | 'up-is-neutral'): boolean {\n if (direction === 'stable') return true;\n if (rule === 'up-is-good') return direction === 'up';\n if (rule === 'down-is-good') return direction === 'down';\n return true; // neutral\n }\n\n // ─── Private: Sparkline ──────────────────────────────────────────\n\n private extractSparkline(trends: TrendData[], metric: 'executions' | 'cost' | 'tokens' | 'avgTime' | 'errors'): number[] {\n if (!trends || trends.length === 0) {\n return [20, 40, 30, 60, 50, 70, 45]; // placeholder\n }\n\n // Sample up to 7 evenly-spaced points\n const step = Math.max(1, Math.floor(trends.length / 7));\n const sampled: number[] = [];\n for (let i = 0; i < trends.length && sampled.length < 7; i += step) {\n sampled.push(this.getMetricFromTrend(trends[i], metric));\n }\n\n // Normalize to 0-100 percentage\n const maxVal = Math.max(...sampled, 1);\n return sampled.map(v => Math.max(5, (v / maxVal) * 100));\n }\n\n private getMetricFromTrend(trend: TrendData, metric: 'executions' | 'cost' | 'tokens' | 'avgTime' | 'errors'): number {\n switch (metric) {\n case 'executions': return trend.executions;\n case 'cost': return trend.cost;\n case 'tokens': return trend.tokens;\n case 'avgTime': return trend.avgTime;\n case 'errors': return trend.errors;\n }\n }\n\n // ─── Private: Top Consumers ──────────────────────────────────────\n\n private buildTopConsumers(chartData: ChartData): TopConsumer[] {\n const consumers: TopConsumer[] = [];\n const maxCost = Math.max(\n ...chartData.costByModel.map(m => m.cost),\n ...chartData.performanceMatrix.map(p => 1), // agents don't have cost here directly\n 1\n );\n\n // Add model-based consumers (from prompt runs)\n for (const model of chartData.costByModel.slice(0, 5)) {\n consumers.push({\n Rank: 0,\n Type: 'prompt',\n Name: model.model,\n Cost: model.cost,\n Proportion: 0\n });\n }\n\n // Sort by cost descending, assign ranks\n consumers.sort((a, b) => b.Cost - a.Cost);\n const topCost = consumers.length > 0 ? consumers[0].Cost : 1;\n return consumers.slice(0, 5).map((c, i) => ({\n ...c,\n Rank: i + 1,\n Proportion: topCost > 0 ? c.Cost / topCost : 0\n }));\n }\n\n // ─── Private: Error Hotspots ─────────────────────────────────────\n // Error hotspots are computed reactively when KPIs change.\n // Since rawData$ is private on the service, we compute from the\n // kpis errorRate + totalExecutions, and rely on chartData for names.\n // For a richer implementation, the service could expose an errors$ stream.\n // For now, we derive from chartData.performanceMatrix entries with low successRate.\n\n private buildErrorHotspots(chartData: ChartData): ErrorHotspot[] {\n const hotspots: ErrorHotspot[] = [];\n\n for (const entry of chartData.performanceMatrix) {\n if (entry.successRate < 1.0) {\n const errorCount = Math.round((1 - entry.successRate) * 10); // approximate\n hotspots.push({\n Source: `${entry.agent} / ${entry.model}`,\n ErrorMessage: `${((1 - entry.successRate) * 100).toFixed(0)}% failure rate (avg ${(entry.avgTime / 1000).toFixed(1)}s)`,\n Count: errorCount\n });\n }\n }\n\n return hotspots\n .sort((a, b) => b.Count - a.Count)\n .slice(0, 4);\n }\n\n // ─── Private: Formatting ─────────────────────────────────────────\n\n private formatNumber(value: number): string {\n if (value >= 1_000_000) return (value / 1_000_000).toFixed(1) + 'M';\n if (value >= 1_000) return (value / 1_000).toFixed(1) + 'K';\n return value.toLocaleString();\n }\n\n private formatLatency(ms: number): string {\n if (ms >= 60_000) return (ms / 60_000).toFixed(1) + 'm';\n if (ms >= 1_000) return (ms / 1_000).toFixed(1) + 's';\n return Math.round(ms) + 'ms';\n }\n}\n\nexport function LoadAnalyticsExecutiveSummary() {\n // Prevents tree-shaking\n}\n"]}
1
+ {"version":3,"file":"executive-summary.component.js","sourceRoot":"","sources":["../../../../../src/AI/components/analytics/executive-summary/executive-summary.component.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Component, Input, Output, EventEmitter, OnInit, OnDestroy,\n ChangeDetectorRef, inject\n} from '@angular/core';\nimport { Subject, Subscription } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport {\n AIInstrumentationService,\n DashboardKPIs,\n TrendData,\n ChartData\n} from '../../../services/ai-instrumentation.service';\nimport { GlobalFilterState } from '../../../interfaces/analytics-preferences.interface';\nimport { TimeSeriesConfig } from '../../charts/time-series-chart.component';\nimport { BaseAngularComponent } from '@memberjunction/ng-base-types';\n\n// ─── Local Interfaces ──────────────────────────────────────────────\n\ninterface KpiDisplayCard {\n Label: string;\n Value: string;\n SparklineData: number[];\n DeltaPercent: number;\n DeltaDirection: 'up' | 'down' | 'stable';\n IsImprovement: boolean;\n BorderColor: string;\n}\n\ninterface TopConsumer {\n Rank: number;\n Type: 'agent' | 'prompt';\n Name: string;\n Cost: number;\n Proportion: number;\n}\n\ninterface ErrorHotspot {\n Source: string;\n ErrorMessage: string;\n Count: number;\n}\n\n// ─── Component ─────────────────────────────────────────────────────\n\n@Component({\n standalone: false,\n selector: 'app-analytics-executive-summary',\n template: `\n <!-- Filter Bar -->\n <app-analytics-filter-bar\n [TimeRange]=\"TimeRange\"\n [Filters]=\"Filters\"\n [ShowCompareToggle]=\"true\"\n [ShowModelFilter]=\"false\"\n [ShowAgentFilter]=\"false\"\n [ShowPromptFilter]=\"false\"\n [ShowStatusFilter]=\"false\"\n (TimeRangeChange)=\"OnTimeRangeChange($event)\"\n (FiltersChange)=\"OnFiltersChange($event)\"\n (CompareToggled)=\"OnCompareToggled($event)\"\n ></app-analytics-filter-bar>\n\n @if (IsLoading && KpiCards.length === 0) {\n <div class=\"loading-container\">\n <mj-loading text=\"Loading executive summary...\" size=\"medium\"></mj-loading>\n </div>\n }\n\n <!-- KPI Row -->\n <div class=\"kpi-row\">\n @for (card of KpiCards; track card.Label) {\n <div class=\"kpi-card\" [style.border-left-color]=\"card.BorderColor\">\n <div class=\"kpi-label\">{{ card.Label }}</div>\n <div class=\"kpi-value\">{{ card.Value }}</div>\n <div class=\"kpi-sparkline\">\n @for (bar of card.SparklineData; track $index) {\n <div\n class=\"spark-bar\"\n [style.height.%]=\"bar\"\n [style.background]=\"card.BorderColor\"\n ></div>\n }\n </div>\n @if (ComparisonEnabled && card.DeltaDirection !== 'stable') {\n <div class=\"kpi-delta\" [class.kpi-delta--good]=\"card.IsImprovement\" [class.kpi-delta--bad]=\"!card.IsImprovement\">\n <i [class]=\"card.DeltaDirection === 'up' ? 'fa-solid fa-arrow-up' : 'fa-solid fa-arrow-down'\"></i>\n {{ card.DeltaPercent | number:'1.1-1' }}%\n <span class=\"kpi-delta__period\">vs prev {{ PeriodLabel }}</span>\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Execution Trends Chart -->\n <div class=\"trends-panel\">\n <app-time-series-chart\n [data]=\"TrendsData\"\n title=\"Execution Trends\"\n [config]=\"TimeSeriesConfig\"\n ></app-time-series-chart>\n </div>\n\n <!-- Two-Column Panels -->\n <div class=\"panels-grid\">\n <!-- Top Consumers -->\n <div class=\"panel\">\n <div class=\"panel-header\">\n <div class=\"panel-header__title\">\n <i class=\"fa-solid fa-ranking-star panel-header__icon\"></i>\n Top Consumers\n </div>\n <span class=\"panel-header__subtitle\">by cost</span>\n </div>\n <div class=\"panel-body\">\n @if (TopConsumers.length === 0) {\n <div class=\"panel-empty\">No data for selected period</div>\n }\n @for (item of TopConsumers; track item.Name) {\n <div\n class=\"consumer-item\"\n (click)=\"OnConsumerClick(item)\"\n role=\"button\"\n tabindex=\"0\"\n (keydown.enter)=\"OnConsumerClick(item)\"\n >\n <div\n class=\"consumer-rank\"\n [class.consumer-rank--top]=\"item.Rank <= 3\"\n >{{ item.Rank }}</div>\n <div\n class=\"consumer-type-pill\"\n [class.consumer-type-pill--agent]=\"item.Type === 'agent'\"\n >{{ item.Type }}</div>\n <div class=\"consumer-name\" [title]=\"item.Name\">{{ item.Name }}</div>\n <div class=\"consumer-cost\">\\${{ FormatCost(item.Cost) }}</div>\n <div class=\"consumer-bar-container\">\n <div\n class=\"consumer-bar\"\n [style.width.%]=\"item.Proportion * 100\"\n ></div>\n </div>\n </div>\n }\n </div>\n </div>\n\n <!-- Error Hotspots -->\n <div class=\"panel\">\n <div class=\"panel-header\">\n <div class=\"panel-header__title\">\n <i class=\"fa-solid fa-triangle-exclamation panel-header__icon panel-header__icon--error\"></i>\n Error Hotspots\n </div>\n <span class=\"panel-header__subtitle\">\n {{ ErrorHotspots.length }} source{{ ErrorHotspots.length !== 1 ? 's' : '' }}\n </span>\n </div>\n <div class=\"panel-body\">\n @if (ErrorHotspots.length === 0) {\n <div class=\"panel-empty\">No errors in selected period</div>\n }\n @for (item of ErrorHotspots; track item.Source) {\n <div class=\"error-item\">\n <div class=\"error-icon\">\n <i class=\"fa-solid fa-circle-exclamation\"></i>\n </div>\n <div class=\"error-info\">\n <div class=\"error-source\">{{ item.Source }}</div>\n <div class=\"error-message\" [title]=\"item.ErrorMessage\">{{ item.ErrorMessage }}</div>\n </div>\n <div class=\"error-count\">{{ item.Count }}</div>\n </div>\n }\n @if (ErrorHotspots.length > 0) {\n <button class=\"view-all-link\" (click)=\"SectionNavigate.emit('error-analysis')\">\n View All Errors <i class=\"fa-solid fa-arrow-right\"></i>\n </button>\n }\n </div>\n </div>\n </div>\n `,\n styles: [`\n /* ─── Host ────────────────────────────────────────────────── */\n :host {\n display: flex;\n flex-direction: column;\n gap: 20px;\n padding: 4px;\n }\n\n /* ─── Loading ─────────────────────────────────────────────── */\n .loading-container {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 60px 20px;\n }\n\n /* ─── KPI Row ─────────────────────────────────────────────── */\n .kpi-row {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));\n gap: 14px;\n }\n .kpi-card {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-left: 4px solid var(--mj-brand-primary);\n border-radius: 12px;\n padding: 16px 18px;\n display: flex;\n flex-direction: column;\n gap: 6px;\n transition: all 0.25s ease;\n }\n .kpi-card:hover {\n transform: translateY(-2px);\n box-shadow: 0 6px 20px color-mix(in srgb, var(--mj-text-primary) 8%, transparent);\n }\n .kpi-label {\n font-size: 10px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.6px;\n color: var(--mj-text-muted);\n }\n .kpi-value {\n font-size: 24px;\n font-weight: 700;\n color: var(--mj-text-primary);\n line-height: 1.1;\n letter-spacing: -0.02em;\n }\n\n /* ─── Sparkline ───────────────────────────────────────────── */\n .kpi-sparkline {\n display: flex;\n align-items: flex-end;\n gap: 2px;\n height: 24px;\n margin-top: 4px;\n }\n .spark-bar {\n flex: 1;\n min-width: 4px;\n max-width: 8px;\n border-radius: 1px;\n opacity: 0.35;\n transition: opacity 0.15s ease;\n }\n .kpi-card:hover .spark-bar {\n opacity: 0.55;\n }\n\n /* ─── Delta Badge ─────────────────────────────────────────── */\n .kpi-delta {\n display: flex;\n align-items: center;\n gap: 4px;\n font-size: 11px;\n font-weight: 600;\n margin-top: 2px;\n }\n .kpi-delta--good {\n color: var(--mj-status-success);\n }\n .kpi-delta--bad {\n color: var(--mj-status-error);\n }\n .kpi-delta__period {\n font-weight: 400;\n color: var(--mj-text-disabled);\n }\n\n /* ─── Trends Panel ────────────────────────────────────────── */\n .trends-panel {\n height: 320px;\n border-radius: 12px;\n overflow: hidden;\n }\n\n /* ─── Panels Grid ─────────────────────────────────────────── */\n .panels-grid {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 16px;\n }\n .panel {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n overflow: hidden;\n }\n .panel-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 14px 18px;\n border-bottom: 1px solid var(--mj-border-subtle);\n }\n .panel-header__title {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n }\n .panel-header__icon {\n color: var(--mj-brand-primary);\n font-size: 14px;\n }\n .panel-header__icon--error {\n color: var(--mj-status-warning);\n }\n .panel-header__subtitle {\n font-size: 12px;\n color: var(--mj-text-muted);\n }\n .panel-body {\n padding: 8px 0;\n }\n .panel-empty {\n padding: 24px 18px;\n text-align: center;\n font-size: 13px;\n color: var(--mj-text-disabled);\n }\n\n /* ─── Consumer Item ───────────────────────────────────────── */\n .consumer-item {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 10px 18px;\n cursor: pointer;\n transition: background 0.15s ease;\n }\n .consumer-item:hover {\n background: var(--mj-bg-surface-hover);\n }\n .consumer-rank {\n width: 22px;\n height: 22px;\n border-radius: 6px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 11px;\n font-weight: 700;\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-muted);\n flex-shrink: 0;\n }\n .consumer-rank--top {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n }\n .consumer-type-pill {\n font-size: 10px;\n font-weight: 600;\n text-transform: uppercase;\n padding: 2px 8px;\n border-radius: 4px;\n background: color-mix(in srgb, var(--mj-status-info) 12%, var(--mj-bg-surface));\n color: var(--mj-status-info);\n flex-shrink: 0;\n }\n .consumer-type-pill--agent {\n background: color-mix(in srgb, var(--mj-status-success) 12%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n }\n .consumer-name {\n flex: 1;\n font-size: 13px;\n font-weight: 500;\n color: var(--mj-text-primary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n .consumer-cost {\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n flex-shrink: 0;\n }\n .consumer-bar-container {\n width: 60px;\n height: 6px;\n border-radius: 3px;\n background: var(--mj-bg-surface-sunken);\n overflow: hidden;\n flex-shrink: 0;\n }\n .consumer-bar {\n height: 100%;\n border-radius: 3px;\n background: var(--mj-brand-primary);\n transition: width 0.3s ease;\n }\n\n /* ─── Error Item ──────────────────────────────────────────── */\n .error-item {\n display: flex;\n align-items: flex-start;\n gap: 10px;\n padding: 10px 18px;\n }\n .error-icon {\n color: var(--mj-status-error);\n font-size: 14px;\n margin-top: 2px;\n flex-shrink: 0;\n }\n .error-info {\n flex: 1;\n min-width: 0;\n }\n .error-source {\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin-bottom: 2px;\n }\n .error-message {\n font-size: 12px;\n color: var(--mj-text-muted);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n .error-count {\n font-size: 13px;\n font-weight: 700;\n color: var(--mj-status-error);\n flex-shrink: 0;\n min-width: 28px;\n height: 28px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 8px;\n background: color-mix(in srgb, var(--mj-status-error) 10%, var(--mj-bg-surface));\n }\n .view-all-link {\n display: flex;\n align-items: center;\n gap: 6px;\n margin: 8px 18px 10px;\n padding: 0;\n border: none;\n background: none;\n font-size: 12px;\n font-weight: 600;\n color: var(--mj-brand-primary);\n cursor: pointer;\n transition: color 0.15s ease;\n }\n .view-all-link:hover {\n color: var(--mj-brand-primary-hover);\n }\n\n /* ─── Responsive ──────────────────────────────────────────── */\n @media (max-width: 1200px) {\n .panels-grid {\n grid-template-columns: 1fr;\n }\n }\n @media (max-width: 768px) {\n .kpi-row {\n grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));\n }\n .trends-panel {\n height: 260px;\n }\n }\n `]\n})\nexport class AnalyticsExecutiveSummaryComponent extends BaseAngularComponent implements OnInit, OnDestroy {\n // ─── Inputs / Outputs ────────────────────────────────────────────\n\n private _timeRange = '24h';\n @Input()\n set TimeRange(value: string) {\n if (value !== this._timeRange) {\n this._timeRange = value;\n if (this.isInitialized) {\n this.applyDateRange();\n }\n }\n }\n get TimeRange(): string { return this._timeRange; }\n\n @Input() Filters: GlobalFilterState = { Models: [], Agents: [], Prompts: [], Statuses: [] };\n\n @Output() TimeRangeChange = new EventEmitter<string>();\n @Output() FiltersChange = new EventEmitter<GlobalFilterState>();\n @Output() SectionNavigate = new EventEmitter<string>();\n\n // ─── DI ──────────────────────────────────────────────────────────\n\n private instrumentationService = inject(AIInstrumentationService);\n private cdr = inject(ChangeDetectorRef);\n\n // ─── Public State ────────────────────────────────────────────────\n\n KpiCards: KpiDisplayCard[] = [];\n TrendsData: TrendData[] = [];\n TopConsumers: TopConsumer[] = [];\n ErrorHotspots: ErrorHotspot[] = [];\n IsLoading = false;\n ComparisonEnabled = false;\n PeriodLabel = 'period';\n\n TimeSeriesConfig: TimeSeriesConfig = {\n showGrid: true,\n showTooltip: true,\n animationDuration: 300,\n useDualAxis: true\n };\n\n // ─── Private State ───────────────────────────────────────────────\n\n private destroy$ = new Subject<void>();\n private isInitialized = false;\n private previousKpis: DashboardKPIs | null = null;\n\n // ─── Lifecycle ───────────────────────────────────────────────────\n\n ngOnInit(): void {\n this.instrumentationService.Provider = this.ProviderToUse;\n this.subscribeToStreams();\n this.applyDateRange();\n this.isInitialized = true;\n }\n\n ngOnDestroy(): void {\n this.destroy$.next();\n this.destroy$.complete();\n }\n\n // ─── Event Handlers ──────────────────────────────────────────────\n\n OnTimeRangeChange(range: string): void {\n this.TimeRange = range;\n this.TimeRangeChange.emit(range);\n }\n\n OnFiltersChange(filters: GlobalFilterState): void {\n this.Filters = filters;\n this.FiltersChange.emit(filters);\n }\n\n OnCompareToggled(active: boolean): void {\n this.ComparisonEnabled = active;\n if (this.ComparisonEnabled) {\n this.loadComparisonData();\n } else {\n this.previousKpis = null;\n this.rebuildKpiCards(this.latestKpis);\n }\n }\n\n OnRefresh(): void {\n this.instrumentationService.refresh();\n if (this.ComparisonEnabled) {\n this.loadComparisonData();\n }\n }\n\n OnConsumerClick(item: TopConsumer): void {\n this.SectionNavigate.emit(item.Type === 'agent' ? 'agent-runs' : 'prompt-runs');\n }\n\n // ─── Formatting Helpers ──────────────────────────────────────────\n\n FormatCost(cost: number): string {\n if (cost >= 1000) {\n return (cost / 1000).toFixed(1) + 'K';\n }\n if (cost >= 1) {\n return cost.toFixed(2);\n }\n return cost.toFixed(4);\n }\n\n // ─── Private: Subscriptions ──────────────────────────────────────\n\n private latestKpis: DashboardKPIs | null = null;\n\n private subscribeToStreams(): void {\n this.instrumentationService.isLoading$\n .pipe(takeUntil(this.destroy$))\n .subscribe(loading => {\n this.IsLoading = loading;\n this.cdr.markForCheck();\n });\n\n this.instrumentationService.kpis$\n .pipe(takeUntil(this.destroy$))\n .subscribe(kpis => {\n this.latestKpis = kpis;\n this.rebuildKpiCards(kpis);\n this.cdr.markForCheck();\n });\n\n this.instrumentationService.trends$\n .pipe(takeUntil(this.destroy$))\n .subscribe(trends => {\n this.TrendsData = trends;\n this.cdr.markForCheck();\n });\n\n this.instrumentationService.chartData$\n .pipe(takeUntil(this.destroy$))\n .subscribe(chartData => {\n this.TopConsumers = this.buildTopConsumers(chartData);\n this.ErrorHotspots = this.buildErrorHotspots(chartData);\n this.cdr.markForCheck();\n });\n }\n\n // ─── Private: Date Range ─────────────────────────────────────────\n\n private applyDateRange(): void {\n const { start, end } = this.computeDateRange(this.TimeRange);\n this.PeriodLabel = this.getPeriodLabel(this.TimeRange);\n this.instrumentationService.setDateRange(start, end);\n // Explicitly refresh to ensure data loads on first visit\n this.instrumentationService.refresh();\n }\n\n private computeDateRange(range: string): { start: Date; end: Date } {\n const end = new Date();\n const start = new Date();\n switch (range) {\n case '1h':\n start.setHours(start.getHours() - 1);\n break;\n case '24h':\n start.setDate(start.getDate() - 1);\n break;\n case '7d':\n start.setDate(start.getDate() - 7);\n break;\n case '30d':\n start.setDate(start.getDate() - 30);\n break;\n case '90d':\n start.setDate(start.getDate() - 90);\n break;\n default:\n start.setDate(start.getDate() - 1);\n }\n return { start, end };\n }\n\n private getPeriodLabel(range: string): string {\n switch (range) {\n case '1h': return 'hour';\n case '24h': return 'day';\n case '7d': return 'week';\n case '30d': return 'month';\n case '90d': return 'quarter';\n default: return 'period';\n }\n }\n\n // ─── Private: Comparison Data ────────────────────────────────────\n\n private async loadComparisonData(): Promise<void> {\n const { start: currentStart, end: currentEnd } = this.computeDateRange(this.TimeRange);\n const durationMs = currentEnd.getTime() - currentStart.getTime();\n const prevEnd = new Date(currentStart.getTime());\n const prevStart = new Date(prevEnd.getTime() - durationMs);\n\n // Temporarily set date range to previous period, capture KPIs, then restore\n const previousService = new AIInstrumentationService();\n previousService.Provider = this.ProviderToUse;\n previousService.setDateRange(prevStart, prevEnd);\n\n // We subscribe to the previousService's kpis$ once\n const sub: Subscription = previousService.kpis$\n .pipe(takeUntil(this.destroy$))\n .subscribe(kpis => {\n this.previousKpis = kpis;\n this.rebuildKpiCards(this.latestKpis);\n this.cdr.markForCheck();\n sub.unsubscribe();\n });\n }\n\n // ─── Private: KPI Card Builder ───────────────────────────────────\n\n private rebuildKpiCards(kpis: DashboardKPIs | null): void {\n if (!kpis) {\n this.KpiCards = [];\n return;\n }\n\n const trends = this.TrendsData;\n this.KpiCards = [\n this.buildKpiCard(\n 'Total Executions', this.formatNumber(kpis.totalExecutions),\n this.extractSparkline(trends, 'executions'),\n kpis.totalExecutions, this.previousKpis?.totalExecutions ?? null,\n 'up-is-neutral', 'var(--mj-brand-primary)'\n ),\n this.buildKpiCard(\n 'Total Cost', '$' + this.FormatCost(kpis.totalCost),\n this.extractSparkline(trends, 'cost'),\n kpis.totalCost, this.previousKpis?.totalCost ?? null,\n 'down-is-good', 'var(--mj-status-warning)'\n ),\n this.buildKpiCard(\n 'Success Rate', (kpis.successRate * 100).toFixed(1) + '%',\n this.extractSparkline(trends, 'executions'),\n kpis.successRate, this.previousKpis?.successRate ?? null,\n 'up-is-good', 'var(--mj-status-success)'\n ),\n this.buildKpiCard(\n 'Avg Latency', this.formatLatency(kpis.avgExecutionTime),\n this.extractSparkline(trends, 'avgTime'),\n kpis.avgExecutionTime, this.previousKpis?.avgExecutionTime ?? null,\n 'down-is-good', 'var(--mj-status-info)'\n ),\n this.buildKpiCard(\n 'Token Usage', this.formatNumber(kpis.totalTokens),\n this.extractSparkline(trends, 'tokens'),\n kpis.totalTokens, this.previousKpis?.totalTokens ?? null,\n 'up-is-neutral', 'var(--mj-brand-accent, var(--mj-brand-primary))'\n ),\n this.buildKpiCard(\n 'Errors', this.formatNumber(Math.round(kpis.errorRate * kpis.totalExecutions)),\n this.extractSparkline(trends, 'errors'),\n kpis.errorRate, this.previousKpis?.errorRate ?? null,\n 'down-is-good', 'var(--mj-status-error)'\n )\n ];\n }\n\n private buildKpiCard(\n label: string,\n value: string,\n sparkline: number[],\n current: number,\n previous: number | null,\n goodDirection: 'up-is-good' | 'down-is-good' | 'up-is-neutral',\n borderColor: string\n ): KpiDisplayCard {\n const { percent, direction } = this.computeDelta(current, previous);\n const isImprovement = this.isDirectionGood(direction, goodDirection);\n\n return {\n Label: label,\n Value: value,\n SparklineData: sparkline,\n DeltaPercent: percent,\n DeltaDirection: direction,\n IsImprovement: isImprovement,\n BorderColor: borderColor\n };\n }\n\n private computeDelta(current: number, previous: number | null): { percent: number; direction: 'up' | 'down' | 'stable' } {\n if (previous == null || previous === 0) {\n return { percent: 0, direction: 'stable' };\n }\n const change = ((current - previous) / previous) * 100;\n if (Math.abs(change) < 0.5) {\n return { percent: 0, direction: 'stable' };\n }\n return {\n percent: Math.abs(change),\n direction: change > 0 ? 'up' : 'down'\n };\n }\n\n private isDirectionGood(direction: 'up' | 'down' | 'stable', rule: 'up-is-good' | 'down-is-good' | 'up-is-neutral'): boolean {\n if (direction === 'stable') return true;\n if (rule === 'up-is-good') return direction === 'up';\n if (rule === 'down-is-good') return direction === 'down';\n return true; // neutral\n }\n\n // ─── Private: Sparkline ──────────────────────────────────────────\n\n private extractSparkline(trends: TrendData[], metric: 'executions' | 'cost' | 'tokens' | 'avgTime' | 'errors'): number[] {\n if (!trends || trends.length === 0) {\n return [20, 40, 30, 60, 50, 70, 45]; // placeholder\n }\n\n // Sample up to 7 evenly-spaced points\n const step = Math.max(1, Math.floor(trends.length / 7));\n const sampled: number[] = [];\n for (let i = 0; i < trends.length && sampled.length < 7; i += step) {\n sampled.push(this.getMetricFromTrend(trends[i], metric));\n }\n\n // Normalize to 0-100 percentage\n const maxVal = Math.max(...sampled, 1);\n return sampled.map(v => Math.max(5, (v / maxVal) * 100));\n }\n\n private getMetricFromTrend(trend: TrendData, metric: 'executions' | 'cost' | 'tokens' | 'avgTime' | 'errors'): number {\n switch (metric) {\n case 'executions': return trend.executions;\n case 'cost': return trend.cost;\n case 'tokens': return trend.tokens;\n case 'avgTime': return trend.avgTime;\n case 'errors': return trend.errors;\n }\n }\n\n // ─── Private: Top Consumers ──────────────────────────────────────\n\n private buildTopConsumers(chartData: ChartData): TopConsumer[] {\n const consumers: TopConsumer[] = [];\n const maxCost = Math.max(\n ...chartData.costByModel.map(m => m.cost),\n ...chartData.performanceMatrix.map(p => 1), // agents don't have cost here directly\n 1\n );\n\n // Add model-based consumers (from prompt runs)\n for (const model of chartData.costByModel.slice(0, 5)) {\n consumers.push({\n Rank: 0,\n Type: 'prompt',\n Name: model.model,\n Cost: model.cost,\n Proportion: 0\n });\n }\n\n // Sort by cost descending, assign ranks\n consumers.sort((a, b) => b.Cost - a.Cost);\n const topCost = consumers.length > 0 ? consumers[0].Cost : 1;\n return consumers.slice(0, 5).map((c, i) => ({\n ...c,\n Rank: i + 1,\n Proportion: topCost > 0 ? c.Cost / topCost : 0\n }));\n }\n\n // ─── Private: Error Hotspots ─────────────────────────────────────\n // Error hotspots are computed reactively when KPIs change.\n // Since rawData$ is private on the service, we compute from the\n // kpis errorRate + totalExecutions, and rely on chartData for names.\n // For a richer implementation, the service could expose an errors$ stream.\n // For now, we derive from chartData.performanceMatrix entries with low successRate.\n\n private buildErrorHotspots(chartData: ChartData): ErrorHotspot[] {\n const hotspots: ErrorHotspot[] = [];\n\n for (const entry of chartData.performanceMatrix) {\n if (entry.successRate < 1.0) {\n const errorCount = Math.round((1 - entry.successRate) * 10); // approximate\n hotspots.push({\n Source: `${entry.agent} / ${entry.model}`,\n ErrorMessage: `${((1 - entry.successRate) * 100).toFixed(0)}% failure rate (avg ${(entry.avgTime / 1000).toFixed(1)}s)`,\n Count: errorCount\n });\n }\n }\n\n return hotspots\n .sort((a, b) => b.Count - a.Count)\n .slice(0, 4);\n }\n\n // ─── Private: Formatting ─────────────────────────────────────────\n\n private formatNumber(value: number): string {\n if (value >= 1_000_000) return (value / 1_000_000).toFixed(1) + 'M';\n if (value >= 1_000) return (value / 1_000).toFixed(1) + 'K';\n return value.toLocaleString();\n }\n\n private formatLatency(ms: number): string {\n if (ms >= 60_000) return (ms / 60_000).toFixed(1) + 'm';\n if (ms >= 1_000) return (ms / 1_000).toFixed(1) + 's';\n return Math.round(ms) + 'ms';\n }\n}\n\nexport function LoadAnalyticsExecutiveSummary() {\n // Prevents tree-shaking\n}\n"]}
@@ -5,6 +5,7 @@
5
5
  * Data is loaded from MJ: AI Prompt Runs and augmented with model metadata from AIEngineBase.
6
6
  */
7
7
  import { EventEmitter, OnInit, OnDestroy } from '@angular/core';
8
+ import { BaseAngularComponent } from '@memberjunction/ng-base-types';
8
9
  import * as i0 from "@angular/core";
9
10
  interface ModelLeaderboardRow {
10
11
  Rank: number;
@@ -22,7 +23,7 @@ interface ModelLeaderboardRow {
22
23
  TotalCost: number;
23
24
  }
24
25
  type SortByOption = 'cost-efficiency' | 'speed' | 'reliability' | 'usage-volume';
25
- export declare class AnalyticsModelPerformanceComponent implements OnInit, OnDestroy {
26
+ export declare class AnalyticsModelPerformanceComponent extends BaseAngularComponent implements OnInit, OnDestroy {
26
27
  TimeRange: string;
27
28
  TimeRangeChange: EventEmitter<string>;
28
29
  private cdr;
@@ -41,7 +42,7 @@ export declare class AnalyticsModelPerformanceComponent implements OnInit, OnDes
41
42
  name: string;
42
43
  }[];
43
44
  private allRuns;
44
- ngOnInit(): void;
45
+ ngOnInit(): Promise<void>;
45
46
  ngOnDestroy(): void;
46
47
  OnTimeRangeSelect(range: string): void;
47
48
  OnSortByChange(event: Event): void;
@@ -1 +1 @@
1
- {"version":3,"file":"model-performance.component.d.ts","sourceRoot":"","sources":["../../../../../src/AI/components/analytics/model-performance/model-performance.component.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACuB,YAAY,EACtC,MAAM,EAAE,SAAS,EACpB,MAAM,eAAe,CAAC;;AAyBvB,UAAU,mBAAmB;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;CACrB;AAED,KAAK,YAAY,GAAG,iBAAiB,GAAG,OAAO,GAAG,aAAa,GAAG,cAAc,CAAC;AAQjF,qBAgXa,kCAAmC,YAAW,MAAM,EAAE,SAAS;IAC/D,SAAS,SAAQ;IAChB,eAAe,uBAA8B;IAEvD,OAAO,CAAC,GAAG,CAA6B;IACxC,OAAO,CAAC,QAAQ,CAAuB;IAEhC,SAAS,UAAS;IAClB,MAAM,EAAE,YAAY,CAAqB;IACzC,cAAc,SAAM;IACpB,IAAI,EAAE,mBAAmB,EAAE,CAAM;IAEjC,gBAAgB,WAAwB;IAExC,aAAa,EAAE;QAAE,KAAK,EAAE,YAAY,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAK5D;IAEK,aAAa,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAM;IAE1D,OAAO,CAAC,OAAO,CAAyB;IAExC,QAAQ,IAAI,IAAI;IAKhB,WAAW,IAAI,IAAI;IAOZ,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAMtC,cAAc,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAMlC,cAAc,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAMlC,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM;IAKjC,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,SAAI,GAAG,MAAM;IAQ1D,OAAO,CAAC,iBAAiB;YAWX,QAAQ;IA4BtB,OAAO,CAAC,SAAS;IAkCjB,OAAO,CAAC,mBAAmB;IAgD3B,OAAO,CAAC,QAAQ;IAmBhB,OAAO,CAAC,iBAAiB;IAOzB,OAAO,CAAC,YAAY;IAOpB,OAAO,CAAC,eAAe;IAMvB,OAAO,CAAC,eAAe;yCApOd,kCAAkC;2CAAlC,kCAAkC;CA+O9C;AAED,wBAAgB,6BAA6B,SAAoC"}
1
+ {"version":3,"file":"model-performance.component.d.ts","sourceRoot":"","sources":["../../../../../src/AI/components/analytics/model-performance/model-performance.component.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACuB,YAAY,EACtC,MAAM,EAAE,SAAS,EACpB,MAAM,eAAe,CAAC;AAGvB,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;;AAuBrE,UAAU,mBAAmB;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;CACrB;AAED,KAAK,YAAY,GAAG,iBAAiB,GAAG,OAAO,GAAG,aAAa,GAAG,cAAc,CAAC;AAQjF,qBAgXa,kCAAmC,SAAQ,oBAAqB,YAAW,MAAM,EAAE,SAAS;IAC5F,SAAS,SAAQ;IAChB,eAAe,uBAA8B;IAEvD,OAAO,CAAC,GAAG,CAA6B;IACxC,OAAO,CAAC,QAAQ,CAAuB;IAEhC,SAAS,UAAS;IAClB,MAAM,EAAE,YAAY,CAAqB;IACzC,cAAc,SAAM;IACpB,IAAI,EAAE,mBAAmB,EAAE,CAAM;IAEjC,gBAAgB,WAAwB;IAExC,aAAa,EAAE;QAAE,KAAK,EAAE,YAAY,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAK5D;IAEK,aAAa,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAM;IAE1D,OAAO,CAAC,OAAO,CAAyB;IAElC,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ/B,WAAW,IAAI,IAAI;IAOZ,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAMtC,cAAc,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAMlC,cAAc,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAMlC,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM;IAKjC,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,SAAI,GAAG,MAAM;IAQ1D,OAAO,CAAC,iBAAiB;YAWX,QAAQ;IA4BtB,OAAO,CAAC,SAAS;IAkCjB,OAAO,CAAC,mBAAmB;IAgD3B,OAAO,CAAC,QAAQ;IAmBhB,OAAO,CAAC,iBAAiB;IAOzB,OAAO,CAAC,YAAY;IAOpB,OAAO,CAAC,eAAe;IAMvB,OAAO,CAAC,eAAe;yCAvOd,kCAAkC;2CAAlC,kCAAkC;CAkP9C;AAED,wBAAgB,6BAA6B,SAAoC"}
@@ -7,6 +7,7 @@
7
7
  import { Component, Input, Output, EventEmitter, ChangeDetectorRef, inject } from '@angular/core';
8
8
  import { Subject } from 'rxjs';
9
9
  import { RunView } from '@memberjunction/core';
10
+ import { BaseAngularComponent } from '@memberjunction/ng-base-types';
10
11
  import { UUIDsEqual } from '@memberjunction/global';
11
12
  import { AIEngineBase } from '@memberjunction/ai-engine-base';
12
13
  import * as i0 from "@angular/core";
@@ -177,7 +178,7 @@ const FIELDS = [
177
178
  'Cost', 'TotalCost', 'TokensUsed', 'TokensPrompt', 'TokensCompletion',
178
179
  'ModelID', 'Model', 'VendorID', 'Vendor'
179
180
  ];
180
- export class AnalyticsModelPerformanceComponent {
181
+ export class AnalyticsModelPerformanceComponent extends BaseAngularComponent {
181
182
  TimeRange = '7d';
182
183
  TimeRangeChange = new EventEmitter();
183
184
  cdr = inject(ChangeDetectorRef);
@@ -195,7 +196,10 @@ export class AnalyticsModelPerformanceComponent {
195
196
  ];
196
197
  VendorOptions = [];
197
198
  allRuns = [];
198
- ngOnInit() {
199
+ async ngOnInit() {
200
+ // AIEngineBase is deferred at startup — make sure it's loaded before
201
+ // we read .Vendors / .Models from it.
202
+ await AIEngineBase.Instance.EnsureLoaded();
199
203
  this.loadVendorOptions();
200
204
  this.LoadData();
201
205
  }
@@ -247,7 +251,7 @@ export class AnalyticsModelPerformanceComponent {
247
251
  this.IsLoading = true;
248
252
  this.cdr.detectChanges();
249
253
  try {
250
- const rv = new RunView();
254
+ const rv = RunView.FromMetadataProvider(this.ProviderToUse);
251
255
  const dateFilter = this.buildDateFilter();
252
256
  const result = await rv.RunView({
253
257
  EntityName: 'MJ: AI Prompt Runs',
@@ -389,8 +393,8 @@ export class AnalyticsModelPerformanceComponent {
389
393
  const start = new Date(now.getTime() - ms);
390
394
  return `RunAt >= '${start.toISOString()}'`;
391
395
  }
392
- static ɵfac = function AnalyticsModelPerformanceComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || AnalyticsModelPerformanceComponent)(); };
393
- static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: AnalyticsModelPerformanceComponent, selectors: [["app-analytics-model-performance"]], inputs: { TimeRange: "TimeRange" }, outputs: { TimeRangeChange: "TimeRangeChange" }, standalone: false, decls: 18, vars: 3, consts: [[1, "filter-bar"], [1, "filter-controls"], [1, "filter-label"], [1, "fa-solid", "fa-trophy"], [1, "filter-select", 3, "change", "value"], [3, "value"], ["value", ""], [1, "time-chips"], [1, "time-chip", 3, "active"], [1, "loading-container"], [1, "leaderboard-panel"], [1, "time-chip", 3, "click"], ["text", "Loading model performance..."], [1, "table-wrapper"], [1, "leaderboard-table"], [1, "col-rank"], [1, "col-model"], [1, "col-vendor"], [1, "col-numeric"], ["colspan", "9", 1, "empty-row"], [1, "rank-badge"], [1, "cell-model"], [1, "model-name"], [1, "model-api-id"], [1, "cell-vendor"], [1, "cell-numeric"], [1, "success-rate-cell"], [1, "success-rate-value"], [1, "success-bar-bg"], [1, "success-bar-fill"], [1, "cell-numeric", "cell-cost"]], template: function AnalyticsModelPerformanceComponent_Template(rf, ctx) { if (rf & 1) {
396
+ static ɵfac = /*@__PURE__*/ (() => { let ɵAnalyticsModelPerformanceComponent_BaseFactory; return function AnalyticsModelPerformanceComponent_Factory(__ngFactoryType__) { return (ɵAnalyticsModelPerformanceComponent_BaseFactory || (ɵAnalyticsModelPerformanceComponent_BaseFactory = i0.ɵɵgetInheritedFactory(AnalyticsModelPerformanceComponent)))(__ngFactoryType__ || AnalyticsModelPerformanceComponent); }; })();
397
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: AnalyticsModelPerformanceComponent, selectors: [["app-analytics-model-performance"]], inputs: { TimeRange: "TimeRange" }, outputs: { TimeRangeChange: "TimeRangeChange" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 18, vars: 3, consts: [[1, "filter-bar"], [1, "filter-controls"], [1, "filter-label"], [1, "fa-solid", "fa-trophy"], [1, "filter-select", 3, "change", "value"], [3, "value"], ["value", ""], [1, "time-chips"], [1, "time-chip", 3, "active"], [1, "loading-container"], [1, "leaderboard-panel"], [1, "time-chip", 3, "click"], ["text", "Loading model performance..."], [1, "table-wrapper"], [1, "leaderboard-table"], [1, "col-rank"], [1, "col-model"], [1, "col-vendor"], [1, "col-numeric"], ["colspan", "9", 1, "empty-row"], [1, "rank-badge"], [1, "cell-model"], [1, "model-name"], [1, "model-api-id"], [1, "cell-vendor"], [1, "cell-numeric"], [1, "success-rate-cell"], [1, "success-rate-value"], [1, "success-bar-bg"], [1, "success-bar-fill"], [1, "cell-numeric", "cell-cost"]], template: function AnalyticsModelPerformanceComponent_Template(rf, ctx) { if (rf & 1) {
394
398
  i0.ɵɵelementStart(0, "div", 0)(1, "div", 1)(2, "span", 2);
395
399
  i0.ɵɵelement(3, "i", 3);
396
400
  i0.ɵɵtext(4, " Leaderboard ");
@@ -532,6 +536,6 @@ export class AnalyticsModelPerformanceComponent {
532
536
  }], TimeRangeChange: [{
533
537
  type: Output
534
538
  }] }); })();
535
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(AnalyticsModelPerformanceComponent, { className: "AnalyticsModelPerformanceComponent", filePath: "src/AI/components/analytics/model-performance/model-performance.component.ts", lineNumber: 428 }); })();
539
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(AnalyticsModelPerformanceComponent, { className: "AnalyticsModelPerformanceComponent", filePath: "src/AI/components/analytics/model-performance/model-performance.component.ts", lineNumber: 429 }); })();
536
540
  export function LoadAnalyticsModelPerformance() { }
537
541
  //# sourceMappingURL=model-performance.component.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"model-performance.component.js","sourceRoot":"","sources":["../../../../../src/AI/components/analytics/model-performance/model-performance.component.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @fileoverview Model Performance Leaderboard.\n *\n * Ranks AI models by configurable metrics (Cost Efficiency, Speed, Reliability, Usage Volume).\n * Data is loaded from MJ: AI Prompt Runs and augmented with model metadata from AIEngineBase.\n */\n\nimport {\n Component, Input, Output, EventEmitter,\n OnInit, OnDestroy, ChangeDetectorRef, inject\n} from '@angular/core';\nimport { Subject } from 'rxjs';\nimport { RunView } from '@memberjunction/core';\nimport { UUIDsEqual } from '@memberjunction/global';\nimport { AIEngineBase } from '@memberjunction/ai-engine-base';\n\n// ── Interfaces ──\n\ninterface PromptRunRecord {\n ID: string;\n RunAt: string;\n CompletedAt: string | null;\n ExecutionTimeMS: number | null;\n Success: boolean;\n Cost: number | null;\n TotalCost: number | null;\n TokensUsed: number | null;\n TokensPrompt: number | null;\n TokensCompletion: number | null;\n ModelID: string | null;\n Model: string | null;\n VendorID: string | null;\n Vendor: string | null;\n}\n\ninterface ModelLeaderboardRow {\n Rank: number;\n RankClass: string;\n ModelName: string;\n ApiId: string;\n Vendor: string;\n VendorID: string;\n Runs: number;\n AvgLatencyMs: number;\n AvgLatencyColor: string;\n P95LatencyMs: number;\n SuccessRate: number;\n CostPer1KTokens: number;\n TotalCost: number;\n}\n\ntype SortByOption = 'cost-efficiency' | 'speed' | 'reliability' | 'usage-volume';\n\nconst FIELDS = [\n 'ID', 'RunAt', 'CompletedAt', 'ExecutionTimeMS', 'Success',\n 'Cost', 'TotalCost', 'TokensUsed', 'TokensPrompt', 'TokensCompletion',\n 'ModelID', 'Model', 'VendorID', 'Vendor'\n];\n\n@Component({\n standalone: false,\n selector: 'app-analytics-model-performance',\n template: `\n <!-- Filter Bar -->\n <div class=\"filter-bar\">\n <div class=\"filter-controls\">\n <span class=\"filter-label\">\n <i class=\"fa-solid fa-trophy\"></i>\n Leaderboard\n </span>\n\n <select class=\"filter-select\" [value]=\"SortBy\" (change)=\"OnSortByChange($event)\">\n @for (opt of SortByOptions; track opt.value) {\n <option [value]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n\n <select class=\"filter-select\" [value]=\"SelectedVendor\" (change)=\"OnVendorChange($event)\">\n <option value=\"\">All Vendors</option>\n @for (v of VendorOptions; track v.id) {\n <option [value]=\"v.id\">{{ v.name }}</option>\n }\n </select>\n </div>\n\n <div class=\"time-chips\">\n @for (opt of TimeRangeOptions; track opt) {\n <button\n class=\"time-chip\"\n [class.active]=\"TimeRange === opt\"\n (click)=\"OnTimeRangeSelect(opt)\">\n {{ opt }}\n </button>\n }\n </div>\n </div>\n\n @if (IsLoading) {\n <div class=\"loading-container\">\n <mj-loading text=\"Loading model performance...\"></mj-loading>\n </div>\n } @else {\n <!-- Leaderboard Table -->\n <div class=\"leaderboard-panel\">\n <div class=\"table-wrapper\">\n <table class=\"leaderboard-table\">\n <thead>\n <tr>\n <th class=\"col-rank\">Rank</th>\n <th class=\"col-model\">Model</th>\n <th class=\"col-vendor\">Vendor</th>\n <th class=\"col-numeric\">Runs</th>\n <th class=\"col-numeric\">Avg Latency</th>\n <th class=\"col-numeric\">P95 Latency</th>\n <th class=\"col-numeric\">Success Rate</th>\n <th class=\"col-numeric\">$/1K Tokens</th>\n <th class=\"col-numeric\">Total Cost</th>\n </tr>\n </thead>\n <tbody>\n @if (Rows.length === 0) {\n <tr><td colspan=\"9\" class=\"empty-row\">No model data for selected period</td></tr>\n }\n @for (row of Rows; track row.ModelName) {\n <tr>\n <td>\n <span class=\"rank-badge\" [class]=\"row.RankClass\">\n {{ row.Rank }}\n </span>\n </td>\n <td class=\"cell-model\">\n <div class=\"model-name\">{{ row.ModelName }}</div>\n @if (row.ApiId && row.ApiId !== row.ModelName) {\n <div class=\"model-api-id\">{{ row.ApiId }}</div>\n }\n </td>\n <td class=\"cell-vendor\">{{ row.Vendor }}</td>\n <td class=\"cell-numeric\">{{ row.Runs | number }}</td>\n <td class=\"cell-numeric\">\n <span [style.color]=\"row.AvgLatencyColor\">\n {{ FormatLatency(row.AvgLatencyMs) }}\n </span>\n </td>\n <td class=\"cell-numeric\">{{ FormatLatency(row.P95LatencyMs) }}</td>\n <td class=\"cell-numeric\">\n <div class=\"success-rate-cell\">\n <span class=\"success-rate-value\">{{ row.SuccessRate | number:'1.1-1' }}%</span>\n <div class=\"success-bar-bg\">\n <div class=\"success-bar-fill\" [style.width.%]=\"row.SuccessRate\"></div>\n </div>\n </div>\n </td>\n <td class=\"cell-numeric\">{{ FormatCurrency(row.CostPer1KTokens, 4) }}</td>\n <td class=\"cell-numeric cell-cost\">{{ FormatCurrency(row.TotalCost) }}</td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n </div>\n }\n `,\n styles: [`\n :host { display: block; }\n\n .loading-container {\n display: flex;\n justify-content: center;\n align-items: center;\n min-height: 300px;\n }\n\n /* ── Filter Bar ── */\n .filter-bar {\n display: flex;\n align-items: center;\n gap: 12px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 10px;\n padding: 12px 16px;\n flex-wrap: wrap;\n margin-bottom: 16px;\n }\n\n .filter-controls {\n display: flex;\n align-items: center;\n gap: 10px;\n flex-wrap: wrap;\n }\n\n .filter-label {\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n white-space: nowrap;\n display: flex;\n align-items: center;\n gap: 6px;\n }\n\n .filter-label i {\n font-size: 13px;\n color: var(--mj-status-warning);\n }\n\n .filter-select {\n padding: 5px 10px;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n font-size: 13px;\n cursor: pointer;\n min-width: 130px;\n outline: none;\n }\n\n .filter-select:focus {\n border-color: var(--mj-border-focus);\n box-shadow: 0 0 0 2px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n }\n\n .time-chips {\n display: flex;\n align-items: center;\n gap: 4px;\n margin-left: auto;\n }\n\n .time-chip {\n padding: 5px 12px;\n border: 1px solid var(--mj-border-default);\n border-radius: 16px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n font-size: 12px;\n font-weight: 500;\n cursor: pointer;\n transition: background 0.15s, color 0.15s, border-color 0.15s;\n white-space: nowrap;\n }\n\n .time-chip:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n }\n\n .time-chip.active {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n font-weight: 600;\n }\n\n /* ── Leaderboard ── */\n .leaderboard-panel {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n overflow: hidden;\n }\n\n .table-wrapper {\n overflow-x: auto;\n }\n\n .leaderboard-table {\n width: 100%;\n border-collapse: collapse;\n font-size: 13px;\n }\n\n .leaderboard-table th,\n .leaderboard-table td {\n padding: 12px 14px;\n text-align: left;\n border-bottom: 1px solid var(--mj-border-subtle);\n }\n\n .leaderboard-table th {\n font-size: 11px;\n font-weight: 600;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.4px;\n background: var(--mj-bg-surface-card);\n position: sticky;\n top: 0;\n white-space: nowrap;\n }\n\n .col-rank { width: 60px; text-align: center; }\n .col-model { min-width: 180px; }\n .col-vendor { min-width: 100px; }\n .col-numeric { text-align: right; white-space: nowrap; }\n\n .leaderboard-table tbody tr {\n transition: background 0.15s;\n }\n\n .leaderboard-table tbody tr:hover {\n background: var(--mj-bg-surface-hover);\n }\n\n .empty-row {\n text-align: center;\n color: var(--mj-text-disabled);\n padding: 32px;\n }\n\n /* ── Rank Badge ── */\n .rank-badge {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n border-radius: 50%;\n font-size: 12px;\n font-weight: 700;\n }\n\n .rank-gold {\n background: linear-gradient(135deg, color-mix(in srgb, var(--mj-status-warning) 35%, var(--mj-bg-surface)), color-mix(in srgb, var(--mj-status-warning) 20%, var(--mj-bg-surface)));\n color: var(--mj-status-warning-text, var(--mj-status-warning));\n box-shadow: 0 0 0 2px color-mix(in srgb, var(--mj-status-warning) 30%, transparent);\n }\n\n .rank-silver {\n background: color-mix(in srgb, var(--mj-text-muted) 18%, var(--mj-bg-surface));\n color: var(--mj-text-secondary);\n box-shadow: 0 0 0 2px color-mix(in srgb, var(--mj-text-muted) 20%, transparent);\n }\n\n .rank-bronze {\n background: color-mix(in srgb, var(--mj-status-warning) 18%, var(--mj-bg-surface));\n color: var(--mj-text-secondary);\n }\n\n .rank-neutral {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-muted);\n }\n\n /* ── Model Cell ── */\n .cell-model {\n font-weight: 500;\n color: var(--mj-text-primary);\n }\n\n .model-name {\n font-weight: 600;\n }\n\n .model-api-id {\n font-size: 11px;\n color: var(--mj-text-muted);\n margin-top: 2px;\n font-family: monospace;\n }\n\n .cell-vendor {\n color: var(--mj-text-secondary);\n }\n\n .cell-numeric {\n text-align: right;\n font-variant-numeric: tabular-nums;\n color: var(--mj-text-secondary);\n }\n\n .cell-cost {\n font-weight: 600;\n color: var(--mj-text-primary);\n }\n\n /* ── Success Rate Mini Bar ── */\n .success-rate-cell {\n display: flex;\n flex-direction: column;\n align-items: flex-end;\n gap: 3px;\n }\n\n .success-rate-value {\n font-weight: 600;\n }\n\n .success-bar-bg {\n width: 60px;\n height: 4px;\n background: var(--mj-bg-surface-sunken);\n border-radius: 2px;\n overflow: hidden;\n }\n\n .success-bar-fill {\n height: 100%;\n background: var(--mj-status-success);\n border-radius: 2px;\n transition: width 0.4s cubic-bezier(0.4, 0, 0.2, 1);\n }\n\n /* ── Responsive ── */\n @media (max-width: 1200px) {\n .leaderboard-table th,\n .leaderboard-table td {\n padding: 10px 10px;\n }\n }\n\n @media (max-width: 768px) {\n .filter-bar {\n flex-direction: column;\n align-items: stretch;\n }\n\n .time-chips {\n margin-left: 0;\n justify-content: flex-start;\n flex-wrap: wrap;\n }\n }\n `]\n})\nexport class AnalyticsModelPerformanceComponent implements OnInit, OnDestroy {\n @Input() TimeRange = '7d';\n @Output() TimeRangeChange = new EventEmitter<string>();\n\n private cdr = inject(ChangeDetectorRef);\n private destroy$ = new Subject<void>();\n\n public IsLoading = false;\n public SortBy: SortByOption = 'cost-efficiency';\n public SelectedVendor = '';\n public Rows: ModelLeaderboardRow[] = [];\n\n public TimeRangeOptions = ['24h', '7d', '30d'];\n\n public SortByOptions: { value: SortByOption; label: string }[] = [\n { value: 'cost-efficiency', label: 'Cost Efficiency' },\n { value: 'speed', label: 'Speed' },\n { value: 'reliability', label: 'Reliability' },\n { value: 'usage-volume', label: 'Usage Volume' }\n ];\n\n public VendorOptions: { id: string; name: string }[] = [];\n\n private allRuns: PromptRunRecord[] = [];\n\n ngOnInit(): void {\n this.loadVendorOptions();\n this.LoadData();\n }\n\n ngOnDestroy(): void {\n this.destroy$.next();\n this.destroy$.complete();\n }\n\n // ── Public Handlers ──\n\n public OnTimeRangeSelect(range: string): void {\n this.TimeRange = range;\n this.TimeRangeChange.emit(range);\n this.LoadData();\n }\n\n public OnSortByChange(event: Event): void {\n this.SortBy = (event.target as HTMLSelectElement).value as SortByOption;\n this.buildRows();\n this.cdr.detectChanges();\n }\n\n public OnVendorChange(event: Event): void {\n this.SelectedVendor = (event.target as HTMLSelectElement).value;\n this.buildRows();\n this.cdr.detectChanges();\n }\n\n public FormatLatency(ms: number): string {\n if (ms < 1000) return Math.round(ms) + 'ms';\n return (ms / 1000).toFixed(2) + 's';\n }\n\n public FormatCurrency(value: number, decimals = 2): string {\n if (value === 0) return '$0.00';\n if (value < 0.01 && decimals < 4) decimals = 4;\n return '$' + value.toFixed(decimals);\n }\n\n // ── Data Loading ──\n\n private loadVendorOptions(): void {\n try {\n this.VendorOptions = AIEngineBase.Instance.Vendors.map(v => ({\n id: v.ID,\n name: v.Name\n }));\n } catch {\n this.VendorOptions = [];\n }\n }\n\n private async LoadData(): Promise<void> {\n this.IsLoading = true;\n this.cdr.detectChanges();\n\n try {\n const rv = new RunView();\n const dateFilter = this.buildDateFilter();\n\n const result = await rv.RunView<PromptRunRecord>({\n EntityName: 'MJ: AI Prompt Runs',\n ExtraFilter: dateFilter,\n Fields: FIELDS,\n OrderBy: 'RunAt DESC',\n ResultType: 'simple'\n });\n\n this.allRuns = (result?.Results ?? []) as PromptRunRecord[];\n this.buildRows();\n } catch (e) {\n console.error('Model Performance load error:', e);\n } finally {\n this.IsLoading = false;\n this.cdr.detectChanges();\n }\n }\n\n // ── Row Building ──\n\n private buildRows(): void {\n // Filter by vendor if needed\n let runs = this.allRuns;\n if (this.SelectedVendor) {\n runs = runs.filter(r => r.VendorID === this.SelectedVendor);\n }\n\n // Group by model\n const groups = new Map<string, PromptRunRecord[]>();\n for (const run of runs) {\n const key = run.ModelID ?? 'unknown';\n if (!groups.has(key)) groups.set(key, []);\n groups.get(key)!.push(run);\n }\n\n // Compute metrics per model\n const modelRows: ModelLeaderboardRow[] = [];\n for (const [modelId, modelRuns] of groups) {\n const row = this.computeModelMetrics(modelId, modelRuns);\n modelRows.push(row);\n }\n\n // Sort by chosen metric\n this.sortRows(modelRows);\n\n // Assign ranks\n modelRows.forEach((row, i) => {\n row.Rank = i + 1;\n row.RankClass = this.getRankClass(i + 1);\n });\n\n this.Rows = modelRows;\n }\n\n private computeModelMetrics(modelId: string, runs: PromptRunRecord[]): ModelLeaderboardRow {\n const totalRuns = runs.length;\n const successCount = runs.filter(r => r.Success).length;\n const successRate = totalRuns > 0 ? (successCount / totalRuns) * 100 : 0;\n\n const latencies = runs\n .filter(r => r.ExecutionTimeMS != null && r.ExecutionTimeMS > 0)\n .map(r => r.ExecutionTimeMS!);\n\n const avgLatency = latencies.length > 0\n ? latencies.reduce((s, l) => s + l, 0) / latencies.length\n : 0;\n\n const p95Latency = this.computePercentile(latencies, 0.95);\n\n const totalTokens = runs.reduce((s, r) => s + (r.TokensUsed ?? 0), 0);\n const totalCost = runs.reduce((s, r) => s + (r.Cost ?? r.TotalCost ?? 0), 0);\n const costPer1K = totalTokens > 0 ? (totalCost / totalTokens) * 1000 : 0;\n\n const firstName = runs.find(r => r.Model != null);\n const firstVendor = runs.find(r => r.Vendor != null);\n\n // Look up model API name from engine\n let apiId = '';\n try {\n const model = AIEngineBase.Instance.Models.find(m => UUIDsEqual(m.ID, modelId));\n apiId = model?.APIName ?? '';\n } catch {\n // engine might not be ready\n }\n\n return {\n Rank: 0,\n RankClass: 'rank-neutral',\n ModelName: firstName?.Model ?? 'Unknown',\n ApiId: apiId,\n Vendor: firstVendor?.Vendor ?? 'Unknown',\n VendorID: firstVendor?.VendorID ?? '',\n Runs: totalRuns,\n AvgLatencyMs: avgLatency,\n AvgLatencyColor: this.getLatencyColor(avgLatency),\n P95LatencyMs: p95Latency,\n SuccessRate: successRate,\n CostPer1KTokens: costPer1K,\n TotalCost: totalCost\n };\n }\n\n private sortRows(rows: ModelLeaderboardRow[]): void {\n switch (this.SortBy) {\n case 'cost-efficiency':\n rows.sort((a, b) => a.CostPer1KTokens - b.CostPer1KTokens);\n break;\n case 'speed':\n rows.sort((a, b) => a.AvgLatencyMs - b.AvgLatencyMs);\n break;\n case 'reliability':\n rows.sort((a, b) => b.SuccessRate - a.SuccessRate);\n break;\n case 'usage-volume':\n rows.sort((a, b) => b.Runs - a.Runs);\n break;\n }\n }\n\n // ── Helpers ──\n\n private computePercentile(sortedValues: number[], percentile: number): number {\n if (sortedValues.length === 0) return 0;\n const sorted = [...sortedValues].sort((a, b) => a - b);\n const idx = Math.ceil(sorted.length * percentile) - 1;\n return sorted[Math.max(0, idx)];\n }\n\n private getRankClass(rank: number): string {\n if (rank === 1) return 'rank-badge rank-gold';\n if (rank === 2) return 'rank-badge rank-silver';\n if (rank === 3) return 'rank-badge rank-bronze';\n return 'rank-badge rank-neutral';\n }\n\n private getLatencyColor(ms: number): string {\n if (ms < 1000) return 'var(--mj-status-success)';\n if (ms < 3000) return 'var(--mj-status-warning)';\n return 'var(--mj-status-error)';\n }\n\n private buildDateFilter(): string {\n const now = new Date();\n const msMap: Record<string, number> = {\n '24h': 86400000,\n '7d': 604800000,\n '30d': 2592000000\n };\n const ms = msMap[this.TimeRange] ?? 604800000;\n const start = new Date(now.getTime() - ms);\n return `RunAt >= '${start.toISOString()}'`;\n }\n}\n\nexport function LoadAnalyticsModelPerformance() { /* tree-shaking prevention */ }\n"]}
1
+ {"version":3,"file":"model-performance.component.js","sourceRoot":"","sources":["../../../../../src/AI/components/analytics/model-performance/model-performance.component.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @fileoverview Model Performance Leaderboard.\n *\n * Ranks AI models by configurable metrics (Cost Efficiency, Speed, Reliability, Usage Volume).\n * Data is loaded from MJ: AI Prompt Runs and augmented with model metadata from AIEngineBase.\n */\n\nimport {\n Component, Input, Output, EventEmitter,\n OnInit, OnDestroy, ChangeDetectorRef, inject\n} from '@angular/core';\nimport { Subject } from 'rxjs';\nimport { RunView } from '@memberjunction/core';\nimport { BaseAngularComponent } from '@memberjunction/ng-base-types';\nimport { UUIDsEqual } from '@memberjunction/global';\nimport { AIEngineBase } from '@memberjunction/ai-engine-base';\n\n// ── Interfaces ──\n\ninterface PromptRunRecord {\n ID: string;\n RunAt: string;\n CompletedAt: string | null;\n ExecutionTimeMS: number | null;\n Success: boolean;\n Cost: number | null;\n TotalCost: number | null;\n TokensUsed: number | null;\n TokensPrompt: number | null;\n TokensCompletion: number | null;\n ModelID: string | null;\n Model: string | null;\n VendorID: string | null;\n Vendor: string | null;\n}\n\ninterface ModelLeaderboardRow {\n Rank: number;\n RankClass: string;\n ModelName: string;\n ApiId: string;\n Vendor: string;\n VendorID: string;\n Runs: number;\n AvgLatencyMs: number;\n AvgLatencyColor: string;\n P95LatencyMs: number;\n SuccessRate: number;\n CostPer1KTokens: number;\n TotalCost: number;\n}\n\ntype SortByOption = 'cost-efficiency' | 'speed' | 'reliability' | 'usage-volume';\n\nconst FIELDS = [\n 'ID', 'RunAt', 'CompletedAt', 'ExecutionTimeMS', 'Success',\n 'Cost', 'TotalCost', 'TokensUsed', 'TokensPrompt', 'TokensCompletion',\n 'ModelID', 'Model', 'VendorID', 'Vendor'\n];\n\n@Component({\n standalone: false,\n selector: 'app-analytics-model-performance',\n template: `\n <!-- Filter Bar -->\n <div class=\"filter-bar\">\n <div class=\"filter-controls\">\n <span class=\"filter-label\">\n <i class=\"fa-solid fa-trophy\"></i>\n Leaderboard\n </span>\n\n <select class=\"filter-select\" [value]=\"SortBy\" (change)=\"OnSortByChange($event)\">\n @for (opt of SortByOptions; track opt.value) {\n <option [value]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n\n <select class=\"filter-select\" [value]=\"SelectedVendor\" (change)=\"OnVendorChange($event)\">\n <option value=\"\">All Vendors</option>\n @for (v of VendorOptions; track v.id) {\n <option [value]=\"v.id\">{{ v.name }}</option>\n }\n </select>\n </div>\n\n <div class=\"time-chips\">\n @for (opt of TimeRangeOptions; track opt) {\n <button\n class=\"time-chip\"\n [class.active]=\"TimeRange === opt\"\n (click)=\"OnTimeRangeSelect(opt)\">\n {{ opt }}\n </button>\n }\n </div>\n </div>\n\n @if (IsLoading) {\n <div class=\"loading-container\">\n <mj-loading text=\"Loading model performance...\"></mj-loading>\n </div>\n } @else {\n <!-- Leaderboard Table -->\n <div class=\"leaderboard-panel\">\n <div class=\"table-wrapper\">\n <table class=\"leaderboard-table\">\n <thead>\n <tr>\n <th class=\"col-rank\">Rank</th>\n <th class=\"col-model\">Model</th>\n <th class=\"col-vendor\">Vendor</th>\n <th class=\"col-numeric\">Runs</th>\n <th class=\"col-numeric\">Avg Latency</th>\n <th class=\"col-numeric\">P95 Latency</th>\n <th class=\"col-numeric\">Success Rate</th>\n <th class=\"col-numeric\">$/1K Tokens</th>\n <th class=\"col-numeric\">Total Cost</th>\n </tr>\n </thead>\n <tbody>\n @if (Rows.length === 0) {\n <tr><td colspan=\"9\" class=\"empty-row\">No model data for selected period</td></tr>\n }\n @for (row of Rows; track row.ModelName) {\n <tr>\n <td>\n <span class=\"rank-badge\" [class]=\"row.RankClass\">\n {{ row.Rank }}\n </span>\n </td>\n <td class=\"cell-model\">\n <div class=\"model-name\">{{ row.ModelName }}</div>\n @if (row.ApiId && row.ApiId !== row.ModelName) {\n <div class=\"model-api-id\">{{ row.ApiId }}</div>\n }\n </td>\n <td class=\"cell-vendor\">{{ row.Vendor }}</td>\n <td class=\"cell-numeric\">{{ row.Runs | number }}</td>\n <td class=\"cell-numeric\">\n <span [style.color]=\"row.AvgLatencyColor\">\n {{ FormatLatency(row.AvgLatencyMs) }}\n </span>\n </td>\n <td class=\"cell-numeric\">{{ FormatLatency(row.P95LatencyMs) }}</td>\n <td class=\"cell-numeric\">\n <div class=\"success-rate-cell\">\n <span class=\"success-rate-value\">{{ row.SuccessRate | number:'1.1-1' }}%</span>\n <div class=\"success-bar-bg\">\n <div class=\"success-bar-fill\" [style.width.%]=\"row.SuccessRate\"></div>\n </div>\n </div>\n </td>\n <td class=\"cell-numeric\">{{ FormatCurrency(row.CostPer1KTokens, 4) }}</td>\n <td class=\"cell-numeric cell-cost\">{{ FormatCurrency(row.TotalCost) }}</td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n </div>\n }\n `,\n styles: [`\n :host { display: block; }\n\n .loading-container {\n display: flex;\n justify-content: center;\n align-items: center;\n min-height: 300px;\n }\n\n /* ── Filter Bar ── */\n .filter-bar {\n display: flex;\n align-items: center;\n gap: 12px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 10px;\n padding: 12px 16px;\n flex-wrap: wrap;\n margin-bottom: 16px;\n }\n\n .filter-controls {\n display: flex;\n align-items: center;\n gap: 10px;\n flex-wrap: wrap;\n }\n\n .filter-label {\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n white-space: nowrap;\n display: flex;\n align-items: center;\n gap: 6px;\n }\n\n .filter-label i {\n font-size: 13px;\n color: var(--mj-status-warning);\n }\n\n .filter-select {\n padding: 5px 10px;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n font-size: 13px;\n cursor: pointer;\n min-width: 130px;\n outline: none;\n }\n\n .filter-select:focus {\n border-color: var(--mj-border-focus);\n box-shadow: 0 0 0 2px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n }\n\n .time-chips {\n display: flex;\n align-items: center;\n gap: 4px;\n margin-left: auto;\n }\n\n .time-chip {\n padding: 5px 12px;\n border: 1px solid var(--mj-border-default);\n border-radius: 16px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n font-size: 12px;\n font-weight: 500;\n cursor: pointer;\n transition: background 0.15s, color 0.15s, border-color 0.15s;\n white-space: nowrap;\n }\n\n .time-chip:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n }\n\n .time-chip.active {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n font-weight: 600;\n }\n\n /* ── Leaderboard ── */\n .leaderboard-panel {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n overflow: hidden;\n }\n\n .table-wrapper {\n overflow-x: auto;\n }\n\n .leaderboard-table {\n width: 100%;\n border-collapse: collapse;\n font-size: 13px;\n }\n\n .leaderboard-table th,\n .leaderboard-table td {\n padding: 12px 14px;\n text-align: left;\n border-bottom: 1px solid var(--mj-border-subtle);\n }\n\n .leaderboard-table th {\n font-size: 11px;\n font-weight: 600;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.4px;\n background: var(--mj-bg-surface-card);\n position: sticky;\n top: 0;\n white-space: nowrap;\n }\n\n .col-rank { width: 60px; text-align: center; }\n .col-model { min-width: 180px; }\n .col-vendor { min-width: 100px; }\n .col-numeric { text-align: right; white-space: nowrap; }\n\n .leaderboard-table tbody tr {\n transition: background 0.15s;\n }\n\n .leaderboard-table tbody tr:hover {\n background: var(--mj-bg-surface-hover);\n }\n\n .empty-row {\n text-align: center;\n color: var(--mj-text-disabled);\n padding: 32px;\n }\n\n /* ── Rank Badge ── */\n .rank-badge {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n border-radius: 50%;\n font-size: 12px;\n font-weight: 700;\n }\n\n .rank-gold {\n background: linear-gradient(135deg, color-mix(in srgb, var(--mj-status-warning) 35%, var(--mj-bg-surface)), color-mix(in srgb, var(--mj-status-warning) 20%, var(--mj-bg-surface)));\n color: var(--mj-status-warning-text, var(--mj-status-warning));\n box-shadow: 0 0 0 2px color-mix(in srgb, var(--mj-status-warning) 30%, transparent);\n }\n\n .rank-silver {\n background: color-mix(in srgb, var(--mj-text-muted) 18%, var(--mj-bg-surface));\n color: var(--mj-text-secondary);\n box-shadow: 0 0 0 2px color-mix(in srgb, var(--mj-text-muted) 20%, transparent);\n }\n\n .rank-bronze {\n background: color-mix(in srgb, var(--mj-status-warning) 18%, var(--mj-bg-surface));\n color: var(--mj-text-secondary);\n }\n\n .rank-neutral {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-muted);\n }\n\n /* ── Model Cell ── */\n .cell-model {\n font-weight: 500;\n color: var(--mj-text-primary);\n }\n\n .model-name {\n font-weight: 600;\n }\n\n .model-api-id {\n font-size: 11px;\n color: var(--mj-text-muted);\n margin-top: 2px;\n font-family: monospace;\n }\n\n .cell-vendor {\n color: var(--mj-text-secondary);\n }\n\n .cell-numeric {\n text-align: right;\n font-variant-numeric: tabular-nums;\n color: var(--mj-text-secondary);\n }\n\n .cell-cost {\n font-weight: 600;\n color: var(--mj-text-primary);\n }\n\n /* ── Success Rate Mini Bar ── */\n .success-rate-cell {\n display: flex;\n flex-direction: column;\n align-items: flex-end;\n gap: 3px;\n }\n\n .success-rate-value {\n font-weight: 600;\n }\n\n .success-bar-bg {\n width: 60px;\n height: 4px;\n background: var(--mj-bg-surface-sunken);\n border-radius: 2px;\n overflow: hidden;\n }\n\n .success-bar-fill {\n height: 100%;\n background: var(--mj-status-success);\n border-radius: 2px;\n transition: width 0.4s cubic-bezier(0.4, 0, 0.2, 1);\n }\n\n /* ── Responsive ── */\n @media (max-width: 1200px) {\n .leaderboard-table th,\n .leaderboard-table td {\n padding: 10px 10px;\n }\n }\n\n @media (max-width: 768px) {\n .filter-bar {\n flex-direction: column;\n align-items: stretch;\n }\n\n .time-chips {\n margin-left: 0;\n justify-content: flex-start;\n flex-wrap: wrap;\n }\n }\n `]\n})\nexport class AnalyticsModelPerformanceComponent extends BaseAngularComponent implements OnInit, OnDestroy {\n @Input() TimeRange = '7d';\n @Output() TimeRangeChange = new EventEmitter<string>();\n\n private cdr = inject(ChangeDetectorRef);\n private destroy$ = new Subject<void>();\n\n public IsLoading = false;\n public SortBy: SortByOption = 'cost-efficiency';\n public SelectedVendor = '';\n public Rows: ModelLeaderboardRow[] = [];\n\n public TimeRangeOptions = ['24h', '7d', '30d'];\n\n public SortByOptions: { value: SortByOption; label: string }[] = [\n { value: 'cost-efficiency', label: 'Cost Efficiency' },\n { value: 'speed', label: 'Speed' },\n { value: 'reliability', label: 'Reliability' },\n { value: 'usage-volume', label: 'Usage Volume' }\n ];\n\n public VendorOptions: { id: string; name: string }[] = [];\n\n private allRuns: PromptRunRecord[] = [];\n\n async ngOnInit(): Promise<void> {\n // AIEngineBase is deferred at startup — make sure it's loaded before\n // we read .Vendors / .Models from it.\n await AIEngineBase.Instance.EnsureLoaded();\n this.loadVendorOptions();\n this.LoadData();\n }\n\n ngOnDestroy(): void {\n this.destroy$.next();\n this.destroy$.complete();\n }\n\n // ── Public Handlers ──\n\n public OnTimeRangeSelect(range: string): void {\n this.TimeRange = range;\n this.TimeRangeChange.emit(range);\n this.LoadData();\n }\n\n public OnSortByChange(event: Event): void {\n this.SortBy = (event.target as HTMLSelectElement).value as SortByOption;\n this.buildRows();\n this.cdr.detectChanges();\n }\n\n public OnVendorChange(event: Event): void {\n this.SelectedVendor = (event.target as HTMLSelectElement).value;\n this.buildRows();\n this.cdr.detectChanges();\n }\n\n public FormatLatency(ms: number): string {\n if (ms < 1000) return Math.round(ms) + 'ms';\n return (ms / 1000).toFixed(2) + 's';\n }\n\n public FormatCurrency(value: number, decimals = 2): string {\n if (value === 0) return '$0.00';\n if (value < 0.01 && decimals < 4) decimals = 4;\n return '$' + value.toFixed(decimals);\n }\n\n // ── Data Loading ──\n\n private loadVendorOptions(): void {\n try {\n this.VendorOptions = AIEngineBase.Instance.Vendors.map(v => ({\n id: v.ID,\n name: v.Name\n }));\n } catch {\n this.VendorOptions = [];\n }\n }\n\n private async LoadData(): Promise<void> {\n this.IsLoading = true;\n this.cdr.detectChanges();\n\n try {\n const rv = RunView.FromMetadataProvider(this.ProviderToUse);\n const dateFilter = this.buildDateFilter();\n\n const result = await rv.RunView<PromptRunRecord>({\n EntityName: 'MJ: AI Prompt Runs',\n ExtraFilter: dateFilter,\n Fields: FIELDS,\n OrderBy: 'RunAt DESC',\n ResultType: 'simple'\n });\n\n this.allRuns = (result?.Results ?? []) as PromptRunRecord[];\n this.buildRows();\n } catch (e) {\n console.error('Model Performance load error:', e);\n } finally {\n this.IsLoading = false;\n this.cdr.detectChanges();\n }\n }\n\n // ── Row Building ──\n\n private buildRows(): void {\n // Filter by vendor if needed\n let runs = this.allRuns;\n if (this.SelectedVendor) {\n runs = runs.filter(r => r.VendorID === this.SelectedVendor);\n }\n\n // Group by model\n const groups = new Map<string, PromptRunRecord[]>();\n for (const run of runs) {\n const key = run.ModelID ?? 'unknown';\n if (!groups.has(key)) groups.set(key, []);\n groups.get(key)!.push(run);\n }\n\n // Compute metrics per model\n const modelRows: ModelLeaderboardRow[] = [];\n for (const [modelId, modelRuns] of groups) {\n const row = this.computeModelMetrics(modelId, modelRuns);\n modelRows.push(row);\n }\n\n // Sort by chosen metric\n this.sortRows(modelRows);\n\n // Assign ranks\n modelRows.forEach((row, i) => {\n row.Rank = i + 1;\n row.RankClass = this.getRankClass(i + 1);\n });\n\n this.Rows = modelRows;\n }\n\n private computeModelMetrics(modelId: string, runs: PromptRunRecord[]): ModelLeaderboardRow {\n const totalRuns = runs.length;\n const successCount = runs.filter(r => r.Success).length;\n const successRate = totalRuns > 0 ? (successCount / totalRuns) * 100 : 0;\n\n const latencies = runs\n .filter(r => r.ExecutionTimeMS != null && r.ExecutionTimeMS > 0)\n .map(r => r.ExecutionTimeMS!);\n\n const avgLatency = latencies.length > 0\n ? latencies.reduce((s, l) => s + l, 0) / latencies.length\n : 0;\n\n const p95Latency = this.computePercentile(latencies, 0.95);\n\n const totalTokens = runs.reduce((s, r) => s + (r.TokensUsed ?? 0), 0);\n const totalCost = runs.reduce((s, r) => s + (r.Cost ?? r.TotalCost ?? 0), 0);\n const costPer1K = totalTokens > 0 ? (totalCost / totalTokens) * 1000 : 0;\n\n const firstName = runs.find(r => r.Model != null);\n const firstVendor = runs.find(r => r.Vendor != null);\n\n // Look up model API name from engine\n let apiId = '';\n try {\n const model = AIEngineBase.Instance.Models.find(m => UUIDsEqual(m.ID, modelId));\n apiId = model?.APIName ?? '';\n } catch {\n // engine might not be ready\n }\n\n return {\n Rank: 0,\n RankClass: 'rank-neutral',\n ModelName: firstName?.Model ?? 'Unknown',\n ApiId: apiId,\n Vendor: firstVendor?.Vendor ?? 'Unknown',\n VendorID: firstVendor?.VendorID ?? '',\n Runs: totalRuns,\n AvgLatencyMs: avgLatency,\n AvgLatencyColor: this.getLatencyColor(avgLatency),\n P95LatencyMs: p95Latency,\n SuccessRate: successRate,\n CostPer1KTokens: costPer1K,\n TotalCost: totalCost\n };\n }\n\n private sortRows(rows: ModelLeaderboardRow[]): void {\n switch (this.SortBy) {\n case 'cost-efficiency':\n rows.sort((a, b) => a.CostPer1KTokens - b.CostPer1KTokens);\n break;\n case 'speed':\n rows.sort((a, b) => a.AvgLatencyMs - b.AvgLatencyMs);\n break;\n case 'reliability':\n rows.sort((a, b) => b.SuccessRate - a.SuccessRate);\n break;\n case 'usage-volume':\n rows.sort((a, b) => b.Runs - a.Runs);\n break;\n }\n }\n\n // ── Helpers ──\n\n private computePercentile(sortedValues: number[], percentile: number): number {\n if (sortedValues.length === 0) return 0;\n const sorted = [...sortedValues].sort((a, b) => a - b);\n const idx = Math.ceil(sorted.length * percentile) - 1;\n return sorted[Math.max(0, idx)];\n }\n\n private getRankClass(rank: number): string {\n if (rank === 1) return 'rank-badge rank-gold';\n if (rank === 2) return 'rank-badge rank-silver';\n if (rank === 3) return 'rank-badge rank-bronze';\n return 'rank-badge rank-neutral';\n }\n\n private getLatencyColor(ms: number): string {\n if (ms < 1000) return 'var(--mj-status-success)';\n if (ms < 3000) return 'var(--mj-status-warning)';\n return 'var(--mj-status-error)';\n }\n\n private buildDateFilter(): string {\n const now = new Date();\n const msMap: Record<string, number> = {\n '24h': 86400000,\n '7d': 604800000,\n '30d': 2592000000\n };\n const ms = msMap[this.TimeRange] ?? 604800000;\n const start = new Date(now.getTime() - ms);\n return `RunAt >= '${start.toISOString()}'`;\n }\n}\n\nexport function LoadAnalyticsModelPerformance() { /* tree-shaking prevention */ }\n"]}
@@ -6,6 +6,7 @@
6
6
  * the "MJ: AI Prompt Runs" entity.
7
7
  */
8
8
  import { EventEmitter, OnInit, OnDestroy } from '@angular/core';
9
+ import { BaseAngularComponent } from '@memberjunction/ng-base-types';
9
10
  import { GlobalFilterState } from '../../../interfaces/analytics-preferences.interface';
10
11
  import * as i0 from "@angular/core";
11
12
  interface PromptRunRecord {
@@ -56,7 +57,7 @@ interface StatusBreakdownItem extends BreakdownItem {
56
57
  type ChartMetric = 'volume' | 'cost' | 'tokens';
57
58
  type SortField = 'RunAt' | 'Prompt' | 'Model' | 'Status' | 'ExecutionTimeMS' | 'TokensUsed' | 'Cost';
58
59
  type SortDirection = 'asc' | 'desc';
59
- export declare class AnalyticsPromptRunsComponent implements OnInit, OnDestroy {
60
+ export declare class AnalyticsPromptRunsComponent extends BaseAngularComponent implements OnInit, OnDestroy {
60
61
  private cdr;
61
62
  private destroy$;
62
63
  private isInitialized;