@memberjunction/ng-dashboards 5.21.0 → 5.23.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 (262) hide show
  1. package/README.md +51 -0
  2. package/dist/AI/components/agents/agent-configuration.component.d.ts.map +1 -1
  3. package/dist/AI/components/agents/agent-configuration.component.js +364 -362
  4. package/dist/AI/components/agents/agent-configuration.component.js.map +1 -1
  5. package/dist/AI/components/agents/agent-editor.component.js +2 -2
  6. package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.d.ts +313 -0
  7. package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.d.ts.map +1 -0
  8. package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.js +2792 -0
  9. package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.js.map +1 -0
  10. package/dist/AI/components/duplicates/duplicate-detection-resource.component.d.ts +382 -0
  11. package/dist/AI/components/duplicates/duplicate-detection-resource.component.d.ts.map +1 -0
  12. package/dist/AI/components/duplicates/duplicate-detection-resource.component.js +2683 -0
  13. package/dist/AI/components/duplicates/duplicate-detection-resource.component.js.map +1 -0
  14. package/dist/AI/components/execution-monitoring.component.d.ts.map +1 -1
  15. package/dist/AI/components/execution-monitoring.component.js +191 -197
  16. package/dist/AI/components/execution-monitoring.component.js.map +1 -1
  17. package/dist/AI/components/models/model-management.component.js +9 -8
  18. package/dist/AI/components/models/model-management.component.js.map +1 -1
  19. package/dist/AI/components/prompts/prompt-management.component.js +305 -299
  20. package/dist/AI/components/prompts/prompt-management.component.js.map +1 -1
  21. package/dist/AI/components/system/system-configuration.component.js +319 -313
  22. package/dist/AI/components/system/system-configuration.component.js.map +1 -1
  23. package/dist/AI/components/vectors/vector-management-resource.component.d.ts +240 -0
  24. package/dist/AI/components/vectors/vector-management-resource.component.d.ts.map +1 -0
  25. package/dist/AI/components/vectors/vector-management-resource.component.js +1767 -0
  26. package/dist/AI/components/vectors/vector-management-resource.component.js.map +1 -0
  27. package/dist/AI/index.d.ts +3 -0
  28. package/dist/AI/index.d.ts.map +1 -1
  29. package/dist/AI/index.js +6 -0
  30. package/dist/AI/index.js.map +1 -1
  31. package/dist/AI/services/ai-instrumentation.service.d.ts +50 -7
  32. package/dist/AI/services/ai-instrumentation.service.d.ts.map +1 -1
  33. package/dist/AI/services/ai-instrumentation.service.js +161 -193
  34. package/dist/AI/services/ai-instrumentation.service.js.map +1 -1
  35. package/dist/APIKeys/api-applications-panel.component.js +10 -12
  36. package/dist/APIKeys/api-applications-panel.component.js.map +1 -1
  37. package/dist/APIKeys/api-key-create-dialog.component.js +13 -19
  38. package/dist/APIKeys/api-key-create-dialog.component.js.map +1 -1
  39. package/dist/APIKeys/api-key-edit-panel.component.js +12 -14
  40. package/dist/APIKeys/api-key-edit-panel.component.js.map +1 -1
  41. package/dist/APIKeys/api-scopes-panel.component.js +61 -68
  42. package/dist/APIKeys/api-scopes-panel.component.js.map +1 -1
  43. package/dist/APIKeys/api-usage-panel.component.js +10 -11
  44. package/dist/APIKeys/api-usage-panel.component.js.map +1 -1
  45. package/dist/Actions/components/actions-list-view.component.js +82 -96
  46. package/dist/Actions/components/actions-list-view.component.js.map +1 -1
  47. package/dist/Actions/components/actions-overview.component.js +130 -134
  48. package/dist/Actions/components/actions-overview.component.js.map +1 -1
  49. package/dist/Actions/components/categories-list-view.component.d.ts.map +1 -1
  50. package/dist/Actions/components/categories-list-view.component.js +40 -46
  51. package/dist/Actions/components/categories-list-view.component.js.map +1 -1
  52. package/dist/Actions/components/code-management.component.js +2 -2
  53. package/dist/Actions/components/code-management.component.js.map +1 -1
  54. package/dist/Actions/components/entity-integration.component.js +2 -2
  55. package/dist/Actions/components/entity-integration.component.js.map +1 -1
  56. package/dist/Actions/components/execution-monitoring.component.js +127 -132
  57. package/dist/Actions/components/execution-monitoring.component.js.map +1 -1
  58. package/dist/Actions/components/executions-list-view.component.js +2 -2
  59. package/dist/Actions/components/executions-list-view.component.js.map +1 -1
  60. package/dist/Actions/components/explorer/action-card.component.js +11 -17
  61. package/dist/Actions/components/explorer/action-card.component.js.map +1 -1
  62. package/dist/Actions/components/explorer/action-explorer.component.js +5 -11
  63. package/dist/Actions/components/explorer/action-explorer.component.js.map +1 -1
  64. package/dist/Actions/components/explorer/action-list-item.component.js +8 -10
  65. package/dist/Actions/components/explorer/action-list-item.component.js.map +1 -1
  66. package/dist/Actions/components/explorer/action-toolbar.component.js +112 -133
  67. package/dist/Actions/components/explorer/action-toolbar.component.js.map +1 -1
  68. package/dist/Actions/components/explorer/action-tree-panel.component.js +63 -83
  69. package/dist/Actions/components/explorer/action-tree-panel.component.js.map +1 -1
  70. package/dist/Actions/components/explorer/new-action-panel.component.js +17 -21
  71. package/dist/Actions/components/explorer/new-action-panel.component.js.map +1 -1
  72. package/dist/Actions/components/explorer/new-category-panel.component.js +17 -21
  73. package/dist/Actions/components/explorer/new-category-panel.component.js.map +1 -1
  74. package/dist/Actions/components/scheduled-actions.component.js +2 -2
  75. package/dist/Actions/components/scheduled-actions.component.js.map +1 -1
  76. package/dist/Actions/components/security-permissions.component.js +2 -2
  77. package/dist/Actions/components/security-permissions.component.js.map +1 -1
  78. package/dist/ComponentStudio/component-studio-dashboard.component.d.ts +13 -5
  79. package/dist/ComponentStudio/component-studio-dashboard.component.d.ts.map +1 -1
  80. package/dist/ComponentStudio/component-studio-dashboard.component.js +168 -145
  81. package/dist/ComponentStudio/component-studio-dashboard.component.js.map +1 -1
  82. package/dist/ComponentStudio/components/artifact-load-dialog.component.d.ts +4 -5
  83. package/dist/ComponentStudio/components/artifact-load-dialog.component.d.ts.map +1 -1
  84. package/dist/ComponentStudio/components/artifact-load-dialog.component.js +197 -200
  85. package/dist/ComponentStudio/components/artifact-load-dialog.component.js.map +1 -1
  86. package/dist/ComponentStudio/components/artifact-selection-dialog.component.d.ts +5 -7
  87. package/dist/ComponentStudio/components/artifact-selection-dialog.component.d.ts.map +1 -1
  88. package/dist/ComponentStudio/components/artifact-selection-dialog.component.js +142 -148
  89. package/dist/ComponentStudio/components/artifact-selection-dialog.component.js.map +1 -1
  90. package/dist/ComponentStudio/components/browser/component-browser.component.js +153 -166
  91. package/dist/ComponentStudio/components/browser/component-browser.component.js.map +1 -1
  92. package/dist/ComponentStudio/components/editors/code-editor-panel.component.js +15 -20
  93. package/dist/ComponentStudio/components/editors/code-editor-panel.component.js.map +1 -1
  94. package/dist/ComponentStudio/components/editors/data-requirements-editor.component.js +16 -21
  95. package/dist/ComponentStudio/components/editors/data-requirements-editor.component.js.map +1 -1
  96. package/dist/ComponentStudio/components/editors/requirements-editor.component.js +18 -23
  97. package/dist/ComponentStudio/components/editors/requirements-editor.component.js.map +1 -1
  98. package/dist/ComponentStudio/components/editors/spec-editor.component.js +25 -30
  99. package/dist/ComponentStudio/components/editors/spec-editor.component.js.map +1 -1
  100. package/dist/ComponentStudio/components/new-component-dialog/new-component-dialog.component.js +10 -11
  101. package/dist/ComponentStudio/components/new-component-dialog/new-component-dialog.component.js.map +1 -1
  102. package/dist/ComponentStudio/components/save-version-dialog/save-version-dialog.component.d.ts.map +1 -1
  103. package/dist/ComponentStudio/components/save-version-dialog/save-version-dialog.component.js +24 -35
  104. package/dist/ComponentStudio/components/save-version-dialog/save-version-dialog.component.js.map +1 -1
  105. package/dist/ComponentStudio/components/text-import-dialog.component.js +15 -17
  106. package/dist/ComponentStudio/components/text-import-dialog.component.js.map +1 -1
  107. package/dist/Credentials/components/credentials-categories-resource.component.js +7 -6
  108. package/dist/Credentials/components/credentials-categories-resource.component.js.map +1 -1
  109. package/dist/Credentials/components/credentials-list-resource.component.js +6 -5
  110. package/dist/Credentials/components/credentials-list-resource.component.js.map +1 -1
  111. package/dist/Credentials/components/credentials-types-resource.component.js +7 -6
  112. package/dist/Credentials/components/credentials-types-resource.component.js.map +1 -1
  113. package/dist/DashboardBrowser/dashboard-browser-resource.component.d.ts +11 -0
  114. package/dist/DashboardBrowser/dashboard-browser-resource.component.d.ts.map +1 -1
  115. package/dist/DashboardBrowser/dashboard-browser-resource.component.js +57 -0
  116. package/dist/DashboardBrowser/dashboard-browser-resource.component.js.map +1 -1
  117. package/dist/DashboardBrowser/dashboard-share-dialog.component.js +9 -9
  118. package/dist/DashboardBrowser/dashboard-share-dialog.component.js.map +1 -1
  119. package/dist/DataExplorer/components/navigation-panel/navigation-panel.component.d.ts +1 -1
  120. package/dist/DataExplorer/data-explorer-dashboard.component.d.ts +10 -2
  121. package/dist/DataExplorer/data-explorer-dashboard.component.d.ts.map +1 -1
  122. package/dist/DataExplorer/data-explorer-dashboard.component.js +35 -11
  123. package/dist/DataExplorer/data-explorer-dashboard.component.js.map +1 -1
  124. package/dist/DataExplorer/data-explorer-resource.component.d.ts +1 -0
  125. package/dist/DataExplorer/data-explorer-resource.component.d.ts.map +1 -1
  126. package/dist/DataExplorer/data-explorer-resource.component.js +8 -4
  127. package/dist/DataExplorer/data-explorer-resource.component.js.map +1 -1
  128. package/dist/Home/home-dashboard.component.d.ts +181 -1
  129. package/dist/Home/home-dashboard.component.d.ts.map +1 -1
  130. package/dist/Home/home-dashboard.component.js +1704 -182
  131. package/dist/Home/home-dashboard.component.js.map +1 -1
  132. package/dist/Integration/components/connections/connections.component.js +4 -4
  133. package/dist/Integration/components/connections/connections.component.js.map +1 -1
  134. package/dist/Integration/components/mapping-workspace/mapping-workspace.component.js +246 -259
  135. package/dist/Integration/components/mapping-workspace/mapping-workspace.component.js.map +1 -1
  136. package/dist/Integration/components/widgets/integration-card.component.js +7 -9
  137. package/dist/Integration/components/widgets/integration-card.component.js.map +1 -1
  138. package/dist/Integration/integration.module.d.ts +6 -10
  139. package/dist/Integration/integration.module.d.ts.map +1 -1
  140. package/dist/Integration/integration.module.js +12 -20
  141. package/dist/Integration/integration.module.js.map +1 -1
  142. package/dist/KnowledgeHub/components/clusters/cluster-visualization-resource.component.d.ts +106 -0
  143. package/dist/KnowledgeHub/components/clusters/cluster-visualization-resource.component.d.ts.map +1 -0
  144. package/dist/KnowledgeHub/components/clusters/cluster-visualization-resource.component.js +607 -0
  145. package/dist/KnowledgeHub/components/clusters/cluster-visualization-resource.component.js.map +1 -0
  146. package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.d.ts +126 -0
  147. package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.d.ts.map +1 -0
  148. package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.js +1086 -0
  149. package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.js.map +1 -0
  150. package/dist/KnowledgeHub/components/results-detail/search-result-detail.component.d.ts +56 -0
  151. package/dist/KnowledgeHub/components/results-detail/search-result-detail.component.d.ts.map +1 -0
  152. package/dist/KnowledgeHub/components/results-detail/search-result-detail.component.js +291 -0
  153. package/dist/KnowledgeHub/components/results-detail/search-result-detail.component.js.map +1 -0
  154. package/dist/KnowledgeHub/components/search/knowledge-search-resource.component.d.ts +85 -0
  155. package/dist/KnowledgeHub/components/search/knowledge-search-resource.component.d.ts.map +1 -0
  156. package/dist/KnowledgeHub/components/search/knowledge-search-resource.component.js +461 -0
  157. package/dist/KnowledgeHub/components/search/knowledge-search-resource.component.js.map +1 -0
  158. package/dist/KnowledgeHub/index.d.ts +5 -0
  159. package/dist/KnowledgeHub/index.d.ts.map +1 -0
  160. package/dist/KnowledgeHub/index.js +6 -0
  161. package/dist/KnowledgeHub/index.js.map +1 -0
  162. package/dist/Lists/components/lists-browse-resource.component.d.ts.map +1 -1
  163. package/dist/Lists/components/lists-browse-resource.component.js +9 -7
  164. package/dist/Lists/components/lists-browse-resource.component.js.map +1 -1
  165. package/dist/Lists/components/lists-my-lists-resource.component.js +5 -4
  166. package/dist/Lists/components/lists-my-lists-resource.component.js.map +1 -1
  167. package/dist/Lists/components/lists-operations-resource.component.js +10 -9
  168. package/dist/Lists/components/lists-operations-resource.component.js.map +1 -1
  169. package/dist/MCP/components/mcp-connection-dialog.component.js +141 -132
  170. package/dist/MCP/components/mcp-connection-dialog.component.js.map +1 -1
  171. package/dist/MCP/components/mcp-log-detail-panel.component.js +4 -4
  172. package/dist/MCP/components/mcp-log-detail-panel.component.js.map +1 -1
  173. package/dist/MCP/components/mcp-server-dialog.component.js +141 -128
  174. package/dist/MCP/components/mcp-server-dialog.component.js.map +1 -1
  175. package/dist/MCP/components/mcp-test-tool-dialog.component.js +210 -218
  176. package/dist/MCP/components/mcp-test-tool-dialog.component.js.map +1 -1
  177. package/dist/MCP/mcp-dashboard.component.js +2 -2
  178. package/dist/MCP/mcp-dashboard.component.js.map +1 -1
  179. package/dist/MCP/mcp.module.d.ts +6 -9
  180. package/dist/MCP/mcp.module.d.ts.map +1 -1
  181. package/dist/MCP/mcp.module.js +20 -22
  182. package/dist/MCP/mcp.module.js.map +1 -1
  183. package/dist/QueryBrowser/query-browser-resource.component.d.ts.map +1 -1
  184. package/dist/QueryBrowser/query-browser-resource.component.js +5 -1
  185. package/dist/QueryBrowser/query-browser-resource.component.js.map +1 -1
  186. package/dist/Scheduling/components/scheduling-activity.component.js +5 -4
  187. package/dist/Scheduling/components/scheduling-activity.component.js.map +1 -1
  188. package/dist/Scheduling/components/scheduling-jobs.component.js +6 -5
  189. package/dist/Scheduling/components/scheduling-jobs.component.js.map +1 -1
  190. package/dist/Scheduling/components/scheduling-overview.component.js +93 -92
  191. package/dist/Scheduling/components/scheduling-overview.component.js.map +1 -1
  192. package/dist/SystemDiagnostics/system-diagnostics.component.d.ts.map +1 -1
  193. package/dist/SystemDiagnostics/system-diagnostics.component.js +1 -0
  194. package/dist/SystemDiagnostics/system-diagnostics.component.js.map +1 -1
  195. package/dist/Testing/components/testing-dashboard-tab-resource.component.d.ts +7 -1
  196. package/dist/Testing/components/testing-dashboard-tab-resource.component.d.ts.map +1 -1
  197. package/dist/Testing/components/testing-dashboard-tab-resource.component.js +63 -8
  198. package/dist/Testing/components/testing-dashboard-tab-resource.component.js.map +1 -1
  199. package/dist/Testing/components/testing-dashboard-tab.component.d.ts +9 -1
  200. package/dist/Testing/components/testing-dashboard-tab.component.d.ts.map +1 -1
  201. package/dist/Testing/components/testing-dashboard-tab.component.js +109 -62
  202. package/dist/Testing/components/testing-dashboard-tab.component.js.map +1 -1
  203. package/dist/Testing/components/testing-explorer.component.d.ts +2 -1
  204. package/dist/Testing/components/testing-explorer.component.d.ts.map +1 -1
  205. package/dist/Testing/components/testing-explorer.component.js +241 -200
  206. package/dist/Testing/components/testing-explorer.component.js.map +1 -1
  207. package/dist/Testing/components/testing-runs-resource.component.d.ts +7 -1
  208. package/dist/Testing/components/testing-runs-resource.component.d.ts.map +1 -1
  209. package/dist/Testing/components/testing-runs-resource.component.js +63 -8
  210. package/dist/Testing/components/testing-runs-resource.component.js.map +1 -1
  211. package/dist/Testing/components/testing-runs.component.d.ts.map +1 -1
  212. package/dist/Testing/components/testing-runs.component.js +7 -5
  213. package/dist/Testing/components/testing-runs.component.js.map +1 -1
  214. package/dist/Testing/testing-dashboard.component.d.ts +9 -1
  215. package/dist/Testing/testing-dashboard.component.d.ts.map +1 -1
  216. package/dist/Testing/testing-dashboard.component.js +122 -54
  217. package/dist/Testing/testing-dashboard.component.js.map +1 -1
  218. package/dist/actions-dashboards.module.d.ts +8 -13
  219. package/dist/actions-dashboards.module.d.ts.map +1 -1
  220. package/dist/actions-dashboards.module.js +6 -27
  221. package/dist/actions-dashboards.module.js.map +1 -1
  222. package/dist/ai-dashboards.module.d.ts +14 -11
  223. package/dist/ai-dashboards.module.d.ts.map +1 -1
  224. package/dist/ai-dashboards.module.js +58 -44
  225. package/dist/ai-dashboards.module.js.map +1 -1
  226. package/dist/communication-dashboards.module.d.ts +4 -8
  227. package/dist/communication-dashboards.module.d.ts.map +1 -1
  228. package/dist/communication-dashboards.module.js +0 -19
  229. package/dist/communication-dashboards.module.js.map +1 -1
  230. package/dist/component-studio-dashboards.module.d.ts +7 -11
  231. package/dist/component-studio-dashboards.module.d.ts.map +1 -1
  232. package/dist/component-studio-dashboards.module.js +22 -34
  233. package/dist/component-studio-dashboards.module.js.map +1 -1
  234. package/dist/core-dashboards.module.d.ts +13 -18
  235. package/dist/core-dashboards.module.d.ts.map +1 -1
  236. package/dist/core-dashboards.module.js +18 -31
  237. package/dist/core-dashboards.module.js.map +1 -1
  238. package/dist/credentials-dashboards.module.d.ts +5 -8
  239. package/dist/credentials-dashboards.module.d.ts.map +1 -1
  240. package/dist/credentials-dashboards.module.js +3 -19
  241. package/dist/credentials-dashboards.module.js.map +1 -1
  242. package/dist/data-explorer-dashboards.module.d.ts +7 -13
  243. package/dist/data-explorer-dashboards.module.d.ts.map +1 -1
  244. package/dist/data-explorer-dashboards.module.js +0 -27
  245. package/dist/data-explorer-dashboards.module.js.map +1 -1
  246. package/dist/lists-dashboards.module.d.ts +5 -8
  247. package/dist/lists-dashboards.module.d.ts.map +1 -1
  248. package/dist/lists-dashboards.module.js +3 -19
  249. package/dist/lists-dashboards.module.js.map +1 -1
  250. package/dist/public-api.d.ts +5 -1
  251. package/dist/public-api.d.ts.map +1 -1
  252. package/dist/public-api.js +6 -1
  253. package/dist/public-api.js.map +1 -1
  254. package/dist/scheduling-dashboards.module.d.ts +6 -10
  255. package/dist/scheduling-dashboards.module.d.ts.map +1 -1
  256. package/dist/scheduling-dashboards.module.js +3 -23
  257. package/dist/scheduling-dashboards.module.js.map +1 -1
  258. package/dist/testing-dashboards.module.d.ts +7 -12
  259. package/dist/testing-dashboards.module.d.ts.map +1 -1
  260. package/dist/testing-dashboards.module.js +4 -27
  261. package/dist/testing-dashboards.module.js.map +1 -1
  262. package/package.json +47 -53
@@ -2,9 +2,8 @@ import { Component } from '@angular/core';
2
2
  import { Metadata, RunView } from '@memberjunction/core';
3
3
  import * as i0 from "@angular/core";
4
4
  import * as i1 from "@angular/common";
5
- import * as i2 from "@progress/kendo-angular-buttons";
6
- import * as i3 from "@progress/kendo-angular-dialog";
7
- import * as i4 from "@memberjunction/ng-shared-generic";
5
+ import * as i2 from "@memberjunction/ng-ui-components";
6
+ import * as i3 from "@memberjunction/ng-shared-generic";
8
7
  function APIUsagePanelComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
9
8
  i0.ɵɵelement(0, "mj-loading", 1);
10
9
  } }
@@ -537,9 +536,9 @@ function APIUsagePanelComponent_Conditional_3_Conditional_12_Template(rf, ctx) {
537
536
  } }
538
537
  function APIUsagePanelComponent_Conditional_3_Template(rf, ctx) { if (rf & 1) {
539
538
  const _r11 = i0.ɵɵgetCurrentView();
540
- i0.ɵɵelementStart(0, "kendo-window", 92);
541
- i0.ɵɵlistener("close", function APIUsagePanelComponent_Conditional_3_Template_kendo_window_close_0_listener() { i0.ɵɵrestoreView(_r11); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.closeLogsPanel()); });
542
- i0.ɵɵelementStart(1, "kendo-window-titlebar")(2, "div", 93);
539
+ i0.ɵɵelementStart(0, "mj-window", 92);
540
+ i0.ɵɵlistener("Close", function APIUsagePanelComponent_Conditional_3_Template_mj_window_Close_0_listener() { i0.ɵɵrestoreView(_r11); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.closeLogsPanel()); });
541
+ i0.ɵɵelementStart(1, "mj-window-titlebar")(2, "div", 93);
543
542
  i0.ɵɵelement(3, "i", 94);
544
543
  i0.ɵɵelementStart(4, "span");
545
544
  i0.ɵɵtext(5, "Request Details");
@@ -557,7 +556,7 @@ function APIUsagePanelComponent_Conditional_3_Template(rf, ctx) { if (rf & 1) {
557
556
  i0.ɵɵelementEnd()();
558
557
  } if (rf & 2) {
559
558
  const ctx_r1 = i0.ɵɵnextContext();
560
- i0.ɵɵproperty("width", 800)("minWidth", 600)("height", 500)("minHeight", 400)("resizable", true)("draggable", true)("top", 80);
559
+ i0.ɵɵproperty("Width", 800)("MinWidth", 600)("Height", 500)("MinHeight", 400)("Resizable", true)("Draggable", true)("Top", 80)("Visible", true);
561
560
  i0.ɵɵadvance(6);
562
561
  i0.ɵɵconditional(ctx_r1.LogsFilter.endpoint ? 6 : -1);
563
562
  i0.ɵɵadvance();
@@ -993,11 +992,11 @@ export class APIUsagePanelComponent {
993
992
  return num.toString();
994
993
  }
995
994
  static ɵfac = function APIUsagePanelComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || APIUsagePanelComponent)(i0.ɵɵdirectiveInject(i0.ChangeDetectorRef)); };
996
- static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: APIUsagePanelComponent, selectors: [["mj-api-usage-panel"]], standalone: false, decls: 4, vars: 3, consts: [[1, "usage-panel"], ["text", "Loading usage analytics..."], [3, "width", "minWidth", "height", "minHeight", "resizable", "draggable", "top"], [1, "panel-header"], [1, "header-left"], [1, "panel-title"], [1, "fa-solid", "fa-chart-line"], [1, "panel-subtitle"], [1, "time-filters"], [1, "time-btn", 3, "click"], [1, "kpi-grid"], [1, "kpi-card"], [1, "kpi-icon", "requests"], [1, "fa-solid", "fa-arrow-right-arrow-left"], [1, "kpi-content"], [1, "kpi-value"], [1, "kpi-label"], [1, "kpi-icon", "success-rate"], [1, "fa-solid", "fa-check-circle"], [1, "kpi-icon", "errors"], [1, "fa-solid", "fa-circle-exclamation"], [1, "kpi-icon", "response-time"], [1, "fa-solid", "fa-gauge-high"], [1, "kpi-icon", "keys"], [1, "fa-solid", "fa-key"], [1, "kpi-icon", "endpoints"], [1, "fa-solid", "fa-code-branch"], [1, "chart-section"], [1, "chart-header"], [1, "chart-legend"], [1, "legend-item"], [1, "legend-color", "requests"], [1, "legend-color", "errors"], [1, "chart-container"], [1, "empty-chart"], [1, "breakdown-grid"], [1, "breakdown-card"], [1, "breakdown-header"], [1, "breakdown-content"], [1, "endpoint-list"], [1, "empty-state"], [1, "key-list"], [1, "fa-solid", "fa-circle-half-stroke"], [1, "status-distribution"], [1, "logs-section"], [1, "logs-header"], [1, "fa-solid", "fa-list"], [1, "logs-table"], [1, "empty-state", "large"], [1, "chart-bars"], [1, "bar-group", 3, "title"], [1, "chart-y-axis"], [1, "bar-wrapper"], [1, "bar", "requests-bar"], [1, "bar", "errors-bar", 3, "height"], [1, "bar-label"], [1, "bar", "errors-bar"], [1, "fa-solid", "fa-chart-area"], [1, "endpoint-item"], [1, "endpoint-item", 3, "click"], [1, "endpoint-info"], [1, "method-badge", 3, "ngClass"], [1, "endpoint-path"], [1, "endpoint-stats"], [1, "endpoint-requests"], [1, "endpoint-time"], [1, "endpoint-error"], [1, "key-item"], [1, "key-item", 3, "click"], [1, "key-info"], [1, "key-label"], [1, "key-last-used"], [1, "key-requests"], [1, "status-bar"], [1, "status-segment", 3, "width", "backgroundColor", "title"], [1, "status-legend"], [1, "status-legend-item"], [1, "status-segment", 3, "title"], [1, "status-color"], [1, "status-label"], [1, "status-count"], [1, "logs-table-header"], [1, "col-time"], [1, "col-key"], [1, "col-method"], [1, "col-endpoint"], [1, "col-status"], [1, "col-duration"], [1, "logs-table-body"], [1, "log-row"], [1, "col-status", 3, "ngClass"], [1, "fa-solid", "fa-inbox"], [3, "close", "width", "minWidth", "height", "minHeight", "resizable", "draggable", "top"], [1, "drilldown-title"], [1, "fa-solid", "fa-magnifying-glass-chart"], [1, "filter-badge"], ["kendoButton", "", "fillMode", "flat", 1, "window-close-btn", 3, "click"], [1, "fa-solid", "fa-times"], [1, "drilldown-content"], ["text", "Loading requests..."], [1, "drilldown-logs"], [1, "logs-table-body", "scrollable"]], template: function APIUsagePanelComponent_Template(rf, ctx) { if (rf & 1) {
995
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: APIUsagePanelComponent, selectors: [["mj-api-usage-panel"]], standalone: false, decls: 4, vars: 3, consts: [[1, "usage-panel"], ["text", "Loading usage analytics..."], [3, "Width", "MinWidth", "Height", "MinHeight", "Resizable", "Draggable", "Top", "Visible"], [1, "panel-header"], [1, "header-left"], [1, "panel-title"], [1, "fa-solid", "fa-chart-line"], [1, "panel-subtitle"], [1, "time-filters"], [1, "time-btn", 3, "click"], [1, "kpi-grid"], [1, "kpi-card"], [1, "kpi-icon", "requests"], [1, "fa-solid", "fa-arrow-right-arrow-left"], [1, "kpi-content"], [1, "kpi-value"], [1, "kpi-label"], [1, "kpi-icon", "success-rate"], [1, "fa-solid", "fa-check-circle"], [1, "kpi-icon", "errors"], [1, "fa-solid", "fa-circle-exclamation"], [1, "kpi-icon", "response-time"], [1, "fa-solid", "fa-gauge-high"], [1, "kpi-icon", "keys"], [1, "fa-solid", "fa-key"], [1, "kpi-icon", "endpoints"], [1, "fa-solid", "fa-code-branch"], [1, "chart-section"], [1, "chart-header"], [1, "chart-legend"], [1, "legend-item"], [1, "legend-color", "requests"], [1, "legend-color", "errors"], [1, "chart-container"], [1, "empty-chart"], [1, "breakdown-grid"], [1, "breakdown-card"], [1, "breakdown-header"], [1, "breakdown-content"], [1, "endpoint-list"], [1, "empty-state"], [1, "key-list"], [1, "fa-solid", "fa-circle-half-stroke"], [1, "status-distribution"], [1, "logs-section"], [1, "logs-header"], [1, "fa-solid", "fa-list"], [1, "logs-table"], [1, "empty-state", "large"], [1, "chart-bars"], [1, "bar-group", 3, "title"], [1, "chart-y-axis"], [1, "bar-wrapper"], [1, "bar", "requests-bar"], [1, "bar", "errors-bar", 3, "height"], [1, "bar-label"], [1, "bar", "errors-bar"], [1, "fa-solid", "fa-chart-area"], [1, "endpoint-item"], [1, "endpoint-item", 3, "click"], [1, "endpoint-info"], [1, "method-badge", 3, "ngClass"], [1, "endpoint-path"], [1, "endpoint-stats"], [1, "endpoint-requests"], [1, "endpoint-time"], [1, "endpoint-error"], [1, "key-item"], [1, "key-item", 3, "click"], [1, "key-info"], [1, "key-label"], [1, "key-last-used"], [1, "key-requests"], [1, "status-bar"], [1, "status-segment", 3, "width", "backgroundColor", "title"], [1, "status-legend"], [1, "status-legend-item"], [1, "status-segment", 3, "title"], [1, "status-color"], [1, "status-label"], [1, "status-count"], [1, "logs-table-header"], [1, "col-time"], [1, "col-key"], [1, "col-method"], [1, "col-endpoint"], [1, "col-status"], [1, "col-duration"], [1, "logs-table-body"], [1, "log-row"], [1, "col-status", 3, "ngClass"], [1, "fa-solid", "fa-inbox"], [3, "Close", "Width", "MinWidth", "Height", "MinHeight", "Resizable", "Draggable", "Top", "Visible"], [1, "drilldown-title"], [1, "fa-solid", "fa-magnifying-glass-chart"], [1, "filter-badge"], ["mjButton", "", "variant", "flat", 1, "window-close-btn", 3, "click"], [1, "fa-solid", "fa-times"], [1, "drilldown-content"], ["text", "Loading requests..."], [1, "drilldown-logs"], [1, "logs-table-body", "scrollable"]], template: function APIUsagePanelComponent_Template(rf, ctx) { if (rf & 1) {
997
996
  i0.ɵɵelementStart(0, "div", 0);
998
997
  i0.ɵɵconditionalCreate(1, APIUsagePanelComponent_Conditional_1_Template, 1, 0, "mj-loading", 1);
999
998
  i0.ɵɵconditionalCreate(2, APIUsagePanelComponent_Conditional_2_Template, 110, 28);
1000
- i0.ɵɵconditionalCreate(3, APIUsagePanelComponent_Conditional_3_Template, 13, 11, "kendo-window", 2);
999
+ i0.ɵɵconditionalCreate(3, APIUsagePanelComponent_Conditional_3_Template, 13, 12, "mj-window", 2);
1001
1000
  i0.ɵɵelementEnd();
1002
1001
  } if (rf & 2) {
1003
1002
  i0.ɵɵadvance();
@@ -1006,11 +1005,11 @@ export class APIUsagePanelComponent {
1006
1005
  i0.ɵɵconditional(!ctx.IsLoading ? 2 : -1);
1007
1006
  i0.ɵɵadvance();
1008
1007
  i0.ɵɵconditional(ctx.ShowLogsPanel ? 3 : -1);
1009
- } }, dependencies: [i1.NgClass, i2.ButtonComponent, i3.WindowComponent, i3.WindowTitleBarComponent, i4.LoadingComponent], styles: [".usage-panel[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 24px;\n padding: 24px;\n background: var(--mj-bg-page);\n min-height: 100%;\n}\n\n\n\n.panel-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n gap: 24px;\n flex-wrap: wrap;\n}\n\n.header-left[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.panel-title[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n margin: 0;\n font-size: 24px;\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n\n.panel-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-color-indigo-500);\n}\n\n.panel-subtitle[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 14px;\n color: var(--mj-text-secondary);\n}\n\n\n\n.time-filters[_ngcontent-%COMP%] {\n display: flex;\n gap: 4px;\n background: var(--mj-bg-surface);\n padding: 4px;\n border-radius: 10px;\n box-shadow: var(--mj-shadow-sm);\n}\n\n.time-btn[_ngcontent-%COMP%] {\n padding: 8px 16px;\n background: transparent;\n border: none;\n border-radius: 8px;\n font-size: 13px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.time-btn[_ngcontent-%COMP%]:hover {\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface-sunken);\n}\n\n.time-btn.active[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, var(--mj-color-indigo-500) 0%, var(--mj-color-indigo-600) 100%);\n color: var(--mj-text-inverse);\n box-shadow: 0 2px 8px color-mix(in srgb, var(--mj-color-indigo-500) 30%, transparent);\n}\n\n\n\n.kpi-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(6, 1fr);\n gap: 16px;\n}\n\n.kpi-card[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 14px;\n padding: 18px 20px;\n background: var(--mj-bg-surface);\n border-radius: 12px;\n box-shadow: var(--mj-shadow-sm);\n transition: all 0.2s ease;\n}\n\n.kpi-card[_ngcontent-%COMP%]:hover {\n box-shadow: var(--mj-shadow-lg);\n transform: translateY(-2px);\n}\n\n.kpi-card.success[_ngcontent-%COMP%] {\n background: var(--mj-status-success-bg);\n}\n\n.kpi-card.warning[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, var(--mj-color-brand-100) 0%, var(--mj-color-brand-200) 100%);\n}\n\n.kpi-icon[_ngcontent-%COMP%] {\n width: 44px;\n height: 44px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 10px;\n font-size: 18px;\n}\n\n.kpi-icon.requests[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, var(--mj-color-info-100) 0%, var(--mj-color-info-100) 100%);\n color: var(--mj-color-info-600);\n}\n\n.kpi-icon.success-rate[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, var(--mj-color-success-100) 0%, var(--mj-color-success-200) 100%);\n color: var(--mj-color-success-600);\n}\n\n.kpi-icon.errors[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, var(--mj-color-error-100) 0%, var(--mj-color-error-200) 100%);\n color: var(--mj-color-error-600);\n}\n\n.kpi-icon.response-time[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, var(--mj-color-indigo-100) 0%, var(--mj-color-indigo-200) 100%);\n color: var(--mj-color-indigo-600);\n}\n\n.kpi-icon.keys[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, var(--mj-color-brand-100) 0%, var(--mj-color-brand-200) 100%);\n color: var(--mj-brand-primary-hover);\n}\n\n.kpi-icon.endpoints[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, var(--mj-color-violet-50) 0%, var(--mj-color-violet-200) 100%);\n color: var(--mj-brand-primary);\n}\n\n.kpi-content[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.kpi-value[_ngcontent-%COMP%] {\n font-size: 22px;\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n\n.kpi-label[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-secondary);\n}\n\n\n\n.chart-section[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n border-radius: 12px;\n padding: 20px;\n box-shadow: var(--mj-shadow-sm);\n}\n\n.chart-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 16px;\n}\n\n.chart-header[_ngcontent-%COMP%] h4[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.chart-legend[_ngcontent-%COMP%] {\n display: flex;\n gap: 16px;\n}\n\n.legend-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 12px;\n color: var(--mj-text-secondary);\n}\n\n.legend-color[_ngcontent-%COMP%] {\n width: 12px;\n height: 12px;\n border-radius: 3px;\n}\n\n.legend-color.requests[_ngcontent-%COMP%] {\n background: var(--mj-color-indigo-500);\n}\n\n.legend-color.errors[_ngcontent-%COMP%] {\n background: var(--mj-status-error);\n}\n\n.chart-container[_ngcontent-%COMP%] {\n display: flex;\n height: 200px;\n gap: 8px;\n}\n\n.chart-bars[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n align-items: flex-end;\n gap: 4px;\n padding-bottom: 24px;\n}\n\n.bar-group[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n min-width: 0;\n}\n\n.bar-wrapper[_ngcontent-%COMP%] {\n width: 100%;\n height: 160px;\n display: flex;\n align-items: flex-end;\n justify-content: center;\n}\n\n.bar[_ngcontent-%COMP%] {\n width: 100%;\n max-width: 32px;\n border-radius: 4px 4px 0 0;\n transition: all 0.3s ease;\n position: relative;\n}\n\n.bar.requests-bar[_ngcontent-%COMP%] {\n background: linear-gradient(180deg, var(--mj-color-indigo-500) 0%, var(--mj-color-indigo-400) 100%);\n}\n\n.bar.requests-bar[_ngcontent-%COMP%]:hover {\n background: linear-gradient(180deg, var(--mj-color-indigo-600) 0%, var(--mj-color-indigo-500) 100%);\n}\n\n.bar.errors-bar[_ngcontent-%COMP%] {\n position: absolute;\n bottom: 0;\n left: 0;\n width: 100%;\n background: var(--mj-status-error);\n border-radius: 0;\n}\n\n.bar-label[_ngcontent-%COMP%] {\n margin-top: 8px;\n font-size: 10px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n text-overflow: ellipsis;\n overflow: hidden;\n max-width: 100%;\n}\n\n.chart-y-axis[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n justify-content: space-between;\n padding-bottom: 24px;\n font-size: 10px;\n color: var(--mj-text-muted);\n text-align: right;\n min-width: 40px;\n}\n\n.empty-chart[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 200px;\n color: var(--mj-text-muted);\n}\n\n.empty-chart[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 32px;\n margin-bottom: 8px;\n opacity: 0.5;\n}\n\n\n\n.breakdown-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: 1fr 1fr 1fr;\n gap: 20px;\n}\n\n.breakdown-card[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n border-radius: 12px;\n box-shadow: var(--mj-shadow-sm);\n overflow: hidden;\n}\n\n.breakdown-header[_ngcontent-%COMP%] {\n padding: 16px 20px;\n background: var(--mj-bg-page);\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.breakdown-header[_ngcontent-%COMP%] h4[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.breakdown-header[_ngcontent-%COMP%] h4[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n}\n\n.breakdown-content[_ngcontent-%COMP%] {\n padding: 12px;\n max-height: 280px;\n overflow-y: auto;\n}\n\n\n\n.endpoint-list[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.endpoint-item[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 10px 12px;\n background: var(--mj-bg-page);\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.endpoint-item[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n}\n\n.endpoint-info[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 0;\n flex: 1;\n}\n\n.method-badge[_ngcontent-%COMP%] {\n padding: 2px 6px;\n border-radius: 4px;\n font-size: 10px;\n font-weight: 600;\n text-transform: uppercase;\n flex-shrink: 0;\n}\n\n.method-get[_ngcontent-%COMP%] { background: var(--mj-status-info-bg); color: var(--mj-color-info-600); }\n.method-post[_ngcontent-%COMP%] { background: var(--mj-color-success-100); color: var(--mj-color-success-600); }\n.method-put[_ngcontent-%COMP%] { background: var(--mj-color-brand-100); color: var(--mj-brand-primary-hover); }\n.method-delete[_ngcontent-%COMP%] { background: var(--mj-color-error-100); color: var(--mj-color-error-600); }\n.method-other[_ngcontent-%COMP%] { background: var(--mj-bg-surface-sunken); color: var(--mj-text-secondary); }\n\n.endpoint-path[_ngcontent-%COMP%] {\n font-size: 12px;\n font-family: 'Fira Code', monospace;\n color: var(--mj-text-secondary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.endpoint-stats[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n font-size: 11px;\n flex-shrink: 0;\n}\n\n.endpoint-requests[_ngcontent-%COMP%] {\n font-weight: 600;\n color: var(--mj-color-indigo-500);\n}\n\n.endpoint-time[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n}\n\n.endpoint-error[_ngcontent-%COMP%] {\n color: var(--mj-status-success);\n}\n\n.endpoint-error.has-errors[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n font-weight: 500;\n}\n\n\n\n.key-list[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.key-item[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 10px 12px;\n background: var(--mj-bg-page);\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.key-item[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n}\n\n.key-info[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n}\n\n.key-label[_ngcontent-%COMP%] {\n font-size: 13px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.key-last-used[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-muted);\n}\n\n.key-requests[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-color-indigo-500);\n}\n\n\n\n.status-distribution[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 16px;\n}\n\n.status-bar[_ngcontent-%COMP%] {\n display: flex;\n height: 24px;\n border-radius: 6px;\n overflow: hidden;\n background: var(--mj-bg-surface-sunken);\n}\n\n.status-segment[_ngcontent-%COMP%] {\n transition: all 0.3s ease;\n}\n\n.status-segment[_ngcontent-%COMP%]:hover {\n filter: brightness(1.1);\n}\n\n.status-legend[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.status-legend-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 12px;\n}\n\n.status-color[_ngcontent-%COMP%] {\n width: 12px;\n height: 12px;\n border-radius: 3px;\n}\n\n.status-label[_ngcontent-%COMP%] {\n flex: 1;\n color: var(--mj-text-secondary);\n}\n\n.status-count[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n font-weight: 500;\n}\n\n\n\n.logs-section[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n border-radius: 12px;\n box-shadow: var(--mj-shadow-sm);\n overflow: hidden;\n}\n\n.logs-header[_ngcontent-%COMP%] {\n padding: 16px 20px;\n background: var(--mj-bg-page);\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.logs-header[_ngcontent-%COMP%] h4[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.logs-header[_ngcontent-%COMP%] h4[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n}\n\n.logs-table[_ngcontent-%COMP%] {\n width: 100%;\n}\n\n.logs-table-header[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: 100px 120px 70px 1fr 70px 80px;\n gap: 12px;\n padding: 12px 20px;\n background: var(--mj-bg-surface-sunken);\n font-size: 11px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.logs-table-body[_ngcontent-%COMP%] {\n max-height: 320px;\n overflow-y: auto;\n}\n\n.logs-table-body.scrollable[_ngcontent-%COMP%] {\n max-height: 380px;\n}\n\n.log-row[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: 100px 120px 70px 1fr 70px 80px;\n gap: 12px;\n padding: 12px 20px;\n border-bottom: 1px solid var(--mj-bg-surface-sunken);\n font-size: 13px;\n align-items: center;\n transition: background 0.2s ease;\n}\n\n.log-row[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-page);\n}\n\n.col-time[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n font-size: 12px;\n}\n\n.col-key[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n font-weight: 500;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.col-endpoint[_ngcontent-%COMP%] {\n font-family: 'Fira Code', monospace;\n font-size: 12px;\n color: var(--mj-text-secondary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.col-status[_ngcontent-%COMP%] {\n font-weight: 600;\n text-align: center;\n}\n\n.col-status.status-success[_ngcontent-%COMP%] { color: var(--mj-status-success); }\n.col-status.status-info[_ngcontent-%COMP%] { color: var(--mj-status-info); }\n.col-status.status-warning[_ngcontent-%COMP%] { color: var(--mj-color-warning-500); }\n.col-status.status-error[_ngcontent-%COMP%] { color: var(--mj-status-error); }\n\n.col-duration[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n text-align: right;\n}\n\n\n\n.empty-state[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 32px 20px;\n color: var(--mj-text-muted);\n text-align: center;\n}\n\n.empty-state[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 32px;\n margin-bottom: 8px;\n opacity: 0.5;\n}\n\n.empty-state[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n font-size: 13px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n}\n\n.empty-state.large[_ngcontent-%COMP%] {\n padding: 48px 24px;\n}\n\n.empty-state.large[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 48px;\n}\n\n.empty-state[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 8px 0 0 0;\n font-size: 12px;\n}\n\n\n\n.drilldown-title[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n font-weight: 600;\n font-size: 15px;\n}\n\n.drilldown-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-color-indigo-500);\n}\n\n.filter-badge[_ngcontent-%COMP%] {\n padding: 4px 10px;\n background: var(--mj-color-indigo-100);\n border-radius: 12px;\n font-size: 11px;\n font-weight: 500;\n color: var(--mj-color-indigo-600);\n}\n\n.window-close-btn[_ngcontent-%COMP%] {\n margin-left: auto;\n color: var(--mj-text-muted);\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 8px;\n}\n\n.window-close-btn[_ngcontent-%COMP%]:hover {\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface-hover);\n}\n\n.drilldown-content[_ngcontent-%COMP%] {\n height: 100%;\n overflow: hidden;\n}\n\n.drilldown-logs[_ngcontent-%COMP%] {\n height: 100%;\n}\n\n\n\n[_nghost-%COMP%] kendo-window {\n border-radius: 12px !important;\n overflow: hidden;\n box-shadow: var(--mj-shadow-2xl) !important;\n}\n\n[_nghost-%COMP%] kendo-window .k-window-content {\n padding: 0 !important;\n}\n\n[_nghost-%COMP%] kendo-window-titlebar {\n padding: 16px 20px !important;\n background: var(--mj-bg-page) !important;\n border-bottom: 1px solid var(--mj-border-default) !important;\n}\n\n\n\n@media (max-width: 1400px) {\n .kpi-grid[_ngcontent-%COMP%] {\n grid-template-columns: repeat(3, 1fr);\n }\n}\n\n@media (max-width: 1200px) {\n .breakdown-grid[_ngcontent-%COMP%] {\n grid-template-columns: 1fr 1fr;\n }\n}\n\n@media (max-width: 900px) {\n .kpi-grid[_ngcontent-%COMP%] {\n grid-template-columns: repeat(2, 1fr);\n }\n\n .breakdown-grid[_ngcontent-%COMP%] {\n grid-template-columns: 1fr;\n }\n\n .logs-table-header[_ngcontent-%COMP%], \n .log-row[_ngcontent-%COMP%] {\n grid-template-columns: 80px 100px 60px 1fr 60px;\n }\n\n .col-duration[_ngcontent-%COMP%] {\n display: none;\n }\n}\n\n@media (max-width: 600px) {\n .panel-header[_ngcontent-%COMP%] {\n flex-direction: column;\n }\n\n .time-filters[_ngcontent-%COMP%] {\n width: 100%;\n justify-content: center;\n }\n\n .kpi-grid[_ngcontent-%COMP%] {\n grid-template-columns: 1fr;\n }\n\n .logs-table-header[_ngcontent-%COMP%], \n .log-row[_ngcontent-%COMP%] {\n grid-template-columns: 1fr 60px;\n }\n\n .col-key[_ngcontent-%COMP%], \n .col-method[_ngcontent-%COMP%], \n .col-endpoint[_ngcontent-%COMP%] {\n display: none;\n }\n}"] });
1008
+ } }, dependencies: [i1.NgClass, i2.MJButtonDirective, i2.MJWindowComponent, i2.MJWindowTitlebarComponent, i3.LoadingComponent], styles: [".usage-panel[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 24px;\n padding: 24px;\n background: var(--mj-bg-page);\n min-height: 100%;\n}\n\n\n\n.panel-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n gap: 24px;\n flex-wrap: wrap;\n}\n\n.header-left[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.panel-title[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n margin: 0;\n font-size: 24px;\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n\n.panel-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-color-indigo-500);\n}\n\n.panel-subtitle[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 14px;\n color: var(--mj-text-secondary);\n}\n\n\n\n.time-filters[_ngcontent-%COMP%] {\n display: flex;\n gap: 4px;\n background: var(--mj-bg-surface);\n padding: 4px;\n border-radius: 10px;\n box-shadow: var(--mj-shadow-sm);\n}\n\n.time-btn[_ngcontent-%COMP%] {\n padding: 8px 16px;\n background: transparent;\n border: none;\n border-radius: 8px;\n font-size: 13px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.time-btn[_ngcontent-%COMP%]:hover {\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface-sunken);\n}\n\n.time-btn.active[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, var(--mj-color-indigo-500) 0%, var(--mj-color-indigo-600) 100%);\n color: var(--mj-text-inverse);\n box-shadow: 0 2px 8px color-mix(in srgb, var(--mj-color-indigo-500) 30%, transparent);\n}\n\n\n\n.kpi-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(6, 1fr);\n gap: 16px;\n}\n\n.kpi-card[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 14px;\n padding: 18px 20px;\n background: var(--mj-bg-surface);\n border-radius: 12px;\n box-shadow: var(--mj-shadow-sm);\n transition: all 0.2s ease;\n}\n\n.kpi-card[_ngcontent-%COMP%]:hover {\n box-shadow: var(--mj-shadow-lg);\n transform: translateY(-2px);\n}\n\n.kpi-card.success[_ngcontent-%COMP%] {\n background: var(--mj-status-success-bg);\n}\n\n.kpi-card.warning[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, var(--mj-color-brand-100) 0%, var(--mj-color-brand-200) 100%);\n}\n\n.kpi-icon[_ngcontent-%COMP%] {\n width: 44px;\n height: 44px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 10px;\n font-size: 18px;\n}\n\n.kpi-icon.requests[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, var(--mj-color-info-100) 0%, var(--mj-color-info-100) 100%);\n color: var(--mj-color-info-600);\n}\n\n.kpi-icon.success-rate[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, var(--mj-color-success-100) 0%, var(--mj-color-success-200) 100%);\n color: var(--mj-color-success-600);\n}\n\n.kpi-icon.errors[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, var(--mj-color-error-100) 0%, var(--mj-color-error-200) 100%);\n color: var(--mj-color-error-600);\n}\n\n.kpi-icon.response-time[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, var(--mj-color-indigo-100) 0%, var(--mj-color-indigo-200) 100%);\n color: var(--mj-color-indigo-600);\n}\n\n.kpi-icon.keys[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, var(--mj-color-brand-100) 0%, var(--mj-color-brand-200) 100%);\n color: var(--mj-brand-primary-hover);\n}\n\n.kpi-icon.endpoints[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, var(--mj-color-violet-50) 0%, var(--mj-color-violet-200) 100%);\n color: var(--mj-brand-primary);\n}\n\n.kpi-content[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.kpi-value[_ngcontent-%COMP%] {\n font-size: 22px;\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n\n.kpi-label[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-secondary);\n}\n\n\n\n.chart-section[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n border-radius: 12px;\n padding: 20px;\n box-shadow: var(--mj-shadow-sm);\n}\n\n.chart-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 16px;\n}\n\n.chart-header[_ngcontent-%COMP%] h4[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.chart-legend[_ngcontent-%COMP%] {\n display: flex;\n gap: 16px;\n}\n\n.legend-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 12px;\n color: var(--mj-text-secondary);\n}\n\n.legend-color[_ngcontent-%COMP%] {\n width: 12px;\n height: 12px;\n border-radius: 3px;\n}\n\n.legend-color.requests[_ngcontent-%COMP%] {\n background: var(--mj-color-indigo-500);\n}\n\n.legend-color.errors[_ngcontent-%COMP%] {\n background: var(--mj-status-error);\n}\n\n.chart-container[_ngcontent-%COMP%] {\n display: flex;\n height: 200px;\n gap: 8px;\n}\n\n.chart-bars[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n align-items: flex-end;\n gap: 4px;\n padding-bottom: 24px;\n}\n\n.bar-group[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n min-width: 0;\n}\n\n.bar-wrapper[_ngcontent-%COMP%] {\n width: 100%;\n height: 160px;\n display: flex;\n align-items: flex-end;\n justify-content: center;\n}\n\n.bar[_ngcontent-%COMP%] {\n width: 100%;\n max-width: 32px;\n border-radius: 4px 4px 0 0;\n transition: all 0.3s ease;\n position: relative;\n}\n\n.bar.requests-bar[_ngcontent-%COMP%] {\n background: linear-gradient(180deg, var(--mj-color-indigo-500) 0%, var(--mj-color-indigo-400) 100%);\n}\n\n.bar.requests-bar[_ngcontent-%COMP%]:hover {\n background: linear-gradient(180deg, var(--mj-color-indigo-600) 0%, var(--mj-color-indigo-500) 100%);\n}\n\n.bar.errors-bar[_ngcontent-%COMP%] {\n position: absolute;\n bottom: 0;\n left: 0;\n width: 100%;\n background: var(--mj-status-error);\n border-radius: 0;\n}\n\n.bar-label[_ngcontent-%COMP%] {\n margin-top: 8px;\n font-size: 10px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n text-overflow: ellipsis;\n overflow: hidden;\n max-width: 100%;\n}\n\n.chart-y-axis[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n justify-content: space-between;\n padding-bottom: 24px;\n font-size: 10px;\n color: var(--mj-text-muted);\n text-align: right;\n min-width: 40px;\n}\n\n.empty-chart[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 200px;\n color: var(--mj-text-muted);\n}\n\n.empty-chart[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 32px;\n margin-bottom: 8px;\n opacity: 0.5;\n}\n\n\n\n.breakdown-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: 1fr 1fr 1fr;\n gap: 20px;\n}\n\n.breakdown-card[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n border-radius: 12px;\n box-shadow: var(--mj-shadow-sm);\n overflow: hidden;\n}\n\n.breakdown-header[_ngcontent-%COMP%] {\n padding: 16px 20px;\n background: var(--mj-bg-page);\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.breakdown-header[_ngcontent-%COMP%] h4[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.breakdown-header[_ngcontent-%COMP%] h4[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n}\n\n.breakdown-content[_ngcontent-%COMP%] {\n padding: 12px;\n max-height: 280px;\n overflow-y: auto;\n}\n\n\n\n.endpoint-list[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.endpoint-item[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 10px 12px;\n background: var(--mj-bg-page);\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.endpoint-item[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n}\n\n.endpoint-info[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 0;\n flex: 1;\n}\n\n.method-badge[_ngcontent-%COMP%] {\n padding: 2px 6px;\n border-radius: 4px;\n font-size: 10px;\n font-weight: 600;\n text-transform: uppercase;\n flex-shrink: 0;\n}\n\n.method-get[_ngcontent-%COMP%] { background: var(--mj-status-info-bg); color: var(--mj-color-info-600); }\n.method-post[_ngcontent-%COMP%] { background: var(--mj-color-success-100); color: var(--mj-color-success-600); }\n.method-put[_ngcontent-%COMP%] { background: var(--mj-color-brand-100); color: var(--mj-brand-primary-hover); }\n.method-delete[_ngcontent-%COMP%] { background: var(--mj-color-error-100); color: var(--mj-color-error-600); }\n.method-other[_ngcontent-%COMP%] { background: var(--mj-bg-surface-sunken); color: var(--mj-text-secondary); }\n\n.endpoint-path[_ngcontent-%COMP%] {\n font-size: 12px;\n font-family: 'Fira Code', monospace;\n color: var(--mj-text-secondary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.endpoint-stats[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n font-size: 11px;\n flex-shrink: 0;\n}\n\n.endpoint-requests[_ngcontent-%COMP%] {\n font-weight: 600;\n color: var(--mj-color-indigo-500);\n}\n\n.endpoint-time[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n}\n\n.endpoint-error[_ngcontent-%COMP%] {\n color: var(--mj-status-success);\n}\n\n.endpoint-error.has-errors[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n font-weight: 500;\n}\n\n\n\n.key-list[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.key-item[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 10px 12px;\n background: var(--mj-bg-page);\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.key-item[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n}\n\n.key-info[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n}\n\n.key-label[_ngcontent-%COMP%] {\n font-size: 13px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.key-last-used[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-muted);\n}\n\n.key-requests[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-color-indigo-500);\n}\n\n\n\n.status-distribution[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 16px;\n}\n\n.status-bar[_ngcontent-%COMP%] {\n display: flex;\n height: 24px;\n border-radius: 6px;\n overflow: hidden;\n background: var(--mj-bg-surface-sunken);\n}\n\n.status-segment[_ngcontent-%COMP%] {\n transition: all 0.3s ease;\n}\n\n.status-segment[_ngcontent-%COMP%]:hover {\n filter: brightness(1.1);\n}\n\n.status-legend[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.status-legend-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 12px;\n}\n\n.status-color[_ngcontent-%COMP%] {\n width: 12px;\n height: 12px;\n border-radius: 3px;\n}\n\n.status-label[_ngcontent-%COMP%] {\n flex: 1;\n color: var(--mj-text-secondary);\n}\n\n.status-count[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n font-weight: 500;\n}\n\n\n\n.logs-section[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n border-radius: 12px;\n box-shadow: var(--mj-shadow-sm);\n overflow: hidden;\n}\n\n.logs-header[_ngcontent-%COMP%] {\n padding: 16px 20px;\n background: var(--mj-bg-page);\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.logs-header[_ngcontent-%COMP%] h4[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.logs-header[_ngcontent-%COMP%] h4[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n}\n\n.logs-table[_ngcontent-%COMP%] {\n width: 100%;\n}\n\n.logs-table-header[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: 100px 120px 70px 1fr 70px 80px;\n gap: 12px;\n padding: 12px 20px;\n background: var(--mj-bg-surface-sunken);\n font-size: 11px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.logs-table-body[_ngcontent-%COMP%] {\n max-height: 320px;\n overflow-y: auto;\n}\n\n.logs-table-body.scrollable[_ngcontent-%COMP%] {\n max-height: 380px;\n}\n\n.log-row[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: 100px 120px 70px 1fr 70px 80px;\n gap: 12px;\n padding: 12px 20px;\n border-bottom: 1px solid var(--mj-bg-surface-sunken);\n font-size: 13px;\n align-items: center;\n transition: background 0.2s ease;\n}\n\n.log-row[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-page);\n}\n\n.col-time[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n font-size: 12px;\n}\n\n.col-key[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n font-weight: 500;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.col-endpoint[_ngcontent-%COMP%] {\n font-family: 'Fira Code', monospace;\n font-size: 12px;\n color: var(--mj-text-secondary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.col-status[_ngcontent-%COMP%] {\n font-weight: 600;\n text-align: center;\n}\n\n.col-status.status-success[_ngcontent-%COMP%] { color: var(--mj-status-success); }\n.col-status.status-info[_ngcontent-%COMP%] { color: var(--mj-status-info); }\n.col-status.status-warning[_ngcontent-%COMP%] { color: var(--mj-color-warning-500); }\n.col-status.status-error[_ngcontent-%COMP%] { color: var(--mj-status-error); }\n\n.col-duration[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n text-align: right;\n}\n\n\n\n.empty-state[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 32px 20px;\n color: var(--mj-text-muted);\n text-align: center;\n}\n\n.empty-state[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 32px;\n margin-bottom: 8px;\n opacity: 0.5;\n}\n\n.empty-state[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n font-size: 13px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n}\n\n.empty-state.large[_ngcontent-%COMP%] {\n padding: 48px 24px;\n}\n\n.empty-state.large[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 48px;\n}\n\n.empty-state[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 8px 0 0 0;\n font-size: 12px;\n}\n\n\n\n.drilldown-title[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n font-weight: 600;\n font-size: 15px;\n}\n\n.drilldown-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-color-indigo-500);\n}\n\n.filter-badge[_ngcontent-%COMP%] {\n padding: 4px 10px;\n background: var(--mj-color-indigo-100);\n border-radius: 12px;\n font-size: 11px;\n font-weight: 500;\n color: var(--mj-color-indigo-600);\n}\n\n.window-close-btn[_ngcontent-%COMP%] {\n margin-left: auto;\n color: var(--mj-text-muted);\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 8px;\n}\n\n.window-close-btn[_ngcontent-%COMP%]:hover {\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface-hover);\n}\n\n.drilldown-content[_ngcontent-%COMP%] {\n height: 100%;\n overflow: hidden;\n}\n\n.drilldown-logs[_ngcontent-%COMP%] {\n height: 100%;\n}\n\n\n\n[_nghost-%COMP%] mj-window .mj-window {\n border-radius: 12px !important;\n overflow: hidden;\n box-shadow: var(--mj-shadow-2xl) !important;\n}\n\n[_nghost-%COMP%] mj-window .mj-window-content {\n padding: 0 !important;\n}\n\n[_nghost-%COMP%] mj-window-titlebar {\n padding: 16px 20px !important;\n background: var(--mj-bg-page) !important;\n border-bottom: 1px solid var(--mj-border-default) !important;\n}\n\n\n\n@media (max-width: 1400px) {\n .kpi-grid[_ngcontent-%COMP%] {\n grid-template-columns: repeat(3, 1fr);\n }\n}\n\n@media (max-width: 1200px) {\n .breakdown-grid[_ngcontent-%COMP%] {\n grid-template-columns: 1fr 1fr;\n }\n}\n\n@media (max-width: 900px) {\n .kpi-grid[_ngcontent-%COMP%] {\n grid-template-columns: repeat(2, 1fr);\n }\n\n .breakdown-grid[_ngcontent-%COMP%] {\n grid-template-columns: 1fr;\n }\n\n .logs-table-header[_ngcontent-%COMP%], \n .log-row[_ngcontent-%COMP%] {\n grid-template-columns: 80px 100px 60px 1fr 60px;\n }\n\n .col-duration[_ngcontent-%COMP%] {\n display: none;\n }\n}\n\n@media (max-width: 600px) {\n .panel-header[_ngcontent-%COMP%] {\n flex-direction: column;\n }\n\n .time-filters[_ngcontent-%COMP%] {\n width: 100%;\n justify-content: center;\n }\n\n .kpi-grid[_ngcontent-%COMP%] {\n grid-template-columns: 1fr;\n }\n\n .logs-table-header[_ngcontent-%COMP%], \n .log-row[_ngcontent-%COMP%] {\n grid-template-columns: 1fr 60px;\n }\n\n .col-key[_ngcontent-%COMP%], \n .col-method[_ngcontent-%COMP%], \n .col-endpoint[_ngcontent-%COMP%] {\n display: none;\n }\n}"] });
1010
1009
  }
1011
1010
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(APIUsagePanelComponent, [{
1012
1011
  type: Component,
1013
- args: [{ standalone: false, selector: 'mj-api-usage-panel', template: "<div class=\"usage-panel\">\n @if (IsLoading) {\n <mj-loading text=\"Loading usage analytics...\"></mj-loading>\n }\n\n @if (!IsLoading) {\n <!-- Header -->\n <div class=\"panel-header\">\n <div class=\"header-left\">\n <h3 class=\"panel-title\">\n <i class=\"fa-solid fa-chart-line\"></i>\n API Usage Analytics\n </h3>\n <p class=\"panel-subtitle\">Monitor API key usage, performance, and trends</p>\n </div>\n <div class=\"time-filters\">\n <button class=\"time-btn\" [class.active]=\"TimeRange === 'day'\"\n (click)=\"setTimeRange('day')\">24 Hours</button>\n <button class=\"time-btn\" [class.active]=\"TimeRange === 'week'\"\n (click)=\"setTimeRange('week')\">7 Days</button>\n <button class=\"time-btn\" [class.active]=\"TimeRange === 'month'\"\n (click)=\"setTimeRange('month')\">30 Days</button>\n <button class=\"time-btn\" [class.active]=\"TimeRange === 'all'\"\n (click)=\"setTimeRange('all')\">All Time</button>\n </div>\n </div>\n <!-- Summary KPIs -->\n <div class=\"kpi-grid\">\n <div class=\"kpi-card\">\n <div class=\"kpi-icon requests\">\n <i class=\"fa-solid fa-arrow-right-arrow-left\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">{{formatNumber(TotalRequests)}}</div>\n <div class=\"kpi-label\">Total Requests</div>\n </div>\n </div>\n <div class=\"kpi-card\" [class.success]=\"SuccessRate >= 95\">\n <div class=\"kpi-icon success-rate\">\n <i class=\"fa-solid fa-check-circle\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">{{SuccessRate}}%</div>\n <div class=\"kpi-label\">Success Rate</div>\n </div>\n </div>\n <div class=\"kpi-card\" [class.warning]=\"TotalErrors > 0\">\n <div class=\"kpi-icon errors\">\n <i class=\"fa-solid fa-circle-exclamation\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">{{formatNumber(TotalErrors)}}</div>\n <div class=\"kpi-label\">Errors</div>\n </div>\n </div>\n <div class=\"kpi-card\">\n <div class=\"kpi-icon response-time\">\n <i class=\"fa-solid fa-gauge-high\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">{{AvgResponseTime}}ms</div>\n <div class=\"kpi-label\">Avg Response Time</div>\n </div>\n </div>\n <div class=\"kpi-card\">\n <div class=\"kpi-icon keys\">\n <i class=\"fa-solid fa-key\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">{{UniqueKeys}}</div>\n <div class=\"kpi-label\">Active Keys</div>\n </div>\n </div>\n <div class=\"kpi-card\">\n <div class=\"kpi-icon endpoints\">\n <i class=\"fa-solid fa-code-branch\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">{{UniqueEndpoints}}</div>\n <div class=\"kpi-label\">Unique Endpoints</div>\n </div>\n </div>\n </div>\n <!-- Usage Chart -->\n <div class=\"chart-section\">\n <div class=\"chart-header\">\n <h4>Request Volume</h4>\n <div class=\"chart-legend\">\n <span class=\"legend-item\">\n <span class=\"legend-color requests\"></span> Requests\n </span>\n <span class=\"legend-item\">\n <span class=\"legend-color errors\"></span> Errors\n </span>\n </div>\n </div>\n @if (TimeBuckets.length > 0) {\n <div class=\"chart-container\">\n <div class=\"chart-bars\">\n @for (bucket of TimeBuckets; track bucket) {\n <div class=\"bar-group\" [title]=\"bucket.requests + ' requests, ' + bucket.errors + ' errors'\">\n <div class=\"bar-wrapper\">\n <div class=\"bar requests-bar\"\n [style.height.%]=\"getBarHeight(bucket.requests)\">\n @if (bucket.errors > 0) {\n <div class=\"bar errors-bar\"\n [style.height.%]=\"getErrorBarHeight(bucket)\"\n >\n </div>\n }\n </div>\n </div>\n <div class=\"bar-label\">{{bucket.label}}</div>\n </div>\n }\n </div>\n <div class=\"chart-y-axis\">\n <span>{{formatNumber(MaxRequests)}}</span>\n <span>{{formatNumber(Math.round(MaxRequests / 2))}}</span>\n <span>0</span>\n </div>\n </div>\n }\n @if (TimeBuckets.length === 0) {\n <div class=\"empty-chart\">\n <i class=\"fa-solid fa-chart-area\"></i>\n <span>No usage data available</span>\n </div>\n }\n </div>\n <!-- Breakdown Grid -->\n <div class=\"breakdown-grid\">\n <!-- Top Endpoints -->\n <div class=\"breakdown-card\">\n <div class=\"breakdown-header\">\n <h4>\n <i class=\"fa-solid fa-code-branch\"></i>\n Top Endpoints\n </h4>\n </div>\n <div class=\"breakdown-content\">\n @if (TopEndpoints.length > 0) {\n <div class=\"endpoint-list\">\n @for (ep of TopEndpoints; track ep) {\n <div class=\"endpoint-item\"\n (click)=\"drillDownEndpoint(ep)\">\n <div class=\"endpoint-info\">\n <span class=\"method-badge\" [ngClass]=\"getMethodClass(ep.method)\">\n {{ep.method}}\n </span>\n <span class=\"endpoint-path\">{{ep.endpoint}}</span>\n </div>\n <div class=\"endpoint-stats\">\n <span class=\"endpoint-requests\">{{formatNumber(ep.requests)}}</span>\n <span class=\"endpoint-time\">{{ep.avgResponseTime}}ms</span>\n <span class=\"endpoint-error\" [class.has-errors]=\"ep.errorRate > 0\">\n {{ep.errorRate}}% err\n </span>\n </div>\n </div>\n }\n </div>\n }\n @if (TopEndpoints.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-code-branch\"></i>\n <span>No endpoint data</span>\n </div>\n }\n </div>\n </div>\n <!-- Top Keys -->\n <div class=\"breakdown-card\">\n <div class=\"breakdown-header\">\n <h4>\n <i class=\"fa-solid fa-key\"></i>\n Most Active Keys\n </h4>\n </div>\n <div class=\"breakdown-content\">\n @if (TopKeys.length > 0) {\n <div class=\"key-list\">\n @for (key of TopKeys; track key) {\n <div class=\"key-item\"\n (click)=\"drillDownKey(key)\">\n <div class=\"key-info\">\n <span class=\"key-label\">{{key.label}}</span>\n <span class=\"key-last-used\">{{formatDate(key.lastUsed)}}</span>\n </div>\n <div class=\"key-requests\">{{formatNumber(key.requests)}}</div>\n </div>\n }\n </div>\n }\n @if (TopKeys.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-key\"></i>\n <span>No key data</span>\n </div>\n }\n </div>\n </div>\n <!-- Status Distribution -->\n <div class=\"breakdown-card\">\n <div class=\"breakdown-header\">\n <h4>\n <i class=\"fa-solid fa-circle-half-stroke\"></i>\n Status Distribution\n </h4>\n </div>\n <div class=\"breakdown-content\">\n @if (StatusGroups.length > 0) {\n <div class=\"status-distribution\">\n <div class=\"status-bar\">\n @for (group of StatusGroups; track group) {\n <div class=\"status-segment\"\n [style.width.%]=\"group.percentage\"\n [style.backgroundColor]=\"group.color\"\n [title]=\"group.label + ': ' + group.count + ' (' + group.percentage + '%)'\">\n </div>\n }\n </div>\n <div class=\"status-legend\">\n @for (group of StatusGroups; track group) {\n <div class=\"status-legend-item\">\n <span class=\"status-color\" [style.backgroundColor]=\"group.color\"></span>\n <span class=\"status-label\">{{group.label}}</span>\n <span class=\"status-count\">{{formatNumber(group.count)}} ({{group.percentage}}%)</span>\n </div>\n }\n </div>\n </div>\n }\n @if (StatusGroups.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-circle-half-stroke\"></i>\n <span>No status data</span>\n </div>\n }\n </div>\n </div>\n </div>\n <!-- Recent Logs -->\n <div class=\"logs-section\">\n <div class=\"logs-header\">\n <h4>\n <i class=\"fa-solid fa-list\"></i>\n Recent Requests\n </h4>\n </div>\n @if (RecentLogs.length > 0) {\n <div class=\"logs-table\">\n <div class=\"logs-table-header\">\n <span class=\"col-time\">Time</span>\n <span class=\"col-key\">API Key</span>\n <span class=\"col-method\">Method</span>\n <span class=\"col-endpoint\">Endpoint</span>\n <span class=\"col-status\">Status</span>\n <span class=\"col-duration\">Duration</span>\n </div>\n <div class=\"logs-table-body\">\n @for (log of RecentLogs; track log) {\n <div class=\"log-row\">\n <span class=\"col-time\">{{formatDate(log.timestamp)}}</span>\n <span class=\"col-key\">{{log.keyLabel}}</span>\n <span class=\"col-method\">\n <span class=\"method-badge\" [ngClass]=\"getMethodClass(log.method)\">\n {{log.method}}\n </span>\n </span>\n <span class=\"col-endpoint\">{{log.endpoint}}</span>\n <span class=\"col-status\" [ngClass]=\"getStatusClass(log.statusCode)\">\n {{log.statusCode}}\n </span>\n <span class=\"col-duration\">{{log.responseTime}}ms</span>\n </div>\n }\n </div>\n </div>\n }\n @if (RecentLogs.length === 0) {\n <div class=\"empty-state large\">\n <i class=\"fa-solid fa-inbox\"></i>\n <span>No requests logged yet</span>\n <p>API usage will appear here once keys are used</p>\n </div>\n }\n </div>\n }\n\n <!-- Drill-down Panel -->\n @if (ShowLogsPanel) {\n <kendo-window\n [width]=\"800\"\n [minWidth]=\"600\"\n [height]=\"500\"\n [minHeight]=\"400\"\n [resizable]=\"true\"\n [draggable]=\"true\"\n [top]=\"80\"\n (close)=\"closeLogsPanel()\">\n <kendo-window-titlebar>\n <div class=\"drilldown-title\">\n <i class=\"fa-solid fa-magnifying-glass-chart\"></i>\n <span>Request Details</span>\n @if (LogsFilter.endpoint) {\n <span class=\"filter-badge\">\n {{LogsFilter.endpoint}}\n </span>\n }\n @if (LogsFilter.keyId) {\n <span class=\"filter-badge\">\n Key: {{KeyMap.get(LogsFilter.keyId) || 'Unknown'}}\n </span>\n }\n </div>\n <button kendoButton fillMode=\"flat\" (click)=\"closeLogsPanel()\" class=\"window-close-btn\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </kendo-window-titlebar>\n <div class=\"drilldown-content\">\n @if (IsLoadingLogs) {\n <mj-loading text=\"Loading requests...\"></mj-loading>\n }\n @if (!IsLoadingLogs) {\n <div class=\"drilldown-logs\">\n <div class=\"logs-table\">\n <div class=\"logs-table-header\">\n <span class=\"col-time\">Time</span>\n <span class=\"col-key\">API Key</span>\n <span class=\"col-method\">Method</span>\n <span class=\"col-endpoint\">Endpoint</span>\n <span class=\"col-status\">Status</span>\n <span class=\"col-duration\">Duration</span>\n </div>\n <div class=\"logs-table-body scrollable\">\n @for (log of RecentLogs; track log) {\n <div class=\"log-row\">\n <span class=\"col-time\">{{formatDate(log.timestamp)}}</span>\n <span class=\"col-key\">{{log.keyLabel}}</span>\n <span class=\"col-method\">\n <span class=\"method-badge\" [ngClass]=\"getMethodClass(log.method)\">\n {{log.method}}\n </span>\n </span>\n <span class=\"col-endpoint\">{{log.endpoint}}</span>\n <span class=\"col-status\" [ngClass]=\"getStatusClass(log.statusCode)\">\n {{log.statusCode}}\n </span>\n <span class=\"col-duration\">{{log.responseTime}}ms</span>\n </div>\n }\n </div>\n </div>\n </div>\n }\n </div>\n </kendo-window>\n }\n</div>\n", styles: [".usage-panel {\n display: flex;\n flex-direction: column;\n gap: 24px;\n padding: 24px;\n background: var(--mj-bg-page);\n min-height: 100%;\n}\n\n/* Header */\n.panel-header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n gap: 24px;\n flex-wrap: wrap;\n}\n\n.header-left {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.panel-title {\n display: flex;\n align-items: center;\n gap: 10px;\n margin: 0;\n font-size: 24px;\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n\n.panel-title i {\n color: var(--mj-color-indigo-500);\n}\n\n.panel-subtitle {\n margin: 0;\n font-size: 14px;\n color: var(--mj-text-secondary);\n}\n\n/* Time Filters */\n.time-filters {\n display: flex;\n gap: 4px;\n background: var(--mj-bg-surface);\n padding: 4px;\n border-radius: 10px;\n box-shadow: var(--mj-shadow-sm);\n}\n\n.time-btn {\n padding: 8px 16px;\n background: transparent;\n border: none;\n border-radius: 8px;\n font-size: 13px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.time-btn:hover {\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface-sunken);\n}\n\n.time-btn.active {\n background: linear-gradient(135deg, var(--mj-color-indigo-500) 0%, var(--mj-color-indigo-600) 100%);\n color: var(--mj-text-inverse);\n box-shadow: 0 2px 8px color-mix(in srgb, var(--mj-color-indigo-500) 30%, transparent);\n}\n\n/* KPI Grid */\n.kpi-grid {\n display: grid;\n grid-template-columns: repeat(6, 1fr);\n gap: 16px;\n}\n\n.kpi-card {\n display: flex;\n align-items: center;\n gap: 14px;\n padding: 18px 20px;\n background: var(--mj-bg-surface);\n border-radius: 12px;\n box-shadow: var(--mj-shadow-sm);\n transition: all 0.2s ease;\n}\n\n.kpi-card:hover {\n box-shadow: var(--mj-shadow-lg);\n transform: translateY(-2px);\n}\n\n.kpi-card.success {\n background: var(--mj-status-success-bg);\n}\n\n.kpi-card.warning {\n background: linear-gradient(135deg, var(--mj-color-brand-100) 0%, var(--mj-color-brand-200) 100%);\n}\n\n.kpi-icon {\n width: 44px;\n height: 44px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 10px;\n font-size: 18px;\n}\n\n.kpi-icon.requests {\n background: linear-gradient(135deg, var(--mj-color-info-100) 0%, var(--mj-color-info-100) 100%);\n color: var(--mj-color-info-600);\n}\n\n.kpi-icon.success-rate {\n background: linear-gradient(135deg, var(--mj-color-success-100) 0%, var(--mj-color-success-200) 100%);\n color: var(--mj-color-success-600);\n}\n\n.kpi-icon.errors {\n background: linear-gradient(135deg, var(--mj-color-error-100) 0%, var(--mj-color-error-200) 100%);\n color: var(--mj-color-error-600);\n}\n\n.kpi-icon.response-time {\n background: linear-gradient(135deg, var(--mj-color-indigo-100) 0%, var(--mj-color-indigo-200) 100%);\n color: var(--mj-color-indigo-600);\n}\n\n.kpi-icon.keys {\n background: linear-gradient(135deg, var(--mj-color-brand-100) 0%, var(--mj-color-brand-200) 100%);\n color: var(--mj-brand-primary-hover);\n}\n\n.kpi-icon.endpoints {\n background: linear-gradient(135deg, var(--mj-color-violet-50) 0%, var(--mj-color-violet-200) 100%);\n color: var(--mj-brand-primary);\n}\n\n.kpi-content {\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.kpi-value {\n font-size: 22px;\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n\n.kpi-label {\n font-size: 12px;\n color: var(--mj-text-secondary);\n}\n\n/* Chart Section */\n.chart-section {\n background: var(--mj-bg-surface);\n border-radius: 12px;\n padding: 20px;\n box-shadow: var(--mj-shadow-sm);\n}\n\n.chart-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 16px;\n}\n\n.chart-header h4 {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.chart-legend {\n display: flex;\n gap: 16px;\n}\n\n.legend-item {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 12px;\n color: var(--mj-text-secondary);\n}\n\n.legend-color {\n width: 12px;\n height: 12px;\n border-radius: 3px;\n}\n\n.legend-color.requests {\n background: var(--mj-color-indigo-500);\n}\n\n.legend-color.errors {\n background: var(--mj-status-error);\n}\n\n.chart-container {\n display: flex;\n height: 200px;\n gap: 8px;\n}\n\n.chart-bars {\n flex: 1;\n display: flex;\n align-items: flex-end;\n gap: 4px;\n padding-bottom: 24px;\n}\n\n.bar-group {\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n min-width: 0;\n}\n\n.bar-wrapper {\n width: 100%;\n height: 160px;\n display: flex;\n align-items: flex-end;\n justify-content: center;\n}\n\n.bar {\n width: 100%;\n max-width: 32px;\n border-radius: 4px 4px 0 0;\n transition: all 0.3s ease;\n position: relative;\n}\n\n.bar.requests-bar {\n background: linear-gradient(180deg, var(--mj-color-indigo-500) 0%, var(--mj-color-indigo-400) 100%);\n}\n\n.bar.requests-bar:hover {\n background: linear-gradient(180deg, var(--mj-color-indigo-600) 0%, var(--mj-color-indigo-500) 100%);\n}\n\n.bar.errors-bar {\n position: absolute;\n bottom: 0;\n left: 0;\n width: 100%;\n background: var(--mj-status-error);\n border-radius: 0;\n}\n\n.bar-label {\n margin-top: 8px;\n font-size: 10px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n text-overflow: ellipsis;\n overflow: hidden;\n max-width: 100%;\n}\n\n.chart-y-axis {\n display: flex;\n flex-direction: column;\n justify-content: space-between;\n padding-bottom: 24px;\n font-size: 10px;\n color: var(--mj-text-muted);\n text-align: right;\n min-width: 40px;\n}\n\n.empty-chart {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 200px;\n color: var(--mj-text-muted);\n}\n\n.empty-chart i {\n font-size: 32px;\n margin-bottom: 8px;\n opacity: 0.5;\n}\n\n/* Breakdown Grid */\n.breakdown-grid {\n display: grid;\n grid-template-columns: 1fr 1fr 1fr;\n gap: 20px;\n}\n\n.breakdown-card {\n background: var(--mj-bg-surface);\n border-radius: 12px;\n box-shadow: var(--mj-shadow-sm);\n overflow: hidden;\n}\n\n.breakdown-header {\n padding: 16px 20px;\n background: var(--mj-bg-page);\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.breakdown-header h4 {\n margin: 0;\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.breakdown-header h4 i {\n color: var(--mj-text-secondary);\n}\n\n.breakdown-content {\n padding: 12px;\n max-height: 280px;\n overflow-y: auto;\n}\n\n/* Endpoint List */\n.endpoint-list {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.endpoint-item {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 10px 12px;\n background: var(--mj-bg-page);\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.endpoint-item:hover {\n background: var(--mj-bg-surface-sunken);\n}\n\n.endpoint-info {\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 0;\n flex: 1;\n}\n\n.method-badge {\n padding: 2px 6px;\n border-radius: 4px;\n font-size: 10px;\n font-weight: 600;\n text-transform: uppercase;\n flex-shrink: 0;\n}\n\n.method-get { background: var(--mj-status-info-bg); color: var(--mj-color-info-600); }\n.method-post { background: var(--mj-color-success-100); color: var(--mj-color-success-600); }\n.method-put { background: var(--mj-color-brand-100); color: var(--mj-brand-primary-hover); }\n.method-delete { background: var(--mj-color-error-100); color: var(--mj-color-error-600); }\n.method-other { background: var(--mj-bg-surface-sunken); color: var(--mj-text-secondary); }\n\n.endpoint-path {\n font-size: 12px;\n font-family: 'Fira Code', monospace;\n color: var(--mj-text-secondary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.endpoint-stats {\n display: flex;\n align-items: center;\n gap: 12px;\n font-size: 11px;\n flex-shrink: 0;\n}\n\n.endpoint-requests {\n font-weight: 600;\n color: var(--mj-color-indigo-500);\n}\n\n.endpoint-time {\n color: var(--mj-text-secondary);\n}\n\n.endpoint-error {\n color: var(--mj-status-success);\n}\n\n.endpoint-error.has-errors {\n color: var(--mj-status-error);\n font-weight: 500;\n}\n\n/* Key List */\n.key-list {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.key-item {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 10px 12px;\n background: var(--mj-bg-page);\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.key-item:hover {\n background: var(--mj-bg-surface-sunken);\n}\n\n.key-info {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n}\n\n.key-label {\n font-size: 13px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.key-last-used {\n font-size: 11px;\n color: var(--mj-text-muted);\n}\n\n.key-requests {\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-color-indigo-500);\n}\n\n/* Status Distribution */\n.status-distribution {\n display: flex;\n flex-direction: column;\n gap: 16px;\n}\n\n.status-bar {\n display: flex;\n height: 24px;\n border-radius: 6px;\n overflow: hidden;\n background: var(--mj-bg-surface-sunken);\n}\n\n.status-segment {\n transition: all 0.3s ease;\n}\n\n.status-segment:hover {\n filter: brightness(1.1);\n}\n\n.status-legend {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.status-legend-item {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 12px;\n}\n\n.status-color {\n width: 12px;\n height: 12px;\n border-radius: 3px;\n}\n\n.status-label {\n flex: 1;\n color: var(--mj-text-secondary);\n}\n\n.status-count {\n color: var(--mj-text-secondary);\n font-weight: 500;\n}\n\n/* Logs Section */\n.logs-section {\n background: var(--mj-bg-surface);\n border-radius: 12px;\n box-shadow: var(--mj-shadow-sm);\n overflow: hidden;\n}\n\n.logs-header {\n padding: 16px 20px;\n background: var(--mj-bg-page);\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.logs-header h4 {\n margin: 0;\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.logs-header h4 i {\n color: var(--mj-text-secondary);\n}\n\n.logs-table {\n width: 100%;\n}\n\n.logs-table-header {\n display: grid;\n grid-template-columns: 100px 120px 70px 1fr 70px 80px;\n gap: 12px;\n padding: 12px 20px;\n background: var(--mj-bg-surface-sunken);\n font-size: 11px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.logs-table-body {\n max-height: 320px;\n overflow-y: auto;\n}\n\n.logs-table-body.scrollable {\n max-height: 380px;\n}\n\n.log-row {\n display: grid;\n grid-template-columns: 100px 120px 70px 1fr 70px 80px;\n gap: 12px;\n padding: 12px 20px;\n border-bottom: 1px solid var(--mj-bg-surface-sunken);\n font-size: 13px;\n align-items: center;\n transition: background 0.2s ease;\n}\n\n.log-row:hover {\n background: var(--mj-bg-page);\n}\n\n.col-time {\n color: var(--mj-text-secondary);\n font-size: 12px;\n}\n\n.col-key {\n color: var(--mj-text-secondary);\n font-weight: 500;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.col-endpoint {\n font-family: 'Fira Code', monospace;\n font-size: 12px;\n color: var(--mj-text-secondary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.col-status {\n font-weight: 600;\n text-align: center;\n}\n\n.col-status.status-success { color: var(--mj-status-success); }\n.col-status.status-info { color: var(--mj-status-info); }\n.col-status.status-warning { color: var(--mj-color-warning-500); }\n.col-status.status-error { color: var(--mj-status-error); }\n\n.col-duration {\n color: var(--mj-text-secondary);\n text-align: right;\n}\n\n/* Empty States */\n.empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 32px 20px;\n color: var(--mj-text-muted);\n text-align: center;\n}\n\n.empty-state i {\n font-size: 32px;\n margin-bottom: 8px;\n opacity: 0.5;\n}\n\n.empty-state span {\n font-size: 13px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n}\n\n.empty-state.large {\n padding: 48px 24px;\n}\n\n.empty-state.large i {\n font-size: 48px;\n}\n\n.empty-state p {\n margin: 8px 0 0 0;\n font-size: 12px;\n}\n\n/* Drill-down Window */\n.drilldown-title {\n display: flex;\n align-items: center;\n gap: 10px;\n font-weight: 600;\n font-size: 15px;\n}\n\n.drilldown-title i {\n color: var(--mj-color-indigo-500);\n}\n\n.filter-badge {\n padding: 4px 10px;\n background: var(--mj-color-indigo-100);\n border-radius: 12px;\n font-size: 11px;\n font-weight: 500;\n color: var(--mj-color-indigo-600);\n}\n\n.window-close-btn {\n margin-left: auto;\n color: var(--mj-text-muted);\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 8px;\n}\n\n.window-close-btn:hover {\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface-hover);\n}\n\n.drilldown-content {\n height: 100%;\n overflow: hidden;\n}\n\n.drilldown-logs {\n height: 100%;\n}\n\n/* Kendo Window Styling */\n:host ::ng-deep kendo-window {\n border-radius: 12px !important;\n overflow: hidden;\n box-shadow: var(--mj-shadow-2xl) !important;\n}\n\n:host ::ng-deep kendo-window .k-window-content {\n padding: 0 !important;\n}\n\n:host ::ng-deep kendo-window-titlebar {\n padding: 16px 20px !important;\n background: var(--mj-bg-page) !important;\n border-bottom: 1px solid var(--mj-border-default) !important;\n}\n\n/* Responsive */\n@media (max-width: 1400px) {\n .kpi-grid {\n grid-template-columns: repeat(3, 1fr);\n }\n}\n\n@media (max-width: 1200px) {\n .breakdown-grid {\n grid-template-columns: 1fr 1fr;\n }\n}\n\n@media (max-width: 900px) {\n .kpi-grid {\n grid-template-columns: repeat(2, 1fr);\n }\n\n .breakdown-grid {\n grid-template-columns: 1fr;\n }\n\n .logs-table-header,\n .log-row {\n grid-template-columns: 80px 100px 60px 1fr 60px;\n }\n\n .col-duration {\n display: none;\n }\n}\n\n@media (max-width: 600px) {\n .panel-header {\n flex-direction: column;\n }\n\n .time-filters {\n width: 100%;\n justify-content: center;\n }\n\n .kpi-grid {\n grid-template-columns: 1fr;\n }\n\n .logs-table-header,\n .log-row {\n grid-template-columns: 1fr 60px;\n }\n\n .col-key,\n .col-method,\n .col-endpoint {\n display: none;\n }\n}\n"] }]
1012
+ args: [{ standalone: false, selector: 'mj-api-usage-panel', template: "<div class=\"usage-panel\">\n @if (IsLoading) {\n <mj-loading text=\"Loading usage analytics...\"></mj-loading>\n }\n\n @if (!IsLoading) {\n <!-- Header -->\n <div class=\"panel-header\">\n <div class=\"header-left\">\n <h3 class=\"panel-title\">\n <i class=\"fa-solid fa-chart-line\"></i>\n API Usage Analytics\n </h3>\n <p class=\"panel-subtitle\">Monitor API key usage, performance, and trends</p>\n </div>\n <div class=\"time-filters\">\n <button class=\"time-btn\" [class.active]=\"TimeRange === 'day'\"\n (click)=\"setTimeRange('day')\">24 Hours</button>\n <button class=\"time-btn\" [class.active]=\"TimeRange === 'week'\"\n (click)=\"setTimeRange('week')\">7 Days</button>\n <button class=\"time-btn\" [class.active]=\"TimeRange === 'month'\"\n (click)=\"setTimeRange('month')\">30 Days</button>\n <button class=\"time-btn\" [class.active]=\"TimeRange === 'all'\"\n (click)=\"setTimeRange('all')\">All Time</button>\n </div>\n </div>\n <!-- Summary KPIs -->\n <div class=\"kpi-grid\">\n <div class=\"kpi-card\">\n <div class=\"kpi-icon requests\">\n <i class=\"fa-solid fa-arrow-right-arrow-left\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">{{formatNumber(TotalRequests)}}</div>\n <div class=\"kpi-label\">Total Requests</div>\n </div>\n </div>\n <div class=\"kpi-card\" [class.success]=\"SuccessRate >= 95\">\n <div class=\"kpi-icon success-rate\">\n <i class=\"fa-solid fa-check-circle\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">{{SuccessRate}}%</div>\n <div class=\"kpi-label\">Success Rate</div>\n </div>\n </div>\n <div class=\"kpi-card\" [class.warning]=\"TotalErrors > 0\">\n <div class=\"kpi-icon errors\">\n <i class=\"fa-solid fa-circle-exclamation\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">{{formatNumber(TotalErrors)}}</div>\n <div class=\"kpi-label\">Errors</div>\n </div>\n </div>\n <div class=\"kpi-card\">\n <div class=\"kpi-icon response-time\">\n <i class=\"fa-solid fa-gauge-high\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">{{AvgResponseTime}}ms</div>\n <div class=\"kpi-label\">Avg Response Time</div>\n </div>\n </div>\n <div class=\"kpi-card\">\n <div class=\"kpi-icon keys\">\n <i class=\"fa-solid fa-key\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">{{UniqueKeys}}</div>\n <div class=\"kpi-label\">Active Keys</div>\n </div>\n </div>\n <div class=\"kpi-card\">\n <div class=\"kpi-icon endpoints\">\n <i class=\"fa-solid fa-code-branch\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">{{UniqueEndpoints}}</div>\n <div class=\"kpi-label\">Unique Endpoints</div>\n </div>\n </div>\n </div>\n <!-- Usage Chart -->\n <div class=\"chart-section\">\n <div class=\"chart-header\">\n <h4>Request Volume</h4>\n <div class=\"chart-legend\">\n <span class=\"legend-item\">\n <span class=\"legend-color requests\"></span> Requests\n </span>\n <span class=\"legend-item\">\n <span class=\"legend-color errors\"></span> Errors\n </span>\n </div>\n </div>\n @if (TimeBuckets.length > 0) {\n <div class=\"chart-container\">\n <div class=\"chart-bars\">\n @for (bucket of TimeBuckets; track bucket) {\n <div class=\"bar-group\" [title]=\"bucket.requests + ' requests, ' + bucket.errors + ' errors'\">\n <div class=\"bar-wrapper\">\n <div class=\"bar requests-bar\"\n [style.height.%]=\"getBarHeight(bucket.requests)\">\n @if (bucket.errors > 0) {\n <div class=\"bar errors-bar\"\n [style.height.%]=\"getErrorBarHeight(bucket)\"\n >\n </div>\n }\n </div>\n </div>\n <div class=\"bar-label\">{{bucket.label}}</div>\n </div>\n }\n </div>\n <div class=\"chart-y-axis\">\n <span>{{formatNumber(MaxRequests)}}</span>\n <span>{{formatNumber(Math.round(MaxRequests / 2))}}</span>\n <span>0</span>\n </div>\n </div>\n }\n @if (TimeBuckets.length === 0) {\n <div class=\"empty-chart\">\n <i class=\"fa-solid fa-chart-area\"></i>\n <span>No usage data available</span>\n </div>\n }\n </div>\n <!-- Breakdown Grid -->\n <div class=\"breakdown-grid\">\n <!-- Top Endpoints -->\n <div class=\"breakdown-card\">\n <div class=\"breakdown-header\">\n <h4>\n <i class=\"fa-solid fa-code-branch\"></i>\n Top Endpoints\n </h4>\n </div>\n <div class=\"breakdown-content\">\n @if (TopEndpoints.length > 0) {\n <div class=\"endpoint-list\">\n @for (ep of TopEndpoints; track ep) {\n <div class=\"endpoint-item\"\n (click)=\"drillDownEndpoint(ep)\">\n <div class=\"endpoint-info\">\n <span class=\"method-badge\" [ngClass]=\"getMethodClass(ep.method)\">\n {{ep.method}}\n </span>\n <span class=\"endpoint-path\">{{ep.endpoint}}</span>\n </div>\n <div class=\"endpoint-stats\">\n <span class=\"endpoint-requests\">{{formatNumber(ep.requests)}}</span>\n <span class=\"endpoint-time\">{{ep.avgResponseTime}}ms</span>\n <span class=\"endpoint-error\" [class.has-errors]=\"ep.errorRate > 0\">\n {{ep.errorRate}}% err\n </span>\n </div>\n </div>\n }\n </div>\n }\n @if (TopEndpoints.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-code-branch\"></i>\n <span>No endpoint data</span>\n </div>\n }\n </div>\n </div>\n <!-- Top Keys -->\n <div class=\"breakdown-card\">\n <div class=\"breakdown-header\">\n <h4>\n <i class=\"fa-solid fa-key\"></i>\n Most Active Keys\n </h4>\n </div>\n <div class=\"breakdown-content\">\n @if (TopKeys.length > 0) {\n <div class=\"key-list\">\n @for (key of TopKeys; track key) {\n <div class=\"key-item\"\n (click)=\"drillDownKey(key)\">\n <div class=\"key-info\">\n <span class=\"key-label\">{{key.label}}</span>\n <span class=\"key-last-used\">{{formatDate(key.lastUsed)}}</span>\n </div>\n <div class=\"key-requests\">{{formatNumber(key.requests)}}</div>\n </div>\n }\n </div>\n }\n @if (TopKeys.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-key\"></i>\n <span>No key data</span>\n </div>\n }\n </div>\n </div>\n <!-- Status Distribution -->\n <div class=\"breakdown-card\">\n <div class=\"breakdown-header\">\n <h4>\n <i class=\"fa-solid fa-circle-half-stroke\"></i>\n Status Distribution\n </h4>\n </div>\n <div class=\"breakdown-content\">\n @if (StatusGroups.length > 0) {\n <div class=\"status-distribution\">\n <div class=\"status-bar\">\n @for (group of StatusGroups; track group) {\n <div class=\"status-segment\"\n [style.width.%]=\"group.percentage\"\n [style.backgroundColor]=\"group.color\"\n [title]=\"group.label + ': ' + group.count + ' (' + group.percentage + '%)'\">\n </div>\n }\n </div>\n <div class=\"status-legend\">\n @for (group of StatusGroups; track group) {\n <div class=\"status-legend-item\">\n <span class=\"status-color\" [style.backgroundColor]=\"group.color\"></span>\n <span class=\"status-label\">{{group.label}}</span>\n <span class=\"status-count\">{{formatNumber(group.count)}} ({{group.percentage}}%)</span>\n </div>\n }\n </div>\n </div>\n }\n @if (StatusGroups.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-circle-half-stroke\"></i>\n <span>No status data</span>\n </div>\n }\n </div>\n </div>\n </div>\n <!-- Recent Logs -->\n <div class=\"logs-section\">\n <div class=\"logs-header\">\n <h4>\n <i class=\"fa-solid fa-list\"></i>\n Recent Requests\n </h4>\n </div>\n @if (RecentLogs.length > 0) {\n <div class=\"logs-table\">\n <div class=\"logs-table-header\">\n <span class=\"col-time\">Time</span>\n <span class=\"col-key\">API Key</span>\n <span class=\"col-method\">Method</span>\n <span class=\"col-endpoint\">Endpoint</span>\n <span class=\"col-status\">Status</span>\n <span class=\"col-duration\">Duration</span>\n </div>\n <div class=\"logs-table-body\">\n @for (log of RecentLogs; track log) {\n <div class=\"log-row\">\n <span class=\"col-time\">{{formatDate(log.timestamp)}}</span>\n <span class=\"col-key\">{{log.keyLabel}}</span>\n <span class=\"col-method\">\n <span class=\"method-badge\" [ngClass]=\"getMethodClass(log.method)\">\n {{log.method}}\n </span>\n </span>\n <span class=\"col-endpoint\">{{log.endpoint}}</span>\n <span class=\"col-status\" [ngClass]=\"getStatusClass(log.statusCode)\">\n {{log.statusCode}}\n </span>\n <span class=\"col-duration\">{{log.responseTime}}ms</span>\n </div>\n }\n </div>\n </div>\n }\n @if (RecentLogs.length === 0) {\n <div class=\"empty-state large\">\n <i class=\"fa-solid fa-inbox\"></i>\n <span>No requests logged yet</span>\n <p>API usage will appear here once keys are used</p>\n </div>\n }\n </div>\n }\n\n <!-- Drill-down Panel -->\n @if (ShowLogsPanel) {\n <mj-window\n [Width]=\"800\"\n [MinWidth]=\"600\"\n [Height]=\"500\"\n [MinHeight]=\"400\"\n [Resizable]=\"true\"\n [Draggable]=\"true\"\n [Top]=\"80\"\n [Visible]=\"true\"\n (Close)=\"closeLogsPanel()\">\n <mj-window-titlebar>\n <div class=\"drilldown-title\">\n <i class=\"fa-solid fa-magnifying-glass-chart\"></i>\n <span>Request Details</span>\n @if (LogsFilter.endpoint) {\n <span class=\"filter-badge\">\n {{LogsFilter.endpoint}}\n </span>\n }\n @if (LogsFilter.keyId) {\n <span class=\"filter-badge\">\n Key: {{KeyMap.get(LogsFilter.keyId) || 'Unknown'}}\n </span>\n }\n </div>\n <button mjButton variant=\"flat\" (click)=\"closeLogsPanel()\" class=\"window-close-btn\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </mj-window-titlebar>\n <div class=\"drilldown-content\">\n @if (IsLoadingLogs) {\n <mj-loading text=\"Loading requests...\"></mj-loading>\n }\n @if (!IsLoadingLogs) {\n <div class=\"drilldown-logs\">\n <div class=\"logs-table\">\n <div class=\"logs-table-header\">\n <span class=\"col-time\">Time</span>\n <span class=\"col-key\">API Key</span>\n <span class=\"col-method\">Method</span>\n <span class=\"col-endpoint\">Endpoint</span>\n <span class=\"col-status\">Status</span>\n <span class=\"col-duration\">Duration</span>\n </div>\n <div class=\"logs-table-body scrollable\">\n @for (log of RecentLogs; track log) {\n <div class=\"log-row\">\n <span class=\"col-time\">{{formatDate(log.timestamp)}}</span>\n <span class=\"col-key\">{{log.keyLabel}}</span>\n <span class=\"col-method\">\n <span class=\"method-badge\" [ngClass]=\"getMethodClass(log.method)\">\n {{log.method}}\n </span>\n </span>\n <span class=\"col-endpoint\">{{log.endpoint}}</span>\n <span class=\"col-status\" [ngClass]=\"getStatusClass(log.statusCode)\">\n {{log.statusCode}}\n </span>\n <span class=\"col-duration\">{{log.responseTime}}ms</span>\n </div>\n }\n </div>\n </div>\n </div>\n }\n </div>\n </mj-window>\n }\n</div>\n", styles: [".usage-panel {\n display: flex;\n flex-direction: column;\n gap: 24px;\n padding: 24px;\n background: var(--mj-bg-page);\n min-height: 100%;\n}\n\n/* Header */\n.panel-header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n gap: 24px;\n flex-wrap: wrap;\n}\n\n.header-left {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.panel-title {\n display: flex;\n align-items: center;\n gap: 10px;\n margin: 0;\n font-size: 24px;\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n\n.panel-title i {\n color: var(--mj-color-indigo-500);\n}\n\n.panel-subtitle {\n margin: 0;\n font-size: 14px;\n color: var(--mj-text-secondary);\n}\n\n/* Time Filters */\n.time-filters {\n display: flex;\n gap: 4px;\n background: var(--mj-bg-surface);\n padding: 4px;\n border-radius: 10px;\n box-shadow: var(--mj-shadow-sm);\n}\n\n.time-btn {\n padding: 8px 16px;\n background: transparent;\n border: none;\n border-radius: 8px;\n font-size: 13px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.time-btn:hover {\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface-sunken);\n}\n\n.time-btn.active {\n background: linear-gradient(135deg, var(--mj-color-indigo-500) 0%, var(--mj-color-indigo-600) 100%);\n color: var(--mj-text-inverse);\n box-shadow: 0 2px 8px color-mix(in srgb, var(--mj-color-indigo-500) 30%, transparent);\n}\n\n/* KPI Grid */\n.kpi-grid {\n display: grid;\n grid-template-columns: repeat(6, 1fr);\n gap: 16px;\n}\n\n.kpi-card {\n display: flex;\n align-items: center;\n gap: 14px;\n padding: 18px 20px;\n background: var(--mj-bg-surface);\n border-radius: 12px;\n box-shadow: var(--mj-shadow-sm);\n transition: all 0.2s ease;\n}\n\n.kpi-card:hover {\n box-shadow: var(--mj-shadow-lg);\n transform: translateY(-2px);\n}\n\n.kpi-card.success {\n background: var(--mj-status-success-bg);\n}\n\n.kpi-card.warning {\n background: linear-gradient(135deg, var(--mj-color-brand-100) 0%, var(--mj-color-brand-200) 100%);\n}\n\n.kpi-icon {\n width: 44px;\n height: 44px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 10px;\n font-size: 18px;\n}\n\n.kpi-icon.requests {\n background: linear-gradient(135deg, var(--mj-color-info-100) 0%, var(--mj-color-info-100) 100%);\n color: var(--mj-color-info-600);\n}\n\n.kpi-icon.success-rate {\n background: linear-gradient(135deg, var(--mj-color-success-100) 0%, var(--mj-color-success-200) 100%);\n color: var(--mj-color-success-600);\n}\n\n.kpi-icon.errors {\n background: linear-gradient(135deg, var(--mj-color-error-100) 0%, var(--mj-color-error-200) 100%);\n color: var(--mj-color-error-600);\n}\n\n.kpi-icon.response-time {\n background: linear-gradient(135deg, var(--mj-color-indigo-100) 0%, var(--mj-color-indigo-200) 100%);\n color: var(--mj-color-indigo-600);\n}\n\n.kpi-icon.keys {\n background: linear-gradient(135deg, var(--mj-color-brand-100) 0%, var(--mj-color-brand-200) 100%);\n color: var(--mj-brand-primary-hover);\n}\n\n.kpi-icon.endpoints {\n background: linear-gradient(135deg, var(--mj-color-violet-50) 0%, var(--mj-color-violet-200) 100%);\n color: var(--mj-brand-primary);\n}\n\n.kpi-content {\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.kpi-value {\n font-size: 22px;\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n\n.kpi-label {\n font-size: 12px;\n color: var(--mj-text-secondary);\n}\n\n/* Chart Section */\n.chart-section {\n background: var(--mj-bg-surface);\n border-radius: 12px;\n padding: 20px;\n box-shadow: var(--mj-shadow-sm);\n}\n\n.chart-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 16px;\n}\n\n.chart-header h4 {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.chart-legend {\n display: flex;\n gap: 16px;\n}\n\n.legend-item {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 12px;\n color: var(--mj-text-secondary);\n}\n\n.legend-color {\n width: 12px;\n height: 12px;\n border-radius: 3px;\n}\n\n.legend-color.requests {\n background: var(--mj-color-indigo-500);\n}\n\n.legend-color.errors {\n background: var(--mj-status-error);\n}\n\n.chart-container {\n display: flex;\n height: 200px;\n gap: 8px;\n}\n\n.chart-bars {\n flex: 1;\n display: flex;\n align-items: flex-end;\n gap: 4px;\n padding-bottom: 24px;\n}\n\n.bar-group {\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n min-width: 0;\n}\n\n.bar-wrapper {\n width: 100%;\n height: 160px;\n display: flex;\n align-items: flex-end;\n justify-content: center;\n}\n\n.bar {\n width: 100%;\n max-width: 32px;\n border-radius: 4px 4px 0 0;\n transition: all 0.3s ease;\n position: relative;\n}\n\n.bar.requests-bar {\n background: linear-gradient(180deg, var(--mj-color-indigo-500) 0%, var(--mj-color-indigo-400) 100%);\n}\n\n.bar.requests-bar:hover {\n background: linear-gradient(180deg, var(--mj-color-indigo-600) 0%, var(--mj-color-indigo-500) 100%);\n}\n\n.bar.errors-bar {\n position: absolute;\n bottom: 0;\n left: 0;\n width: 100%;\n background: var(--mj-status-error);\n border-radius: 0;\n}\n\n.bar-label {\n margin-top: 8px;\n font-size: 10px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n text-overflow: ellipsis;\n overflow: hidden;\n max-width: 100%;\n}\n\n.chart-y-axis {\n display: flex;\n flex-direction: column;\n justify-content: space-between;\n padding-bottom: 24px;\n font-size: 10px;\n color: var(--mj-text-muted);\n text-align: right;\n min-width: 40px;\n}\n\n.empty-chart {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 200px;\n color: var(--mj-text-muted);\n}\n\n.empty-chart i {\n font-size: 32px;\n margin-bottom: 8px;\n opacity: 0.5;\n}\n\n/* Breakdown Grid */\n.breakdown-grid {\n display: grid;\n grid-template-columns: 1fr 1fr 1fr;\n gap: 20px;\n}\n\n.breakdown-card {\n background: var(--mj-bg-surface);\n border-radius: 12px;\n box-shadow: var(--mj-shadow-sm);\n overflow: hidden;\n}\n\n.breakdown-header {\n padding: 16px 20px;\n background: var(--mj-bg-page);\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.breakdown-header h4 {\n margin: 0;\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.breakdown-header h4 i {\n color: var(--mj-text-secondary);\n}\n\n.breakdown-content {\n padding: 12px;\n max-height: 280px;\n overflow-y: auto;\n}\n\n/* Endpoint List */\n.endpoint-list {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.endpoint-item {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 10px 12px;\n background: var(--mj-bg-page);\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.endpoint-item:hover {\n background: var(--mj-bg-surface-sunken);\n}\n\n.endpoint-info {\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 0;\n flex: 1;\n}\n\n.method-badge {\n padding: 2px 6px;\n border-radius: 4px;\n font-size: 10px;\n font-weight: 600;\n text-transform: uppercase;\n flex-shrink: 0;\n}\n\n.method-get { background: var(--mj-status-info-bg); color: var(--mj-color-info-600); }\n.method-post { background: var(--mj-color-success-100); color: var(--mj-color-success-600); }\n.method-put { background: var(--mj-color-brand-100); color: var(--mj-brand-primary-hover); }\n.method-delete { background: var(--mj-color-error-100); color: var(--mj-color-error-600); }\n.method-other { background: var(--mj-bg-surface-sunken); color: var(--mj-text-secondary); }\n\n.endpoint-path {\n font-size: 12px;\n font-family: 'Fira Code', monospace;\n color: var(--mj-text-secondary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.endpoint-stats {\n display: flex;\n align-items: center;\n gap: 12px;\n font-size: 11px;\n flex-shrink: 0;\n}\n\n.endpoint-requests {\n font-weight: 600;\n color: var(--mj-color-indigo-500);\n}\n\n.endpoint-time {\n color: var(--mj-text-secondary);\n}\n\n.endpoint-error {\n color: var(--mj-status-success);\n}\n\n.endpoint-error.has-errors {\n color: var(--mj-status-error);\n font-weight: 500;\n}\n\n/* Key List */\n.key-list {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.key-item {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 10px 12px;\n background: var(--mj-bg-page);\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.key-item:hover {\n background: var(--mj-bg-surface-sunken);\n}\n\n.key-info {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n}\n\n.key-label {\n font-size: 13px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.key-last-used {\n font-size: 11px;\n color: var(--mj-text-muted);\n}\n\n.key-requests {\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-color-indigo-500);\n}\n\n/* Status Distribution */\n.status-distribution {\n display: flex;\n flex-direction: column;\n gap: 16px;\n}\n\n.status-bar {\n display: flex;\n height: 24px;\n border-radius: 6px;\n overflow: hidden;\n background: var(--mj-bg-surface-sunken);\n}\n\n.status-segment {\n transition: all 0.3s ease;\n}\n\n.status-segment:hover {\n filter: brightness(1.1);\n}\n\n.status-legend {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.status-legend-item {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 12px;\n}\n\n.status-color {\n width: 12px;\n height: 12px;\n border-radius: 3px;\n}\n\n.status-label {\n flex: 1;\n color: var(--mj-text-secondary);\n}\n\n.status-count {\n color: var(--mj-text-secondary);\n font-weight: 500;\n}\n\n/* Logs Section */\n.logs-section {\n background: var(--mj-bg-surface);\n border-radius: 12px;\n box-shadow: var(--mj-shadow-sm);\n overflow: hidden;\n}\n\n.logs-header {\n padding: 16px 20px;\n background: var(--mj-bg-page);\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.logs-header h4 {\n margin: 0;\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.logs-header h4 i {\n color: var(--mj-text-secondary);\n}\n\n.logs-table {\n width: 100%;\n}\n\n.logs-table-header {\n display: grid;\n grid-template-columns: 100px 120px 70px 1fr 70px 80px;\n gap: 12px;\n padding: 12px 20px;\n background: var(--mj-bg-surface-sunken);\n font-size: 11px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.logs-table-body {\n max-height: 320px;\n overflow-y: auto;\n}\n\n.logs-table-body.scrollable {\n max-height: 380px;\n}\n\n.log-row {\n display: grid;\n grid-template-columns: 100px 120px 70px 1fr 70px 80px;\n gap: 12px;\n padding: 12px 20px;\n border-bottom: 1px solid var(--mj-bg-surface-sunken);\n font-size: 13px;\n align-items: center;\n transition: background 0.2s ease;\n}\n\n.log-row:hover {\n background: var(--mj-bg-page);\n}\n\n.col-time {\n color: var(--mj-text-secondary);\n font-size: 12px;\n}\n\n.col-key {\n color: var(--mj-text-secondary);\n font-weight: 500;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.col-endpoint {\n font-family: 'Fira Code', monospace;\n font-size: 12px;\n color: var(--mj-text-secondary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.col-status {\n font-weight: 600;\n text-align: center;\n}\n\n.col-status.status-success { color: var(--mj-status-success); }\n.col-status.status-info { color: var(--mj-status-info); }\n.col-status.status-warning { color: var(--mj-color-warning-500); }\n.col-status.status-error { color: var(--mj-status-error); }\n\n.col-duration {\n color: var(--mj-text-secondary);\n text-align: right;\n}\n\n/* Empty States */\n.empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 32px 20px;\n color: var(--mj-text-muted);\n text-align: center;\n}\n\n.empty-state i {\n font-size: 32px;\n margin-bottom: 8px;\n opacity: 0.5;\n}\n\n.empty-state span {\n font-size: 13px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n}\n\n.empty-state.large {\n padding: 48px 24px;\n}\n\n.empty-state.large i {\n font-size: 48px;\n}\n\n.empty-state p {\n margin: 8px 0 0 0;\n font-size: 12px;\n}\n\n/* Drill-down Window */\n.drilldown-title {\n display: flex;\n align-items: center;\n gap: 10px;\n font-weight: 600;\n font-size: 15px;\n}\n\n.drilldown-title i {\n color: var(--mj-color-indigo-500);\n}\n\n.filter-badge {\n padding: 4px 10px;\n background: var(--mj-color-indigo-100);\n border-radius: 12px;\n font-size: 11px;\n font-weight: 500;\n color: var(--mj-color-indigo-600);\n}\n\n.window-close-btn {\n margin-left: auto;\n color: var(--mj-text-muted);\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 8px;\n}\n\n.window-close-btn:hover {\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface-hover);\n}\n\n.drilldown-content {\n height: 100%;\n overflow: hidden;\n}\n\n.drilldown-logs {\n height: 100%;\n}\n\n/* MJ Window Styling */\n:host ::ng-deep mj-window .mj-window {\n border-radius: 12px !important;\n overflow: hidden;\n box-shadow: var(--mj-shadow-2xl) !important;\n}\n\n:host ::ng-deep mj-window .mj-window-content {\n padding: 0 !important;\n}\n\n:host ::ng-deep mj-window-titlebar {\n padding: 16px 20px !important;\n background: var(--mj-bg-page) !important;\n border-bottom: 1px solid var(--mj-border-default) !important;\n}\n\n/* Responsive */\n@media (max-width: 1400px) {\n .kpi-grid {\n grid-template-columns: repeat(3, 1fr);\n }\n}\n\n@media (max-width: 1200px) {\n .breakdown-grid {\n grid-template-columns: 1fr 1fr;\n }\n}\n\n@media (max-width: 900px) {\n .kpi-grid {\n grid-template-columns: repeat(2, 1fr);\n }\n\n .breakdown-grid {\n grid-template-columns: 1fr;\n }\n\n .logs-table-header,\n .log-row {\n grid-template-columns: 80px 100px 60px 1fr 60px;\n }\n\n .col-duration {\n display: none;\n }\n}\n\n@media (max-width: 600px) {\n .panel-header {\n flex-direction: column;\n }\n\n .time-filters {\n width: 100%;\n justify-content: center;\n }\n\n .kpi-grid {\n grid-template-columns: 1fr;\n }\n\n .logs-table-header,\n .log-row {\n grid-template-columns: 1fr 60px;\n }\n\n .col-key,\n .col-method,\n .col-endpoint {\n display: none;\n }\n}\n"] }]
1014
1013
  }], () => [{ type: i0.ChangeDetectorRef }], null); })();
1015
1014
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(APIUsagePanelComponent, { className: "APIUsagePanelComponent", filePath: "src/APIKeys/api-usage-panel.component.ts", lineNumber: 61 }); })();
1016
1015
  //# sourceMappingURL=api-usage-panel.component.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"api-usage-panel.component.js","sourceRoot":"","sources":["../../src/APIKeys/api-usage-panel.component.ts","../../src/APIKeys/api-usage-panel.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, OnInit, ChangeDetectorRef } from '@angular/core';\nimport { Metadata, RunView } from '@memberjunction/core';\nimport { MJAPIKeyEntity, MJAPIKeyUsageLogEntity } from '@memberjunction/core-entities';\n/** Time bucket for aggregation */\ninterface TimeBucket {\n label: string;\n date: Date;\n requests: number;\n errors: number;\n avgResponseTime: number;\n}\n\n/** Endpoint stats */\ninterface EndpointStats {\n endpoint: string;\n method: string;\n requests: number;\n avgResponseTime: number;\n errorRate: number;\n}\n\n/** Key stats */\ninterface KeyStats {\n keyId: string;\n label: string;\n requests: number;\n lastUsed: Date | null;\n}\n\n/** Status code group */\ninterface StatusGroup {\n label: string;\n code: string;\n count: number;\n percentage: number;\n color: string;\n}\n\n/** Usage log item for display */\ninterface UsageLogItem {\n id: string;\n timestamp: Date;\n endpoint: string;\n method: string;\n statusCode: number;\n responseTime: number;\n keyLabel: string;\n keyId: string;\n}\n\n/**\n * API Usage Analytics Panel Component\n * Comprehensive usage statistics and drill-down capabilities\n */\n@Component({\n standalone: false,\n selector: 'mj-api-usage-panel',\n templateUrl: './api-usage-panel.component.html',\n styleUrls: ['./api-usage-panel.component.css']\n})\nexport class APIUsagePanelComponent implements OnInit {\n private md = new Metadata();\n private cdr: ChangeDetectorRef;\n\n // Loading states\n public IsLoading = true;\n public IsLoadingLogs = false;\n\n // Time range filter\n public TimeRange: 'day' | 'week' | 'month' | 'all' = 'week';\n\n // Summary KPIs\n public TotalRequests = 0;\n public TotalErrors = 0;\n public AvgResponseTime = 0;\n public SuccessRate = 0;\n public UniqueKeys = 0;\n public UniqueEndpoints = 0;\n\n // Trend data (vs previous period)\n public RequestsTrend = 0;\n public ErrorsTrend = 0;\n public ResponseTimeTrend = 0;\n\n // Chart data\n public TimeBuckets: TimeBucket[] = [];\n public MaxRequests = 0;\n public MaxErrors = 0;\n\n // Breakdown data\n public TopEndpoints: EndpointStats[] = [];\n public TopKeys: KeyStats[] = [];\n public StatusGroups: StatusGroup[] = [];\n\n // Recent logs\n public RecentLogs: UsageLogItem[] = [];\n public ShowLogsPanel = false;\n public LogsFilter: { endpoint?: string; keyId?: string } = {};\n\n // Key map for labels\n public KeyMap = new Map<string, string>();\n\n // Expose Math for template\n public Math = Math;\n\n constructor(cdr: ChangeDetectorRef) {\n this.cdr = cdr;\n }\n\n async ngOnInit(): Promise<void> {\n await this.loadData();\n }\n\n /**\n * Load all usage data\n */\n public async loadData(): Promise<void> {\n this.IsLoading = true;\n try {\n // Load keys for label lookup\n await this.loadKeys();\n // Load usage data\n await this.loadUsageStats();\n } catch (error) {\n console.error('Error loading usage data:', error);\n } finally {\n this.IsLoading = false;\n this.cdr.markForCheck();\n }\n }\n\n /**\n * Load API keys for label lookup\n */\n private async loadKeys(): Promise<void> {\n const rv = new RunView();\n const result = await rv.RunView<MJAPIKeyEntity>({\n EntityName: 'MJ: API Keys',\n Fields: ['ID', 'Label'],\n ResultType: 'simple'\n });\n if (result.Success) {\n for (const key of result.Results) {\n this.KeyMap.set(key.ID, key.Label);\n }\n }\n }\n\n /**\n * Load usage statistics based on time range\n */\n private async loadUsageStats(): Promise<void> {\n const rv = new RunView();\n const filter = this.getTimeFilter();\n\n const result = await rv.RunView<MJAPIKeyUsageLogEntity>({\n EntityName: 'MJ: API Key Usage Logs',\n ExtraFilter: filter,\n OrderBy: '__mj_CreatedAt DESC',\n MaxRows: 5000,\n ResultType: 'entity_object'\n });\n\n if (result.Success) {\n const logs = result.Results;\n this.calculateSummaryKPIs(logs);\n this.buildTimeBuckets(logs);\n this.buildEndpointStats(logs);\n this.buildKeyStats(logs);\n this.buildStatusGroups(logs);\n this.RecentLogs = logs.slice(0, 20).map(log => this.mapLogToItem(log));\n }\n }\n\n /**\n * Get time filter for RunView based on selected range\n */\n private getTimeFilter(): string {\n const now = new Date();\n let startDate: Date;\n\n switch (this.TimeRange) {\n case 'day':\n startDate = new Date(now.getTime() - 24 * 60 * 60 * 1000);\n break;\n case 'week':\n startDate = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000);\n break;\n case 'month':\n startDate = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000);\n break;\n case 'all':\n default:\n return '';\n }\n\n return `__mj_CreatedAt >= '${startDate.toISOString()}'`;\n }\n\n /**\n * Calculate summary KPIs\n */\n private calculateSummaryKPIs(logs: MJAPIKeyUsageLogEntity[]): void {\n this.TotalRequests = logs.length;\n\n // Count errors (4xx and 5xx status codes)\n this.TotalErrors = logs.filter(l => l.StatusCode >= 400).length;\n\n // Calculate average response time\n const totalResponseTime = logs.reduce((sum, l) => sum + (l.ResponseTimeMs || 0), 0);\n this.AvgResponseTime = this.TotalRequests > 0\n ? Math.round(totalResponseTime / this.TotalRequests)\n : 0;\n\n // Success rate\n this.SuccessRate = this.TotalRequests > 0\n ? Math.round(((this.TotalRequests - this.TotalErrors) / this.TotalRequests) * 100)\n : 100;\n\n // Unique counts\n const keySet = new Set(logs.map(l => l.APIKeyID));\n const endpointSet = new Set(logs.map(l => l.Endpoint));\n this.UniqueKeys = keySet.size;\n this.UniqueEndpoints = endpointSet.size;\n }\n\n /**\n * Build time buckets for chart\n */\n private buildTimeBuckets(logs: MJAPIKeyUsageLogEntity[]): void {\n const bucketCount = this.TimeRange === 'day' ? 24 : this.TimeRange === 'week' ? 7 : 30;\n const bucketDuration = this.TimeRange === 'day' ? 60 * 60 * 1000 : 24 * 60 * 60 * 1000;\n\n const now = new Date();\n const buckets: TimeBucket[] = [];\n\n for (let i = bucketCount - 1; i >= 0; i--) {\n const bucketDate = new Date(now.getTime() - i * bucketDuration);\n const bucketLogs = logs.filter(l => {\n const logDate = new Date(l.__mj_CreatedAt);\n const nextBucket = new Date(bucketDate.getTime() + bucketDuration);\n return logDate >= bucketDate && logDate < nextBucket;\n });\n\n const errors = bucketLogs.filter(l => l.StatusCode >= 400).length;\n const totalTime = bucketLogs.reduce((sum, l) => sum + (l.ResponseTimeMs || 0), 0);\n\n buckets.push({\n label: this.formatBucketLabel(bucketDate),\n date: bucketDate,\n requests: bucketLogs.length,\n errors,\n avgResponseTime: bucketLogs.length > 0 ? Math.round(totalTime / bucketLogs.length) : 0\n });\n }\n\n this.TimeBuckets = buckets;\n this.MaxRequests = Math.max(...buckets.map(b => b.requests), 1);\n this.MaxErrors = Math.max(...buckets.map(b => b.errors), 1);\n }\n\n /**\n * Format bucket label based on time range\n */\n private formatBucketLabel(date: Date): string {\n if (this.TimeRange === 'day') {\n return date.toLocaleTimeString('en-US', { hour: 'numeric' });\n }\n return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric' });\n }\n\n /**\n * Build endpoint statistics\n */\n private buildEndpointStats(logs: MJAPIKeyUsageLogEntity[]): void {\n const endpointMap = new Map<string, {\n endpoint: string;\n method: string;\n requests: number;\n totalTime: number;\n errors: number\n }>();\n\n for (const log of logs) {\n const key = `${log.Method}:${log.Endpoint}`;\n const existing = endpointMap.get(key);\n if (existing) {\n existing.requests++;\n existing.totalTime += log.ResponseTimeMs || 0;\n if (log.StatusCode >= 400) existing.errors++;\n } else {\n endpointMap.set(key, {\n endpoint: log.Endpoint,\n method: log.Method,\n requests: 1,\n totalTime: log.ResponseTimeMs || 0,\n errors: log.StatusCode >= 400 ? 1 : 0\n });\n }\n }\n\n this.TopEndpoints = Array.from(endpointMap.values())\n .map(e => ({\n endpoint: e.endpoint,\n method: e.method,\n requests: e.requests,\n avgResponseTime: Math.round(e.totalTime / e.requests),\n errorRate: Math.round((e.errors / e.requests) * 100)\n }))\n .sort((a, b) => b.requests - a.requests)\n .slice(0, 10);\n }\n\n /**\n * Build key statistics\n */\n private buildKeyStats(logs: MJAPIKeyUsageLogEntity[]): void {\n const keyMap = new Map<string, { requests: number; lastUsed: Date | null }>();\n\n for (const log of logs) {\n const existing = keyMap.get(log.APIKeyID);\n const logDate = new Date(log.__mj_CreatedAt);\n if (existing) {\n existing.requests++;\n if (!existing.lastUsed || logDate > existing.lastUsed) {\n existing.lastUsed = logDate;\n }\n } else {\n keyMap.set(log.APIKeyID, {\n requests: 1,\n lastUsed: logDate\n });\n }\n }\n\n this.TopKeys = Array.from(keyMap.entries())\n .map(([keyId, stats]) => ({\n keyId,\n label: this.KeyMap.get(keyId) || 'Unknown Key',\n requests: stats.requests,\n lastUsed: stats.lastUsed\n }))\n .sort((a, b) => b.requests - a.requests)\n .slice(0, 10);\n }\n\n /**\n * Build status code groups\n */\n private buildStatusGroups(logs: MJAPIKeyUsageLogEntity[]): void {\n const groups: Record<string, { count: number; label: string; color: string }> = {\n '2xx': { count: 0, label: 'Success (2xx)', color: '#10b981' },\n '3xx': { count: 0, label: 'Redirect (3xx)', color: '#3b82f6' },\n '4xx': { count: 0, label: 'Client Error (4xx)', color: '#f59e0b' },\n '5xx': { count: 0, label: 'Server Error (5xx)', color: '#ef4444' }\n };\n\n for (const log of logs) {\n const code = Math.floor(log.StatusCode / 100);\n const key = `${code}xx`;\n if (groups[key]) {\n groups[key].count++;\n }\n }\n\n this.StatusGroups = Object.entries(groups)\n .filter(([_, v]) => v.count > 0)\n .map(([code, v]) => ({\n code,\n label: v.label,\n count: v.count,\n percentage: this.TotalRequests > 0 ? Math.round((v.count / this.TotalRequests) * 100) : 0,\n color: v.color\n }));\n }\n\n /**\n * Map log entity to display item\n */\n private mapLogToItem(log: MJAPIKeyUsageLogEntity): UsageLogItem {\n return {\n id: log.ID,\n timestamp: new Date(log.__mj_CreatedAt),\n endpoint: log.Endpoint,\n method: log.Method,\n statusCode: log.StatusCode,\n responseTime: log.ResponseTimeMs || 0,\n keyLabel: this.KeyMap.get(log.APIKeyID) || 'Unknown',\n keyId: log.APIKeyID\n };\n }\n\n /**\n * Change time range and reload\n */\n public async setTimeRange(range: 'day' | 'week' | 'month' | 'all'): Promise<void> {\n this.TimeRange = range;\n await this.loadData();\n }\n\n /**\n * Get bar height percentage for chart\n */\n public getBarHeight(value: number): number {\n if (this.MaxRequests === 0) return 0;\n return Math.max(2, (value / this.MaxRequests) * 100);\n }\n\n /**\n * Get error bar height for chart\n */\n public getErrorBarHeight(bucket: TimeBucket): number {\n if (bucket.requests === 0) return 0;\n return (bucket.errors / bucket.requests) * 100;\n }\n\n /**\n * Drill down into endpoint\n */\n public drillDownEndpoint(endpoint: EndpointStats): void {\n this.LogsFilter = { endpoint: endpoint.endpoint };\n this.loadFilteredLogs();\n this.ShowLogsPanel = true;\n }\n\n /**\n * Drill down into key\n */\n public drillDownKey(key: KeyStats): void {\n this.LogsFilter = { keyId: key.keyId };\n this.loadFilteredLogs();\n this.ShowLogsPanel = true;\n }\n\n /**\n * Load filtered logs for drill-down\n */\n private async loadFilteredLogs(): Promise<void> {\n this.IsLoadingLogs = true;\n const rv = new RunView();\n let filter = this.getTimeFilter();\n\n if (this.LogsFilter.endpoint) {\n filter += filter ? ' AND ' : '';\n filter += `Endpoint = '${this.LogsFilter.endpoint}'`;\n }\n if (this.LogsFilter.keyId) {\n filter += filter ? ' AND ' : '';\n filter += `APIKeyID = '${this.LogsFilter.keyId}'`;\n }\n\n const result = await rv.RunView<MJAPIKeyUsageLogEntity>({\n EntityName: 'MJ: API Key Usage Logs',\n ExtraFilter: filter,\n OrderBy: '__mj_CreatedAt DESC',\n MaxRows: 100,\n ResultType: 'entity_object'\n });\n\n if (result.Success) {\n this.RecentLogs = result.Results.map(log => this.mapLogToItem(log));\n }\n\n this.IsLoadingLogs = false;\n this.cdr.markForCheck();\n }\n\n /**\n * Close logs panel\n */\n public closeLogsPanel(): void {\n this.ShowLogsPanel = false;\n this.LogsFilter = {};\n }\n\n /**\n * Get status class for HTTP status code\n */\n public getStatusClass(statusCode: number): string {\n if (statusCode >= 200 && statusCode < 300) return 'status-success';\n if (statusCode >= 300 && statusCode < 400) return 'status-info';\n if (statusCode >= 400 && statusCode < 500) return 'status-warning';\n if (statusCode >= 500) return 'status-error';\n return '';\n }\n\n /**\n * Get method badge class\n */\n public getMethodClass(method: string): string {\n const m = method.toUpperCase();\n if (m === 'GET') return 'method-get';\n if (m === 'POST') return 'method-post';\n if (m === 'PUT' || m === 'PATCH') return 'method-put';\n if (m === 'DELETE') return 'method-delete';\n return 'method-other';\n }\n\n /**\n * Format date for display\n */\n public formatDate(date: Date | null): string {\n if (!date) return 'Never';\n const d = new Date(date);\n const now = new Date();\n const diff = now.getTime() - d.getTime();\n const minutes = Math.floor(diff / 60000);\n const hours = Math.floor(diff / 3600000);\n\n if (minutes < 1) return 'Just now';\n if (minutes < 60) return `${minutes}m ago`;\n if (hours < 24) return `${hours}h ago`;\n\n return d.toLocaleDateString('en-US', { month: 'short', day: 'numeric', hour: 'numeric', minute: '2-digit' });\n }\n\n /**\n * Format number with K/M suffix\n */\n public formatNumber(num: number): string {\n if (num >= 1000000) return (num / 1000000).toFixed(1) + 'M';\n if (num >= 1000) return (num / 1000).toFixed(1) + 'K';\n return num.toString();\n }\n}\n","<div class=\"usage-panel\">\n @if (IsLoading) {\n <mj-loading text=\"Loading usage analytics...\"></mj-loading>\n }\n\n @if (!IsLoading) {\n <!-- Header -->\n <div class=\"panel-header\">\n <div class=\"header-left\">\n <h3 class=\"panel-title\">\n <i class=\"fa-solid fa-chart-line\"></i>\n API Usage Analytics\n </h3>\n <p class=\"panel-subtitle\">Monitor API key usage, performance, and trends</p>\n </div>\n <div class=\"time-filters\">\n <button class=\"time-btn\" [class.active]=\"TimeRange === 'day'\"\n (click)=\"setTimeRange('day')\">24 Hours</button>\n <button class=\"time-btn\" [class.active]=\"TimeRange === 'week'\"\n (click)=\"setTimeRange('week')\">7 Days</button>\n <button class=\"time-btn\" [class.active]=\"TimeRange === 'month'\"\n (click)=\"setTimeRange('month')\">30 Days</button>\n <button class=\"time-btn\" [class.active]=\"TimeRange === 'all'\"\n (click)=\"setTimeRange('all')\">All Time</button>\n </div>\n </div>\n <!-- Summary KPIs -->\n <div class=\"kpi-grid\">\n <div class=\"kpi-card\">\n <div class=\"kpi-icon requests\">\n <i class=\"fa-solid fa-arrow-right-arrow-left\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">{{formatNumber(TotalRequests)}}</div>\n <div class=\"kpi-label\">Total Requests</div>\n </div>\n </div>\n <div class=\"kpi-card\" [class.success]=\"SuccessRate >= 95\">\n <div class=\"kpi-icon success-rate\">\n <i class=\"fa-solid fa-check-circle\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">{{SuccessRate}}%</div>\n <div class=\"kpi-label\">Success Rate</div>\n </div>\n </div>\n <div class=\"kpi-card\" [class.warning]=\"TotalErrors > 0\">\n <div class=\"kpi-icon errors\">\n <i class=\"fa-solid fa-circle-exclamation\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">{{formatNumber(TotalErrors)}}</div>\n <div class=\"kpi-label\">Errors</div>\n </div>\n </div>\n <div class=\"kpi-card\">\n <div class=\"kpi-icon response-time\">\n <i class=\"fa-solid fa-gauge-high\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">{{AvgResponseTime}}ms</div>\n <div class=\"kpi-label\">Avg Response Time</div>\n </div>\n </div>\n <div class=\"kpi-card\">\n <div class=\"kpi-icon keys\">\n <i class=\"fa-solid fa-key\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">{{UniqueKeys}}</div>\n <div class=\"kpi-label\">Active Keys</div>\n </div>\n </div>\n <div class=\"kpi-card\">\n <div class=\"kpi-icon endpoints\">\n <i class=\"fa-solid fa-code-branch\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">{{UniqueEndpoints}}</div>\n <div class=\"kpi-label\">Unique Endpoints</div>\n </div>\n </div>\n </div>\n <!-- Usage Chart -->\n <div class=\"chart-section\">\n <div class=\"chart-header\">\n <h4>Request Volume</h4>\n <div class=\"chart-legend\">\n <span class=\"legend-item\">\n <span class=\"legend-color requests\"></span> Requests\n </span>\n <span class=\"legend-item\">\n <span class=\"legend-color errors\"></span> Errors\n </span>\n </div>\n </div>\n @if (TimeBuckets.length > 0) {\n <div class=\"chart-container\">\n <div class=\"chart-bars\">\n @for (bucket of TimeBuckets; track bucket) {\n <div class=\"bar-group\" [title]=\"bucket.requests + ' requests, ' + bucket.errors + ' errors'\">\n <div class=\"bar-wrapper\">\n <div class=\"bar requests-bar\"\n [style.height.%]=\"getBarHeight(bucket.requests)\">\n @if (bucket.errors > 0) {\n <div class=\"bar errors-bar\"\n [style.height.%]=\"getErrorBarHeight(bucket)\"\n >\n </div>\n }\n </div>\n </div>\n <div class=\"bar-label\">{{bucket.label}}</div>\n </div>\n }\n </div>\n <div class=\"chart-y-axis\">\n <span>{{formatNumber(MaxRequests)}}</span>\n <span>{{formatNumber(Math.round(MaxRequests / 2))}}</span>\n <span>0</span>\n </div>\n </div>\n }\n @if (TimeBuckets.length === 0) {\n <div class=\"empty-chart\">\n <i class=\"fa-solid fa-chart-area\"></i>\n <span>No usage data available</span>\n </div>\n }\n </div>\n <!-- Breakdown Grid -->\n <div class=\"breakdown-grid\">\n <!-- Top Endpoints -->\n <div class=\"breakdown-card\">\n <div class=\"breakdown-header\">\n <h4>\n <i class=\"fa-solid fa-code-branch\"></i>\n Top Endpoints\n </h4>\n </div>\n <div class=\"breakdown-content\">\n @if (TopEndpoints.length > 0) {\n <div class=\"endpoint-list\">\n @for (ep of TopEndpoints; track ep) {\n <div class=\"endpoint-item\"\n (click)=\"drillDownEndpoint(ep)\">\n <div class=\"endpoint-info\">\n <span class=\"method-badge\" [ngClass]=\"getMethodClass(ep.method)\">\n {{ep.method}}\n </span>\n <span class=\"endpoint-path\">{{ep.endpoint}}</span>\n </div>\n <div class=\"endpoint-stats\">\n <span class=\"endpoint-requests\">{{formatNumber(ep.requests)}}</span>\n <span class=\"endpoint-time\">{{ep.avgResponseTime}}ms</span>\n <span class=\"endpoint-error\" [class.has-errors]=\"ep.errorRate > 0\">\n {{ep.errorRate}}% err\n </span>\n </div>\n </div>\n }\n </div>\n }\n @if (TopEndpoints.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-code-branch\"></i>\n <span>No endpoint data</span>\n </div>\n }\n </div>\n </div>\n <!-- Top Keys -->\n <div class=\"breakdown-card\">\n <div class=\"breakdown-header\">\n <h4>\n <i class=\"fa-solid fa-key\"></i>\n Most Active Keys\n </h4>\n </div>\n <div class=\"breakdown-content\">\n @if (TopKeys.length > 0) {\n <div class=\"key-list\">\n @for (key of TopKeys; track key) {\n <div class=\"key-item\"\n (click)=\"drillDownKey(key)\">\n <div class=\"key-info\">\n <span class=\"key-label\">{{key.label}}</span>\n <span class=\"key-last-used\">{{formatDate(key.lastUsed)}}</span>\n </div>\n <div class=\"key-requests\">{{formatNumber(key.requests)}}</div>\n </div>\n }\n </div>\n }\n @if (TopKeys.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-key\"></i>\n <span>No key data</span>\n </div>\n }\n </div>\n </div>\n <!-- Status Distribution -->\n <div class=\"breakdown-card\">\n <div class=\"breakdown-header\">\n <h4>\n <i class=\"fa-solid fa-circle-half-stroke\"></i>\n Status Distribution\n </h4>\n </div>\n <div class=\"breakdown-content\">\n @if (StatusGroups.length > 0) {\n <div class=\"status-distribution\">\n <div class=\"status-bar\">\n @for (group of StatusGroups; track group) {\n <div class=\"status-segment\"\n [style.width.%]=\"group.percentage\"\n [style.backgroundColor]=\"group.color\"\n [title]=\"group.label + ': ' + group.count + ' (' + group.percentage + '%)'\">\n </div>\n }\n </div>\n <div class=\"status-legend\">\n @for (group of StatusGroups; track group) {\n <div class=\"status-legend-item\">\n <span class=\"status-color\" [style.backgroundColor]=\"group.color\"></span>\n <span class=\"status-label\">{{group.label}}</span>\n <span class=\"status-count\">{{formatNumber(group.count)}} ({{group.percentage}}%)</span>\n </div>\n }\n </div>\n </div>\n }\n @if (StatusGroups.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-circle-half-stroke\"></i>\n <span>No status data</span>\n </div>\n }\n </div>\n </div>\n </div>\n <!-- Recent Logs -->\n <div class=\"logs-section\">\n <div class=\"logs-header\">\n <h4>\n <i class=\"fa-solid fa-list\"></i>\n Recent Requests\n </h4>\n </div>\n @if (RecentLogs.length > 0) {\n <div class=\"logs-table\">\n <div class=\"logs-table-header\">\n <span class=\"col-time\">Time</span>\n <span class=\"col-key\">API Key</span>\n <span class=\"col-method\">Method</span>\n <span class=\"col-endpoint\">Endpoint</span>\n <span class=\"col-status\">Status</span>\n <span class=\"col-duration\">Duration</span>\n </div>\n <div class=\"logs-table-body\">\n @for (log of RecentLogs; track log) {\n <div class=\"log-row\">\n <span class=\"col-time\">{{formatDate(log.timestamp)}}</span>\n <span class=\"col-key\">{{log.keyLabel}}</span>\n <span class=\"col-method\">\n <span class=\"method-badge\" [ngClass]=\"getMethodClass(log.method)\">\n {{log.method}}\n </span>\n </span>\n <span class=\"col-endpoint\">{{log.endpoint}}</span>\n <span class=\"col-status\" [ngClass]=\"getStatusClass(log.statusCode)\">\n {{log.statusCode}}\n </span>\n <span class=\"col-duration\">{{log.responseTime}}ms</span>\n </div>\n }\n </div>\n </div>\n }\n @if (RecentLogs.length === 0) {\n <div class=\"empty-state large\">\n <i class=\"fa-solid fa-inbox\"></i>\n <span>No requests logged yet</span>\n <p>API usage will appear here once keys are used</p>\n </div>\n }\n </div>\n }\n\n <!-- Drill-down Panel -->\n @if (ShowLogsPanel) {\n <kendo-window\n [width]=\"800\"\n [minWidth]=\"600\"\n [height]=\"500\"\n [minHeight]=\"400\"\n [resizable]=\"true\"\n [draggable]=\"true\"\n [top]=\"80\"\n (close)=\"closeLogsPanel()\">\n <kendo-window-titlebar>\n <div class=\"drilldown-title\">\n <i class=\"fa-solid fa-magnifying-glass-chart\"></i>\n <span>Request Details</span>\n @if (LogsFilter.endpoint) {\n <span class=\"filter-badge\">\n {{LogsFilter.endpoint}}\n </span>\n }\n @if (LogsFilter.keyId) {\n <span class=\"filter-badge\">\n Key: {{KeyMap.get(LogsFilter.keyId) || 'Unknown'}}\n </span>\n }\n </div>\n <button kendoButton fillMode=\"flat\" (click)=\"closeLogsPanel()\" class=\"window-close-btn\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </kendo-window-titlebar>\n <div class=\"drilldown-content\">\n @if (IsLoadingLogs) {\n <mj-loading text=\"Loading requests...\"></mj-loading>\n }\n @if (!IsLoadingLogs) {\n <div class=\"drilldown-logs\">\n <div class=\"logs-table\">\n <div class=\"logs-table-header\">\n <span class=\"col-time\">Time</span>\n <span class=\"col-key\">API Key</span>\n <span class=\"col-method\">Method</span>\n <span class=\"col-endpoint\">Endpoint</span>\n <span class=\"col-status\">Status</span>\n <span class=\"col-duration\">Duration</span>\n </div>\n <div class=\"logs-table-body scrollable\">\n @for (log of RecentLogs; track log) {\n <div class=\"log-row\">\n <span class=\"col-time\">{{formatDate(log.timestamp)}}</span>\n <span class=\"col-key\">{{log.keyLabel}}</span>\n <span class=\"col-method\">\n <span class=\"method-badge\" [ngClass]=\"getMethodClass(log.method)\">\n {{log.method}}\n </span>\n </span>\n <span class=\"col-endpoint\">{{log.endpoint}}</span>\n <span class=\"col-status\" [ngClass]=\"getStatusClass(log.statusCode)\">\n {{log.statusCode}}\n </span>\n <span class=\"col-duration\">{{log.responseTime}}ms</span>\n </div>\n }\n </div>\n </div>\n </div>\n }\n </div>\n </kendo-window>\n }\n</div>\n"]}
1
+ {"version":3,"file":"api-usage-panel.component.js","sourceRoot":"","sources":["../../src/APIKeys/api-usage-panel.component.ts","../../src/APIKeys/api-usage-panel.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, OnInit, ChangeDetectorRef } from '@angular/core';\nimport { Metadata, RunView } from '@memberjunction/core';\nimport { MJAPIKeyEntity, MJAPIKeyUsageLogEntity } from '@memberjunction/core-entities';\n/** Time bucket for aggregation */\ninterface TimeBucket {\n label: string;\n date: Date;\n requests: number;\n errors: number;\n avgResponseTime: number;\n}\n\n/** Endpoint stats */\ninterface EndpointStats {\n endpoint: string;\n method: string;\n requests: number;\n avgResponseTime: number;\n errorRate: number;\n}\n\n/** Key stats */\ninterface KeyStats {\n keyId: string;\n label: string;\n requests: number;\n lastUsed: Date | null;\n}\n\n/** Status code group */\ninterface StatusGroup {\n label: string;\n code: string;\n count: number;\n percentage: number;\n color: string;\n}\n\n/** Usage log item for display */\ninterface UsageLogItem {\n id: string;\n timestamp: Date;\n endpoint: string;\n method: string;\n statusCode: number;\n responseTime: number;\n keyLabel: string;\n keyId: string;\n}\n\n/**\n * API Usage Analytics Panel Component\n * Comprehensive usage statistics and drill-down capabilities\n */\n@Component({\n standalone: false,\n selector: 'mj-api-usage-panel',\n templateUrl: './api-usage-panel.component.html',\n styleUrls: ['./api-usage-panel.component.css']\n})\nexport class APIUsagePanelComponent implements OnInit {\n private md = new Metadata();\n private cdr: ChangeDetectorRef;\n\n // Loading states\n public IsLoading = true;\n public IsLoadingLogs = false;\n\n // Time range filter\n public TimeRange: 'day' | 'week' | 'month' | 'all' = 'week';\n\n // Summary KPIs\n public TotalRequests = 0;\n public TotalErrors = 0;\n public AvgResponseTime = 0;\n public SuccessRate = 0;\n public UniqueKeys = 0;\n public UniqueEndpoints = 0;\n\n // Trend data (vs previous period)\n public RequestsTrend = 0;\n public ErrorsTrend = 0;\n public ResponseTimeTrend = 0;\n\n // Chart data\n public TimeBuckets: TimeBucket[] = [];\n public MaxRequests = 0;\n public MaxErrors = 0;\n\n // Breakdown data\n public TopEndpoints: EndpointStats[] = [];\n public TopKeys: KeyStats[] = [];\n public StatusGroups: StatusGroup[] = [];\n\n // Recent logs\n public RecentLogs: UsageLogItem[] = [];\n public ShowLogsPanel = false;\n public LogsFilter: { endpoint?: string; keyId?: string } = {};\n\n // Key map for labels\n public KeyMap = new Map<string, string>();\n\n // Expose Math for template\n public Math = Math;\n\n constructor(cdr: ChangeDetectorRef) {\n this.cdr = cdr;\n }\n\n async ngOnInit(): Promise<void> {\n await this.loadData();\n }\n\n /**\n * Load all usage data\n */\n public async loadData(): Promise<void> {\n this.IsLoading = true;\n try {\n // Load keys for label lookup\n await this.loadKeys();\n // Load usage data\n await this.loadUsageStats();\n } catch (error) {\n console.error('Error loading usage data:', error);\n } finally {\n this.IsLoading = false;\n this.cdr.markForCheck();\n }\n }\n\n /**\n * Load API keys for label lookup\n */\n private async loadKeys(): Promise<void> {\n const rv = new RunView();\n const result = await rv.RunView<MJAPIKeyEntity>({\n EntityName: 'MJ: API Keys',\n Fields: ['ID', 'Label'],\n ResultType: 'simple'\n });\n if (result.Success) {\n for (const key of result.Results) {\n this.KeyMap.set(key.ID, key.Label);\n }\n }\n }\n\n /**\n * Load usage statistics based on time range\n */\n private async loadUsageStats(): Promise<void> {\n const rv = new RunView();\n const filter = this.getTimeFilter();\n\n const result = await rv.RunView<MJAPIKeyUsageLogEntity>({\n EntityName: 'MJ: API Key Usage Logs',\n ExtraFilter: filter,\n OrderBy: '__mj_CreatedAt DESC',\n MaxRows: 5000,\n ResultType: 'entity_object'\n });\n\n if (result.Success) {\n const logs = result.Results;\n this.calculateSummaryKPIs(logs);\n this.buildTimeBuckets(logs);\n this.buildEndpointStats(logs);\n this.buildKeyStats(logs);\n this.buildStatusGroups(logs);\n this.RecentLogs = logs.slice(0, 20).map(log => this.mapLogToItem(log));\n }\n }\n\n /**\n * Get time filter for RunView based on selected range\n */\n private getTimeFilter(): string {\n const now = new Date();\n let startDate: Date;\n\n switch (this.TimeRange) {\n case 'day':\n startDate = new Date(now.getTime() - 24 * 60 * 60 * 1000);\n break;\n case 'week':\n startDate = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000);\n break;\n case 'month':\n startDate = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000);\n break;\n case 'all':\n default:\n return '';\n }\n\n return `__mj_CreatedAt >= '${startDate.toISOString()}'`;\n }\n\n /**\n * Calculate summary KPIs\n */\n private calculateSummaryKPIs(logs: MJAPIKeyUsageLogEntity[]): void {\n this.TotalRequests = logs.length;\n\n // Count errors (4xx and 5xx status codes)\n this.TotalErrors = logs.filter(l => l.StatusCode >= 400).length;\n\n // Calculate average response time\n const totalResponseTime = logs.reduce((sum, l) => sum + (l.ResponseTimeMs || 0), 0);\n this.AvgResponseTime = this.TotalRequests > 0\n ? Math.round(totalResponseTime / this.TotalRequests)\n : 0;\n\n // Success rate\n this.SuccessRate = this.TotalRequests > 0\n ? Math.round(((this.TotalRequests - this.TotalErrors) / this.TotalRequests) * 100)\n : 100;\n\n // Unique counts\n const keySet = new Set(logs.map(l => l.APIKeyID));\n const endpointSet = new Set(logs.map(l => l.Endpoint));\n this.UniqueKeys = keySet.size;\n this.UniqueEndpoints = endpointSet.size;\n }\n\n /**\n * Build time buckets for chart\n */\n private buildTimeBuckets(logs: MJAPIKeyUsageLogEntity[]): void {\n const bucketCount = this.TimeRange === 'day' ? 24 : this.TimeRange === 'week' ? 7 : 30;\n const bucketDuration = this.TimeRange === 'day' ? 60 * 60 * 1000 : 24 * 60 * 60 * 1000;\n\n const now = new Date();\n const buckets: TimeBucket[] = [];\n\n for (let i = bucketCount - 1; i >= 0; i--) {\n const bucketDate = new Date(now.getTime() - i * bucketDuration);\n const bucketLogs = logs.filter(l => {\n const logDate = new Date(l.__mj_CreatedAt);\n const nextBucket = new Date(bucketDate.getTime() + bucketDuration);\n return logDate >= bucketDate && logDate < nextBucket;\n });\n\n const errors = bucketLogs.filter(l => l.StatusCode >= 400).length;\n const totalTime = bucketLogs.reduce((sum, l) => sum + (l.ResponseTimeMs || 0), 0);\n\n buckets.push({\n label: this.formatBucketLabel(bucketDate),\n date: bucketDate,\n requests: bucketLogs.length,\n errors,\n avgResponseTime: bucketLogs.length > 0 ? Math.round(totalTime / bucketLogs.length) : 0\n });\n }\n\n this.TimeBuckets = buckets;\n this.MaxRequests = Math.max(...buckets.map(b => b.requests), 1);\n this.MaxErrors = Math.max(...buckets.map(b => b.errors), 1);\n }\n\n /**\n * Format bucket label based on time range\n */\n private formatBucketLabel(date: Date): string {\n if (this.TimeRange === 'day') {\n return date.toLocaleTimeString('en-US', { hour: 'numeric' });\n }\n return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric' });\n }\n\n /**\n * Build endpoint statistics\n */\n private buildEndpointStats(logs: MJAPIKeyUsageLogEntity[]): void {\n const endpointMap = new Map<string, {\n endpoint: string;\n method: string;\n requests: number;\n totalTime: number;\n errors: number\n }>();\n\n for (const log of logs) {\n const key = `${log.Method}:${log.Endpoint}`;\n const existing = endpointMap.get(key);\n if (existing) {\n existing.requests++;\n existing.totalTime += log.ResponseTimeMs || 0;\n if (log.StatusCode >= 400) existing.errors++;\n } else {\n endpointMap.set(key, {\n endpoint: log.Endpoint,\n method: log.Method,\n requests: 1,\n totalTime: log.ResponseTimeMs || 0,\n errors: log.StatusCode >= 400 ? 1 : 0\n });\n }\n }\n\n this.TopEndpoints = Array.from(endpointMap.values())\n .map(e => ({\n endpoint: e.endpoint,\n method: e.method,\n requests: e.requests,\n avgResponseTime: Math.round(e.totalTime / e.requests),\n errorRate: Math.round((e.errors / e.requests) * 100)\n }))\n .sort((a, b) => b.requests - a.requests)\n .slice(0, 10);\n }\n\n /**\n * Build key statistics\n */\n private buildKeyStats(logs: MJAPIKeyUsageLogEntity[]): void {\n const keyMap = new Map<string, { requests: number; lastUsed: Date | null }>();\n\n for (const log of logs) {\n const existing = keyMap.get(log.APIKeyID);\n const logDate = new Date(log.__mj_CreatedAt);\n if (existing) {\n existing.requests++;\n if (!existing.lastUsed || logDate > existing.lastUsed) {\n existing.lastUsed = logDate;\n }\n } else {\n keyMap.set(log.APIKeyID, {\n requests: 1,\n lastUsed: logDate\n });\n }\n }\n\n this.TopKeys = Array.from(keyMap.entries())\n .map(([keyId, stats]) => ({\n keyId,\n label: this.KeyMap.get(keyId) || 'Unknown Key',\n requests: stats.requests,\n lastUsed: stats.lastUsed\n }))\n .sort((a, b) => b.requests - a.requests)\n .slice(0, 10);\n }\n\n /**\n * Build status code groups\n */\n private buildStatusGroups(logs: MJAPIKeyUsageLogEntity[]): void {\n const groups: Record<string, { count: number; label: string; color: string }> = {\n '2xx': { count: 0, label: 'Success (2xx)', color: '#10b981' },\n '3xx': { count: 0, label: 'Redirect (3xx)', color: '#3b82f6' },\n '4xx': { count: 0, label: 'Client Error (4xx)', color: '#f59e0b' },\n '5xx': { count: 0, label: 'Server Error (5xx)', color: '#ef4444' }\n };\n\n for (const log of logs) {\n const code = Math.floor(log.StatusCode / 100);\n const key = `${code}xx`;\n if (groups[key]) {\n groups[key].count++;\n }\n }\n\n this.StatusGroups = Object.entries(groups)\n .filter(([_, v]) => v.count > 0)\n .map(([code, v]) => ({\n code,\n label: v.label,\n count: v.count,\n percentage: this.TotalRequests > 0 ? Math.round((v.count / this.TotalRequests) * 100) : 0,\n color: v.color\n }));\n }\n\n /**\n * Map log entity to display item\n */\n private mapLogToItem(log: MJAPIKeyUsageLogEntity): UsageLogItem {\n return {\n id: log.ID,\n timestamp: new Date(log.__mj_CreatedAt),\n endpoint: log.Endpoint,\n method: log.Method,\n statusCode: log.StatusCode,\n responseTime: log.ResponseTimeMs || 0,\n keyLabel: this.KeyMap.get(log.APIKeyID) || 'Unknown',\n keyId: log.APIKeyID\n };\n }\n\n /**\n * Change time range and reload\n */\n public async setTimeRange(range: 'day' | 'week' | 'month' | 'all'): Promise<void> {\n this.TimeRange = range;\n await this.loadData();\n }\n\n /**\n * Get bar height percentage for chart\n */\n public getBarHeight(value: number): number {\n if (this.MaxRequests === 0) return 0;\n return Math.max(2, (value / this.MaxRequests) * 100);\n }\n\n /**\n * Get error bar height for chart\n */\n public getErrorBarHeight(bucket: TimeBucket): number {\n if (bucket.requests === 0) return 0;\n return (bucket.errors / bucket.requests) * 100;\n }\n\n /**\n * Drill down into endpoint\n */\n public drillDownEndpoint(endpoint: EndpointStats): void {\n this.LogsFilter = { endpoint: endpoint.endpoint };\n this.loadFilteredLogs();\n this.ShowLogsPanel = true;\n }\n\n /**\n * Drill down into key\n */\n public drillDownKey(key: KeyStats): void {\n this.LogsFilter = { keyId: key.keyId };\n this.loadFilteredLogs();\n this.ShowLogsPanel = true;\n }\n\n /**\n * Load filtered logs for drill-down\n */\n private async loadFilteredLogs(): Promise<void> {\n this.IsLoadingLogs = true;\n const rv = new RunView();\n let filter = this.getTimeFilter();\n\n if (this.LogsFilter.endpoint) {\n filter += filter ? ' AND ' : '';\n filter += `Endpoint = '${this.LogsFilter.endpoint}'`;\n }\n if (this.LogsFilter.keyId) {\n filter += filter ? ' AND ' : '';\n filter += `APIKeyID = '${this.LogsFilter.keyId}'`;\n }\n\n const result = await rv.RunView<MJAPIKeyUsageLogEntity>({\n EntityName: 'MJ: API Key Usage Logs',\n ExtraFilter: filter,\n OrderBy: '__mj_CreatedAt DESC',\n MaxRows: 100,\n ResultType: 'entity_object'\n });\n\n if (result.Success) {\n this.RecentLogs = result.Results.map(log => this.mapLogToItem(log));\n }\n\n this.IsLoadingLogs = false;\n this.cdr.markForCheck();\n }\n\n /**\n * Close logs panel\n */\n public closeLogsPanel(): void {\n this.ShowLogsPanel = false;\n this.LogsFilter = {};\n }\n\n /**\n * Get status class for HTTP status code\n */\n public getStatusClass(statusCode: number): string {\n if (statusCode >= 200 && statusCode < 300) return 'status-success';\n if (statusCode >= 300 && statusCode < 400) return 'status-info';\n if (statusCode >= 400 && statusCode < 500) return 'status-warning';\n if (statusCode >= 500) return 'status-error';\n return '';\n }\n\n /**\n * Get method badge class\n */\n public getMethodClass(method: string): string {\n const m = method.toUpperCase();\n if (m === 'GET') return 'method-get';\n if (m === 'POST') return 'method-post';\n if (m === 'PUT' || m === 'PATCH') return 'method-put';\n if (m === 'DELETE') return 'method-delete';\n return 'method-other';\n }\n\n /**\n * Format date for display\n */\n public formatDate(date: Date | null): string {\n if (!date) return 'Never';\n const d = new Date(date);\n const now = new Date();\n const diff = now.getTime() - d.getTime();\n const minutes = Math.floor(diff / 60000);\n const hours = Math.floor(diff / 3600000);\n\n if (minutes < 1) return 'Just now';\n if (minutes < 60) return `${minutes}m ago`;\n if (hours < 24) return `${hours}h ago`;\n\n return d.toLocaleDateString('en-US', { month: 'short', day: 'numeric', hour: 'numeric', minute: '2-digit' });\n }\n\n /**\n * Format number with K/M suffix\n */\n public formatNumber(num: number): string {\n if (num >= 1000000) return (num / 1000000).toFixed(1) + 'M';\n if (num >= 1000) return (num / 1000).toFixed(1) + 'K';\n return num.toString();\n }\n}\n","<div class=\"usage-panel\">\n @if (IsLoading) {\n <mj-loading text=\"Loading usage analytics...\"></mj-loading>\n }\n\n @if (!IsLoading) {\n <!-- Header -->\n <div class=\"panel-header\">\n <div class=\"header-left\">\n <h3 class=\"panel-title\">\n <i class=\"fa-solid fa-chart-line\"></i>\n API Usage Analytics\n </h3>\n <p class=\"panel-subtitle\">Monitor API key usage, performance, and trends</p>\n </div>\n <div class=\"time-filters\">\n <button class=\"time-btn\" [class.active]=\"TimeRange === 'day'\"\n (click)=\"setTimeRange('day')\">24 Hours</button>\n <button class=\"time-btn\" [class.active]=\"TimeRange === 'week'\"\n (click)=\"setTimeRange('week')\">7 Days</button>\n <button class=\"time-btn\" [class.active]=\"TimeRange === 'month'\"\n (click)=\"setTimeRange('month')\">30 Days</button>\n <button class=\"time-btn\" [class.active]=\"TimeRange === 'all'\"\n (click)=\"setTimeRange('all')\">All Time</button>\n </div>\n </div>\n <!-- Summary KPIs -->\n <div class=\"kpi-grid\">\n <div class=\"kpi-card\">\n <div class=\"kpi-icon requests\">\n <i class=\"fa-solid fa-arrow-right-arrow-left\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">{{formatNumber(TotalRequests)}}</div>\n <div class=\"kpi-label\">Total Requests</div>\n </div>\n </div>\n <div class=\"kpi-card\" [class.success]=\"SuccessRate >= 95\">\n <div class=\"kpi-icon success-rate\">\n <i class=\"fa-solid fa-check-circle\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">{{SuccessRate}}%</div>\n <div class=\"kpi-label\">Success Rate</div>\n </div>\n </div>\n <div class=\"kpi-card\" [class.warning]=\"TotalErrors > 0\">\n <div class=\"kpi-icon errors\">\n <i class=\"fa-solid fa-circle-exclamation\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">{{formatNumber(TotalErrors)}}</div>\n <div class=\"kpi-label\">Errors</div>\n </div>\n </div>\n <div class=\"kpi-card\">\n <div class=\"kpi-icon response-time\">\n <i class=\"fa-solid fa-gauge-high\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">{{AvgResponseTime}}ms</div>\n <div class=\"kpi-label\">Avg Response Time</div>\n </div>\n </div>\n <div class=\"kpi-card\">\n <div class=\"kpi-icon keys\">\n <i class=\"fa-solid fa-key\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">{{UniqueKeys}}</div>\n <div class=\"kpi-label\">Active Keys</div>\n </div>\n </div>\n <div class=\"kpi-card\">\n <div class=\"kpi-icon endpoints\">\n <i class=\"fa-solid fa-code-branch\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">{{UniqueEndpoints}}</div>\n <div class=\"kpi-label\">Unique Endpoints</div>\n </div>\n </div>\n </div>\n <!-- Usage Chart -->\n <div class=\"chart-section\">\n <div class=\"chart-header\">\n <h4>Request Volume</h4>\n <div class=\"chart-legend\">\n <span class=\"legend-item\">\n <span class=\"legend-color requests\"></span> Requests\n </span>\n <span class=\"legend-item\">\n <span class=\"legend-color errors\"></span> Errors\n </span>\n </div>\n </div>\n @if (TimeBuckets.length > 0) {\n <div class=\"chart-container\">\n <div class=\"chart-bars\">\n @for (bucket of TimeBuckets; track bucket) {\n <div class=\"bar-group\" [title]=\"bucket.requests + ' requests, ' + bucket.errors + ' errors'\">\n <div class=\"bar-wrapper\">\n <div class=\"bar requests-bar\"\n [style.height.%]=\"getBarHeight(bucket.requests)\">\n @if (bucket.errors > 0) {\n <div class=\"bar errors-bar\"\n [style.height.%]=\"getErrorBarHeight(bucket)\"\n >\n </div>\n }\n </div>\n </div>\n <div class=\"bar-label\">{{bucket.label}}</div>\n </div>\n }\n </div>\n <div class=\"chart-y-axis\">\n <span>{{formatNumber(MaxRequests)}}</span>\n <span>{{formatNumber(Math.round(MaxRequests / 2))}}</span>\n <span>0</span>\n </div>\n </div>\n }\n @if (TimeBuckets.length === 0) {\n <div class=\"empty-chart\">\n <i class=\"fa-solid fa-chart-area\"></i>\n <span>No usage data available</span>\n </div>\n }\n </div>\n <!-- Breakdown Grid -->\n <div class=\"breakdown-grid\">\n <!-- Top Endpoints -->\n <div class=\"breakdown-card\">\n <div class=\"breakdown-header\">\n <h4>\n <i class=\"fa-solid fa-code-branch\"></i>\n Top Endpoints\n </h4>\n </div>\n <div class=\"breakdown-content\">\n @if (TopEndpoints.length > 0) {\n <div class=\"endpoint-list\">\n @for (ep of TopEndpoints; track ep) {\n <div class=\"endpoint-item\"\n (click)=\"drillDownEndpoint(ep)\">\n <div class=\"endpoint-info\">\n <span class=\"method-badge\" [ngClass]=\"getMethodClass(ep.method)\">\n {{ep.method}}\n </span>\n <span class=\"endpoint-path\">{{ep.endpoint}}</span>\n </div>\n <div class=\"endpoint-stats\">\n <span class=\"endpoint-requests\">{{formatNumber(ep.requests)}}</span>\n <span class=\"endpoint-time\">{{ep.avgResponseTime}}ms</span>\n <span class=\"endpoint-error\" [class.has-errors]=\"ep.errorRate > 0\">\n {{ep.errorRate}}% err\n </span>\n </div>\n </div>\n }\n </div>\n }\n @if (TopEndpoints.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-code-branch\"></i>\n <span>No endpoint data</span>\n </div>\n }\n </div>\n </div>\n <!-- Top Keys -->\n <div class=\"breakdown-card\">\n <div class=\"breakdown-header\">\n <h4>\n <i class=\"fa-solid fa-key\"></i>\n Most Active Keys\n </h4>\n </div>\n <div class=\"breakdown-content\">\n @if (TopKeys.length > 0) {\n <div class=\"key-list\">\n @for (key of TopKeys; track key) {\n <div class=\"key-item\"\n (click)=\"drillDownKey(key)\">\n <div class=\"key-info\">\n <span class=\"key-label\">{{key.label}}</span>\n <span class=\"key-last-used\">{{formatDate(key.lastUsed)}}</span>\n </div>\n <div class=\"key-requests\">{{formatNumber(key.requests)}}</div>\n </div>\n }\n </div>\n }\n @if (TopKeys.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-key\"></i>\n <span>No key data</span>\n </div>\n }\n </div>\n </div>\n <!-- Status Distribution -->\n <div class=\"breakdown-card\">\n <div class=\"breakdown-header\">\n <h4>\n <i class=\"fa-solid fa-circle-half-stroke\"></i>\n Status Distribution\n </h4>\n </div>\n <div class=\"breakdown-content\">\n @if (StatusGroups.length > 0) {\n <div class=\"status-distribution\">\n <div class=\"status-bar\">\n @for (group of StatusGroups; track group) {\n <div class=\"status-segment\"\n [style.width.%]=\"group.percentage\"\n [style.backgroundColor]=\"group.color\"\n [title]=\"group.label + ': ' + group.count + ' (' + group.percentage + '%)'\">\n </div>\n }\n </div>\n <div class=\"status-legend\">\n @for (group of StatusGroups; track group) {\n <div class=\"status-legend-item\">\n <span class=\"status-color\" [style.backgroundColor]=\"group.color\"></span>\n <span class=\"status-label\">{{group.label}}</span>\n <span class=\"status-count\">{{formatNumber(group.count)}} ({{group.percentage}}%)</span>\n </div>\n }\n </div>\n </div>\n }\n @if (StatusGroups.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-circle-half-stroke\"></i>\n <span>No status data</span>\n </div>\n }\n </div>\n </div>\n </div>\n <!-- Recent Logs -->\n <div class=\"logs-section\">\n <div class=\"logs-header\">\n <h4>\n <i class=\"fa-solid fa-list\"></i>\n Recent Requests\n </h4>\n </div>\n @if (RecentLogs.length > 0) {\n <div class=\"logs-table\">\n <div class=\"logs-table-header\">\n <span class=\"col-time\">Time</span>\n <span class=\"col-key\">API Key</span>\n <span class=\"col-method\">Method</span>\n <span class=\"col-endpoint\">Endpoint</span>\n <span class=\"col-status\">Status</span>\n <span class=\"col-duration\">Duration</span>\n </div>\n <div class=\"logs-table-body\">\n @for (log of RecentLogs; track log) {\n <div class=\"log-row\">\n <span class=\"col-time\">{{formatDate(log.timestamp)}}</span>\n <span class=\"col-key\">{{log.keyLabel}}</span>\n <span class=\"col-method\">\n <span class=\"method-badge\" [ngClass]=\"getMethodClass(log.method)\">\n {{log.method}}\n </span>\n </span>\n <span class=\"col-endpoint\">{{log.endpoint}}</span>\n <span class=\"col-status\" [ngClass]=\"getStatusClass(log.statusCode)\">\n {{log.statusCode}}\n </span>\n <span class=\"col-duration\">{{log.responseTime}}ms</span>\n </div>\n }\n </div>\n </div>\n }\n @if (RecentLogs.length === 0) {\n <div class=\"empty-state large\">\n <i class=\"fa-solid fa-inbox\"></i>\n <span>No requests logged yet</span>\n <p>API usage will appear here once keys are used</p>\n </div>\n }\n </div>\n }\n\n <!-- Drill-down Panel -->\n @if (ShowLogsPanel) {\n <mj-window\n [Width]=\"800\"\n [MinWidth]=\"600\"\n [Height]=\"500\"\n [MinHeight]=\"400\"\n [Resizable]=\"true\"\n [Draggable]=\"true\"\n [Top]=\"80\"\n [Visible]=\"true\"\n (Close)=\"closeLogsPanel()\">\n <mj-window-titlebar>\n <div class=\"drilldown-title\">\n <i class=\"fa-solid fa-magnifying-glass-chart\"></i>\n <span>Request Details</span>\n @if (LogsFilter.endpoint) {\n <span class=\"filter-badge\">\n {{LogsFilter.endpoint}}\n </span>\n }\n @if (LogsFilter.keyId) {\n <span class=\"filter-badge\">\n Key: {{KeyMap.get(LogsFilter.keyId) || 'Unknown'}}\n </span>\n }\n </div>\n <button mjButton variant=\"flat\" (click)=\"closeLogsPanel()\" class=\"window-close-btn\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </mj-window-titlebar>\n <div class=\"drilldown-content\">\n @if (IsLoadingLogs) {\n <mj-loading text=\"Loading requests...\"></mj-loading>\n }\n @if (!IsLoadingLogs) {\n <div class=\"drilldown-logs\">\n <div class=\"logs-table\">\n <div class=\"logs-table-header\">\n <span class=\"col-time\">Time</span>\n <span class=\"col-key\">API Key</span>\n <span class=\"col-method\">Method</span>\n <span class=\"col-endpoint\">Endpoint</span>\n <span class=\"col-status\">Status</span>\n <span class=\"col-duration\">Duration</span>\n </div>\n <div class=\"logs-table-body scrollable\">\n @for (log of RecentLogs; track log) {\n <div class=\"log-row\">\n <span class=\"col-time\">{{formatDate(log.timestamp)}}</span>\n <span class=\"col-key\">{{log.keyLabel}}</span>\n <span class=\"col-method\">\n <span class=\"method-badge\" [ngClass]=\"getMethodClass(log.method)\">\n {{log.method}}\n </span>\n </span>\n <span class=\"col-endpoint\">{{log.endpoint}}</span>\n <span class=\"col-status\" [ngClass]=\"getStatusClass(log.statusCode)\">\n {{log.statusCode}}\n </span>\n <span class=\"col-duration\">{{log.responseTime}}ms</span>\n </div>\n }\n </div>\n </div>\n </div>\n }\n </div>\n </mj-window>\n }\n</div>\n"]}