@memberjunction/ng-dashboards 5.3.0 → 5.4.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 (173) hide show
  1. package/dist/AI/components/agents/agent-configuration.component.js.map +1 -1
  2. package/dist/AI/components/agents/agent-editor.component.js.map +1 -1
  3. package/dist/AI/components/agents/agent-filter-panel.component.js.map +1 -1
  4. package/dist/AI/components/charts/performance-heatmap.component.js.map +1 -1
  5. package/dist/AI/components/charts/time-series-chart.component.js.map +1 -1
  6. package/dist/AI/components/execution-monitoring.component.js.map +1 -1
  7. package/dist/AI/components/models/model-management.component.js.map +1 -1
  8. package/dist/AI/components/prompts/model-prompt-priority-matrix.component.js.map +1 -1
  9. package/dist/AI/components/prompts/prompt-filter-panel.component.js.map +1 -1
  10. package/dist/AI/components/prompts/prompt-management.component.js.map +1 -1
  11. package/dist/AI/components/prompts/prompt-version-control.component.js.map +1 -1
  12. package/dist/AI/components/system/system-config-filter-panel.component.js.map +1 -1
  13. package/dist/AI/components/system/system-configuration.component.js.map +1 -1
  14. package/dist/AI/components/widgets/kpi-card.component.js.map +1 -1
  15. package/dist/AI/components/widgets/live-execution-widget.component.js.map +1 -1
  16. package/dist/AI/index.js.map +1 -1
  17. package/dist/AI/services/ai-instrumentation.service.js.map +1 -1
  18. package/dist/APIKeys/api-applications-panel.component.js +2 -2
  19. package/dist/APIKeys/api-applications-panel.component.js.map +1 -1
  20. package/dist/APIKeys/api-key-create-dialog.component.js +2 -2
  21. package/dist/APIKeys/api-key-create-dialog.component.js.map +1 -1
  22. package/dist/APIKeys/api-key-edit-panel.component.js +2 -2
  23. package/dist/APIKeys/api-key-edit-panel.component.js.map +1 -1
  24. package/dist/APIKeys/api-key-list.component.js +2 -2
  25. package/dist/APIKeys/api-key-list.component.js.map +1 -1
  26. package/dist/APIKeys/api-keys-resource.component.js +2 -2
  27. package/dist/APIKeys/api-keys-resource.component.js.map +1 -1
  28. package/dist/APIKeys/api-scopes-panel.component.js +2 -2
  29. package/dist/APIKeys/api-scopes-panel.component.js.map +1 -1
  30. package/dist/APIKeys/api-usage-panel.component.js +2 -2
  31. package/dist/APIKeys/api-usage-panel.component.js.map +1 -1
  32. package/dist/APIKeys/index.js.map +1 -1
  33. package/dist/Actions/components/actions-list-view.component.js.map +1 -1
  34. package/dist/Actions/components/actions-overview.component.js.map +1 -1
  35. package/dist/Actions/components/categories-list-view.component.js.map +1 -1
  36. package/dist/Actions/components/code-management.component.js.map +1 -1
  37. package/dist/Actions/components/entity-integration.component.js.map +1 -1
  38. package/dist/Actions/components/execution-monitoring.component.js.map +1 -1
  39. package/dist/Actions/components/executions-list-view.component.js.map +1 -1
  40. package/dist/Actions/components/explorer/action-breadcrumb.component.js.map +1 -1
  41. package/dist/Actions/components/explorer/action-card.component.js.map +1 -1
  42. package/dist/Actions/components/explorer/action-explorer.component.js.map +1 -1
  43. package/dist/Actions/components/explorer/action-list-item.component.js.map +1 -1
  44. package/dist/Actions/components/explorer/action-toolbar.component.js.map +1 -1
  45. package/dist/Actions/components/explorer/action-tree-panel.component.js.map +1 -1
  46. package/dist/Actions/components/explorer/index.js.map +1 -1
  47. package/dist/Actions/components/explorer/new-action-panel.component.js.map +1 -1
  48. package/dist/Actions/components/explorer/new-category-panel.component.js.map +1 -1
  49. package/dist/Actions/components/scheduled-actions.component.js.map +1 -1
  50. package/dist/Actions/components/security-permissions.component.js.map +1 -1
  51. package/dist/Actions/index.js.map +1 -1
  52. package/dist/Actions/services/action-explorer-state.service.js.map +1 -1
  53. package/dist/Communication/communication-dashboard.component.js.map +1 -1
  54. package/dist/Communication/communication-logs-resource.component.js.map +1 -1
  55. package/dist/Communication/communication-monitor-resource.component.js.map +1 -1
  56. package/dist/Communication/communication-providers-resource.component.js.map +1 -1
  57. package/dist/Communication/communication-runs-resource.component.js.map +1 -1
  58. package/dist/Communication/communication-templates-resource.component.js.map +1 -1
  59. package/dist/ComponentStudio/component-studio-dashboard.component.js.map +1 -1
  60. package/dist/ComponentStudio/components/ai-assistant/ai-assistant-panel.component.js.map +1 -1
  61. package/dist/ComponentStudio/components/artifact-load-dialog.component.js.map +1 -1
  62. package/dist/ComponentStudio/components/artifact-selection-dialog.component.js.map +1 -1
  63. package/dist/ComponentStudio/components/browser/component-browser.component.js.map +1 -1
  64. package/dist/ComponentStudio/components/editors/code-editor-panel.component.js.map +1 -1
  65. package/dist/ComponentStudio/components/editors/data-requirements-editor.component.js.map +1 -1
  66. package/dist/ComponentStudio/components/editors/requirements-editor.component.js.map +1 -1
  67. package/dist/ComponentStudio/components/editors/spec-editor.component.js.map +1 -1
  68. package/dist/ComponentStudio/components/new-component-dialog/new-component-dialog.component.js.map +1 -1
  69. package/dist/ComponentStudio/components/save-version-dialog/save-version-dialog.component.js.map +1 -1
  70. package/dist/ComponentStudio/components/text-import-dialog.component.js.map +1 -1
  71. package/dist/ComponentStudio/components/workspace/component-preview.component.js.map +1 -1
  72. package/dist/ComponentStudio/components/workspace/editor-tabs.component.js.map +1 -1
  73. package/dist/ComponentStudio/index.js.map +1 -1
  74. package/dist/ComponentStudio/services/component-studio-state.service.js.map +1 -1
  75. package/dist/ComponentStudio/services/component-version.service.js.map +1 -1
  76. package/dist/Credentials/components/credentials-audit-resource.component.js.map +1 -1
  77. package/dist/Credentials/components/credentials-categories-resource.component.js.map +1 -1
  78. package/dist/Credentials/components/credentials-list-resource.component.js.map +1 -1
  79. package/dist/Credentials/components/credentials-overview-resource.component.js.map +1 -1
  80. package/dist/Credentials/components/credentials-types-resource.component.js.map +1 -1
  81. package/dist/Credentials/credentials-dashboard.component.js.map +1 -1
  82. package/dist/Credentials/index.js.map +1 -1
  83. package/dist/Credentials/pipes/group-by.pipe.js.map +1 -1
  84. package/dist/DashboardBrowser/dashboard-browser-resource.component.js.map +1 -1
  85. package/dist/DashboardBrowser/dashboard-share-dialog.component.js.map +1 -1
  86. package/dist/DataExplorer/components/filter-dialog/filter-dialog.component.js.map +1 -1
  87. package/dist/DataExplorer/components/navigation-panel/navigation-panel.component.d.ts +25 -3
  88. package/dist/DataExplorer/components/navigation-panel/navigation-panel.component.d.ts.map +1 -1
  89. package/dist/DataExplorer/components/navigation-panel/navigation-panel.component.js +158 -34
  90. package/dist/DataExplorer/components/navigation-panel/navigation-panel.component.js.map +1 -1
  91. package/dist/DataExplorer/components/view-selector/view-selector.component.js.map +1 -1
  92. package/dist/DataExplorer/data-explorer-dashboard.component.d.ts +57 -23
  93. package/dist/DataExplorer/data-explorer-dashboard.component.d.ts.map +1 -1
  94. package/dist/DataExplorer/data-explorer-dashboard.component.js +600 -445
  95. package/dist/DataExplorer/data-explorer-dashboard.component.js.map +1 -1
  96. package/dist/DataExplorer/data-explorer-resource.component.js.map +1 -1
  97. package/dist/DataExplorer/index.js.map +1 -1
  98. package/dist/DataExplorer/models/explorer-state.interface.d.ts +25 -0
  99. package/dist/DataExplorer/models/explorer-state.interface.d.ts.map +1 -1
  100. package/dist/DataExplorer/models/explorer-state.interface.js +6 -1
  101. package/dist/DataExplorer/models/explorer-state.interface.js.map +1 -1
  102. package/dist/DataExplorer/services/explorer-state.service.d.ts +21 -3
  103. package/dist/DataExplorer/services/explorer-state.service.d.ts.map +1 -1
  104. package/dist/DataExplorer/services/explorer-state.service.js +70 -36
  105. package/dist/DataExplorer/services/explorer-state.service.js.map +1 -1
  106. package/dist/EntityAdmin/entity-admin-dashboard.component.js +2 -2
  107. package/dist/EntityAdmin/entity-admin-dashboard.component.js.map +1 -1
  108. package/dist/Home/home-application.js.map +1 -1
  109. package/dist/Home/home-dashboard.component.d.ts +20 -5
  110. package/dist/Home/home-dashboard.component.d.ts.map +1 -1
  111. package/dist/Home/home-dashboard.component.js +128 -79
  112. package/dist/Home/home-dashboard.component.js.map +1 -1
  113. package/dist/Lists/components/lists-browse-resource.component.js.map +1 -1
  114. package/dist/Lists/components/lists-categories-resource.component.js.map +1 -1
  115. package/dist/Lists/components/lists-my-lists-resource.component.js.map +1 -1
  116. package/dist/Lists/components/lists-operations-resource.component.js.map +1 -1
  117. package/dist/Lists/components/venn-diagram/venn-diagram.component.js.map +1 -1
  118. package/dist/Lists/index.js.map +1 -1
  119. package/dist/Lists/services/list-set-operations.service.js.map +1 -1
  120. package/dist/MCP/components/mcp-connection-dialog.component.js.map +1 -1
  121. package/dist/MCP/components/mcp-log-detail-panel.component.js.map +1 -1
  122. package/dist/MCP/components/mcp-server-dialog.component.js.map +1 -1
  123. package/dist/MCP/components/mcp-test-tool-dialog.component.js.map +1 -1
  124. package/dist/MCP/index.js.map +1 -1
  125. package/dist/MCP/mcp-dashboard.component.js.map +1 -1
  126. package/dist/MCP/mcp-filter-panel.component.js.map +1 -1
  127. package/dist/MCP/mcp-resource.component.js.map +1 -1
  128. package/dist/MCP/mcp.module.js.map +1 -1
  129. package/dist/MCP/services/mcp-tools.service.js.map +1 -1
  130. package/dist/QueryBrowser/query-browser-resource.component.js.map +1 -1
  131. package/dist/Scheduling/components/index.js.map +1 -1
  132. package/dist/Scheduling/components/job-slideout.component.js.map +1 -1
  133. package/dist/Scheduling/components/scheduling-activity-resource.component.js.map +1 -1
  134. package/dist/Scheduling/components/scheduling-activity.component.js.map +1 -1
  135. package/dist/Scheduling/components/scheduling-jobs-resource.component.js.map +1 -1
  136. package/dist/Scheduling/components/scheduling-jobs.component.js.map +1 -1
  137. package/dist/Scheduling/components/scheduling-overview-resource.component.js.map +1 -1
  138. package/dist/Scheduling/components/scheduling-overview.component.js.map +1 -1
  139. package/dist/Scheduling/scheduling-dashboard.component.js.map +1 -1
  140. package/dist/Scheduling/services/scheduling-instrumentation.service.js.map +1 -1
  141. package/dist/SystemDiagnostics/index.js.map +1 -1
  142. package/dist/SystemDiagnostics/system-diagnostics.component.d.ts.map +1 -1
  143. package/dist/SystemDiagnostics/system-diagnostics.component.js +3 -3
  144. package/dist/SystemDiagnostics/system-diagnostics.component.js.map +1 -1
  145. package/dist/Testing/components/index.js.map +1 -1
  146. package/dist/Testing/components/testing-analytics-resource.component.js.map +1 -1
  147. package/dist/Testing/components/testing-analytics.component.js.map +1 -1
  148. package/dist/Testing/components/testing-dashboard-tab-resource.component.js.map +1 -1
  149. package/dist/Testing/components/testing-dashboard-tab.component.js.map +1 -1
  150. package/dist/Testing/components/testing-explorer-resource.component.js.map +1 -1
  151. package/dist/Testing/components/testing-explorer.component.js.map +1 -1
  152. package/dist/Testing/components/testing-review-resource.component.js.map +1 -1
  153. package/dist/Testing/components/testing-review.component.js.map +1 -1
  154. package/dist/Testing/components/testing-runs-resource.component.js.map +1 -1
  155. package/dist/Testing/components/testing-runs.component.js.map +1 -1
  156. package/dist/Testing/components/widgets/oracle-breakdown-table.component.js.map +1 -1
  157. package/dist/Testing/components/widgets/suite-tree.component.js.map +1 -1
  158. package/dist/Testing/components/widgets/test-run-detail-panel.component.js.map +1 -1
  159. package/dist/Testing/services/testing-instrumentation.service.js.map +1 -1
  160. package/dist/Testing/testing-dashboard.component.js.map +1 -1
  161. package/dist/VersionHistory/components/diff-resource.component.js.map +1 -1
  162. package/dist/VersionHistory/components/graph-resource.component.js.map +1 -1
  163. package/dist/VersionHistory/components/index.js.map +1 -1
  164. package/dist/VersionHistory/components/labels-resource.component.js.map +1 -1
  165. package/dist/VersionHistory/components/restore-resource.component.js.map +1 -1
  166. package/dist/VersionHistory/index.js.map +1 -1
  167. package/dist/__tests__/dashboards.test.js.map +1 -1
  168. package/dist/module.js.map +1 -1
  169. package/dist/public-api.js.map +1 -1
  170. package/dist/shared/pipes/highlight-search.pipe.js.map +1 -1
  171. package/dist/shared/pipes/index.js.map +1 -1
  172. package/dist/shared/shared-pipes.module.js.map +1 -1
  173. package/package.json +38 -38
@@ -636,11 +636,11 @@ export class APIScopesPanelComponent {
636
636
  i0.ɵɵconditional(!ctx.IsLoading ? 2 : -1);
637
637
  i0.ɵɵadvance();
638
638
  i0.ɵɵconditional(ctx.ShowCreateDialog || ctx.ShowEditDialog ? 3 : -1);
639
- } }, dependencies: [i1.NgTemplateOutlet, i2.DefaultValueAccessor, i2.CheckboxControlValueAccessor, i2.NgControlStatus, i2.NgModel, i3.DropDownListComponent, i4.TextBoxDirective, i4.TextAreaDirective, i4.CheckBoxDirective, i5.WindowComponent, i5.WindowTitleBarComponent, i6.ButtonComponent, i7.LoadingComponent], styles: [".scopes-panel[_ngcontent-%COMP%] {\n height: 100%;\n display: flex;\n flex-direction: column;\n}\n\n\n\n.panel-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 24px;\n flex-wrap: wrap;\n gap: 16px;\n}\n\n.header-left[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 200px;\n}\n\n.panel-title[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n font-size: 18px;\n font-weight: 600;\n color: var(--text-primary, #1f2937);\n margin: 0 0 4px 0;\n}\n\n.panel-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: #10b981;\n}\n\n.panel-subtitle[_ngcontent-%COMP%] {\n font-size: 14px;\n color: var(--text-secondary, #6b7280);\n margin: 0;\n}\n\n.header-actions[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 16px;\n}\n\n.scope-stats[_ngcontent-%COMP%] {\n display: flex;\n gap: 16px;\n}\n\n.stat[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 13px;\n color: var(--text-secondary, #6b7280);\n}\n\n.stat.active[_ngcontent-%COMP%] {\n color: #10b981;\n}\n\n.stat[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n}\n\n.tree-controls[_ngcontent-%COMP%] {\n display: flex;\n gap: 4px;\n}\n\n.btn-icon[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n background: var(--card-background, #ffffff);\n border: 1px solid var(--border-color, #e5e7eb);\n border-radius: 6px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.btn-icon[_ngcontent-%COMP%]:hover {\n background: var(--item-hover, #f3f4f6);\n}\n\n.btn-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n color: var(--text-secondary, #6b7280);\n}\n\n.btn-create[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 20px;\n background: linear-gradient(135deg, #10b981 0%, #059669 100%);\n color: white;\n border: none;\n border-radius: 8px;\n font-weight: 600;\n font-size: 14px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.btn-create[_ngcontent-%COMP%]:hover {\n transform: translateY(-1px);\n box-shadow: 0 4px 12px rgba(16, 185, 129, 0.4);\n}\n\n\n\n.message[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 12px 16px;\n border-radius: 8px;\n margin-bottom: 16px;\n font-size: 14px;\n}\n\n.message.success[_ngcontent-%COMP%] {\n background: #d1fae5;\n color: #065f46;\n border: 1px solid #a7f3d0;\n}\n\n.message.error[_ngcontent-%COMP%] {\n background: #fee2e2;\n color: #991b1b;\n border: 1px solid #fca5a5;\n}\n\n\n\n.scope-tree[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n background: var(--card-background, #ffffff);\n border-radius: 12px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);\n}\n\n.scope-node[_ngcontent-%COMP%] {\n border-bottom: 1px solid var(--border-color, #e5e7eb);\n}\n\n.scope-node[_ngcontent-%COMP%]:last-child {\n border-bottom: none;\n}\n\n.node-content[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n padding: 12px 16px;\n transition: background 0.2s ease;\n}\n\n.node-content[_ngcontent-%COMP%]:hover {\n background: var(--item-hover, #f9fafb);\n}\n\n.node-content.inactive[_ngcontent-%COMP%] {\n opacity: 0.6;\n}\n\n.expand-btn[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n background: none;\n border: none;\n cursor: pointer;\n color: var(--text-tertiary, #9ca3af);\n transition: transform 0.2s ease;\n flex-shrink: 0;\n}\n\n.expand-btn[_ngcontent-%COMP%]:hover {\n color: var(--text-secondary, #6b7280);\n}\n\n.expand-placeholder[_ngcontent-%COMP%] {\n width: 24px;\n flex-shrink: 0;\n}\n\n.scope-info[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n flex: 1;\n min-width: 0;\n cursor: pointer;\n}\n\n.scope-icon[_ngcontent-%COMP%] {\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 8px;\n margin-right: 12px;\n flex-shrink: 0;\n}\n\n.scope-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n color: white;\n}\n\n.scope-details[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n.scope-name[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 14px;\n font-weight: 500;\n color: var(--text-primary, #1f2937);\n flex-wrap: wrap;\n}\n\n.full-path[_ngcontent-%COMP%] {\n font-family: monospace;\n font-size: 12px;\n color: var(--text-tertiary, #9ca3af);\n background: var(--tag-background, #f3f4f6);\n padding: 2px 6px;\n border-radius: 4px;\n}\n\n.status-badge[_ngcontent-%COMP%] {\n font-size: 10px;\n font-weight: 500;\n padding: 2px 6px;\n border-radius: 4px;\n background: #f3f4f6;\n color: #6b7280;\n}\n\n.scope-meta[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n margin-top: 4px;\n font-size: 12px;\n flex-wrap: wrap;\n}\n\n.category[_ngcontent-%COMP%] {\n font-weight: 500;\n}\n\n.resource-type[_ngcontent-%COMP%] {\n color: var(--text-secondary, #6b7280);\n background: var(--tag-background, #f3f4f6);\n padding: 2px 6px;\n border-radius: 4px;\n}\n\n.description[_ngcontent-%COMP%] {\n color: var(--text-tertiary, #9ca3af);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n max-width: 300px;\n}\n\n.node-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 4px;\n margin-left: 12px;\n opacity: 0;\n transition: opacity 0.2s ease;\n}\n\n.node-content[_ngcontent-%COMP%]:hover .node-actions[_ngcontent-%COMP%] {\n opacity: 1;\n}\n\n.btn-node-action[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n background: var(--card-background, #ffffff);\n border: 1px solid var(--border-color, #e5e7eb);\n border-radius: 6px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.btn-node-action[_ngcontent-%COMP%]:hover {\n background: #10b981;\n border-color: #10b981;\n color: white;\n}\n\n.btn-node-action[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 12px;\n}\n\n.children[_ngcontent-%COMP%] {\n margin-left: 0;\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: 48px;\n color: var(--text-secondary, #6b7280);\n text-align: center;\n}\n\n.empty-state[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 48px;\n margin-bottom: 16px;\n opacity: 0.5;\n}\n\n.empty-state[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n font-size: 16px;\n font-weight: 500;\n}\n\n.empty-state[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n font-size: 14px;\n margin-top: 8px;\n}\n\n\n\n\n\n\n\n\n[_nghost-%COMP%] kendo-window {\n border-radius: 16px !important;\n overflow: hidden;\n box-shadow: 0 25px 60px rgba(0, 0, 0, 0.15),\n 0 10px 30px rgba(0, 0, 0, 0.1),\n 0 0 0 1px rgba(0, 0, 0, 0.05) !important;\n}\n\n[_nghost-%COMP%] kendo-window .k-window-content {\n padding: 0 !important;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n\n[_nghost-%COMP%] kendo-window-titlebar {\n display: flex !important;\n align-items: center;\n justify-content: space-between;\n padding: 18px 24px !important;\n background: linear-gradient(135deg, #fafafa 0%, #f3f4f6 100%) !important;\n border-bottom: 1px solid #e5e7eb !important;\n}\n\n.dialog-title[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n font-weight: 600;\n font-size: 17px;\n color: #1f2937;\n}\n\n.dialog-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: #10b981;\n font-size: 18px;\n}\n\n.window-close-btn[_ngcontent-%COMP%] {\n margin-left: auto;\n color: #9ca3af;\n transition: all 0.2s ease;\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: #374151;\n background: rgba(0, 0, 0, 0.05);\n}\n\n.window-close-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 16px;\n}\n\n\n\n.dialog-content[_ngcontent-%COMP%] {\n padding: 24px;\n flex: 1;\n overflow-y: auto;\n}\n\n\n\n.form-field[_ngcontent-%COMP%] {\n margin-bottom: 20px;\n}\n\n.form-field[_ngcontent-%COMP%]:last-of-type {\n margin-bottom: 0;\n}\n\n.form-field[_ngcontent-%COMP%] label[_ngcontent-%COMP%] {\n display: block;\n font-size: 13px;\n font-weight: 600;\n color: #374151;\n margin-bottom: 8px;\n letter-spacing: 0.01em;\n}\n\n.form-input[_ngcontent-%COMP%] {\n width: 100%;\n}\n\n.form-textarea[_ngcontent-%COMP%] {\n width: 100%;\n resize: vertical;\n min-height: 80px;\n}\n\n[_nghost-%COMP%] .form-input .k-input, \n[_nghost-%COMP%] .form-textarea .k-input-inner, \n[_nghost-%COMP%] .form-field .k-dropdownlist {\n padding: 10px 14px;\n border-radius: 8px;\n font-size: 14px;\n border-color: #e5e7eb;\n transition: all 0.2s ease;\n}\n\n[_nghost-%COMP%] .form-input:focus-within, \n[_nghost-%COMP%] .form-textarea:focus-within, \n[_nghost-%COMP%] .form-field .k-dropdownlist.k-focus {\n box-shadow: 0 0 0 3px rgba(16, 185, 129, 0.1);\n}\n\n.field-hint[_ngcontent-%COMP%] {\n display: block;\n font-size: 12px;\n color: #6b7280;\n margin-top: 6px;\n line-height: 1.4;\n}\n\n.form-row[_ngcontent-%COMP%] {\n display: flex;\n gap: 16px;\n}\n\n.form-field.half[_ngcontent-%COMP%] {\n flex: 1;\n}\n\n.checkbox-label[_ngcontent-%COMP%] {\n display: flex;\n align-items: flex-start;\n gap: 12px;\n cursor: pointer;\n padding: 12px 16px;\n background: #f9fafb;\n border-radius: 10px;\n border: 1px solid #e5e7eb;\n transition: all 0.2s ease;\n}\n\n.checkbox-label[_ngcontent-%COMP%]:hover {\n background: #f3f4f6;\n border-color: #d1d5db;\n}\n\n.checkbox-label[_ngcontent-%COMP%] input[_ngcontent-%COMP%] {\n margin-top: 2px;\n flex-shrink: 0;\n}\n\n.checkbox-label[_ngcontent-%COMP%] span[_ngcontent-%COMP%]:first-of-type {\n font-weight: 600;\n color: #374151;\n font-size: 14px;\n}\n\n.checkbox-hint[_ngcontent-%COMP%] {\n display: block;\n font-size: 12px;\n color: #6b7280;\n margin-top: 4px;\n line-height: 1.4;\n}\n\n\n\n.dialog-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 12px;\n padding: 20px 24px;\n background: #f9fafb;\n border-top: 1px solid #e5e7eb;\n margin: 0 -24px -24px -24px;\n}\n\n[_nghost-%COMP%] .dialog-actions .k-button {\n min-width: 100px;\n padding: 10px 20px;\n font-weight: 600;\n border-radius: 8px;\n transition: all 0.2s ease;\n}\n\n[_nghost-%COMP%] .dialog-actions .k-button-solid-primary {\n background: linear-gradient(135deg, #10b981 0%, #059669 100%);\n border: none;\n box-shadow: 0 2px 8px rgba(16, 185, 129, 0.3);\n}\n\n[_nghost-%COMP%] .dialog-actions .k-button-solid-primary:hover {\n transform: translateY(-1px);\n box-shadow: 0 4px 12px rgba(16, 185, 129, 0.4);\n}"] });
639
+ } }, dependencies: [i1.NgTemplateOutlet, i2.DefaultValueAccessor, i2.CheckboxControlValueAccessor, i2.NgControlStatus, i2.NgModel, i3.DropDownListComponent, i4.TextBoxDirective, i4.TextAreaDirective, i4.CheckBoxDirective, i5.WindowComponent, i5.WindowTitleBarComponent, i6.ButtonComponent, i7.LoadingComponent], styles: [".scopes-panel[_ngcontent-%COMP%] {\n height: 100%;\n display: flex;\n flex-direction: column;\n}\n\n\n\n.panel-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 24px;\n flex-wrap: wrap;\n gap: 16px;\n}\n\n.header-left[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 200px;\n}\n\n.panel-title[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n font-size: 18px;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0 0 4px 0;\n}\n\n.panel-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-status-success);\n}\n\n.panel-subtitle[_ngcontent-%COMP%] {\n font-size: 14px;\n color: var(--mj-text-secondary);\n margin: 0;\n}\n\n.header-actions[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 16px;\n}\n\n.scope-stats[_ngcontent-%COMP%] {\n display: flex;\n gap: 16px;\n}\n\n.stat[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 13px;\n color: var(--mj-text-secondary);\n}\n\n.stat.active[_ngcontent-%COMP%] {\n color: var(--mj-status-success);\n}\n\n.stat[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n}\n\n.tree-controls[_ngcontent-%COMP%] {\n display: flex;\n gap: 4px;\n}\n\n.btn-icon[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.btn-icon[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.btn-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n color: var(--mj-text-secondary);\n}\n\n.btn-create[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 20px;\n background: linear-gradient(135deg, var(--mj-status-success) 0%, var(--mj-color-success-600) 100%);\n color: var(--mj-text-inverse);\n border: none;\n border-radius: 8px;\n font-weight: 600;\n font-size: 14px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.btn-create[_ngcontent-%COMP%]:hover {\n transform: translateY(-1px);\n box-shadow: 0 4px 12px color-mix(in srgb, var(--mj-status-success) 40%, transparent);\n}\n\n\n\n.message[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 12px 16px;\n border-radius: 8px;\n margin-bottom: 16px;\n font-size: 14px;\n}\n\n.message.success[_ngcontent-%COMP%] {\n background: var(--mj-color-success-100);\n color: var(--mj-color-success-800);\n border: 1px solid var(--mj-status-success-border);\n}\n\n.message.error[_ngcontent-%COMP%] {\n background: var(--mj-color-error-100);\n color: var(--mj-color-error-700);\n border: 1px solid var(--mj-status-error-border);\n}\n\n\n\n.scope-tree[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n background: var(--mj-bg-surface);\n border-radius: 12px;\n box-shadow: var(--mj-shadow-md);\n}\n\n.scope-node[_ngcontent-%COMP%] {\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.scope-node[_ngcontent-%COMP%]:last-child {\n border-bottom: none;\n}\n\n.node-content[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n padding: 12px 16px;\n transition: background 0.2s ease;\n}\n\n.node-content[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.node-content.inactive[_ngcontent-%COMP%] {\n opacity: 0.6;\n}\n\n.expand-btn[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n background: none;\n border: none;\n cursor: pointer;\n color: var(--mj-text-muted);\n transition: transform 0.2s ease;\n flex-shrink: 0;\n}\n\n.expand-btn[_ngcontent-%COMP%]:hover {\n color: var(--mj-text-secondary);\n}\n\n.expand-placeholder[_ngcontent-%COMP%] {\n width: 24px;\n flex-shrink: 0;\n}\n\n.scope-info[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n flex: 1;\n min-width: 0;\n cursor: pointer;\n}\n\n.scope-icon[_ngcontent-%COMP%] {\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 8px;\n margin-right: 12px;\n flex-shrink: 0;\n}\n\n.scope-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n color: var(--mj-text-inverse);\n}\n\n.scope-details[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n.scope-name[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 14px;\n font-weight: 500;\n color: var(--mj-text-primary);\n flex-wrap: wrap;\n}\n\n.full-path[_ngcontent-%COMP%] {\n font-family: monospace;\n font-size: 12px;\n color: var(--mj-text-muted);\n background: var(--mj-bg-surface-sunken);\n padding: 2px 6px;\n border-radius: 4px;\n}\n\n.status-badge[_ngcontent-%COMP%] {\n font-size: 10px;\n font-weight: 500;\n padding: 2px 6px;\n border-radius: 4px;\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-secondary);\n}\n\n.scope-meta[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n margin-top: 4px;\n font-size: 12px;\n flex-wrap: wrap;\n}\n\n.category[_ngcontent-%COMP%] {\n font-weight: 500;\n}\n\n.resource-type[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface-sunken);\n padding: 2px 6px;\n border-radius: 4px;\n}\n\n.description[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n max-width: 300px;\n}\n\n.node-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 4px;\n margin-left: 12px;\n opacity: 0;\n transition: opacity 0.2s ease;\n}\n\n.node-content[_ngcontent-%COMP%]:hover .node-actions[_ngcontent-%COMP%] {\n opacity: 1;\n}\n\n.btn-node-action[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.btn-node-action[_ngcontent-%COMP%]:hover {\n background: var(--mj-status-success);\n border-color: var(--mj-status-success);\n color: var(--mj-text-inverse);\n}\n\n.btn-node-action[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 12px;\n}\n\n.children[_ngcontent-%COMP%] {\n margin-left: 0;\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: 48px;\n color: var(--mj-text-secondary);\n text-align: center;\n}\n\n.empty-state[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 48px;\n margin-bottom: 16px;\n opacity: 0.5;\n}\n\n.empty-state[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n font-size: 16px;\n font-weight: 500;\n}\n\n.empty-state[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n font-size: 14px;\n margin-top: 8px;\n}\n\n\n\n\n\n\n\n\n[_nghost-%COMP%] kendo-window {\n border-radius: 16px !important;\n overflow: hidden;\n box-shadow: var(--mj-shadow-2xl) !important;\n background: var(--mj-bg-surface) !important;\n}\n\n[_nghost-%COMP%] kendo-window .k-window-content {\n padding: 0 !important;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n background: var(--mj-bg-surface) !important;\n}\n\n[_nghost-%COMP%] kendo-window-titlebar {\n display: flex !important;\n align-items: center;\n justify-content: space-between;\n padding: 18px 24px !important;\n background: var(--mj-bg-page) !important;\n border-bottom: 1px solid var(--mj-border-default) !important;\n}\n\n.dialog-title[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n font-weight: 600;\n font-size: 17px;\n color: var(--mj-text-primary);\n}\n\n.dialog-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-status-success);\n font-size: 18px;\n}\n\n.window-close-btn[_ngcontent-%COMP%] {\n margin-left: auto;\n color: var(--mj-text-muted);\n transition: all 0.2s ease;\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-primary);\n background: var(--mj-bg-surface-hover);\n}\n\n.window-close-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 16px;\n}\n\n\n\n.dialog-content[_ngcontent-%COMP%] {\n padding: 24px;\n flex: 1;\n overflow-y: auto;\n}\n\n\n\n.form-field[_ngcontent-%COMP%] {\n margin-bottom: 20px;\n}\n\n.form-field[_ngcontent-%COMP%]:last-of-type {\n margin-bottom: 0;\n}\n\n.form-field[_ngcontent-%COMP%] label[_ngcontent-%COMP%] {\n display: block;\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin-bottom: 8px;\n letter-spacing: 0.01em;\n}\n\n.form-input[_ngcontent-%COMP%] {\n width: 100%;\n}\n\n.form-textarea[_ngcontent-%COMP%] {\n width: 100%;\n resize: vertical;\n min-height: 80px;\n}\n\n[_nghost-%COMP%] .form-input .k-input, \n[_nghost-%COMP%] .form-textarea .k-input-inner, \n[_nghost-%COMP%] .form-field .k-dropdownlist {\n padding: 10px 14px;\n border-radius: 8px;\n font-size: 14px;\n border-color: var(--mj-border-default);\n background: var(--mj-bg-surface) !important;\n color: var(--mj-text-primary) !important;\n transition: all 0.2s ease;\n}\n\n[_nghost-%COMP%] .form-input:focus-within, \n[_nghost-%COMP%] .form-textarea:focus-within, \n[_nghost-%COMP%] .form-field .k-dropdownlist.k-focus {\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-status-success) 10%, transparent);\n}\n\n.field-hint[_ngcontent-%COMP%] {\n display: block;\n font-size: 12px;\n color: var(--mj-text-secondary);\n margin-top: 6px;\n line-height: 1.4;\n}\n\n.form-row[_ngcontent-%COMP%] {\n display: flex;\n gap: 16px;\n}\n\n.form-field.half[_ngcontent-%COMP%] {\n flex: 1;\n}\n\n.checkbox-label[_ngcontent-%COMP%] {\n display: flex;\n align-items: flex-start;\n gap: 12px;\n cursor: pointer;\n padding: 12px 16px;\n background: var(--mj-bg-page);\n border-radius: 10px;\n border: 1px solid var(--mj-border-default);\n transition: all 0.2s ease;\n}\n\n.checkbox-label[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n border-color: var(--mj-border-strong);\n}\n\n.checkbox-label[_ngcontent-%COMP%] input[_ngcontent-%COMP%] {\n margin-top: 2px;\n flex-shrink: 0;\n}\n\n.checkbox-label[_ngcontent-%COMP%] span[_ngcontent-%COMP%]:first-of-type {\n font-weight: 600;\n color: var(--mj-text-primary);\n font-size: 14px;\n}\n\n.checkbox-hint[_ngcontent-%COMP%] {\n display: block;\n font-size: 12px;\n color: var(--mj-text-secondary);\n margin-top: 4px;\n line-height: 1.4;\n}\n\n\n\n.dialog-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 12px;\n padding: 20px 24px;\n background: var(--mj-bg-page);\n border-top: 1px solid var(--mj-border-default);\n margin: 0 -24px -24px -24px;\n}\n\n[_nghost-%COMP%] .dialog-actions .k-button {\n min-width: 100px;\n padding: 10px 20px;\n font-weight: 600;\n border-radius: 8px;\n transition: all 0.2s ease;\n}\n\n[_nghost-%COMP%] .dialog-actions .k-button-solid-primary {\n background: linear-gradient(135deg, var(--mj-status-success) 0%, var(--mj-color-success-600) 100%);\n border: none;\n box-shadow: 0 2px 8px color-mix(in srgb, var(--mj-status-success) 30%, transparent);\n}\n\n[_nghost-%COMP%] .dialog-actions .k-button-solid-primary:hover {\n transform: translateY(-1px);\n box-shadow: 0 4px 12px color-mix(in srgb, var(--mj-status-success) 40%, transparent);\n}"] });
640
640
  }
641
641
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(APIScopesPanelComponent, [{
642
642
  type: Component,
643
- args: [{ standalone: false, selector: 'mj-api-scopes-panel', template: "<div class=\"scopes-panel\">\n @if (IsLoading) {\n <mj-loading text=\"Loading scopes...\"></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-shield-halved\"></i>\n API Scopes\n </h3>\n <p class=\"panel-subtitle\">Manage hierarchical permission scopes for API access</p>\n </div>\n <div class=\"header-actions\">\n <div class=\"scope-stats\">\n <span class=\"stat\">\n <i class=\"fa-solid fa-shield\"></i>\n {{getTotalCount()}} total\n </span>\n <span class=\"stat active\">\n <i class=\"fa-solid fa-check-circle\"></i>\n {{getActiveCount()}} active\n </span>\n </div>\n <div class=\"tree-controls\">\n <button class=\"btn-icon\" (click)=\"expandAll()\" title=\"Expand All\">\n <i class=\"fa-solid fa-plus-square\"></i>\n </button>\n <button class=\"btn-icon\" (click)=\"collapseAll()\" title=\"Collapse All\">\n <i class=\"fa-solid fa-minus-square\"></i>\n </button>\n </div>\n <button class=\"btn-create\" (click)=\"openCreateDialog()\">\n <i class=\"fa-solid fa-plus\"></i>\n New Scope\n </button>\n </div>\n </div>\n <!-- Messages -->\n @if (SuccessMessage) {\n <div class=\"message success\">\n <i class=\"fa-solid fa-check-circle\"></i>\n {{SuccessMessage}}\n </div>\n }\n @if (ErrorMessage) {\n <div class=\"message error\">\n <i class=\"fa-solid fa-circle-exclamation\"></i>\n {{ErrorMessage}}\n </div>\n }\n <!-- Scope Tree -->\n <div class=\"scope-tree\">\n @for (node of ScopeTree; track node) {\n <ng-container *ngTemplateOutlet=\"scopeNode; context: { node: node }\"></ng-container>\n }\n <!-- Empty State -->\n @if (ScopeTree.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-shield-halved\"></i>\n <span>No scopes configured</span>\n <p>Create scopes to define API access permissions</p>\n </div>\n }\n </div>\n <!-- Recursive Node Template -->\n <ng-template #scopeNode let-node=\"node\">\n <div class=\"scope-node\" [style.padding-left.px]=\"node.level * 24\">\n <div class=\"node-content\" [class.inactive]=\"!node.scope.IsActive\">\n @if (node.children.length > 0) {\n <button class=\"expand-btn\"\n (click)=\"toggleExpanded(node)\">\n <i class=\"fa-solid\"\n [class.fa-chevron-right]=\"!node.expanded\"\n [class.fa-chevron-down]=\"node.expanded\"></i>\n </button>\n }\n @if (node.children.length === 0) {\n <span class=\"expand-placeholder\"></span>\n }\n <div class=\"scope-info\" (click)=\"openEditDialog(node.scope)\">\n <div class=\"scope-icon\" [style.backgroundColor]=\"getCategoryColor(node.scope.Category)\">\n <i class=\"fa-solid fa-shield\"></i>\n </div>\n <div class=\"scope-details\">\n <div class=\"scope-name\">\n {{node.scope.Name}}\n @if (node.scope.FullPath && node.scope.FullPath !== node.scope.Name) {\n <span class=\"full-path\">\n {{node.scope.FullPath}}\n </span>\n }\n @if (!node.scope.IsActive) {\n <span class=\"status-badge\">Inactive</span>\n }\n </div>\n <div class=\"scope-meta\">\n <span class=\"category\" [style.color]=\"getCategoryColor(node.scope.Category)\">\n {{node.scope.Category}}\n </span>\n @if (node.scope.ResourceType) {\n <span class=\"resource-type\">\n {{node.scope.ResourceType}}\n </span>\n }\n @if (node.scope.Description) {\n <span class=\"description\">\n {{node.scope.Description}}\n </span>\n }\n </div>\n </div>\n </div>\n <div class=\"node-actions\">\n <button class=\"btn-node-action\" (click)=\"openCreateDialog(node.scope)\" title=\"Add Child Scope\">\n <i class=\"fa-solid fa-plus\"></i>\n </button>\n <button class=\"btn-node-action\" (click)=\"openEditDialog(node.scope)\" title=\"Edit Scope\">\n <i class=\"fa-solid fa-pencil\"></i>\n </button>\n </div>\n </div>\n @if (node.expanded && node.children.length > 0) {\n <div class=\"children\">\n @for (child of node.children; track child) {\n <ng-container *ngTemplateOutlet=\"scopeNode; context: { node: child }\"></ng-container>\n }\n </div>\n }\n </div>\n </ng-template>\n }\n\n <!-- Create/Edit Dialog -->\n @if (ShowCreateDialog || ShowEditDialog) {\n <kendo-window\n [width]=\"560\"\n [minWidth]=\"420\"\n [minHeight]=\"480\"\n [resizable]=\"true\"\n [draggable]=\"true\"\n [top]=\"80\"\n (close)=\"closeDialogs()\">\n <kendo-window-titlebar>\n <div class=\"dialog-title\">\n <i class=\"fa-solid fa-shield-halved\"></i>\n <span>{{EditingScope ? 'Edit Scope' : 'New Scope'}}</span>\n </div>\n <button kendoButton fillMode=\"flat\" (click)=\"closeDialogs()\" class=\"window-close-btn\" title=\"Close (Esc)\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </kendo-window-titlebar>\n <div class=\"dialog-content\">\n <div class=\"form-field\">\n <label>Scope Name *</label>\n <input kendoTextBox [(ngModel)]=\"EditName\"\n placeholder=\"e.g., runview, create, execute\"\n class=\"form-input\" />\n <span class=\"field-hint\">Use lowercase, single word. Will be combined with parent for full path.</span>\n </div>\n <div class=\"form-field\">\n <label>Parent Scope</label>\n <kendo-dropdownlist [(ngModel)]=\"EditParentId\"\n [data]=\"getParentOptions()\"\n [textField]=\"'FullPath'\"\n [valueField]=\"'ID'\"\n [valuePrimitive]=\"true\"\n [defaultItem]=\"{ FullPath: '(No Parent - Root Level)', ID: null }\">\n </kendo-dropdownlist>\n @if (SelectedParentScope) {\n <span class=\"field-hint\">\n Full path will be: <code>{{SelectedParentScope.FullPath}}:{{EditName || '...'}}</code>\n </span>\n }\n </div>\n <div class=\"form-row\">\n <div class=\"form-field half\">\n <label>Category</label>\n <kendo-dropdownlist [(ngModel)]=\"EditCategory\"\n [data]=\"Categories\"\n [valuePrimitive]=\"true\">\n </kendo-dropdownlist>\n </div>\n <div class=\"form-field half\">\n <label>Resource Type</label>\n <kendo-dropdownlist [(ngModel)]=\"EditResourceType\"\n [data]=\"ResourceTypes\"\n [valuePrimitive]=\"true\"\n [defaultItem]=\"''\">\n </kendo-dropdownlist>\n </div>\n </div>\n <div class=\"form-field\">\n <label>Description</label>\n <textarea kendoTextArea [(ngModel)]=\"EditDescription\"\n placeholder=\"Describe what this scope allows...\"\n [rows]=\"3\"\n class=\"form-textarea\"></textarea>\n </div>\n <div class=\"form-field\">\n <label class=\"checkbox-label\">\n <input type=\"checkbox\" kendoCheckBox [(ngModel)]=\"EditIsActive\" />\n <div>\n <span>Active</span>\n <span class=\"checkbox-hint\">Inactive scopes cannot be assigned to keys or applications</span>\n </div>\n </label>\n </div>\n <div class=\"dialog-actions\">\n <button kendoButton [themeColor]=\"'primary'\"\n [disabled]=\"!EditName.trim() || IsSaving\"\n (click)=\"saveScope()\">\n @if (IsSaving) {\n <mj-loading [showText]=\"false\" size=\"small\"></mj-loading>\n }\n @if (!IsSaving) {\n <span>\n <i class=\"fa-solid fa-save\"></i>\n {{EditingScope ? 'Update' : 'Create'}}\n </span>\n }\n </button>\n <button kendoButton (click)=\"closeDialogs()\">Cancel</button>\n </div>\n </div>\n </kendo-window>\n }\n</div>\n", styles: [".scopes-panel {\n height: 100%;\n display: flex;\n flex-direction: column;\n}\n\n/* Panel Header */\n.panel-header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 24px;\n flex-wrap: wrap;\n gap: 16px;\n}\n\n.header-left {\n flex: 1;\n min-width: 200px;\n}\n\n.panel-title {\n display: flex;\n align-items: center;\n gap: 10px;\n font-size: 18px;\n font-weight: 600;\n color: var(--text-primary, #1f2937);\n margin: 0 0 4px 0;\n}\n\n.panel-title i {\n color: #10b981;\n}\n\n.panel-subtitle {\n font-size: 14px;\n color: var(--text-secondary, #6b7280);\n margin: 0;\n}\n\n.header-actions {\n display: flex;\n align-items: center;\n gap: 16px;\n}\n\n.scope-stats {\n display: flex;\n gap: 16px;\n}\n\n.stat {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 13px;\n color: var(--text-secondary, #6b7280);\n}\n\n.stat.active {\n color: #10b981;\n}\n\n.stat i {\n font-size: 14px;\n}\n\n.tree-controls {\n display: flex;\n gap: 4px;\n}\n\n.btn-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n background: var(--card-background, #ffffff);\n border: 1px solid var(--border-color, #e5e7eb);\n border-radius: 6px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.btn-icon:hover {\n background: var(--item-hover, #f3f4f6);\n}\n\n.btn-icon i {\n font-size: 14px;\n color: var(--text-secondary, #6b7280);\n}\n\n.btn-create {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 20px;\n background: linear-gradient(135deg, #10b981 0%, #059669 100%);\n color: white;\n border: none;\n border-radius: 8px;\n font-weight: 600;\n font-size: 14px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.btn-create:hover {\n transform: translateY(-1px);\n box-shadow: 0 4px 12px rgba(16, 185, 129, 0.4);\n}\n\n/* Messages */\n.message {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 12px 16px;\n border-radius: 8px;\n margin-bottom: 16px;\n font-size: 14px;\n}\n\n.message.success {\n background: #d1fae5;\n color: #065f46;\n border: 1px solid #a7f3d0;\n}\n\n.message.error {\n background: #fee2e2;\n color: #991b1b;\n border: 1px solid #fca5a5;\n}\n\n/* Scope Tree */\n.scope-tree {\n flex: 1;\n overflow-y: auto;\n background: var(--card-background, #ffffff);\n border-radius: 12px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);\n}\n\n.scope-node {\n border-bottom: 1px solid var(--border-color, #e5e7eb);\n}\n\n.scope-node:last-child {\n border-bottom: none;\n}\n\n.node-content {\n display: flex;\n align-items: center;\n padding: 12px 16px;\n transition: background 0.2s ease;\n}\n\n.node-content:hover {\n background: var(--item-hover, #f9fafb);\n}\n\n.node-content.inactive {\n opacity: 0.6;\n}\n\n.expand-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n background: none;\n border: none;\n cursor: pointer;\n color: var(--text-tertiary, #9ca3af);\n transition: transform 0.2s ease;\n flex-shrink: 0;\n}\n\n.expand-btn:hover {\n color: var(--text-secondary, #6b7280);\n}\n\n.expand-placeholder {\n width: 24px;\n flex-shrink: 0;\n}\n\n.scope-info {\n display: flex;\n align-items: center;\n flex: 1;\n min-width: 0;\n cursor: pointer;\n}\n\n.scope-icon {\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 8px;\n margin-right: 12px;\n flex-shrink: 0;\n}\n\n.scope-icon i {\n font-size: 14px;\n color: white;\n}\n\n.scope-details {\n flex: 1;\n min-width: 0;\n}\n\n.scope-name {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 14px;\n font-weight: 500;\n color: var(--text-primary, #1f2937);\n flex-wrap: wrap;\n}\n\n.full-path {\n font-family: monospace;\n font-size: 12px;\n color: var(--text-tertiary, #9ca3af);\n background: var(--tag-background, #f3f4f6);\n padding: 2px 6px;\n border-radius: 4px;\n}\n\n.status-badge {\n font-size: 10px;\n font-weight: 500;\n padding: 2px 6px;\n border-radius: 4px;\n background: #f3f4f6;\n color: #6b7280;\n}\n\n.scope-meta {\n display: flex;\n align-items: center;\n gap: 12px;\n margin-top: 4px;\n font-size: 12px;\n flex-wrap: wrap;\n}\n\n.category {\n font-weight: 500;\n}\n\n.resource-type {\n color: var(--text-secondary, #6b7280);\n background: var(--tag-background, #f3f4f6);\n padding: 2px 6px;\n border-radius: 4px;\n}\n\n.description {\n color: var(--text-tertiary, #9ca3af);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n max-width: 300px;\n}\n\n.node-actions {\n display: flex;\n gap: 4px;\n margin-left: 12px;\n opacity: 0;\n transition: opacity 0.2s ease;\n}\n\n.node-content:hover .node-actions {\n opacity: 1;\n}\n\n.btn-node-action {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n background: var(--card-background, #ffffff);\n border: 1px solid var(--border-color, #e5e7eb);\n border-radius: 6px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.btn-node-action:hover {\n background: #10b981;\n border-color: #10b981;\n color: white;\n}\n\n.btn-node-action i {\n font-size: 12px;\n}\n\n.children {\n margin-left: 0;\n}\n\n/* Empty State */\n.empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 48px;\n color: var(--text-secondary, #6b7280);\n text-align: center;\n}\n\n.empty-state i {\n font-size: 48px;\n margin-bottom: 16px;\n opacity: 0.5;\n}\n\n.empty-state span {\n font-size: 16px;\n font-weight: 500;\n}\n\n.empty-state p {\n font-size: 14px;\n margin-top: 8px;\n}\n\n/* ========================================\n Dialog Styles - Polished & Professional\n ======================================== */\n\n/* Window styling */\n:host ::ng-deep kendo-window {\n border-radius: 16px !important;\n overflow: hidden;\n box-shadow: 0 25px 60px rgba(0, 0, 0, 0.15),\n 0 10px 30px rgba(0, 0, 0, 0.1),\n 0 0 0 1px rgba(0, 0, 0, 0.05) !important;\n}\n\n:host ::ng-deep kendo-window .k-window-content {\n padding: 0 !important;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n\n:host ::ng-deep kendo-window-titlebar {\n display: flex !important;\n align-items: center;\n justify-content: space-between;\n padding: 18px 24px !important;\n background: linear-gradient(135deg, #fafafa 0%, #f3f4f6 100%) !important;\n border-bottom: 1px solid #e5e7eb !important;\n}\n\n.dialog-title {\n display: flex;\n align-items: center;\n gap: 12px;\n font-weight: 600;\n font-size: 17px;\n color: #1f2937;\n}\n\n.dialog-title i {\n color: #10b981;\n font-size: 18px;\n}\n\n.window-close-btn {\n margin-left: auto;\n color: #9ca3af;\n transition: all 0.2s ease;\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: #374151;\n background: rgba(0, 0, 0, 0.05);\n}\n\n.window-close-btn i {\n font-size: 16px;\n}\n\n/* Dialog Content */\n.dialog-content {\n padding: 24px;\n flex: 1;\n overflow-y: auto;\n}\n\n/* Form Fields */\n.form-field {\n margin-bottom: 20px;\n}\n\n.form-field:last-of-type {\n margin-bottom: 0;\n}\n\n.form-field label {\n display: block;\n font-size: 13px;\n font-weight: 600;\n color: #374151;\n margin-bottom: 8px;\n letter-spacing: 0.01em;\n}\n\n.form-input {\n width: 100%;\n}\n\n.form-textarea {\n width: 100%;\n resize: vertical;\n min-height: 80px;\n}\n\n:host ::ng-deep .form-input .k-input,\n:host ::ng-deep .form-textarea .k-input-inner,\n:host ::ng-deep .form-field .k-dropdownlist {\n padding: 10px 14px;\n border-radius: 8px;\n font-size: 14px;\n border-color: #e5e7eb;\n transition: all 0.2s ease;\n}\n\n:host ::ng-deep .form-input:focus-within,\n:host ::ng-deep .form-textarea:focus-within,\n:host ::ng-deep .form-field .k-dropdownlist.k-focus {\n box-shadow: 0 0 0 3px rgba(16, 185, 129, 0.1);\n}\n\n.field-hint {\n display: block;\n font-size: 12px;\n color: #6b7280;\n margin-top: 6px;\n line-height: 1.4;\n}\n\n.form-row {\n display: flex;\n gap: 16px;\n}\n\n.form-field.half {\n flex: 1;\n}\n\n.checkbox-label {\n display: flex;\n align-items: flex-start;\n gap: 12px;\n cursor: pointer;\n padding: 12px 16px;\n background: #f9fafb;\n border-radius: 10px;\n border: 1px solid #e5e7eb;\n transition: all 0.2s ease;\n}\n\n.checkbox-label:hover {\n background: #f3f4f6;\n border-color: #d1d5db;\n}\n\n.checkbox-label input {\n margin-top: 2px;\n flex-shrink: 0;\n}\n\n.checkbox-label span:first-of-type {\n font-weight: 600;\n color: #374151;\n font-size: 14px;\n}\n\n.checkbox-hint {\n display: block;\n font-size: 12px;\n color: #6b7280;\n margin-top: 4px;\n line-height: 1.4;\n}\n\n/* Dialog Actions */\n.dialog-actions {\n display: flex;\n gap: 12px;\n padding: 20px 24px;\n background: #f9fafb;\n border-top: 1px solid #e5e7eb;\n margin: 0 -24px -24px -24px;\n}\n\n:host ::ng-deep .dialog-actions .k-button {\n min-width: 100px;\n padding: 10px 20px;\n font-weight: 600;\n border-radius: 8px;\n transition: all 0.2s ease;\n}\n\n:host ::ng-deep .dialog-actions .k-button-solid-primary {\n background: linear-gradient(135deg, #10b981 0%, #059669 100%);\n border: none;\n box-shadow: 0 2px 8px rgba(16, 185, 129, 0.3);\n}\n\n:host ::ng-deep .dialog-actions .k-button-solid-primary:hover {\n transform: translateY(-1px);\n box-shadow: 0 4px 12px rgba(16, 185, 129, 0.4);\n}\n"] }]
643
+ args: [{ standalone: false, selector: 'mj-api-scopes-panel', template: "<div class=\"scopes-panel\">\n @if (IsLoading) {\n <mj-loading text=\"Loading scopes...\"></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-shield-halved\"></i>\n API Scopes\n </h3>\n <p class=\"panel-subtitle\">Manage hierarchical permission scopes for API access</p>\n </div>\n <div class=\"header-actions\">\n <div class=\"scope-stats\">\n <span class=\"stat\">\n <i class=\"fa-solid fa-shield\"></i>\n {{getTotalCount()}} total\n </span>\n <span class=\"stat active\">\n <i class=\"fa-solid fa-check-circle\"></i>\n {{getActiveCount()}} active\n </span>\n </div>\n <div class=\"tree-controls\">\n <button class=\"btn-icon\" (click)=\"expandAll()\" title=\"Expand All\">\n <i class=\"fa-solid fa-plus-square\"></i>\n </button>\n <button class=\"btn-icon\" (click)=\"collapseAll()\" title=\"Collapse All\">\n <i class=\"fa-solid fa-minus-square\"></i>\n </button>\n </div>\n <button class=\"btn-create\" (click)=\"openCreateDialog()\">\n <i class=\"fa-solid fa-plus\"></i>\n New Scope\n </button>\n </div>\n </div>\n <!-- Messages -->\n @if (SuccessMessage) {\n <div class=\"message success\">\n <i class=\"fa-solid fa-check-circle\"></i>\n {{SuccessMessage}}\n </div>\n }\n @if (ErrorMessage) {\n <div class=\"message error\">\n <i class=\"fa-solid fa-circle-exclamation\"></i>\n {{ErrorMessage}}\n </div>\n }\n <!-- Scope Tree -->\n <div class=\"scope-tree\">\n @for (node of ScopeTree; track node) {\n <ng-container *ngTemplateOutlet=\"scopeNode; context: { node: node }\"></ng-container>\n }\n <!-- Empty State -->\n @if (ScopeTree.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-shield-halved\"></i>\n <span>No scopes configured</span>\n <p>Create scopes to define API access permissions</p>\n </div>\n }\n </div>\n <!-- Recursive Node Template -->\n <ng-template #scopeNode let-node=\"node\">\n <div class=\"scope-node\" [style.padding-left.px]=\"node.level * 24\">\n <div class=\"node-content\" [class.inactive]=\"!node.scope.IsActive\">\n @if (node.children.length > 0) {\n <button class=\"expand-btn\"\n (click)=\"toggleExpanded(node)\">\n <i class=\"fa-solid\"\n [class.fa-chevron-right]=\"!node.expanded\"\n [class.fa-chevron-down]=\"node.expanded\"></i>\n </button>\n }\n @if (node.children.length === 0) {\n <span class=\"expand-placeholder\"></span>\n }\n <div class=\"scope-info\" (click)=\"openEditDialog(node.scope)\">\n <div class=\"scope-icon\" [style.backgroundColor]=\"getCategoryColor(node.scope.Category)\">\n <i class=\"fa-solid fa-shield\"></i>\n </div>\n <div class=\"scope-details\">\n <div class=\"scope-name\">\n {{node.scope.Name}}\n @if (node.scope.FullPath && node.scope.FullPath !== node.scope.Name) {\n <span class=\"full-path\">\n {{node.scope.FullPath}}\n </span>\n }\n @if (!node.scope.IsActive) {\n <span class=\"status-badge\">Inactive</span>\n }\n </div>\n <div class=\"scope-meta\">\n <span class=\"category\" [style.color]=\"getCategoryColor(node.scope.Category)\">\n {{node.scope.Category}}\n </span>\n @if (node.scope.ResourceType) {\n <span class=\"resource-type\">\n {{node.scope.ResourceType}}\n </span>\n }\n @if (node.scope.Description) {\n <span class=\"description\">\n {{node.scope.Description}}\n </span>\n }\n </div>\n </div>\n </div>\n <div class=\"node-actions\">\n <button class=\"btn-node-action\" (click)=\"openCreateDialog(node.scope)\" title=\"Add Child Scope\">\n <i class=\"fa-solid fa-plus\"></i>\n </button>\n <button class=\"btn-node-action\" (click)=\"openEditDialog(node.scope)\" title=\"Edit Scope\">\n <i class=\"fa-solid fa-pencil\"></i>\n </button>\n </div>\n </div>\n @if (node.expanded && node.children.length > 0) {\n <div class=\"children\">\n @for (child of node.children; track child) {\n <ng-container *ngTemplateOutlet=\"scopeNode; context: { node: child }\"></ng-container>\n }\n </div>\n }\n </div>\n </ng-template>\n }\n\n <!-- Create/Edit Dialog -->\n @if (ShowCreateDialog || ShowEditDialog) {\n <kendo-window\n [width]=\"560\"\n [minWidth]=\"420\"\n [minHeight]=\"480\"\n [resizable]=\"true\"\n [draggable]=\"true\"\n [top]=\"80\"\n (close)=\"closeDialogs()\">\n <kendo-window-titlebar>\n <div class=\"dialog-title\">\n <i class=\"fa-solid fa-shield-halved\"></i>\n <span>{{EditingScope ? 'Edit Scope' : 'New Scope'}}</span>\n </div>\n <button kendoButton fillMode=\"flat\" (click)=\"closeDialogs()\" class=\"window-close-btn\" title=\"Close (Esc)\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </kendo-window-titlebar>\n <div class=\"dialog-content\">\n <div class=\"form-field\">\n <label>Scope Name *</label>\n <input kendoTextBox [(ngModel)]=\"EditName\"\n placeholder=\"e.g., runview, create, execute\"\n class=\"form-input\" />\n <span class=\"field-hint\">Use lowercase, single word. Will be combined with parent for full path.</span>\n </div>\n <div class=\"form-field\">\n <label>Parent Scope</label>\n <kendo-dropdownlist [(ngModel)]=\"EditParentId\"\n [data]=\"getParentOptions()\"\n [textField]=\"'FullPath'\"\n [valueField]=\"'ID'\"\n [valuePrimitive]=\"true\"\n [defaultItem]=\"{ FullPath: '(No Parent - Root Level)', ID: null }\">\n </kendo-dropdownlist>\n @if (SelectedParentScope) {\n <span class=\"field-hint\">\n Full path will be: <code>{{SelectedParentScope.FullPath}}:{{EditName || '...'}}</code>\n </span>\n }\n </div>\n <div class=\"form-row\">\n <div class=\"form-field half\">\n <label>Category</label>\n <kendo-dropdownlist [(ngModel)]=\"EditCategory\"\n [data]=\"Categories\"\n [valuePrimitive]=\"true\">\n </kendo-dropdownlist>\n </div>\n <div class=\"form-field half\">\n <label>Resource Type</label>\n <kendo-dropdownlist [(ngModel)]=\"EditResourceType\"\n [data]=\"ResourceTypes\"\n [valuePrimitive]=\"true\"\n [defaultItem]=\"''\">\n </kendo-dropdownlist>\n </div>\n </div>\n <div class=\"form-field\">\n <label>Description</label>\n <textarea kendoTextArea [(ngModel)]=\"EditDescription\"\n placeholder=\"Describe what this scope allows...\"\n [rows]=\"3\"\n class=\"form-textarea\"></textarea>\n </div>\n <div class=\"form-field\">\n <label class=\"checkbox-label\">\n <input type=\"checkbox\" kendoCheckBox [(ngModel)]=\"EditIsActive\" />\n <div>\n <span>Active</span>\n <span class=\"checkbox-hint\">Inactive scopes cannot be assigned to keys or applications</span>\n </div>\n </label>\n </div>\n <div class=\"dialog-actions\">\n <button kendoButton [themeColor]=\"'primary'\"\n [disabled]=\"!EditName.trim() || IsSaving\"\n (click)=\"saveScope()\">\n @if (IsSaving) {\n <mj-loading [showText]=\"false\" size=\"small\"></mj-loading>\n }\n @if (!IsSaving) {\n <span>\n <i class=\"fa-solid fa-save\"></i>\n {{EditingScope ? 'Update' : 'Create'}}\n </span>\n }\n </button>\n <button kendoButton (click)=\"closeDialogs()\">Cancel</button>\n </div>\n </div>\n </kendo-window>\n }\n</div>\n", styles: [".scopes-panel {\n height: 100%;\n display: flex;\n flex-direction: column;\n}\n\n/* Panel Header */\n.panel-header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 24px;\n flex-wrap: wrap;\n gap: 16px;\n}\n\n.header-left {\n flex: 1;\n min-width: 200px;\n}\n\n.panel-title {\n display: flex;\n align-items: center;\n gap: 10px;\n font-size: 18px;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0 0 4px 0;\n}\n\n.panel-title i {\n color: var(--mj-status-success);\n}\n\n.panel-subtitle {\n font-size: 14px;\n color: var(--mj-text-secondary);\n margin: 0;\n}\n\n.header-actions {\n display: flex;\n align-items: center;\n gap: 16px;\n}\n\n.scope-stats {\n display: flex;\n gap: 16px;\n}\n\n.stat {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 13px;\n color: var(--mj-text-secondary);\n}\n\n.stat.active {\n color: var(--mj-status-success);\n}\n\n.stat i {\n font-size: 14px;\n}\n\n.tree-controls {\n display: flex;\n gap: 4px;\n}\n\n.btn-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.btn-icon:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.btn-icon i {\n font-size: 14px;\n color: var(--mj-text-secondary);\n}\n\n.btn-create {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 20px;\n background: linear-gradient(135deg, var(--mj-status-success) 0%, var(--mj-color-success-600) 100%);\n color: var(--mj-text-inverse);\n border: none;\n border-radius: 8px;\n font-weight: 600;\n font-size: 14px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.btn-create:hover {\n transform: translateY(-1px);\n box-shadow: 0 4px 12px color-mix(in srgb, var(--mj-status-success) 40%, transparent);\n}\n\n/* Messages */\n.message {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 12px 16px;\n border-radius: 8px;\n margin-bottom: 16px;\n font-size: 14px;\n}\n\n.message.success {\n background: var(--mj-color-success-100);\n color: var(--mj-color-success-800);\n border: 1px solid var(--mj-status-success-border);\n}\n\n.message.error {\n background: var(--mj-color-error-100);\n color: var(--mj-color-error-700);\n border: 1px solid var(--mj-status-error-border);\n}\n\n/* Scope Tree */\n.scope-tree {\n flex: 1;\n overflow-y: auto;\n background: var(--mj-bg-surface);\n border-radius: 12px;\n box-shadow: var(--mj-shadow-md);\n}\n\n.scope-node {\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.scope-node:last-child {\n border-bottom: none;\n}\n\n.node-content {\n display: flex;\n align-items: center;\n padding: 12px 16px;\n transition: background 0.2s ease;\n}\n\n.node-content:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.node-content.inactive {\n opacity: 0.6;\n}\n\n.expand-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n background: none;\n border: none;\n cursor: pointer;\n color: var(--mj-text-muted);\n transition: transform 0.2s ease;\n flex-shrink: 0;\n}\n\n.expand-btn:hover {\n color: var(--mj-text-secondary);\n}\n\n.expand-placeholder {\n width: 24px;\n flex-shrink: 0;\n}\n\n.scope-info {\n display: flex;\n align-items: center;\n flex: 1;\n min-width: 0;\n cursor: pointer;\n}\n\n.scope-icon {\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 8px;\n margin-right: 12px;\n flex-shrink: 0;\n}\n\n.scope-icon i {\n font-size: 14px;\n color: var(--mj-text-inverse);\n}\n\n.scope-details {\n flex: 1;\n min-width: 0;\n}\n\n.scope-name {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 14px;\n font-weight: 500;\n color: var(--mj-text-primary);\n flex-wrap: wrap;\n}\n\n.full-path {\n font-family: monospace;\n font-size: 12px;\n color: var(--mj-text-muted);\n background: var(--mj-bg-surface-sunken);\n padding: 2px 6px;\n border-radius: 4px;\n}\n\n.status-badge {\n font-size: 10px;\n font-weight: 500;\n padding: 2px 6px;\n border-radius: 4px;\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-secondary);\n}\n\n.scope-meta {\n display: flex;\n align-items: center;\n gap: 12px;\n margin-top: 4px;\n font-size: 12px;\n flex-wrap: wrap;\n}\n\n.category {\n font-weight: 500;\n}\n\n.resource-type {\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface-sunken);\n padding: 2px 6px;\n border-radius: 4px;\n}\n\n.description {\n color: var(--mj-text-muted);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n max-width: 300px;\n}\n\n.node-actions {\n display: flex;\n gap: 4px;\n margin-left: 12px;\n opacity: 0;\n transition: opacity 0.2s ease;\n}\n\n.node-content:hover .node-actions {\n opacity: 1;\n}\n\n.btn-node-action {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.btn-node-action:hover {\n background: var(--mj-status-success);\n border-color: var(--mj-status-success);\n color: var(--mj-text-inverse);\n}\n\n.btn-node-action i {\n font-size: 12px;\n}\n\n.children {\n margin-left: 0;\n}\n\n/* Empty State */\n.empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 48px;\n color: var(--mj-text-secondary);\n text-align: center;\n}\n\n.empty-state i {\n font-size: 48px;\n margin-bottom: 16px;\n opacity: 0.5;\n}\n\n.empty-state span {\n font-size: 16px;\n font-weight: 500;\n}\n\n.empty-state p {\n font-size: 14px;\n margin-top: 8px;\n}\n\n/* ========================================\n Dialog Styles - Polished & Professional\n ======================================== */\n\n/* Window styling */\n:host ::ng-deep kendo-window {\n border-radius: 16px !important;\n overflow: hidden;\n box-shadow: var(--mj-shadow-2xl) !important;\n background: var(--mj-bg-surface) !important;\n}\n\n:host ::ng-deep kendo-window .k-window-content {\n padding: 0 !important;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n background: var(--mj-bg-surface) !important;\n}\n\n:host ::ng-deep kendo-window-titlebar {\n display: flex !important;\n align-items: center;\n justify-content: space-between;\n padding: 18px 24px !important;\n background: var(--mj-bg-page) !important;\n border-bottom: 1px solid var(--mj-border-default) !important;\n}\n\n.dialog-title {\n display: flex;\n align-items: center;\n gap: 12px;\n font-weight: 600;\n font-size: 17px;\n color: var(--mj-text-primary);\n}\n\n.dialog-title i {\n color: var(--mj-status-success);\n font-size: 18px;\n}\n\n.window-close-btn {\n margin-left: auto;\n color: var(--mj-text-muted);\n transition: all 0.2s ease;\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-primary);\n background: var(--mj-bg-surface-hover);\n}\n\n.window-close-btn i {\n font-size: 16px;\n}\n\n/* Dialog Content */\n.dialog-content {\n padding: 24px;\n flex: 1;\n overflow-y: auto;\n}\n\n/* Form Fields */\n.form-field {\n margin-bottom: 20px;\n}\n\n.form-field:last-of-type {\n margin-bottom: 0;\n}\n\n.form-field label {\n display: block;\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin-bottom: 8px;\n letter-spacing: 0.01em;\n}\n\n.form-input {\n width: 100%;\n}\n\n.form-textarea {\n width: 100%;\n resize: vertical;\n min-height: 80px;\n}\n\n:host ::ng-deep .form-input .k-input,\n:host ::ng-deep .form-textarea .k-input-inner,\n:host ::ng-deep .form-field .k-dropdownlist {\n padding: 10px 14px;\n border-radius: 8px;\n font-size: 14px;\n border-color: var(--mj-border-default);\n background: var(--mj-bg-surface) !important;\n color: var(--mj-text-primary) !important;\n transition: all 0.2s ease;\n}\n\n:host ::ng-deep .form-input:focus-within,\n:host ::ng-deep .form-textarea:focus-within,\n:host ::ng-deep .form-field .k-dropdownlist.k-focus {\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-status-success) 10%, transparent);\n}\n\n.field-hint {\n display: block;\n font-size: 12px;\n color: var(--mj-text-secondary);\n margin-top: 6px;\n line-height: 1.4;\n}\n\n.form-row {\n display: flex;\n gap: 16px;\n}\n\n.form-field.half {\n flex: 1;\n}\n\n.checkbox-label {\n display: flex;\n align-items: flex-start;\n gap: 12px;\n cursor: pointer;\n padding: 12px 16px;\n background: var(--mj-bg-page);\n border-radius: 10px;\n border: 1px solid var(--mj-border-default);\n transition: all 0.2s ease;\n}\n\n.checkbox-label:hover {\n background: var(--mj-bg-surface-sunken);\n border-color: var(--mj-border-strong);\n}\n\n.checkbox-label input {\n margin-top: 2px;\n flex-shrink: 0;\n}\n\n.checkbox-label span:first-of-type {\n font-weight: 600;\n color: var(--mj-text-primary);\n font-size: 14px;\n}\n\n.checkbox-hint {\n display: block;\n font-size: 12px;\n color: var(--mj-text-secondary);\n margin-top: 4px;\n line-height: 1.4;\n}\n\n/* Dialog Actions */\n.dialog-actions {\n display: flex;\n gap: 12px;\n padding: 20px 24px;\n background: var(--mj-bg-page);\n border-top: 1px solid var(--mj-border-default);\n margin: 0 -24px -24px -24px;\n}\n\n:host ::ng-deep .dialog-actions .k-button {\n min-width: 100px;\n padding: 10px 20px;\n font-weight: 600;\n border-radius: 8px;\n transition: all 0.2s ease;\n}\n\n:host ::ng-deep .dialog-actions .k-button-solid-primary {\n background: linear-gradient(135deg, var(--mj-status-success) 0%, var(--mj-color-success-600) 100%);\n border: none;\n box-shadow: 0 2px 8px color-mix(in srgb, var(--mj-status-success) 30%, transparent);\n}\n\n:host ::ng-deep .dialog-actions .k-button-solid-primary:hover {\n transform: translateY(-1px);\n box-shadow: 0 4px 12px color-mix(in srgb, var(--mj-status-success) 40%, transparent);\n}\n"] }]
644
644
  }], () => [{ type: i0.ChangeDetectorRef }], { ScopeUpdated: [{
645
645
  type: Output
646
646
  }] }); })();
@@ -1 +1 @@
1
- {"version":3,"file":"api-scopes-panel.component.js","sourceRoot":"","sources":["../../src/APIKeys/api-scopes-panel.component.ts","../../src/APIKeys/api-scopes-panel.component.html"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"api-scopes-panel.component.js","sourceRoot":"","sources":["../../src/APIKeys/api-scopes-panel.component.ts","../../src/APIKeys/api-scopes-panel.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, OnInit, EventEmitter, Output, ChangeDetectorRef } from '@angular/core';\nimport { Metadata, RunView } from '@memberjunction/core';\nimport { MJAPIScopeEntity } from '@memberjunction/core-entities';\n/** Scope tree node structure */\ninterface ScopeTreeNode {\n scope: MJAPIScopeEntity;\n children: ScopeTreeNode[];\n expanded: boolean;\n level: number;\n}\n\n/**\n * API Scopes Panel Component\n * Manages API Scopes in a hierarchical tree structure\n */\n@Component({\n standalone: false,\n selector: 'mj-api-scopes-panel',\n templateUrl: './api-scopes-panel.component.html',\n styleUrls: ['./api-scopes-panel.component.css']\n})\nexport class APIScopesPanelComponent implements OnInit {\n @Output() ScopeUpdated = new EventEmitter<void>();\n\n private md = new Metadata();\n private cdr: ChangeDetectorRef;\n\n // Loading states\n public IsLoading = true;\n public IsSaving = false;\n\n // Data\n public ScopeTree: ScopeTreeNode[] = [];\n public FlatScopes: MJAPIScopeEntity[] = [];\n\n // Edit state\n public EditingScope: MJAPIScopeEntity | null = null;\n public EditName = '';\n public EditDescription = '';\n public EditCategory = '';\n public EditResourceType = '';\n public EditParentId: string | null = null;\n public EditIsActive = true;\n\n // Dialog states\n public ShowCreateDialog = false;\n public ShowEditDialog = false;\n public SelectedParentScope: MJAPIScopeEntity | null = null;\n\n // Messages\n public SuccessMessage = '';\n public ErrorMessage = '';\n\n // Category colors\n public readonly CategoryColors: Record<string, string> = {\n 'Entities': '#6366f1',\n 'Agents': '#10b981',\n 'Admin': '#f59e0b',\n 'Actions': '#8b5cf6',\n 'Queries': '#3b82f6',\n 'Reports': '#ef4444',\n 'Communication': '#ec4899',\n 'Other': '#6b7280'\n };\n\n // Resource type options\n public readonly ResourceTypes = ['Entity', 'Agent', 'Query', 'Mutation', 'Action', 'Report', 'Admin', 'Other'];\n public readonly Categories = ['Entities', 'Agents', 'Admin', 'Actions', 'Queries', 'Reports', 'Communication', 'Other'];\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 scopes\n */\n public async loadData(): Promise<void> {\n this.IsLoading = true;\n try {\n const rv = new RunView();\n const result = await rv.RunView<MJAPIScopeEntity>({\n EntityName: 'MJ: API Scopes',\n OrderBy: 'FullPath',\n ResultType: 'entity_object'\n });\n\n if (result.Success) {\n this.FlatScopes = result.Results;\n this.buildTree();\n }\n } catch (error) {\n console.error('Error loading scopes:', error);\n this.ErrorMessage = 'Failed to load scopes';\n } finally {\n this.IsLoading = false;\n this.cdr.markForCheck();\n }\n }\n\n /**\n * Build tree structure from flat scopes\n */\n private buildTree(): void {\n const scopeMap = new Map<string, ScopeTreeNode>();\n const rootNodes: ScopeTreeNode[] = [];\n\n // Create nodes\n for (const scope of this.FlatScopes) {\n scopeMap.set(scope.ID, {\n scope,\n children: [],\n expanded: true,\n level: 0\n });\n }\n\n // Build hierarchy\n for (const scope of this.FlatScopes) {\n const node = scopeMap.get(scope.ID)!;\n if (scope.ParentID) {\n const parent = scopeMap.get(scope.ParentID);\n if (parent) {\n parent.children.push(node);\n node.level = parent.level + 1;\n } else {\n rootNodes.push(node);\n }\n } else {\n rootNodes.push(node);\n }\n }\n\n // Calculate levels recursively\n const calculateLevels = (nodes: ScopeTreeNode[], level: number) => {\n for (const node of nodes) {\n node.level = level;\n calculateLevels(node.children, level + 1);\n }\n };\n calculateLevels(rootNodes, 0);\n\n this.ScopeTree = rootNodes;\n }\n\n /**\n * Open create dialog for new scope\n */\n public openCreateDialog(parentScope: MJAPIScopeEntity | null = null): void {\n this.EditName = '';\n this.EditDescription = '';\n this.EditCategory = parentScope?.Category || 'Entities';\n this.EditResourceType = '';\n this.EditParentId = parentScope?.ID || null;\n this.EditIsActive = true;\n this.EditingScope = null;\n this.SelectedParentScope = parentScope;\n this.ShowCreateDialog = true;\n }\n\n /**\n * Open edit dialog for existing scope\n */\n public openEditDialog(scope: MJAPIScopeEntity): void {\n this.EditingScope = scope;\n this.EditName = scope.Name;\n this.EditDescription = scope.Description || '';\n this.EditCategory = scope.Category || 'Entities';\n this.EditResourceType = scope.ResourceType || '';\n this.EditParentId = scope.ParentID;\n this.EditIsActive = scope.IsActive;\n this.SelectedParentScope = scope.ParentID\n ? this.FlatScopes.find(s => s.ID === scope.ParentID) || null\n : null;\n this.ShowEditDialog = true;\n }\n\n /**\n * Save scope (create or update)\n */\n public async saveScope(): Promise<void> {\n this.IsSaving = true;\n this.ErrorMessage = '';\n\n try {\n let scope: MJAPIScopeEntity;\n\n if (this.EditingScope) {\n scope = this.EditingScope;\n } else {\n scope = await this.md.GetEntityObject<MJAPIScopeEntity>('MJ: API Scopes');\n scope.NewRecord();\n }\n\n scope.Name = this.EditName.trim();\n scope.Description = this.EditDescription.trim() || null;\n scope.Category = this.EditCategory;\n scope.ResourceType = this.EditResourceType || null;\n scope.ParentID = this.EditParentId;\n scope.IsActive = this.EditIsActive;\n // FullPath is auto-computed by the trigger\n\n const result = await scope.Save();\n if (result) {\n this.SuccessMessage = this.EditingScope\n ? 'Scope updated successfully'\n : 'Scope created successfully';\n this.closeDialogs();\n await this.loadData();\n this.ScopeUpdated.emit();\n setTimeout(() => this.SuccessMessage = '', 3000);\n } else {\n this.ErrorMessage = 'Failed to save scope';\n }\n } catch (error) {\n console.error('Error saving scope:', error);\n this.ErrorMessage = 'An error occurred while saving';\n } finally {\n this.IsSaving = false;\n }\n }\n\n /**\n * Toggle node expansion\n */\n public toggleExpanded(node: ScopeTreeNode): void {\n node.expanded = !node.expanded;\n }\n\n /**\n * Expand all nodes\n */\n public expandAll(): void {\n const expand = (nodes: ScopeTreeNode[]) => {\n for (const node of nodes) {\n node.expanded = true;\n expand(node.children);\n }\n };\n expand(this.ScopeTree);\n }\n\n /**\n * Collapse all nodes\n */\n public collapseAll(): void {\n const collapse = (nodes: ScopeTreeNode[]) => {\n for (const node of nodes) {\n node.expanded = false;\n collapse(node.children);\n }\n };\n collapse(this.ScopeTree);\n }\n\n /**\n * Close all dialogs\n */\n public closeDialogs(): void {\n this.ShowCreateDialog = false;\n this.ShowEditDialog = false;\n this.EditingScope = null;\n this.SelectedParentScope = null;\n }\n\n /**\n * Get parent scopes for dropdown (exclude self and descendants)\n */\n public getParentOptions(): MJAPIScopeEntity[] {\n if (!this.EditingScope) {\n return this.FlatScopes;\n }\n\n // Exclude self and all descendants\n const excludeIds = new Set<string>([this.EditingScope.ID]);\n const addDescendants = (parentId: string) => {\n for (const scope of this.FlatScopes) {\n if (scope.ParentID === parentId && !excludeIds.has(scope.ID)) {\n excludeIds.add(scope.ID);\n addDescendants(scope.ID);\n }\n }\n };\n addDescendants(this.EditingScope.ID);\n\n return this.FlatScopes.filter(s => !excludeIds.has(s.ID));\n }\n\n /**\n * Get category color\n */\n public getCategoryColor(category: string | null): string {\n return this.CategoryColors[category || 'Other'] || this.CategoryColors['Other'];\n }\n\n /**\n * Get count of total scopes\n */\n public getTotalCount(): number {\n return this.FlatScopes.length;\n }\n\n /**\n * Get count of active scopes\n */\n public getActiveCount(): number {\n return this.FlatScopes.filter(s => s.IsActive).length;\n }\n}\n","<div class=\"scopes-panel\">\n @if (IsLoading) {\n <mj-loading text=\"Loading scopes...\"></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-shield-halved\"></i>\n API Scopes\n </h3>\n <p class=\"panel-subtitle\">Manage hierarchical permission scopes for API access</p>\n </div>\n <div class=\"header-actions\">\n <div class=\"scope-stats\">\n <span class=\"stat\">\n <i class=\"fa-solid fa-shield\"></i>\n {{getTotalCount()}} total\n </span>\n <span class=\"stat active\">\n <i class=\"fa-solid fa-check-circle\"></i>\n {{getActiveCount()}} active\n </span>\n </div>\n <div class=\"tree-controls\">\n <button class=\"btn-icon\" (click)=\"expandAll()\" title=\"Expand All\">\n <i class=\"fa-solid fa-plus-square\"></i>\n </button>\n <button class=\"btn-icon\" (click)=\"collapseAll()\" title=\"Collapse All\">\n <i class=\"fa-solid fa-minus-square\"></i>\n </button>\n </div>\n <button class=\"btn-create\" (click)=\"openCreateDialog()\">\n <i class=\"fa-solid fa-plus\"></i>\n New Scope\n </button>\n </div>\n </div>\n <!-- Messages -->\n @if (SuccessMessage) {\n <div class=\"message success\">\n <i class=\"fa-solid fa-check-circle\"></i>\n {{SuccessMessage}}\n </div>\n }\n @if (ErrorMessage) {\n <div class=\"message error\">\n <i class=\"fa-solid fa-circle-exclamation\"></i>\n {{ErrorMessage}}\n </div>\n }\n <!-- Scope Tree -->\n <div class=\"scope-tree\">\n @for (node of ScopeTree; track node) {\n <ng-container *ngTemplateOutlet=\"scopeNode; context: { node: node }\"></ng-container>\n }\n <!-- Empty State -->\n @if (ScopeTree.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-shield-halved\"></i>\n <span>No scopes configured</span>\n <p>Create scopes to define API access permissions</p>\n </div>\n }\n </div>\n <!-- Recursive Node Template -->\n <ng-template #scopeNode let-node=\"node\">\n <div class=\"scope-node\" [style.padding-left.px]=\"node.level * 24\">\n <div class=\"node-content\" [class.inactive]=\"!node.scope.IsActive\">\n @if (node.children.length > 0) {\n <button class=\"expand-btn\"\n (click)=\"toggleExpanded(node)\">\n <i class=\"fa-solid\"\n [class.fa-chevron-right]=\"!node.expanded\"\n [class.fa-chevron-down]=\"node.expanded\"></i>\n </button>\n }\n @if (node.children.length === 0) {\n <span class=\"expand-placeholder\"></span>\n }\n <div class=\"scope-info\" (click)=\"openEditDialog(node.scope)\">\n <div class=\"scope-icon\" [style.backgroundColor]=\"getCategoryColor(node.scope.Category)\">\n <i class=\"fa-solid fa-shield\"></i>\n </div>\n <div class=\"scope-details\">\n <div class=\"scope-name\">\n {{node.scope.Name}}\n @if (node.scope.FullPath && node.scope.FullPath !== node.scope.Name) {\n <span class=\"full-path\">\n {{node.scope.FullPath}}\n </span>\n }\n @if (!node.scope.IsActive) {\n <span class=\"status-badge\">Inactive</span>\n }\n </div>\n <div class=\"scope-meta\">\n <span class=\"category\" [style.color]=\"getCategoryColor(node.scope.Category)\">\n {{node.scope.Category}}\n </span>\n @if (node.scope.ResourceType) {\n <span class=\"resource-type\">\n {{node.scope.ResourceType}}\n </span>\n }\n @if (node.scope.Description) {\n <span class=\"description\">\n {{node.scope.Description}}\n </span>\n }\n </div>\n </div>\n </div>\n <div class=\"node-actions\">\n <button class=\"btn-node-action\" (click)=\"openCreateDialog(node.scope)\" title=\"Add Child Scope\">\n <i class=\"fa-solid fa-plus\"></i>\n </button>\n <button class=\"btn-node-action\" (click)=\"openEditDialog(node.scope)\" title=\"Edit Scope\">\n <i class=\"fa-solid fa-pencil\"></i>\n </button>\n </div>\n </div>\n @if (node.expanded && node.children.length > 0) {\n <div class=\"children\">\n @for (child of node.children; track child) {\n <ng-container *ngTemplateOutlet=\"scopeNode; context: { node: child }\"></ng-container>\n }\n </div>\n }\n </div>\n </ng-template>\n }\n\n <!-- Create/Edit Dialog -->\n @if (ShowCreateDialog || ShowEditDialog) {\n <kendo-window\n [width]=\"560\"\n [minWidth]=\"420\"\n [minHeight]=\"480\"\n [resizable]=\"true\"\n [draggable]=\"true\"\n [top]=\"80\"\n (close)=\"closeDialogs()\">\n <kendo-window-titlebar>\n <div class=\"dialog-title\">\n <i class=\"fa-solid fa-shield-halved\"></i>\n <span>{{EditingScope ? 'Edit Scope' : 'New Scope'}}</span>\n </div>\n <button kendoButton fillMode=\"flat\" (click)=\"closeDialogs()\" class=\"window-close-btn\" title=\"Close (Esc)\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </kendo-window-titlebar>\n <div class=\"dialog-content\">\n <div class=\"form-field\">\n <label>Scope Name *</label>\n <input kendoTextBox [(ngModel)]=\"EditName\"\n placeholder=\"e.g., runview, create, execute\"\n class=\"form-input\" />\n <span class=\"field-hint\">Use lowercase, single word. Will be combined with parent for full path.</span>\n </div>\n <div class=\"form-field\">\n <label>Parent Scope</label>\n <kendo-dropdownlist [(ngModel)]=\"EditParentId\"\n [data]=\"getParentOptions()\"\n [textField]=\"'FullPath'\"\n [valueField]=\"'ID'\"\n [valuePrimitive]=\"true\"\n [defaultItem]=\"{ FullPath: '(No Parent - Root Level)', ID: null }\">\n </kendo-dropdownlist>\n @if (SelectedParentScope) {\n <span class=\"field-hint\">\n Full path will be: <code>{{SelectedParentScope.FullPath}}:{{EditName || '...'}}</code>\n </span>\n }\n </div>\n <div class=\"form-row\">\n <div class=\"form-field half\">\n <label>Category</label>\n <kendo-dropdownlist [(ngModel)]=\"EditCategory\"\n [data]=\"Categories\"\n [valuePrimitive]=\"true\">\n </kendo-dropdownlist>\n </div>\n <div class=\"form-field half\">\n <label>Resource Type</label>\n <kendo-dropdownlist [(ngModel)]=\"EditResourceType\"\n [data]=\"ResourceTypes\"\n [valuePrimitive]=\"true\"\n [defaultItem]=\"''\">\n </kendo-dropdownlist>\n </div>\n </div>\n <div class=\"form-field\">\n <label>Description</label>\n <textarea kendoTextArea [(ngModel)]=\"EditDescription\"\n placeholder=\"Describe what this scope allows...\"\n [rows]=\"3\"\n class=\"form-textarea\"></textarea>\n </div>\n <div class=\"form-field\">\n <label class=\"checkbox-label\">\n <input type=\"checkbox\" kendoCheckBox [(ngModel)]=\"EditIsActive\" />\n <div>\n <span>Active</span>\n <span class=\"checkbox-hint\">Inactive scopes cannot be assigned to keys or applications</span>\n </div>\n </label>\n </div>\n <div class=\"dialog-actions\">\n <button kendoButton [themeColor]=\"'primary'\"\n [disabled]=\"!EditName.trim() || IsSaving\"\n (click)=\"saveScope()\">\n @if (IsSaving) {\n <mj-loading [showText]=\"false\" size=\"small\"></mj-loading>\n }\n @if (!IsSaving) {\n <span>\n <i class=\"fa-solid fa-save\"></i>\n {{EditingScope ? 'Update' : 'Create'}}\n </span>\n }\n </button>\n <button kendoButton (click)=\"closeDialogs()\">Cancel</button>\n </div>\n </div>\n </kendo-window>\n }\n</div>\n"]}
@@ -1006,11 +1006,11 @@ export class APIUsagePanelComponent {
1006
1006
  i0.ɵɵconditional(!ctx.IsLoading ? 2 : -1);
1007
1007
  i0.ɵɵadvance();
1008
1008
  i0.ɵɵconditional(ctx.ShowLogsPanel ? 3 : -1);
1009
- } }, dependencies: [i1.NgClass, i2.WindowComponent, i2.WindowTitleBarComponent, i3.ButtonComponent, i4.LoadingComponent], styles: [".usage-panel[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 24px;\n padding: 24px;\n background: #f8fafc;\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: #1f2937;\n}\n\n.panel-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: #6366f1;\n}\n\n.panel-subtitle[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 14px;\n color: #6b7280;\n}\n\n\n\n.time-filters[_ngcontent-%COMP%] {\n display: flex;\n gap: 4px;\n background: white;\n padding: 4px;\n border-radius: 10px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);\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: #6b7280;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.time-btn[_ngcontent-%COMP%]:hover {\n color: #374151;\n background: #f3f4f6;\n}\n\n.time-btn.active[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, #6366f1 0%, #4f46e5 100%);\n color: white;\n box-shadow: 0 2px 8px rgba(99, 102, 241, 0.3);\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: white;\n border-radius: 12px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);\n transition: all 0.2s ease;\n}\n\n.kpi-card[_ngcontent-%COMP%]:hover {\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);\n transform: translateY(-2px);\n}\n\n.kpi-card.success[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, #ecfdf5 0%, #d1fae5 100%);\n}\n\n.kpi-card.warning[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, #fef3c7 0%, #fde68a 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, #dbeafe 0%, #bfdbfe 100%);\n color: #2563eb;\n}\n\n.kpi-icon.success-rate[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, #d1fae5 0%, #a7f3d0 100%);\n color: #059669;\n}\n\n.kpi-icon.errors[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, #fee2e2 0%, #fecaca 100%);\n color: #dc2626;\n}\n\n.kpi-icon.response-time[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, #e0e7ff 0%, #c7d2fe 100%);\n color: #4f46e5;\n}\n\n.kpi-icon.keys[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%);\n color: #d97706;\n}\n\n.kpi-icon.endpoints[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, #f3e8ff 0%, #e9d5ff 100%);\n color: #7c3aed;\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: #1f2937;\n}\n\n.kpi-label[_ngcontent-%COMP%] {\n font-size: 12px;\n color: #6b7280;\n}\n\n\n\n.chart-section[_ngcontent-%COMP%] {\n background: white;\n border-radius: 12px;\n padding: 20px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);\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: #1f2937;\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: #6b7280;\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: #6366f1;\n}\n\n.legend-color.errors[_ngcontent-%COMP%] {\n background: #ef4444;\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, #6366f1 0%, #818cf8 100%);\n}\n\n.bar.requests-bar[_ngcontent-%COMP%]:hover {\n background: linear-gradient(180deg, #4f46e5 0%, #6366f1 100%);\n}\n\n.bar.errors-bar[_ngcontent-%COMP%] {\n position: absolute;\n bottom: 0;\n left: 0;\n width: 100%;\n background: #ef4444;\n border-radius: 0;\n}\n\n.bar-label[_ngcontent-%COMP%] {\n margin-top: 8px;\n font-size: 10px;\n color: #9ca3af;\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: #9ca3af;\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: #9ca3af;\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: white;\n border-radius: 12px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);\n overflow: hidden;\n}\n\n.breakdown-header[_ngcontent-%COMP%] {\n padding: 16px 20px;\n background: #f9fafb;\n border-bottom: 1px solid #e5e7eb;\n}\n\n.breakdown-header[_ngcontent-%COMP%] h4[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 14px;\n font-weight: 600;\n color: #374151;\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: #6b7280;\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: #f9fafb;\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.endpoint-item[_ngcontent-%COMP%]:hover {\n background: #f3f4f6;\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: #dbeafe; color: #2563eb; }\n.method-post[_ngcontent-%COMP%] { background: #d1fae5; color: #059669; }\n.method-put[_ngcontent-%COMP%] { background: #fef3c7; color: #d97706; }\n.method-delete[_ngcontent-%COMP%] { background: #fee2e2; color: #dc2626; }\n.method-other[_ngcontent-%COMP%] { background: #f3f4f6; color: #6b7280; }\n\n.endpoint-path[_ngcontent-%COMP%] {\n font-size: 12px;\n font-family: 'Fira Code', monospace;\n color: #374151;\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: #6366f1;\n}\n\n.endpoint-time[_ngcontent-%COMP%] {\n color: #6b7280;\n}\n\n.endpoint-error[_ngcontent-%COMP%] {\n color: #10b981;\n}\n\n.endpoint-error.has-errors[_ngcontent-%COMP%] {\n color: #ef4444;\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: #f9fafb;\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.key-item[_ngcontent-%COMP%]:hover {\n background: #f3f4f6;\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: #374151;\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: #9ca3af;\n}\n\n.key-requests[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: 600;\n color: #6366f1;\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: #f3f4f6;\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: #374151;\n}\n\n.status-count[_ngcontent-%COMP%] {\n color: #6b7280;\n font-weight: 500;\n}\n\n\n\n.logs-section[_ngcontent-%COMP%] {\n background: white;\n border-radius: 12px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);\n overflow: hidden;\n}\n\n.logs-header[_ngcontent-%COMP%] {\n padding: 16px 20px;\n background: #f9fafb;\n border-bottom: 1px solid #e5e7eb;\n}\n\n.logs-header[_ngcontent-%COMP%] h4[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 14px;\n font-weight: 600;\n color: #374151;\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: #6b7280;\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: #f3f4f6;\n font-size: 11px;\n font-weight: 600;\n color: #6b7280;\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 #f3f4f6;\n font-size: 13px;\n align-items: center;\n transition: background 0.2s ease;\n}\n\n.log-row[_ngcontent-%COMP%]:hover {\n background: #f9fafb;\n}\n\n.col-time[_ngcontent-%COMP%] {\n color: #6b7280;\n font-size: 12px;\n}\n\n.col-key[_ngcontent-%COMP%] {\n color: #374151;\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: #374151;\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: #10b981; }\n.col-status.status-info[_ngcontent-%COMP%] { color: #3b82f6; }\n.col-status.status-warning[_ngcontent-%COMP%] { color: #f59e0b; }\n.col-status.status-error[_ngcontent-%COMP%] { color: #ef4444; }\n\n.col-duration[_ngcontent-%COMP%] {\n color: #6b7280;\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: #9ca3af;\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: #6b7280;\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: #6366f1;\n}\n\n.filter-badge[_ngcontent-%COMP%] {\n padding: 4px 10px;\n background: #e0e7ff;\n border-radius: 12px;\n font-size: 11px;\n font-weight: 500;\n color: #4f46e5;\n}\n\n.window-close-btn[_ngcontent-%COMP%] {\n margin-left: auto;\n color: #9ca3af;\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: #374151;\n background: rgba(0, 0, 0, 0.05);\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: 0 20px 50px rgba(0, 0, 0, 0.15) !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: #f9fafb !important;\n border-bottom: 1px solid #e5e7eb !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}"] });
1009
+ } }, dependencies: [i1.NgClass, i2.WindowComponent, i2.WindowTitleBarComponent, i3.ButtonComponent, 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-color-neutral-700);\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-color-violet-600);\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-color-neutral-700);\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-color-neutral-700);\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-color-neutral-700);\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-color-neutral-700);\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-color-neutral-700);\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-color-neutral-700);\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-color-neutral-700);\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-color-neutral-700);\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}"] });
1010
1010
  }
1011
1011
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(APIUsagePanelComponent, [{
1012
1012
  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: #f8fafc;\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: #1f2937;\n}\n\n.panel-title i {\n color: #6366f1;\n}\n\n.panel-subtitle {\n margin: 0;\n font-size: 14px;\n color: #6b7280;\n}\n\n/* Time Filters */\n.time-filters {\n display: flex;\n gap: 4px;\n background: white;\n padding: 4px;\n border-radius: 10px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);\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: #6b7280;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.time-btn:hover {\n color: #374151;\n background: #f3f4f6;\n}\n\n.time-btn.active {\n background: linear-gradient(135deg, #6366f1 0%, #4f46e5 100%);\n color: white;\n box-shadow: 0 2px 8px rgba(99, 102, 241, 0.3);\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: white;\n border-radius: 12px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);\n transition: all 0.2s ease;\n}\n\n.kpi-card:hover {\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);\n transform: translateY(-2px);\n}\n\n.kpi-card.success {\n background: linear-gradient(135deg, #ecfdf5 0%, #d1fae5 100%);\n}\n\n.kpi-card.warning {\n background: linear-gradient(135deg, #fef3c7 0%, #fde68a 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, #dbeafe 0%, #bfdbfe 100%);\n color: #2563eb;\n}\n\n.kpi-icon.success-rate {\n background: linear-gradient(135deg, #d1fae5 0%, #a7f3d0 100%);\n color: #059669;\n}\n\n.kpi-icon.errors {\n background: linear-gradient(135deg, #fee2e2 0%, #fecaca 100%);\n color: #dc2626;\n}\n\n.kpi-icon.response-time {\n background: linear-gradient(135deg, #e0e7ff 0%, #c7d2fe 100%);\n color: #4f46e5;\n}\n\n.kpi-icon.keys {\n background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%);\n color: #d97706;\n}\n\n.kpi-icon.endpoints {\n background: linear-gradient(135deg, #f3e8ff 0%, #e9d5ff 100%);\n color: #7c3aed;\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: #1f2937;\n}\n\n.kpi-label {\n font-size: 12px;\n color: #6b7280;\n}\n\n/* Chart Section */\n.chart-section {\n background: white;\n border-radius: 12px;\n padding: 20px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);\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: #1f2937;\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: #6b7280;\n}\n\n.legend-color {\n width: 12px;\n height: 12px;\n border-radius: 3px;\n}\n\n.legend-color.requests {\n background: #6366f1;\n}\n\n.legend-color.errors {\n background: #ef4444;\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, #6366f1 0%, #818cf8 100%);\n}\n\n.bar.requests-bar:hover {\n background: linear-gradient(180deg, #4f46e5 0%, #6366f1 100%);\n}\n\n.bar.errors-bar {\n position: absolute;\n bottom: 0;\n left: 0;\n width: 100%;\n background: #ef4444;\n border-radius: 0;\n}\n\n.bar-label {\n margin-top: 8px;\n font-size: 10px;\n color: #9ca3af;\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: #9ca3af;\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: #9ca3af;\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: white;\n border-radius: 12px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);\n overflow: hidden;\n}\n\n.breakdown-header {\n padding: 16px 20px;\n background: #f9fafb;\n border-bottom: 1px solid #e5e7eb;\n}\n\n.breakdown-header h4 {\n margin: 0;\n font-size: 14px;\n font-weight: 600;\n color: #374151;\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.breakdown-header h4 i {\n color: #6b7280;\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: #f9fafb;\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.endpoint-item:hover {\n background: #f3f4f6;\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: #dbeafe; color: #2563eb; }\n.method-post { background: #d1fae5; color: #059669; }\n.method-put { background: #fef3c7; color: #d97706; }\n.method-delete { background: #fee2e2; color: #dc2626; }\n.method-other { background: #f3f4f6; color: #6b7280; }\n\n.endpoint-path {\n font-size: 12px;\n font-family: 'Fira Code', monospace;\n color: #374151;\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: #6366f1;\n}\n\n.endpoint-time {\n color: #6b7280;\n}\n\n.endpoint-error {\n color: #10b981;\n}\n\n.endpoint-error.has-errors {\n color: #ef4444;\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: #f9fafb;\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.key-item:hover {\n background: #f3f4f6;\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: #374151;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.key-last-used {\n font-size: 11px;\n color: #9ca3af;\n}\n\n.key-requests {\n font-size: 14px;\n font-weight: 600;\n color: #6366f1;\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: #f3f4f6;\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: #374151;\n}\n\n.status-count {\n color: #6b7280;\n font-weight: 500;\n}\n\n/* Logs Section */\n.logs-section {\n background: white;\n border-radius: 12px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);\n overflow: hidden;\n}\n\n.logs-header {\n padding: 16px 20px;\n background: #f9fafb;\n border-bottom: 1px solid #e5e7eb;\n}\n\n.logs-header h4 {\n margin: 0;\n font-size: 14px;\n font-weight: 600;\n color: #374151;\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.logs-header h4 i {\n color: #6b7280;\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: #f3f4f6;\n font-size: 11px;\n font-weight: 600;\n color: #6b7280;\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 #f3f4f6;\n font-size: 13px;\n align-items: center;\n transition: background 0.2s ease;\n}\n\n.log-row:hover {\n background: #f9fafb;\n}\n\n.col-time {\n color: #6b7280;\n font-size: 12px;\n}\n\n.col-key {\n color: #374151;\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: #374151;\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: #10b981; }\n.col-status.status-info { color: #3b82f6; }\n.col-status.status-warning { color: #f59e0b; }\n.col-status.status-error { color: #ef4444; }\n\n.col-duration {\n color: #6b7280;\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: #9ca3af;\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: #6b7280;\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: #6366f1;\n}\n\n.filter-badge {\n padding: 4px 10px;\n background: #e0e7ff;\n border-radius: 12px;\n font-size: 11px;\n font-weight: 500;\n color: #4f46e5;\n}\n\n.window-close-btn {\n margin-left: auto;\n color: #9ca3af;\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: #374151;\n background: rgba(0, 0, 0, 0.05);\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: 0 20px 50px rgba(0, 0, 0, 0.15) !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: #f9fafb !important;\n border-bottom: 1px solid #e5e7eb !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"] }]
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-color-neutral-700);\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-color-violet-600);\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-color-neutral-700);\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-color-neutral-700);\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-color-neutral-700);\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-color-neutral-700);\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-color-neutral-700);\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-color-neutral-700);\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-color-neutral-700);\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-color-neutral-700);\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"] }]
1014
1014
  }], () => [{ type: i0.ChangeDetectorRef }], null); })();
1015
1015
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(APIUsagePanelComponent, { className: "APIUsagePanelComponent", filePath: "src/APIKeys/api-usage-panel.component.ts", lineNumber: 61 }); })();
1016
1016
  //# sourceMappingURL=api-usage-panel.component.js.map