@memberjunction/ng-dashboards 3.2.0 → 3.3.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 (49) hide show
  1. package/dist/APIKeys/api-applications-panel.component.d.ts +167 -0
  2. package/dist/APIKeys/api-applications-panel.component.d.ts.map +1 -0
  3. package/dist/APIKeys/api-applications-panel.component.js +1059 -0
  4. package/dist/APIKeys/api-applications-panel.component.js.map +1 -0
  5. package/dist/APIKeys/api-key-create-dialog.component.d.ts +124 -0
  6. package/dist/APIKeys/api-key-create-dialog.component.d.ts.map +1 -0
  7. package/dist/APIKeys/api-key-create-dialog.component.js +743 -0
  8. package/dist/APIKeys/api-key-create-dialog.component.js.map +1 -0
  9. package/dist/APIKeys/api-key-edit-panel.component.d.ts +149 -0
  10. package/dist/APIKeys/api-key-edit-panel.component.d.ts.map +1 -0
  11. package/dist/APIKeys/api-key-edit-panel.component.js +1061 -0
  12. package/dist/APIKeys/api-key-edit-panel.component.js.map +1 -0
  13. package/dist/APIKeys/api-key-list.component.d.ts +130 -0
  14. package/dist/APIKeys/api-key-list.component.d.ts.map +1 -0
  15. package/dist/APIKeys/api-key-list.component.js +814 -0
  16. package/dist/APIKeys/api-key-list.component.js.map +1 -0
  17. package/dist/APIKeys/api-keys-resource.component.d.ts +209 -0
  18. package/dist/APIKeys/api-keys-resource.component.d.ts.map +1 -0
  19. package/dist/APIKeys/api-keys-resource.component.js +1165 -0
  20. package/dist/APIKeys/api-keys-resource.component.js.map +1 -0
  21. package/dist/APIKeys/api-scopes-panel.component.d.ts +98 -0
  22. package/dist/APIKeys/api-scopes-panel.component.d.ts.map +1 -0
  23. package/dist/APIKeys/api-scopes-panel.component.js +652 -0
  24. package/dist/APIKeys/api-scopes-panel.component.js.map +1 -0
  25. package/dist/APIKeys/api-usage-panel.component.d.ts +174 -0
  26. package/dist/APIKeys/api-usage-panel.component.d.ts.map +1 -0
  27. package/dist/APIKeys/api-usage-panel.component.js +1013 -0
  28. package/dist/APIKeys/api-usage-panel.component.js.map +1 -0
  29. package/dist/APIKeys/index.d.ts +7 -0
  30. package/dist/APIKeys/index.d.ts.map +1 -0
  31. package/dist/APIKeys/index.js +8 -0
  32. package/dist/APIKeys/index.js.map +1 -0
  33. package/dist/DashboardBrowser/dashboard-browser-resource.component.d.ts.map +1 -1
  34. package/dist/DashboardBrowser/dashboard-browser-resource.component.js +4 -2
  35. package/dist/DashboardBrowser/dashboard-browser-resource.component.js.map +1 -1
  36. package/dist/DataExplorer/data-explorer-dashboard.component.d.ts +3 -3
  37. package/dist/DataExplorer/data-explorer-dashboard.component.d.ts.map +1 -1
  38. package/dist/DataExplorer/data-explorer-dashboard.component.js +22 -6
  39. package/dist/DataExplorer/data-explorer-dashboard.component.js.map +1 -1
  40. package/dist/EntityAdmin/entity-admin-dashboard.component.js +2 -2
  41. package/dist/module.d.ts +39 -32
  42. package/dist/module.d.ts.map +1 -1
  43. package/dist/module.js +44 -4
  44. package/dist/module.js.map +1 -1
  45. package/dist/public-api.d.ts +7 -0
  46. package/dist/public-api.d.ts.map +1 -1
  47. package/dist/public-api.js +24 -0
  48. package/dist/public-api.js.map +1 -1
  49. package/package.json +32 -32
@@ -0,0 +1,1165 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { Component, ViewChild } from '@angular/core';
8
+ import { BaseResourceComponent } from '@memberjunction/ng-shared';
9
+ import { RegisterClass } from '@memberjunction/global';
10
+ import { Metadata, RunView } from '@memberjunction/core';
11
+ import { Subject } from 'rxjs';
12
+ import * as i0 from "@angular/core";
13
+ import * as i1 from "@angular/common";
14
+ import * as i2 from "@memberjunction/ng-shared-generic";
15
+ import * as i3 from "./api-key-create-dialog.component";
16
+ import * as i4 from "./api-key-edit-panel.component";
17
+ import * as i5 from "./api-key-list.component";
18
+ import * as i6 from "./api-applications-panel.component";
19
+ import * as i7 from "./api-scopes-panel.component";
20
+ import * as i8 from "./api-usage-panel.component";
21
+ const _c0 = ["keyList"];
22
+ function APIKeysResourceComponent_mj_loading_1_Template(rf, ctx) { if (rf & 1) {
23
+ i0.ɵɵelement(0, "mj-loading", 6);
24
+ } }
25
+ function APIKeysResourceComponent_ng_container_2_ng_container_32_ng_container_1_button_10_Template(rf, ctx) { if (rf & 1) {
26
+ const _r4 = i0.ɵɵgetCurrentView();
27
+ i0.ɵɵelementStart(0, "button", 78);
28
+ i0.ɵɵlistener("click", function APIKeysResourceComponent_ng_container_2_ng_container_32_ng_container_1_button_10_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r4); const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.openCreateDialog()); });
29
+ i0.ɵɵelement(1, "i", 79);
30
+ i0.ɵɵelementStart(2, "span");
31
+ i0.ɵɵtext(3, "Generate New Key");
32
+ i0.ɵɵelementEnd()();
33
+ } }
34
+ function APIKeysResourceComponent_ng_container_2_ng_container_32_ng_container_1_span_23_Template(rf, ctx) { if (rf & 1) {
35
+ const _r5 = i0.ɵɵgetCurrentView();
36
+ i0.ɵɵelementStart(0, "span", 80);
37
+ i0.ɵɵlistener("click", function APIKeysResourceComponent_ng_container_2_ng_container_32_ng_container_1_span_23_Template_span_click_0_listener() { i0.ɵɵrestoreView(_r5); const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.showListView("expired")); });
38
+ i0.ɵɵelement(1, "i", 81);
39
+ i0.ɵɵtext(2);
40
+ i0.ɵɵelementEnd();
41
+ } if (rf & 2) {
42
+ const ctx_r1 = i0.ɵɵnextContext(4);
43
+ i0.ɵɵadvance(2);
44
+ i0.ɵɵtextInterpolate1(" ", ctx_r1.ExpiredKeys, " expired ");
45
+ } }
46
+ function APIKeysResourceComponent_ng_container_2_ng_container_32_ng_container_1_span_24_Template(rf, ctx) { if (rf & 1) {
47
+ const _r6 = i0.ɵɵgetCurrentView();
48
+ i0.ɵɵelementStart(0, "span", 82);
49
+ i0.ɵɵlistener("click", function APIKeysResourceComponent_ng_container_2_ng_container_32_ng_container_1_span_24_Template_span_click_0_listener() { i0.ɵɵrestoreView(_r6); const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.showListView("expiring")); });
50
+ i0.ɵɵelement(1, "i", 57);
51
+ i0.ɵɵtext(2);
52
+ i0.ɵɵelementEnd();
53
+ } if (rf & 2) {
54
+ const ctx_r1 = i0.ɵɵnextContext(4);
55
+ i0.ɵɵadvance(2);
56
+ i0.ɵɵtextInterpolate1(" ", ctx_r1.ExpiringSoonCount, " expiring soon ");
57
+ } }
58
+ function APIKeysResourceComponent_ng_container_2_ng_container_32_ng_container_1_span_25_Template(rf, ctx) { if (rf & 1) {
59
+ const _r7 = i0.ɵɵgetCurrentView();
60
+ i0.ɵɵelementStart(0, "span", 83);
61
+ i0.ɵɵlistener("click", function APIKeysResourceComponent_ng_container_2_ng_container_32_ng_container_1_span_25_Template_span_click_0_listener() { i0.ɵɵrestoreView(_r7); const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.showListView("never-used")); });
62
+ i0.ɵɵelement(1, "i", 84);
63
+ i0.ɵɵtext(2);
64
+ i0.ɵɵelementEnd();
65
+ } if (rf & 2) {
66
+ const ctx_r1 = i0.ɵɵnextContext(4);
67
+ i0.ɵɵadvance(2);
68
+ i0.ɵɵtextInterpolate1(" ", ctx_r1.NeverUsedKeys, " never used ");
69
+ } }
70
+ function APIKeysResourceComponent_ng_container_2_ng_container_32_ng_container_1_span_26_Template(rf, ctx) { if (rf & 1) {
71
+ i0.ɵɵelementStart(0, "span", 85);
72
+ i0.ɵɵelement(1, "i", 54);
73
+ i0.ɵɵtext(2, " All keys healthy ");
74
+ i0.ɵɵelementEnd();
75
+ } }
76
+ function APIKeysResourceComponent_ng_container_2_ng_container_32_ng_container_1_div_57_Template(rf, ctx) { if (rf & 1) {
77
+ i0.ɵɵelementStart(0, "div", 86);
78
+ i0.ɵɵelement(1, "i", 52);
79
+ i0.ɵɵelementEnd();
80
+ } }
81
+ function APIKeysResourceComponent_ng_container_2_ng_container_32_ng_container_1_div_85_div_1_Template(rf, ctx) { if (rf & 1) {
82
+ const _r8 = i0.ɵɵgetCurrentView();
83
+ i0.ɵɵelementStart(0, "div", 89);
84
+ i0.ɵɵlistener("click", function APIKeysResourceComponent_ng_container_2_ng_container_32_ng_container_1_div_85_div_1_Template_div_click_0_listener() { const key_r9 = i0.ɵɵrestoreView(_r8).$implicit; const ctx_r1 = i0.ɵɵnextContext(5); return i0.ɵɵresetView(ctx_r1.openEditPanel(key_r9)); });
85
+ i0.ɵɵelementStart(1, "div", 90);
86
+ i0.ɵɵelement(2, "i", 10);
87
+ i0.ɵɵelementEnd();
88
+ i0.ɵɵelementStart(3, "div", 91)(4, "div", 92);
89
+ i0.ɵɵtext(5);
90
+ i0.ɵɵelementEnd();
91
+ i0.ɵɵelementStart(6, "div", 93)(7, "span", 94);
92
+ i0.ɵɵtext(8);
93
+ i0.ɵɵelementEnd();
94
+ i0.ɵɵelementStart(9, "span", 95);
95
+ i0.ɵɵtext(10);
96
+ i0.ɵɵelementEnd()()();
97
+ i0.ɵɵelementStart(11, "div", 96)(12, "div", 97);
98
+ i0.ɵɵtext(13);
99
+ i0.ɵɵelementEnd();
100
+ i0.ɵɵelementStart(14, "div", 98);
101
+ i0.ɵɵtext(15);
102
+ i0.ɵɵelementEnd()()();
103
+ } if (rf & 2) {
104
+ const key_r9 = ctx.$implicit;
105
+ const ctx_r1 = i0.ɵɵnextContext(5);
106
+ i0.ɵɵadvance();
107
+ i0.ɵɵclassProp("active", key_r9.Status === "Active");
108
+ i0.ɵɵadvance(4);
109
+ i0.ɵɵtextInterpolate(key_r9.Label);
110
+ i0.ɵɵadvance(3);
111
+ i0.ɵɵtextInterpolate(key_r9.User);
112
+ i0.ɵɵadvance(2);
113
+ i0.ɵɵtextInterpolate1("...", key_r9.Hash.slice(-8), "");
114
+ i0.ɵɵadvance(3);
115
+ i0.ɵɵtextInterpolate(ctx_r1.formatDate(key_r9.LastUsedAt));
116
+ i0.ɵɵadvance();
117
+ i0.ɵɵproperty("ngClass", ctx_r1.getExpirationClass(key_r9));
118
+ i0.ɵɵadvance();
119
+ i0.ɵɵtextInterpolate1(" ", ctx_r1.formatExpiration(key_r9.ExpiresAt), " ");
120
+ } }
121
+ function APIKeysResourceComponent_ng_container_2_ng_container_32_ng_container_1_div_85_Template(rf, ctx) { if (rf & 1) {
122
+ i0.ɵɵelementStart(0, "div", 87);
123
+ i0.ɵɵtemplate(1, APIKeysResourceComponent_ng_container_2_ng_container_32_ng_container_1_div_85_div_1_Template, 16, 8, "div", 88);
124
+ i0.ɵɵelementEnd();
125
+ } if (rf & 2) {
126
+ const ctx_r1 = i0.ɵɵnextContext(4);
127
+ i0.ɵɵadvance();
128
+ i0.ɵɵproperty("ngForOf", ctx_r1.TopUsedKeys);
129
+ } }
130
+ function APIKeysResourceComponent_ng_container_2_ng_container_32_ng_container_1_div_86_Template(rf, ctx) { if (rf & 1) {
131
+ i0.ɵɵelementStart(0, "div", 99);
132
+ i0.ɵɵelement(1, "i", 10);
133
+ i0.ɵɵelementStart(2, "span");
134
+ i0.ɵɵtext(3, "No active keys with recent usage");
135
+ i0.ɵɵelementEnd()();
136
+ } }
137
+ function APIKeysResourceComponent_ng_container_2_ng_container_32_ng_container_1_div_96__svg_ng_container_4_Template(rf, ctx) { if (rf & 1) {
138
+ const _r10 = i0.ɵɵgetCurrentView();
139
+ i0.ɵɵnamespaceSVG();
140
+ i0.ɵɵelementContainerStart(0);
141
+ i0.ɵɵelementStart(1, "circle", 110);
142
+ i0.ɵɵlistener("click", function APIKeysResourceComponent_ng_container_2_ng_container_32_ng_container_1_div_96__svg_ng_container_4_Template_circle_click_1_listener() { const stat_r11 = i0.ɵɵrestoreView(_r10).$implicit; const ctx_r1 = i0.ɵɵnextContext(5); return i0.ɵɵresetView(ctx_r1.onScopeClick(stat_r11)); });
143
+ i0.ɵɵelementEnd();
144
+ i0.ɵɵelementContainerEnd();
145
+ } if (rf & 2) {
146
+ const stat_r11 = ctx.$implicit;
147
+ const i_r12 = ctx.index;
148
+ const ctx_r1 = i0.ɵɵnextContext(5);
149
+ i0.ɵɵadvance();
150
+ i0.ɵɵattribute("stroke", stat_r11.color)("stroke-dasharray", stat_r11.percentage * 2.51 + " " + (251 - stat_r11.percentage * 2.51))("stroke-dashoffset", ctx_r1.getDonutOffset(i_r12));
151
+ } }
152
+ function APIKeysResourceComponent_ng_container_2_ng_container_32_ng_container_1_div_96_div_11_Template(rf, ctx) { if (rf & 1) {
153
+ const _r13 = i0.ɵɵgetCurrentView();
154
+ i0.ɵɵelementStart(0, "div", 111);
155
+ i0.ɵɵlistener("click", function APIKeysResourceComponent_ng_container_2_ng_container_32_ng_container_1_div_96_div_11_Template_div_click_0_listener() { const stat_r14 = i0.ɵɵrestoreView(_r13).$implicit; const ctx_r1 = i0.ɵɵnextContext(5); return i0.ɵɵresetView(ctx_r1.onScopeClick(stat_r14)); });
156
+ i0.ɵɵelement(1, "div", 112);
157
+ i0.ɵɵelementStart(2, "div", 113)(3, "div", 114);
158
+ i0.ɵɵelement(4, "i");
159
+ i0.ɵɵtext(5);
160
+ i0.ɵɵelementEnd();
161
+ i0.ɵɵelementStart(6, "div", 115);
162
+ i0.ɵɵtext(7);
163
+ i0.ɵɵelementEnd()();
164
+ i0.ɵɵelement(8, "i", 116);
165
+ i0.ɵɵelementEnd();
166
+ } if (rf & 2) {
167
+ const stat_r14 = ctx.$implicit;
168
+ i0.ɵɵadvance();
169
+ i0.ɵɵstyleProp("background-color", stat_r14.color);
170
+ i0.ɵɵadvance(3);
171
+ i0.ɵɵclassMap(stat_r14.iconClass);
172
+ i0.ɵɵadvance();
173
+ i0.ɵɵtextInterpolate1(" ", stat_r14.category, " ");
174
+ i0.ɵɵadvance(2);
175
+ i0.ɵɵtextInterpolate1("", stat_r14.count, " scopes");
176
+ } }
177
+ function APIKeysResourceComponent_ng_container_2_ng_container_32_ng_container_1_div_96_Template(rf, ctx) { if (rf & 1) {
178
+ i0.ɵɵelementStart(0, "div", 100)(1, "div", 101);
179
+ i0.ɵɵnamespaceSVG();
180
+ i0.ɵɵelementStart(2, "svg", 102);
181
+ i0.ɵɵelement(3, "circle", 103);
182
+ i0.ɵɵtemplate(4, APIKeysResourceComponent_ng_container_2_ng_container_32_ng_container_1_div_96__svg_ng_container_4_Template, 2, 3, "ng-container", 104);
183
+ i0.ɵɵelementEnd();
184
+ i0.ɵɵnamespaceHTML();
185
+ i0.ɵɵelementStart(5, "div", 105)(6, "div", 106);
186
+ i0.ɵɵtext(7);
187
+ i0.ɵɵelementEnd();
188
+ i0.ɵɵelementStart(8, "div", 107);
189
+ i0.ɵɵtext(9, "Categories");
190
+ i0.ɵɵelementEnd()()();
191
+ i0.ɵɵelementStart(10, "div", 108);
192
+ i0.ɵɵtemplate(11, APIKeysResourceComponent_ng_container_2_ng_container_32_ng_container_1_div_96_div_11_Template, 9, 6, "div", 109);
193
+ i0.ɵɵelementEnd()();
194
+ } if (rf & 2) {
195
+ const ctx_r1 = i0.ɵɵnextContext(4);
196
+ i0.ɵɵadvance(4);
197
+ i0.ɵɵproperty("ngForOf", ctx_r1.ScopeStats);
198
+ i0.ɵɵadvance(3);
199
+ i0.ɵɵtextInterpolate(ctx_r1.ScopeStats.length);
200
+ i0.ɵɵadvance(4);
201
+ i0.ɵɵproperty("ngForOf", ctx_r1.ScopeStats);
202
+ } }
203
+ function APIKeysResourceComponent_ng_container_2_ng_container_32_ng_container_1_div_97_Template(rf, ctx) { if (rf & 1) {
204
+ i0.ɵɵelementStart(0, "div", 99);
205
+ i0.ɵɵelement(1, "i", 16);
206
+ i0.ɵɵelementStart(2, "span");
207
+ i0.ɵɵtext(3, "No scopes configured");
208
+ i0.ɵɵelementEnd()();
209
+ } }
210
+ function APIKeysResourceComponent_ng_container_2_ng_container_32_ng_container_1_div_105_div_1_span_9_Template(rf, ctx) { if (rf & 1) {
211
+ i0.ɵɵelementStart(0, "span", 127);
212
+ i0.ɵɵtext(1);
213
+ i0.ɵɵelementEnd();
214
+ } if (rf & 2) {
215
+ const activity_r16 = i0.ɵɵnextContext().$implicit;
216
+ i0.ɵɵadvance();
217
+ i0.ɵɵtextInterpolate1("by ", activity_r16.user, "");
218
+ } }
219
+ function APIKeysResourceComponent_ng_container_2_ng_container_32_ng_container_1_div_105_div_1_Template(rf, ctx) { if (rf & 1) {
220
+ const _r15 = i0.ɵɵgetCurrentView();
221
+ i0.ɵɵelementStart(0, "div", 119);
222
+ i0.ɵɵlistener("click", function APIKeysResourceComponent_ng_container_2_ng_container_32_ng_container_1_div_105_div_1_Template_div_click_0_listener() { const activity_r16 = i0.ɵɵrestoreView(_r15).$implicit; const ctx_r1 = i0.ɵɵnextContext(5); return i0.ɵɵresetView(ctx_r1.onActivityClick(activity_r16)); });
223
+ i0.ɵɵelementStart(1, "div", 120);
224
+ i0.ɵɵelement(2, "i");
225
+ i0.ɵɵelementEnd();
226
+ i0.ɵɵelementStart(3, "div", 121)(4, "div", 122);
227
+ i0.ɵɵtext(5);
228
+ i0.ɵɵelementEnd();
229
+ i0.ɵɵelementStart(6, "div", 123)(7, "span", 124);
230
+ i0.ɵɵtext(8);
231
+ i0.ɵɵelementEnd();
232
+ i0.ɵɵtemplate(9, APIKeysResourceComponent_ng_container_2_ng_container_32_ng_container_1_div_105_div_1_span_9_Template, 2, 1, "span", 125);
233
+ i0.ɵɵelementEnd()();
234
+ i0.ɵɵelementStart(10, "div", 126);
235
+ i0.ɵɵtext(11);
236
+ i0.ɵɵelementEnd()();
237
+ } if (rf & 2) {
238
+ const activity_r16 = ctx.$implicit;
239
+ const ctx_r1 = i0.ɵɵnextContext(5);
240
+ i0.ɵɵadvance();
241
+ i0.ɵɵproperty("ngClass", ctx_r1.getActionClass(activity_r16.action));
242
+ i0.ɵɵadvance();
243
+ i0.ɵɵclassMap(ctx_r1.getActionIcon(activity_r16.action));
244
+ i0.ɵɵadvance(3);
245
+ i0.ɵɵtextInterpolate(activity_r16.keyLabel);
246
+ i0.ɵɵadvance(3);
247
+ i0.ɵɵtextInterpolate(activity_r16.action);
248
+ i0.ɵɵadvance();
249
+ i0.ɵɵproperty("ngIf", activity_r16.user);
250
+ i0.ɵɵadvance(2);
251
+ i0.ɵɵtextInterpolate1(" ", ctx_r1.formatDate(activity_r16.date), " ");
252
+ } }
253
+ function APIKeysResourceComponent_ng_container_2_ng_container_32_ng_container_1_div_105_Template(rf, ctx) { if (rf & 1) {
254
+ i0.ɵɵelementStart(0, "div", 117);
255
+ i0.ɵɵtemplate(1, APIKeysResourceComponent_ng_container_2_ng_container_32_ng_container_1_div_105_div_1_Template, 12, 7, "div", 118);
256
+ i0.ɵɵelementEnd();
257
+ } if (rf & 2) {
258
+ const ctx_r1 = i0.ɵɵnextContext(4);
259
+ i0.ɵɵadvance();
260
+ i0.ɵɵproperty("ngForOf", ctx_r1.RecentActivity);
261
+ } }
262
+ function APIKeysResourceComponent_ng_container_2_ng_container_32_ng_container_1_div_106_Template(rf, ctx) { if (rf & 1) {
263
+ i0.ɵɵelementStart(0, "div", 99);
264
+ i0.ɵɵelement(1, "i", 128);
265
+ i0.ɵɵelementStart(2, "span");
266
+ i0.ɵɵtext(3, "No recent activity");
267
+ i0.ɵɵelementEnd()();
268
+ } }
269
+ function APIKeysResourceComponent_ng_container_2_ng_container_32_ng_container_1_div_107_Template(rf, ctx) { if (rf & 1) {
270
+ const _r17 = i0.ɵɵgetCurrentView();
271
+ i0.ɵɵelementStart(0, "div", 129)(1, "div", 130);
272
+ i0.ɵɵtext(2, "Quick Actions");
273
+ i0.ɵɵelementEnd();
274
+ i0.ɵɵelementStart(3, "div", 131)(4, "button", 132);
275
+ i0.ɵɵlistener("click", function APIKeysResourceComponent_ng_container_2_ng_container_32_ng_container_1_div_107_Template_button_click_4_listener() { i0.ɵɵrestoreView(_r17); const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.openCreateDialog()); });
276
+ i0.ɵɵelement(5, "i", 79);
277
+ i0.ɵɵelementStart(6, "span");
278
+ i0.ɵɵtext(7, "Generate Key");
279
+ i0.ɵɵelementEnd()();
280
+ i0.ɵɵelementStart(8, "button", 132);
281
+ i0.ɵɵlistener("click", function APIKeysResourceComponent_ng_container_2_ng_container_32_ng_container_1_div_107_Template_button_click_8_listener() { i0.ɵɵrestoreView(_r17); const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.showListView("all")); });
282
+ i0.ɵɵelement(9, "i", 133);
283
+ i0.ɵɵelementStart(10, "span");
284
+ i0.ɵɵtext(11, "View All Keys");
285
+ i0.ɵɵelementEnd()();
286
+ i0.ɵɵelementStart(12, "button", 132);
287
+ i0.ɵɵlistener("click", function APIKeysResourceComponent_ng_container_2_ng_container_32_ng_container_1_div_107_Template_button_click_12_listener() { i0.ɵɵrestoreView(_r17); const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.showListView("expiring")); });
288
+ i0.ɵɵelement(13, "i", 57);
289
+ i0.ɵɵelementStart(14, "span");
290
+ i0.ɵɵtext(15, "Expiring Keys");
291
+ i0.ɵɵelementEnd()();
292
+ i0.ɵɵelementStart(16, "button", 132);
293
+ i0.ɵɵlistener("click", function APIKeysResourceComponent_ng_container_2_ng_container_32_ng_container_1_div_107_Template_button_click_16_listener() { i0.ɵɵrestoreView(_r17); const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.showListView("never-used")); });
294
+ i0.ɵɵelement(17, "i", 84);
295
+ i0.ɵɵelementStart(18, "span");
296
+ i0.ɵɵtext(19, "Never Used");
297
+ i0.ɵɵelementEnd()()()();
298
+ } }
299
+ function APIKeysResourceComponent_ng_container_2_ng_container_32_ng_container_1_Template(rf, ctx) { if (rf & 1) {
300
+ const _r3 = i0.ɵɵgetCurrentView();
301
+ i0.ɵɵelementContainerStart(0);
302
+ i0.ɵɵelementStart(1, "div", 23)(2, "div", 24)(3, "h2", 25);
303
+ i0.ɵɵtext(4, "API Keys Management");
304
+ i0.ɵɵelementEnd();
305
+ i0.ɵɵelementStart(5, "p", 26);
306
+ i0.ɵɵtext(6, "Manage API keys for external integrations and services");
307
+ i0.ɵɵelementEnd()();
308
+ i0.ɵɵelementStart(7, "div", 27)(8, "button", 28);
309
+ i0.ɵɵlistener("click", function APIKeysResourceComponent_ng_container_2_ng_container_32_ng_container_1_Template_button_click_8_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.refresh()); });
310
+ i0.ɵɵelement(9, "i", 29);
311
+ i0.ɵɵelementEnd();
312
+ i0.ɵɵtemplate(10, APIKeysResourceComponent_ng_container_2_ng_container_32_ng_container_1_button_10_Template, 4, 0, "button", 30);
313
+ i0.ɵɵelementEnd()();
314
+ i0.ɵɵelementStart(11, "div", 31)(12, "div", 32)(13, "div", 33);
315
+ i0.ɵɵnamespaceSVG();
316
+ i0.ɵɵelementStart(14, "svg", 34);
317
+ i0.ɵɵelement(15, "path", 35)(16, "path", 36);
318
+ i0.ɵɵelementEnd();
319
+ i0.ɵɵnamespaceHTML();
320
+ i0.ɵɵelementStart(17, "div", 37);
321
+ i0.ɵɵtext(18);
322
+ i0.ɵɵelementEnd()()();
323
+ i0.ɵɵelementStart(19, "div", 38)(20, "div", 39);
324
+ i0.ɵɵtext(21);
325
+ i0.ɵɵelementEnd();
326
+ i0.ɵɵelementStart(22, "div", 40);
327
+ i0.ɵɵtemplate(23, APIKeysResourceComponent_ng_container_2_ng_container_32_ng_container_1_span_23_Template, 3, 1, "span", 41)(24, APIKeysResourceComponent_ng_container_2_ng_container_32_ng_container_1_span_24_Template, 3, 1, "span", 42)(25, APIKeysResourceComponent_ng_container_2_ng_container_32_ng_container_1_span_25_Template, 3, 1, "span", 43)(26, APIKeysResourceComponent_ng_container_2_ng_container_32_ng_container_1_span_26_Template, 3, 0, "span", 44);
328
+ i0.ɵɵelementEnd()()();
329
+ i0.ɵɵelementStart(27, "div", 45)(28, "div", 46);
330
+ i0.ɵɵlistener("click", function APIKeysResourceComponent_ng_container_2_ng_container_32_ng_container_1_Template_div_click_28_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.showListView("all")); });
331
+ i0.ɵɵelementStart(29, "div", 47);
332
+ i0.ɵɵelement(30, "i", 10);
333
+ i0.ɵɵelementEnd();
334
+ i0.ɵɵelementStart(31, "div", 48)(32, "div", 49);
335
+ i0.ɵɵtext(33);
336
+ i0.ɵɵelementEnd();
337
+ i0.ɵɵelementStart(34, "div", 50);
338
+ i0.ɵɵtext(35, "Total Keys");
339
+ i0.ɵɵelementEnd()();
340
+ i0.ɵɵelementStart(36, "div", 51);
341
+ i0.ɵɵelement(37, "i", 52);
342
+ i0.ɵɵelementEnd()();
343
+ i0.ɵɵelementStart(38, "div", 53);
344
+ i0.ɵɵlistener("click", function APIKeysResourceComponent_ng_container_2_ng_container_32_ng_container_1_Template_div_click_38_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.showListView("active")); });
345
+ i0.ɵɵelementStart(39, "div", 47);
346
+ i0.ɵɵelement(40, "i", 54);
347
+ i0.ɵɵelementEnd();
348
+ i0.ɵɵelementStart(41, "div", 48)(42, "div", 49);
349
+ i0.ɵɵtext(43);
350
+ i0.ɵɵelementEnd();
351
+ i0.ɵɵelementStart(44, "div", 50);
352
+ i0.ɵɵtext(45, "Active");
353
+ i0.ɵɵelementEnd()();
354
+ i0.ɵɵelementStart(46, "div", 55)(47, "span", 56);
355
+ i0.ɵɵtext(48);
356
+ i0.ɵɵelementEnd()()();
357
+ i0.ɵɵelementStart(49, "div", 46);
358
+ i0.ɵɵlistener("click", function APIKeysResourceComponent_ng_container_2_ng_container_32_ng_container_1_Template_div_click_49_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.showListView("expiring")); });
359
+ i0.ɵɵelementStart(50, "div", 47);
360
+ i0.ɵɵelement(51, "i", 57);
361
+ i0.ɵɵelementEnd();
362
+ i0.ɵɵelementStart(52, "div", 48)(53, "div", 49);
363
+ i0.ɵɵtext(54);
364
+ i0.ɵɵelementEnd();
365
+ i0.ɵɵelementStart(55, "div", 50);
366
+ i0.ɵɵtext(56, "Expiring Soon");
367
+ i0.ɵɵelementEnd()();
368
+ i0.ɵɵtemplate(57, APIKeysResourceComponent_ng_container_2_ng_container_32_ng_container_1_div_57_Template, 2, 0, "div", 58);
369
+ i0.ɵɵelementEnd();
370
+ i0.ɵɵelementStart(58, "div", 46);
371
+ i0.ɵɵlistener("click", function APIKeysResourceComponent_ng_container_2_ng_container_32_ng_container_1_Template_div_click_58_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.showListView("revoked")); });
372
+ i0.ɵɵelementStart(59, "div", 47);
373
+ i0.ɵɵelement(60, "i", 59);
374
+ i0.ɵɵelementEnd();
375
+ i0.ɵɵelementStart(61, "div", 48)(62, "div", 49);
376
+ i0.ɵɵtext(63);
377
+ i0.ɵɵelementEnd();
378
+ i0.ɵɵelementStart(64, "div", 50);
379
+ i0.ɵɵtext(65, "Revoked");
380
+ i0.ɵɵelementEnd()()();
381
+ i0.ɵɵelementStart(66, "div", 46);
382
+ i0.ɵɵlistener("click", function APIKeysResourceComponent_ng_container_2_ng_container_32_ng_container_1_Template_div_click_66_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.switchTab("scopes")); });
383
+ i0.ɵɵelementStart(67, "div", 47);
384
+ i0.ɵɵelement(68, "i", 16);
385
+ i0.ɵɵelementEnd();
386
+ i0.ɵɵelementStart(69, "div", 48)(70, "div", 49);
387
+ i0.ɵɵtext(71);
388
+ i0.ɵɵelementEnd();
389
+ i0.ɵɵelementStart(72, "div", 50);
390
+ i0.ɵɵtext(73, "Scope Categories");
391
+ i0.ɵɵelementEnd()()()();
392
+ i0.ɵɵelementStart(74, "div", 60)(75, "div", 61)(76, "div", 62)(77, "div", 63);
393
+ i0.ɵɵelement(78, "i", 10);
394
+ i0.ɵɵelementStart(79, "span");
395
+ i0.ɵɵtext(80, "Recently Used Keys");
396
+ i0.ɵɵelementEnd()();
397
+ i0.ɵɵelementStart(81, "button", 64);
398
+ i0.ɵɵlistener("click", function APIKeysResourceComponent_ng_container_2_ng_container_32_ng_container_1_Template_button_click_81_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.showListView("all")); });
399
+ i0.ɵɵtext(82, " View All ");
400
+ i0.ɵɵelement(83, "i", 52);
401
+ i0.ɵɵelementEnd()();
402
+ i0.ɵɵelementStart(84, "div", 65);
403
+ i0.ɵɵtemplate(85, APIKeysResourceComponent_ng_container_2_ng_container_32_ng_container_1_div_85_Template, 2, 1, "div", 66)(86, APIKeysResourceComponent_ng_container_2_ng_container_32_ng_container_1_div_86_Template, 4, 0, "div", 67);
404
+ i0.ɵɵelementEnd()();
405
+ i0.ɵɵelementStart(87, "div", 68)(88, "div", 62)(89, "div", 63);
406
+ i0.ɵɵelement(90, "i", 16);
407
+ i0.ɵɵelementStart(91, "span");
408
+ i0.ɵɵtext(92, "Permission Scopes");
409
+ i0.ɵɵelementEnd()();
410
+ i0.ɵɵelementStart(93, "span", 69);
411
+ i0.ɵɵtext(94, "Available scope categories");
412
+ i0.ɵɵelementEnd()();
413
+ i0.ɵɵelementStart(95, "div", 65);
414
+ i0.ɵɵtemplate(96, APIKeysResourceComponent_ng_container_2_ng_container_32_ng_container_1_div_96_Template, 12, 3, "div", 70)(97, APIKeysResourceComponent_ng_container_2_ng_container_32_ng_container_1_div_97_Template, 4, 0, "div", 67);
415
+ i0.ɵɵelementEnd()();
416
+ i0.ɵɵelementStart(98, "div", 71)(99, "div", 62)(100, "div", 63);
417
+ i0.ɵɵelement(101, "i", 72);
418
+ i0.ɵɵelementStart(102, "span");
419
+ i0.ɵɵtext(103, "Recent Activity");
420
+ i0.ɵɵelementEnd()()();
421
+ i0.ɵɵelementStart(104, "div", 65);
422
+ i0.ɵɵtemplate(105, APIKeysResourceComponent_ng_container_2_ng_container_32_ng_container_1_div_105_Template, 2, 1, "div", 73)(106, APIKeysResourceComponent_ng_container_2_ng_container_32_ng_container_1_div_106_Template, 4, 0, "div", 67);
423
+ i0.ɵɵelementEnd()()();
424
+ i0.ɵɵtemplate(107, APIKeysResourceComponent_ng_container_2_ng_container_32_ng_container_1_div_107_Template, 20, 0, "div", 74);
425
+ i0.ɵɵelementStart(108, "div", 75);
426
+ i0.ɵɵelement(109, "i", 76);
427
+ i0.ɵɵelementStart(110, "div", 77)(111, "strong");
428
+ i0.ɵɵtext(112, "Security Best Practices:");
429
+ i0.ɵɵelementEnd();
430
+ i0.ɵɵtext(113, " API keys should be rotated regularly and revoked when no longer needed. Keys are hashed and stored securely - the raw key is only shown once at creation time. All API key usage is logged for audit purposes. ");
431
+ i0.ɵɵelementEnd()();
432
+ i0.ɵɵelementContainerEnd();
433
+ } if (rf & 2) {
434
+ const ctx_r1 = i0.ɵɵnextContext(3);
435
+ i0.ɵɵadvance(10);
436
+ i0.ɵɵproperty("ngIf", ctx_r1.UserCanCreateKeys);
437
+ i0.ɵɵadvance();
438
+ i0.ɵɵproperty("ngClass", ctx_r1.getHealthClass());
439
+ i0.ɵɵadvance(5);
440
+ i0.ɵɵattribute("stroke-dasharray", ctx_r1.getHealthScore() + ", 100");
441
+ i0.ɵɵadvance(2);
442
+ i0.ɵɵtextInterpolate(ctx_r1.getHealthScore());
443
+ i0.ɵɵadvance(3);
444
+ i0.ɵɵtextInterpolate(ctx_r1.getHealthLabel());
445
+ i0.ɵɵadvance(2);
446
+ i0.ɵɵproperty("ngIf", ctx_r1.ExpiredKeys > 0);
447
+ i0.ɵɵadvance();
448
+ i0.ɵɵproperty("ngIf", ctx_r1.ExpiringSoonCount > 0);
449
+ i0.ɵɵadvance();
450
+ i0.ɵɵproperty("ngIf", ctx_r1.NeverUsedKeys > 0);
451
+ i0.ɵɵadvance();
452
+ i0.ɵɵproperty("ngIf", ctx_r1.ExpiredKeys === 0 && ctx_r1.ExpiringSoonCount === 0 && ctx_r1.NeverUsedKeys === 0);
453
+ i0.ɵɵadvance(7);
454
+ i0.ɵɵtextInterpolate(ctx_r1.TotalKeys);
455
+ i0.ɵɵadvance(10);
456
+ i0.ɵɵtextInterpolate(ctx_r1.ActiveKeys);
457
+ i0.ɵɵadvance(5);
458
+ i0.ɵɵtextInterpolate1("", ctx_r1.TotalKeys > 0 ? (ctx_r1.ActiveKeys / ctx_r1.TotalKeys * 100).toFixed(0) : 100, "%");
459
+ i0.ɵɵadvance();
460
+ i0.ɵɵclassProp("warning", ctx_r1.ExpiringSoonCount > 0);
461
+ i0.ɵɵadvance(5);
462
+ i0.ɵɵtextInterpolate(ctx_r1.ExpiringSoonCount);
463
+ i0.ɵɵadvance(3);
464
+ i0.ɵɵproperty("ngIf", ctx_r1.ExpiringSoonCount > 0);
465
+ i0.ɵɵadvance();
466
+ i0.ɵɵclassProp("danger", ctx_r1.RevokedKeys > 0);
467
+ i0.ɵɵadvance(5);
468
+ i0.ɵɵtextInterpolate(ctx_r1.RevokedKeys);
469
+ i0.ɵɵadvance(8);
470
+ i0.ɵɵtextInterpolate(ctx_r1.ScopeStats.length);
471
+ i0.ɵɵadvance(14);
472
+ i0.ɵɵproperty("ngIf", ctx_r1.TopUsedKeys.length > 0);
473
+ i0.ɵɵadvance();
474
+ i0.ɵɵproperty("ngIf", ctx_r1.TopUsedKeys.length === 0);
475
+ i0.ɵɵadvance(10);
476
+ i0.ɵɵproperty("ngIf", ctx_r1.ScopeStats.length > 0);
477
+ i0.ɵɵadvance();
478
+ i0.ɵɵproperty("ngIf", ctx_r1.ScopeStats.length === 0);
479
+ i0.ɵɵadvance(8);
480
+ i0.ɵɵproperty("ngIf", ctx_r1.RecentActivity.length > 0);
481
+ i0.ɵɵadvance();
482
+ i0.ɵɵproperty("ngIf", ctx_r1.RecentActivity.length === 0);
483
+ i0.ɵɵadvance();
484
+ i0.ɵɵproperty("ngIf", ctx_r1.UserCanCreateKeys);
485
+ } }
486
+ function APIKeysResourceComponent_ng_container_2_ng_container_32_ng_container_2_Template(rf, ctx) { if (rf & 1) {
487
+ const _r18 = i0.ɵɵgetCurrentView();
488
+ i0.ɵɵelementContainerStart(0);
489
+ i0.ɵɵelementStart(1, "div", 134)(2, "button", 135);
490
+ i0.ɵɵlistener("click", function APIKeysResourceComponent_ng_container_2_ng_container_32_ng_container_2_Template_button_click_2_listener() { i0.ɵɵrestoreView(_r18); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.showOverview()); });
491
+ i0.ɵɵelement(3, "i", 136);
492
+ i0.ɵɵtext(4, " Back to Overview ");
493
+ i0.ɵɵelementEnd()();
494
+ i0.ɵɵelementStart(5, "mj-api-key-list", 137, 0);
495
+ i0.ɵɵlistener("KeySelected", function APIKeysResourceComponent_ng_container_2_ng_container_32_ng_container_2_Template_mj_api_key_list_KeySelected_5_listener($event) { i0.ɵɵrestoreView(_r18); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.onKeySelected($event)); })("CreateRequested", function APIKeysResourceComponent_ng_container_2_ng_container_32_ng_container_2_Template_mj_api_key_list_CreateRequested_5_listener() { i0.ɵɵrestoreView(_r18); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.openCreateDialog()); });
496
+ i0.ɵɵelementEnd();
497
+ i0.ɵɵelementContainerEnd();
498
+ } if (rf & 2) {
499
+ const ctx_r1 = i0.ɵɵnextContext(3);
500
+ i0.ɵɵadvance(5);
501
+ i0.ɵɵproperty("Filter", ctx_r1.ListFilter);
502
+ } }
503
+ function APIKeysResourceComponent_ng_container_2_ng_container_32_Template(rf, ctx) { if (rf & 1) {
504
+ i0.ɵɵelementContainerStart(0);
505
+ i0.ɵɵtemplate(1, APIKeysResourceComponent_ng_container_2_ng_container_32_ng_container_1_Template, 114, 27, "ng-container", 3)(2, APIKeysResourceComponent_ng_container_2_ng_container_32_ng_container_2_Template, 7, 1, "ng-container", 3);
506
+ i0.ɵɵelementContainerEnd();
507
+ } if (rf & 2) {
508
+ const ctx_r1 = i0.ɵɵnextContext(2);
509
+ i0.ɵɵadvance();
510
+ i0.ɵɵproperty("ngIf", ctx_r1.CurrentView === "overview");
511
+ i0.ɵɵadvance();
512
+ i0.ɵɵproperty("ngIf", ctx_r1.CurrentView === "list");
513
+ } }
514
+ function APIKeysResourceComponent_ng_container_2_ng_container_33_Template(rf, ctx) { if (rf & 1) {
515
+ const _r19 = i0.ɵɵgetCurrentView();
516
+ i0.ɵɵelementContainerStart(0);
517
+ i0.ɵɵelementStart(1, "mj-api-applications-panel", 138);
518
+ i0.ɵɵlistener("ApplicationUpdated", function APIKeysResourceComponent_ng_container_2_ng_container_33_Template_mj_api_applications_panel_ApplicationUpdated_1_listener() { i0.ɵɵrestoreView(_r19); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onDataUpdated()); });
519
+ i0.ɵɵelementEnd();
520
+ i0.ɵɵelementContainerEnd();
521
+ } }
522
+ function APIKeysResourceComponent_ng_container_2_ng_container_34_Template(rf, ctx) { if (rf & 1) {
523
+ const _r20 = i0.ɵɵgetCurrentView();
524
+ i0.ɵɵelementContainerStart(0);
525
+ i0.ɵɵelementStart(1, "mj-api-scopes-panel", 139);
526
+ i0.ɵɵlistener("ScopeUpdated", function APIKeysResourceComponent_ng_container_2_ng_container_34_Template_mj_api_scopes_panel_ScopeUpdated_1_listener() { i0.ɵɵrestoreView(_r20); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onDataUpdated()); });
527
+ i0.ɵɵelementEnd();
528
+ i0.ɵɵelementContainerEnd();
529
+ } }
530
+ function APIKeysResourceComponent_ng_container_2_ng_container_35_Template(rf, ctx) { if (rf & 1) {
531
+ i0.ɵɵelementContainerStart(0);
532
+ i0.ɵɵelement(1, "mj-api-usage-panel");
533
+ i0.ɵɵelementContainerEnd();
534
+ } }
535
+ function APIKeysResourceComponent_ng_container_2_Template(rf, ctx) { if (rf & 1) {
536
+ const _r1 = i0.ɵɵgetCurrentView();
537
+ i0.ɵɵelementContainerStart(0);
538
+ i0.ɵɵelementStart(1, "div", 7)(2, "div", 8)(3, "div", 9);
539
+ i0.ɵɵelement(4, "i", 10);
540
+ i0.ɵɵelementStart(5, "span");
541
+ i0.ɵɵtext(6, "API Keys");
542
+ i0.ɵɵelementEnd()()();
543
+ i0.ɵɵelementStart(7, "div", 11)(8, "button", 12);
544
+ i0.ɵɵlistener("click", function APIKeysResourceComponent_ng_container_2_Template_button_click_8_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); ctx_r1.switchTab("keys"); return i0.ɵɵresetView(ctx_r1.closeNav()); });
545
+ i0.ɵɵelement(9, "i", 10);
546
+ i0.ɵɵelementStart(10, "span", 13);
547
+ i0.ɵɵtext(11, "API Keys");
548
+ i0.ɵɵelementEnd();
549
+ i0.ɵɵelementStart(12, "span", 14);
550
+ i0.ɵɵtext(13);
551
+ i0.ɵɵelementEnd()();
552
+ i0.ɵɵelementStart(14, "button", 12);
553
+ i0.ɵɵlistener("click", function APIKeysResourceComponent_ng_container_2_Template_button_click_14_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); ctx_r1.switchTab("applications"); return i0.ɵɵresetView(ctx_r1.closeNav()); });
554
+ i0.ɵɵelement(15, "i", 15);
555
+ i0.ɵɵelementStart(16, "span", 13);
556
+ i0.ɵɵtext(17, "Applications");
557
+ i0.ɵɵelementEnd();
558
+ i0.ɵɵelementStart(18, "span", 14);
559
+ i0.ɵɵtext(19);
560
+ i0.ɵɵelementEnd()();
561
+ i0.ɵɵelementStart(20, "button", 12);
562
+ i0.ɵɵlistener("click", function APIKeysResourceComponent_ng_container_2_Template_button_click_20_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); ctx_r1.switchTab("scopes"); return i0.ɵɵresetView(ctx_r1.closeNav()); });
563
+ i0.ɵɵelement(21, "i", 16);
564
+ i0.ɵɵelementStart(22, "span", 13);
565
+ i0.ɵɵtext(23, "Scopes");
566
+ i0.ɵɵelementEnd();
567
+ i0.ɵɵelementStart(24, "span", 14);
568
+ i0.ɵɵtext(25);
569
+ i0.ɵɵelementEnd()();
570
+ i0.ɵɵelementStart(26, "button", 12);
571
+ i0.ɵɵlistener("click", function APIKeysResourceComponent_ng_container_2_Template_button_click_26_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); ctx_r1.switchTab("usage"); return i0.ɵɵresetView(ctx_r1.closeNav()); });
572
+ i0.ɵɵelement(27, "i", 17);
573
+ i0.ɵɵelementStart(28, "span", 13);
574
+ i0.ɵɵtext(29, "Usage Analytics");
575
+ i0.ɵɵelementEnd()()()();
576
+ i0.ɵɵelementStart(30, "div", 18)(31, "div", 19);
577
+ i0.ɵɵtemplate(32, APIKeysResourceComponent_ng_container_2_ng_container_32_Template, 3, 2, "ng-container", 3)(33, APIKeysResourceComponent_ng_container_2_ng_container_33_Template, 2, 0, "ng-container", 3)(34, APIKeysResourceComponent_ng_container_2_ng_container_34_Template, 2, 0, "ng-container", 3)(35, APIKeysResourceComponent_ng_container_2_ng_container_35_Template, 2, 0, "ng-container", 3);
578
+ i0.ɵɵelementEnd()();
579
+ i0.ɵɵelementStart(36, "button", 20);
580
+ i0.ɵɵlistener("click", function APIKeysResourceComponent_ng_container_2_Template_button_click_36_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.toggleNav()); });
581
+ i0.ɵɵelement(37, "i", 21);
582
+ i0.ɵɵelementEnd();
583
+ i0.ɵɵelementStart(38, "div", 22);
584
+ i0.ɵɵlistener("click", function APIKeysResourceComponent_ng_container_2_Template_div_click_38_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.closeNav()); });
585
+ i0.ɵɵelementEnd();
586
+ i0.ɵɵelementContainerEnd();
587
+ } if (rf & 2) {
588
+ const ctx_r1 = i0.ɵɵnextContext();
589
+ i0.ɵɵadvance(8);
590
+ i0.ɵɵclassProp("active", ctx_r1.MainTab === "keys");
591
+ i0.ɵɵadvance(5);
592
+ i0.ɵɵtextInterpolate(ctx_r1.TotalKeys);
593
+ i0.ɵɵadvance();
594
+ i0.ɵɵclassProp("active", ctx_r1.MainTab === "applications");
595
+ i0.ɵɵadvance(5);
596
+ i0.ɵɵtextInterpolate(ctx_r1.ApplicationCount);
597
+ i0.ɵɵadvance();
598
+ i0.ɵɵclassProp("active", ctx_r1.MainTab === "scopes");
599
+ i0.ɵɵadvance(5);
600
+ i0.ɵɵtextInterpolate(ctx_r1.ScopeCount);
601
+ i0.ɵɵadvance();
602
+ i0.ɵɵclassProp("active", ctx_r1.MainTab === "usage");
603
+ i0.ɵɵadvance(6);
604
+ i0.ɵɵproperty("ngIf", ctx_r1.MainTab === "keys");
605
+ i0.ɵɵadvance();
606
+ i0.ɵɵproperty("ngIf", ctx_r1.MainTab === "applications");
607
+ i0.ɵɵadvance();
608
+ i0.ɵɵproperty("ngIf", ctx_r1.MainTab === "scopes");
609
+ i0.ɵɵadvance();
610
+ i0.ɵɵproperty("ngIf", ctx_r1.MainTab === "usage");
611
+ i0.ɵɵadvance(2);
612
+ i0.ɵɵclassProp("fa-bars", !ctx_r1.NavOpen)("fa-times", ctx_r1.NavOpen);
613
+ } }
614
+ /** Tree shaking prevention function */
615
+ export function LoadAPIKeysResource() {
616
+ // This function prevents tree shaking
617
+ }
618
+ /**
619
+ * API Keys Resource Component
620
+ * Provides management interface for MJ API Keys including:
621
+ * - Overview statistics and health monitoring
622
+ * - Key listing with status filters
623
+ * - Key creation and revocation
624
+ * - Usage tracking and analytics
625
+ */
626
+ let APIKeysResourceComponent = class APIKeysResourceComponent extends BaseResourceComponent {
627
+ keyListComponent;
628
+ destroy$ = new Subject();
629
+ md = new Metadata();
630
+ cdr;
631
+ // View state
632
+ CurrentView = 'overview';
633
+ ListFilter = 'all';
634
+ MainTab = 'keys';
635
+ NavOpen = false;
636
+ // Application and scope counts for tab badges
637
+ ApplicationCount = 0;
638
+ ScopeCount = 0;
639
+ // Loading states
640
+ IsLoading = true;
641
+ // Statistics
642
+ TotalKeys = 0;
643
+ ActiveKeys = 0;
644
+ RevokedKeys = 0;
645
+ ExpiringSoonCount = 0;
646
+ ExpiredKeys = 0;
647
+ NeverUsedKeys = 0;
648
+ // Data collections
649
+ APIKeys = [];
650
+ RecentActivity = [];
651
+ ScopeStats = [];
652
+ TopUsedKeys = [];
653
+ // Dialog states
654
+ ShowCreateDialog = false;
655
+ ShowEditPanel = false;
656
+ SelectedKeyId = null;
657
+ // Scope category colors
658
+ categoryColors = {
659
+ 'Entities': '#6366f1',
660
+ 'Agents': '#10b981',
661
+ 'Admin': '#f59e0b',
662
+ 'Actions': '#8b5cf6',
663
+ 'Queries': '#3b82f6',
664
+ 'Reports': '#ef4444',
665
+ 'Communication': '#ec4899',
666
+ 'Other': '#6b7280'
667
+ };
668
+ categoryIcons = {
669
+ 'Entities': 'fa-solid fa-database',
670
+ 'Agents': 'fa-solid fa-robot',
671
+ 'Admin': 'fa-solid fa-shield-halved',
672
+ 'Actions': 'fa-solid fa-bolt',
673
+ 'Queries': 'fa-solid fa-magnifying-glass',
674
+ 'Reports': 'fa-solid fa-chart-bar',
675
+ 'Communication': 'fa-solid fa-envelope',
676
+ 'Other': 'fa-solid fa-ellipsis'
677
+ };
678
+ // User permissions
679
+ UserCanCreateKeys = false;
680
+ UserCanRevokeKeys = false;
681
+ constructor(cdr) {
682
+ super();
683
+ this.cdr = cdr;
684
+ }
685
+ async ngOnInit() {
686
+ await this.loadData();
687
+ }
688
+ ngOnDestroy() {
689
+ this.destroy$.next();
690
+ this.destroy$.complete();
691
+ }
692
+ async GetResourceDisplayName(_data) {
693
+ return 'API Keys';
694
+ }
695
+ async GetResourceIconClass(_data) {
696
+ return 'fa-solid fa-key';
697
+ }
698
+ /**
699
+ * Load all dashboard data
700
+ */
701
+ async loadData() {
702
+ this.IsLoading = true;
703
+ this.cdr.markForCheck();
704
+ try {
705
+ await Promise.all([
706
+ this.loadAPIKeys(),
707
+ this.loadScopeStats(),
708
+ this.loadRecentActivity(),
709
+ this.loadCounts(),
710
+ this.checkPermissions()
711
+ ]);
712
+ this.calculateStatistics();
713
+ }
714
+ catch (error) {
715
+ console.error('Error loading API Keys dashboard data:', error);
716
+ }
717
+ finally {
718
+ this.IsLoading = false;
719
+ this.NotifyLoadComplete();
720
+ this.cdr.markForCheck();
721
+ }
722
+ }
723
+ /**
724
+ * Load application and scope counts for tab badges
725
+ */
726
+ async loadCounts() {
727
+ const rv = new RunView();
728
+ const [appsResult, scopesResult] = await rv.RunViews([
729
+ {
730
+ EntityName: 'MJ: API Applications',
731
+ ResultType: 'simple',
732
+ Fields: ['ID']
733
+ },
734
+ {
735
+ EntityName: 'MJ: API Scopes',
736
+ ResultType: 'simple',
737
+ Fields: ['ID']
738
+ }
739
+ ]);
740
+ this.ApplicationCount = appsResult.Success ? appsResult.Results.length : 0;
741
+ this.ScopeCount = scopesResult.Success ? scopesResult.Results.length : 0;
742
+ }
743
+ /**
744
+ * Load all API keys
745
+ */
746
+ async loadAPIKeys() {
747
+ const rv = new RunView();
748
+ const result = await rv.RunView({
749
+ EntityName: 'MJ: API Keys',
750
+ OrderBy: '__mj_CreatedAt DESC',
751
+ ResultType: 'entity_object'
752
+ });
753
+ if (result.Success) {
754
+ this.APIKeys = result.Results;
755
+ }
756
+ }
757
+ /**
758
+ * Load scope statistics by category
759
+ */
760
+ async loadScopeStats() {
761
+ const rv = new RunView();
762
+ const result = await rv.RunView({
763
+ EntityName: 'MJ: API Scopes',
764
+ OrderBy: 'Category, Name',
765
+ ResultType: 'entity_object'
766
+ });
767
+ if (result.Success) {
768
+ const categoryMap = new Map();
769
+ for (const scope of result.Results) {
770
+ const category = scope.Category || 'Other';
771
+ categoryMap.set(category, (categoryMap.get(category) || 0) + 1);
772
+ }
773
+ const total = result.Results.length;
774
+ this.ScopeStats = Array.from(categoryMap.entries()).map(([category, count]) => ({
775
+ category,
776
+ count,
777
+ percentage: total > 0 ? Math.round((count / total) * 100) : 0,
778
+ color: this.categoryColors[category] || this.categoryColors['Other'],
779
+ iconClass: this.categoryIcons[category] || this.categoryIcons['Other']
780
+ }));
781
+ }
782
+ }
783
+ /**
784
+ * Load recent activity from usage logs and key changes
785
+ */
786
+ async loadRecentActivity() {
787
+ const rv = new RunView();
788
+ // Load usage logs
789
+ const usageResult = await rv.RunView({
790
+ EntityName: 'MJ: API Key Usage Logs',
791
+ OrderBy: '__mj_CreatedAt DESC',
792
+ MaxRows: 20,
793
+ ResultType: 'entity_object'
794
+ });
795
+ const activities = [];
796
+ if (usageResult.Success) {
797
+ for (const log of usageResult.Results.slice(0, 10)) {
798
+ activities.push({
799
+ keyLabel: log.APIKey || 'Unknown Key',
800
+ action: 'Used',
801
+ user: log.APIKey || 'System',
802
+ date: log.__mj_CreatedAt,
803
+ keyId: log.APIKeyID
804
+ });
805
+ }
806
+ }
807
+ // Add key creation/update activities from keys
808
+ for (const key of this.APIKeys.slice(0, 10)) {
809
+ if (key.Status === 'Revoked') {
810
+ activities.push({
811
+ keyLabel: key.Label,
812
+ action: 'Revoked',
813
+ user: key.User,
814
+ date: key.__mj_UpdatedAt,
815
+ keyId: key.ID
816
+ });
817
+ }
818
+ else {
819
+ activities.push({
820
+ keyLabel: key.Label,
821
+ action: 'Created',
822
+ user: key.CreatedByUser,
823
+ date: key.__mj_CreatedAt,
824
+ keyId: key.ID
825
+ });
826
+ }
827
+ }
828
+ // Sort by date and take top 10
829
+ this.RecentActivity = activities
830
+ .sort((a, b) => b.date.getTime() - a.date.getTime())
831
+ .slice(0, 10);
832
+ }
833
+ /**
834
+ * Check user permissions
835
+ */
836
+ async checkPermissions() {
837
+ // Check if user can create/manage API keys
838
+ const entityInfo = this.md.Entities.find(e => e.Name === 'MJ: API Keys');
839
+ if (entityInfo) {
840
+ const permissions = entityInfo.GetUserPermisions(this.md.CurrentUser);
841
+ this.UserCanCreateKeys = permissions.CanCreate;
842
+ this.UserCanRevokeKeys = permissions.CanUpdate;
843
+ }
844
+ }
845
+ /**
846
+ * Calculate dashboard statistics from loaded data
847
+ */
848
+ calculateStatistics() {
849
+ const now = new Date();
850
+ const thirtyDaysFromNow = new Date(now.getTime() + 30 * 24 * 60 * 60 * 1000);
851
+ this.TotalKeys = this.APIKeys.length;
852
+ this.ActiveKeys = this.APIKeys.filter(k => k.Status === 'Active').length;
853
+ this.RevokedKeys = this.APIKeys.filter(k => k.Status === 'Revoked').length;
854
+ this.ExpiredKeys = this.APIKeys.filter(k => k.ExpiresAt && new Date(k.ExpiresAt) < now).length;
855
+ this.ExpiringSoonCount = this.APIKeys.filter(k => k.Status === 'Active' &&
856
+ k.ExpiresAt &&
857
+ new Date(k.ExpiresAt) > now &&
858
+ new Date(k.ExpiresAt) < thirtyDaysFromNow).length;
859
+ this.NeverUsedKeys = this.APIKeys.filter(k => k.Status === 'Active' && !k.LastUsedAt).length;
860
+ // Get top used keys (most recently used active keys)
861
+ this.TopUsedKeys = this.APIKeys
862
+ .filter(k => k.Status === 'Active' && k.LastUsedAt)
863
+ .sort((a, b) => {
864
+ const aDate = a.LastUsedAt ? new Date(a.LastUsedAt).getTime() : 0;
865
+ const bDate = b.LastUsedAt ? new Date(b.LastUsedAt).getTime() : 0;
866
+ return bDate - aDate;
867
+ })
868
+ .slice(0, 5);
869
+ }
870
+ /**
871
+ * Refresh all data
872
+ */
873
+ async refresh() {
874
+ await this.loadData();
875
+ if (this.keyListComponent) {
876
+ await this.keyListComponent.loadKeys();
877
+ }
878
+ }
879
+ /**
880
+ * Switch to list view
881
+ */
882
+ showListView(filter = 'all') {
883
+ this.ListFilter = filter;
884
+ this.CurrentView = 'list';
885
+ }
886
+ /**
887
+ * Switch to overview
888
+ */
889
+ showOverview() {
890
+ this.CurrentView = 'overview';
891
+ }
892
+ /**
893
+ * Open create dialog
894
+ */
895
+ openCreateDialog() {
896
+ this.ShowCreateDialog = true;
897
+ }
898
+ /**
899
+ * Handle key created
900
+ */
901
+ async onKeyCreated(result) {
902
+ if (result.success) {
903
+ await this.refresh();
904
+ }
905
+ }
906
+ /**
907
+ * Handle create dialog closed
908
+ */
909
+ onCreateDialogClosed() {
910
+ this.ShowCreateDialog = false;
911
+ }
912
+ /**
913
+ * Open edit panel for a key
914
+ */
915
+ openEditPanel(key) {
916
+ this.SelectedKeyId = key.ID;
917
+ this.ShowEditPanel = true;
918
+ }
919
+ /**
920
+ * Handle key from list selected
921
+ */
922
+ onKeySelected(key) {
923
+ this.openEditPanel(key);
924
+ }
925
+ /**
926
+ * Handle key updated
927
+ */
928
+ async onKeyUpdated() {
929
+ await this.refresh();
930
+ }
931
+ /**
932
+ * Handle key revoked
933
+ */
934
+ async onKeyRevoked() {
935
+ await this.refresh();
936
+ }
937
+ /**
938
+ * Handle edit panel closed
939
+ */
940
+ onEditPanelClosed() {
941
+ this.ShowEditPanel = false;
942
+ this.SelectedKeyId = null;
943
+ }
944
+ /**
945
+ * Get health score (0-100) based on key status
946
+ */
947
+ getHealthScore() {
948
+ if (this.TotalKeys === 0)
949
+ return 100;
950
+ let score = 100;
951
+ // Deduct for expired keys
952
+ score -= (this.ExpiredKeys / this.TotalKeys) * 40;
953
+ // Deduct for expiring soon
954
+ score -= (this.ExpiringSoonCount / this.TotalKeys) * 20;
955
+ // Deduct for never used active keys (might be leaked)
956
+ score -= (this.NeverUsedKeys / this.TotalKeys) * 10;
957
+ // Deduct if too many active keys
958
+ if (this.ActiveKeys > 20) {
959
+ score -= Math.min(15, (this.ActiveKeys - 20) * 0.5);
960
+ }
961
+ return Math.max(0, Math.round(score));
962
+ }
963
+ /**
964
+ * Get health label based on score
965
+ */
966
+ getHealthLabel() {
967
+ const score = this.getHealthScore();
968
+ if (score >= 90)
969
+ return 'Excellent Security';
970
+ if (score >= 75)
971
+ return 'Good Security';
972
+ if (score >= 50)
973
+ return 'Needs Attention';
974
+ return 'Critical Issues';
975
+ }
976
+ /**
977
+ * Get CSS class for health banner
978
+ */
979
+ getHealthClass() {
980
+ const score = this.getHealthScore();
981
+ if (score >= 75)
982
+ return '';
983
+ if (score >= 50)
984
+ return 'health-warning';
985
+ return 'health-critical';
986
+ }
987
+ /**
988
+ * Get donut chart offset for segment
989
+ */
990
+ getDonutOffset(index) {
991
+ let offset = 0;
992
+ for (let i = 0; i < index; i++) {
993
+ offset -= this.ScopeStats[i].percentage * 2.51;
994
+ }
995
+ return offset;
996
+ }
997
+ /**
998
+ * Get activity icon based on action
999
+ */
1000
+ getActionIcon(action) {
1001
+ switch (action) {
1002
+ case 'Created': return 'fa-solid fa-plus';
1003
+ case 'Updated': return 'fa-solid fa-pencil';
1004
+ case 'Revoked': return 'fa-solid fa-ban';
1005
+ case 'Used': return 'fa-solid fa-arrow-right-to-bracket';
1006
+ case 'Extended': return 'fa-solid fa-clock-rotate-left';
1007
+ default: return 'fa-solid fa-circle';
1008
+ }
1009
+ }
1010
+ /**
1011
+ * Get CSS class for activity action
1012
+ */
1013
+ getActionClass(action) {
1014
+ switch (action) {
1015
+ case 'Created': return 'action-created';
1016
+ case 'Updated': return 'action-updated';
1017
+ case 'Revoked': return 'action-revoked';
1018
+ case 'Used': return 'action-used';
1019
+ case 'Extended': return 'action-extended';
1020
+ default: return '';
1021
+ }
1022
+ }
1023
+ /**
1024
+ * Format date for display
1025
+ */
1026
+ formatDate(date) {
1027
+ if (!date)
1028
+ return 'Never';
1029
+ const now = new Date();
1030
+ const diff = now.getTime() - new Date(date).getTime();
1031
+ const minutes = Math.floor(diff / 60000);
1032
+ const hours = Math.floor(diff / 3600000);
1033
+ const days = Math.floor(diff / 86400000);
1034
+ if (minutes < 1)
1035
+ return 'Just now';
1036
+ if (minutes < 60)
1037
+ return `${minutes}m ago`;
1038
+ if (hours < 24)
1039
+ return `${hours}h ago`;
1040
+ if (days < 7)
1041
+ return `${days}d ago`;
1042
+ return new Date(date).toLocaleDateString();
1043
+ }
1044
+ /**
1045
+ * Format expiration for display
1046
+ */
1047
+ formatExpiration(date) {
1048
+ if (!date)
1049
+ return 'Never expires';
1050
+ const now = new Date();
1051
+ const expiresAt = new Date(date);
1052
+ const diff = expiresAt.getTime() - now.getTime();
1053
+ if (diff < 0)
1054
+ return 'Expired';
1055
+ const days = Math.floor(diff / 86400000);
1056
+ if (days === 0)
1057
+ return 'Expires today';
1058
+ if (days === 1)
1059
+ return 'Expires tomorrow';
1060
+ if (days < 30)
1061
+ return `Expires in ${days} days`;
1062
+ return `Expires ${expiresAt.toLocaleDateString()}`;
1063
+ }
1064
+ /**
1065
+ * Get expiration status class
1066
+ */
1067
+ getExpirationClass(key) {
1068
+ if (!key.ExpiresAt)
1069
+ return '';
1070
+ const now = new Date();
1071
+ const expiresAt = new Date(key.ExpiresAt);
1072
+ const diff = expiresAt.getTime() - now.getTime();
1073
+ const days = Math.floor(diff / 86400000);
1074
+ if (diff < 0)
1075
+ return 'expired';
1076
+ if (days < 7)
1077
+ return 'expiring-critical';
1078
+ if (days < 30)
1079
+ return 'expiring-soon';
1080
+ return '';
1081
+ }
1082
+ /**
1083
+ * View activity for a key
1084
+ */
1085
+ onActivityClick(activity) {
1086
+ const key = this.APIKeys.find(k => k.ID === activity.keyId);
1087
+ if (key) {
1088
+ this.openEditPanel(key);
1089
+ }
1090
+ }
1091
+ /**
1092
+ * View scope details - now navigates to scopes tab
1093
+ */
1094
+ onScopeClick(_stat) {
1095
+ this.MainTab = 'scopes';
1096
+ }
1097
+ /**
1098
+ * Switch to a main tab
1099
+ */
1100
+ switchTab(tab) {
1101
+ this.MainTab = tab;
1102
+ // Reset to overview when switching back to keys
1103
+ if (tab === 'keys') {
1104
+ this.CurrentView = 'overview';
1105
+ }
1106
+ }
1107
+ /**
1108
+ * Toggle mobile navigation
1109
+ */
1110
+ toggleNav() {
1111
+ this.NavOpen = !this.NavOpen;
1112
+ }
1113
+ /**
1114
+ * Close mobile navigation
1115
+ */
1116
+ closeNav() {
1117
+ this.NavOpen = false;
1118
+ }
1119
+ /**
1120
+ * Handle updates from child panels
1121
+ */
1122
+ async onDataUpdated() {
1123
+ await this.loadCounts();
1124
+ this.cdr.markForCheck();
1125
+ }
1126
+ static ɵfac = function APIKeysResourceComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || APIKeysResourceComponent)(i0.ɵɵdirectiveInject(i0.ChangeDetectorRef)); };
1127
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: APIKeysResourceComponent, selectors: [["mj-api-keys-resource"]], viewQuery: function APIKeysResourceComponent_Query(rf, ctx) { if (rf & 1) {
1128
+ i0.ɵɵviewQuery(_c0, 5);
1129
+ } if (rf & 2) {
1130
+ let _t;
1131
+ i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.keyListComponent = _t.first);
1132
+ } }, features: [i0.ɵɵInheritDefinitionFeature], decls: 5, vars: 9, consts: [["keyList", ""], [1, "api-keys-dashboard"], ["text", "Loading API Keys...", 4, "ngIf"], [4, "ngIf"], [3, "Created", "Closed", "Visible"], [3, "Updated", "Revoked", "Closed", "Visible", "KeyId"], ["text", "Loading API Keys..."], [1, "dashboard-nav"], [1, "nav-header"], [1, "nav-title"], [1, "fa-solid", "fa-key"], [1, "nav-items"], [1, "nav-item", 3, "click"], [1, "nav-label"], [1, "nav-badge"], [1, "fa-solid", "fa-cube"], [1, "fa-solid", "fa-shield-halved"], [1, "fa-solid", "fa-chart-line"], [1, "dashboard-content"], [1, "content-wrapper"], [1, "mobile-nav-toggle", 3, "click"], [1, "fa-solid"], [1, "mobile-nav-overlay", 3, "click"], [1, "overview-header"], [1, "header-left"], [1, "overview-title"], [1, "overview-subtitle"], [1, "header-actions"], ["title", "Refresh", 1, "btn-refresh", 3, "click"], [1, "fa-solid", "fa-refresh"], ["class", "btn-primary", 3, "click", 4, "ngIf"], [1, "health-banner", 3, "ngClass"], [1, "health-score-container"], [1, "health-score-ring"], ["viewBox", "0 0 36 36", 1, "circular-chart"], ["d", "M18 2.0845\n a 15.9155 15.9155 0 0 1 0 31.831\n a 15.9155 15.9155 0 0 1 0 -31.831", 1, "circle-bg"], ["d", "M18 2.0845\n a 15.9155 15.9155 0 0 1 0 31.831\n a 15.9155 15.9155 0 0 1 0 -31.831", 1, "circle"], [1, "health-score-value"], [1, "health-info"], [1, "health-label"], [1, "health-details"], ["class", "health-alert", 3, "click", 4, "ngIf"], ["class", "health-warning-text", 3, "click", 4, "ngIf"], ["class", "health-info-text", 3, "click", 4, "ngIf"], ["class", "health-ok", 4, "ngIf"], [1, "kpi-row"], [1, "kpi-card", "clickable", 3, "click"], [1, "kpi-icon"], [1, "kpi-content"], [1, "kpi-value"], [1, "kpi-label"], [1, "kpi-trend"], [1, "fa-solid", "fa-arrow-right"], [1, "kpi-card", "active", "clickable", 3, "click"], [1, "fa-solid", "fa-check-circle"], [1, "kpi-trend", "success"], [1, "percentage"], [1, "fa-solid", "fa-clock"], ["class", "kpi-trend warning", 4, "ngIf"], [1, "fa-solid", "fa-ban"], [1, "content-grid"], [1, "panel", "keys-panel"], [1, "panel-header"], [1, "panel-title"], [1, "panel-action", 3, "click"], [1, "panel-body"], ["class", "key-list", 4, "ngIf"], ["class", "empty-state", 4, "ngIf"], [1, "panel", "scope-panel"], [1, "panel-subtitle"], ["class", "scope-chart", 4, "ngIf"], [1, "panel", "activity-panel"], [1, "fa-solid", "fa-clock-rotate-left"], ["class", "activity-list", 4, "ngIf"], ["class", "quick-actions", 4, "ngIf"], [1, "security-notice"], [1, "fa-solid", "fa-shield-check"], [1, "notice-content"], [1, "btn-primary", 3, "click"], [1, "fa-solid", "fa-plus"], [1, "health-alert", 3, "click"], [1, "fa-solid", "fa-circle-exclamation"], [1, "health-warning-text", 3, "click"], [1, "health-info-text", 3, "click"], [1, "fa-solid", "fa-question-circle"], [1, "health-ok"], [1, "kpi-trend", "warning"], [1, "key-list"], ["class", "key-item", 3, "click", 4, "ngFor", "ngForOf"], [1, "key-item", 3, "click"], [1, "key-icon"], [1, "key-info"], [1, "key-label"], [1, "key-meta"], [1, "key-user"], [1, "key-hash"], [1, "key-status"], [1, "last-used"], [1, "expiration", 3, "ngClass"], [1, "empty-state"], [1, "scope-chart"], [1, "donut-chart-container"], ["viewBox", "0 0 100 100", 1, "donut-chart"], ["cx", "50", "cy", "50", "r", "40", "fill", "none", "stroke", "#e5e7eb", "stroke-width", "12"], [4, "ngFor", "ngForOf"], [1, "donut-center"], [1, "donut-total"], [1, "donut-label"], [1, "scope-legend"], ["class", "legend-item", 3, "click", 4, "ngFor", "ngForOf"], ["cx", "50", "cy", "50", "r", "40", "fill", "none", "stroke-width", "12", 1, "donut-segment", 3, "click"], [1, "legend-item", 3, "click"], [1, "legend-color"], [1, "legend-info"], [1, "legend-name"], [1, "legend-value"], [1, "fa-solid", "fa-chevron-right", "legend-arrow"], [1, "activity-list"], ["class", "activity-item", 3, "click", 4, "ngFor", "ngForOf"], [1, "activity-item", 3, "click"], [1, "activity-icon", 3, "ngClass"], [1, "activity-info"], [1, "activity-name"], [1, "activity-meta"], [1, "activity-action"], ["class", "activity-user", 4, "ngIf"], [1, "activity-time"], [1, "activity-user"], [1, "fa-solid", "fa-inbox"], [1, "quick-actions"], [1, "quick-actions-title"], [1, "quick-actions-grid"], [1, "quick-action", 3, "click"], [1, "fa-solid", "fa-list"], [1, "list-view-header"], [1, "back-btn", 3, "click"], [1, "fa-solid", "fa-arrow-left"], [3, "KeySelected", "CreateRequested", "Filter"], [3, "ApplicationUpdated"], [3, "ScopeUpdated"]], template: function APIKeysResourceComponent_Template(rf, ctx) { if (rf & 1) {
1133
+ i0.ɵɵelementStart(0, "div", 1);
1134
+ i0.ɵɵtemplate(1, APIKeysResourceComponent_mj_loading_1_Template, 1, 0, "mj-loading", 2)(2, APIKeysResourceComponent_ng_container_2_Template, 39, 19, "ng-container", 3);
1135
+ i0.ɵɵelementStart(3, "mj-api-key-create-dialog", 4);
1136
+ i0.ɵɵlistener("Created", function APIKeysResourceComponent_Template_mj_api_key_create_dialog_Created_3_listener($event) { return ctx.onKeyCreated($event); })("Closed", function APIKeysResourceComponent_Template_mj_api_key_create_dialog_Closed_3_listener() { return ctx.onCreateDialogClosed(); });
1137
+ i0.ɵɵelementEnd();
1138
+ i0.ɵɵelementStart(4, "mj-api-key-edit-panel", 5);
1139
+ i0.ɵɵlistener("Updated", function APIKeysResourceComponent_Template_mj_api_key_edit_panel_Updated_4_listener() { return ctx.onKeyUpdated(); })("Revoked", function APIKeysResourceComponent_Template_mj_api_key_edit_panel_Revoked_4_listener() { return ctx.onKeyRevoked(); })("Closed", function APIKeysResourceComponent_Template_mj_api_key_edit_panel_Closed_4_listener() { return ctx.onEditPanelClosed(); });
1140
+ i0.ɵɵelementEnd()();
1141
+ } if (rf & 2) {
1142
+ i0.ɵɵclassProp("panel-open", ctx.ShowCreateDialog || ctx.ShowEditPanel)("nav-open", ctx.NavOpen);
1143
+ i0.ɵɵadvance();
1144
+ i0.ɵɵproperty("ngIf", ctx.IsLoading);
1145
+ i0.ɵɵadvance();
1146
+ i0.ɵɵproperty("ngIf", !ctx.IsLoading);
1147
+ i0.ɵɵadvance();
1148
+ i0.ɵɵproperty("Visible", ctx.ShowCreateDialog);
1149
+ i0.ɵɵadvance();
1150
+ i0.ɵɵproperty("Visible", ctx.ShowEditPanel)("KeyId", ctx.SelectedKeyId);
1151
+ } }, dependencies: [i1.NgClass, i1.NgForOf, i1.NgIf, i2.LoadingComponent, i3.APIKeyCreateDialogComponent, i4.APIKeyEditPanelComponent, i5.APIKeyListComponent, i6.APIApplicationsPanelComponent, i7.APIScopesPanelComponent, i8.APIUsagePanelComponent], styles: ["\n\n.api-keys-dashboard[_ngcontent-%COMP%] {\n display: flex;\n height: 100%;\n position: relative;\n overflow: hidden;\n}\n\n.api-keys-dashboard.panel-open[_ngcontent-%COMP%] .dashboard-content[_ngcontent-%COMP%] {\n overflow: hidden;\n}\n\n\n\n.dashboard-nav[_ngcontent-%COMP%] {\n width: 220px;\n background: var(--card-background, #ffffff);\n border-right: 1px solid var(--border-color, #e5e7eb);\n display: flex;\n flex-direction: column;\n flex-shrink: 0;\n}\n\n.nav-header[_ngcontent-%COMP%] {\n padding: 20px;\n border-bottom: 1px solid var(--border-color, #e5e7eb);\n}\n\n.nav-title[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n font-weight: 700;\n font-size: 16px;\n color: var(--text-primary, #1f2937);\n}\n\n.nav-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: #f59e0b;\n font-size: 18px;\n}\n\n.nav-items[_ngcontent-%COMP%] {\n flex: 1;\n padding: 12px;\n overflow-y: auto;\n}\n\n.nav-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px 16px;\n margin-bottom: 4px;\n background: transparent;\n border: none;\n border-radius: 8px;\n font-size: 14px;\n font-weight: 500;\n color: var(--text-secondary, #6b7280);\n cursor: pointer;\n transition: all 0.2s ease;\n width: 100%;\n text-align: left;\n}\n\n.nav-item[_ngcontent-%COMP%]:hover {\n background: var(--item-hover, #f3f4f6);\n color: var(--text-primary, #1f2937);\n}\n\n.nav-item.active[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%);\n color: white;\n box-shadow: 0 2px 8px rgba(245, 158, 11, 0.3);\n}\n\n.nav-item[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 16px;\n width: 20px;\n text-align: center;\n}\n\n.nav-item[_ngcontent-%COMP%] .nav-label[_ngcontent-%COMP%] {\n flex: 1;\n}\n\n.nav-badge[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 22px;\n height: 20px;\n padding: 0 6px;\n background: rgba(0, 0, 0, 0.1);\n border-radius: 10px;\n font-size: 11px;\n font-weight: 600;\n}\n\n.nav-item.active[_ngcontent-%COMP%] .nav-badge[_ngcontent-%COMP%] {\n background: rgba(255, 255, 255, 0.25);\n}\n\n\n\n.dashboard-content[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n overflow-y: auto;\n min-width: 0;\n}\n\n.content-wrapper[_ngcontent-%COMP%] {\n flex: 1;\n padding: 24px;\n overflow-y: auto;\n}\n\n\n\n.list-view-header[_ngcontent-%COMP%] {\n margin-bottom: 16px;\n}\n\n.back-btn[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n padding: 8px 16px;\n background: var(--card-background, #ffffff);\n border: 1px solid var(--border-color, #e5e7eb);\n border-radius: 8px;\n font-size: 14px;\n font-weight: 500;\n color: var(--text-secondary, #6b7280);\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.back-btn[_ngcontent-%COMP%]:hover {\n background: var(--item-hover, #f3f4f6);\n color: var(--text-primary, #1f2937);\n}\n\n\n\n.overview-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 24px;\n}\n\n.header-left[_ngcontent-%COMP%] {\n flex: 1;\n}\n\n.overview-title[_ngcontent-%COMP%] {\n font-size: 24px;\n font-weight: 700;\n color: var(--text-primary, #1f2937);\n margin: 0 0 4px 0;\n}\n\n.overview-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 gap: 12px;\n}\n\n.btn-refresh[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 40px;\n height: 40px;\n background: var(--card-background, #ffffff);\n border: 1px solid var(--border-color, #e5e7eb);\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.btn-refresh[_ngcontent-%COMP%]:hover {\n background: var(--item-hover, #f3f4f6);\n}\n\n.btn-refresh[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--text-secondary, #6b7280);\n}\n\n.btn-primary[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 20px;\n background: linear-gradient(135deg, #f59e0b 0%, #d97706 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-primary[_ngcontent-%COMP%]:hover {\n transform: translateY(-1px);\n box-shadow: 0 4px 12px rgba(245, 158, 11, 0.4);\n}\n\n\n\n.health-banner[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n padding: 20px 24px;\n background: linear-gradient(135deg, #ecfdf5 0%, #d1fae5 100%);\n border: 1px solid #a7f3d0;\n border-radius: 16px;\n margin-bottom: 24px;\n}\n\n.health-banner.health-warning[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, #fffbeb 0%, #fef3c7 100%);\n border-color: #fcd34d;\n}\n\n.health-banner.health-critical[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, #fef2f2 0%, #fee2e2 100%);\n border-color: #fca5a5;\n}\n\n.health-score-container[_ngcontent-%COMP%] {\n margin-right: 24px;\n}\n\n.health-score-ring[_ngcontent-%COMP%] {\n position: relative;\n width: 80px;\n height: 80px;\n}\n\n.circular-chart[_ngcontent-%COMP%] {\n display: block;\n margin: 0 auto;\n max-height: 80px;\n transform: rotate(-90deg);\n}\n\n.circle-bg[_ngcontent-%COMP%] {\n fill: none;\n stroke: #e5e7eb;\n stroke-width: 3.8;\n}\n\n.circle[_ngcontent-%COMP%] {\n fill: none;\n stroke-width: 3.8;\n stroke-linecap: round;\n stroke: #10b981;\n animation: _ngcontent-%COMP%_progress 1s ease-out forwards;\n}\n\n.health-banner.health-warning[_ngcontent-%COMP%] .circle[_ngcontent-%COMP%] {\n stroke: #f59e0b;\n}\n\n.health-banner.health-critical[_ngcontent-%COMP%] .circle[_ngcontent-%COMP%] {\n stroke: #ef4444;\n}\n\n@keyframes _ngcontent-%COMP%_progress {\n 0% {\n stroke-dasharray: 0 100;\n }\n}\n\n.health-score-value[_ngcontent-%COMP%] {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n font-size: 20px;\n font-weight: 700;\n color: var(--text-primary, #1f2937);\n}\n\n.health-info[_ngcontent-%COMP%] {\n flex: 1;\n}\n\n.health-label[_ngcontent-%COMP%] {\n font-size: 18px;\n font-weight: 700;\n color: #059669;\n margin-bottom: 4px;\n}\n\n.health-banner.health-warning[_ngcontent-%COMP%] .health-label[_ngcontent-%COMP%] {\n color: #d97706;\n}\n\n.health-banner.health-critical[_ngcontent-%COMP%] .health-label[_ngcontent-%COMP%] {\n color: #dc2626;\n}\n\n.health-details[_ngcontent-%COMP%] {\n display: flex;\n gap: 16px;\n flex-wrap: wrap;\n}\n\n.health-alert[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n color: #dc2626;\n font-weight: 500;\n font-size: 14px;\n cursor: pointer;\n}\n\n.health-alert[_ngcontent-%COMP%]:hover {\n text-decoration: underline;\n}\n\n.health-warning-text[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n color: #d97706;\n font-weight: 500;\n font-size: 14px;\n cursor: pointer;\n}\n\n.health-warning-text[_ngcontent-%COMP%]:hover {\n text-decoration: underline;\n}\n\n.health-info-text[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n color: #6b7280;\n font-weight: 500;\n font-size: 14px;\n cursor: pointer;\n}\n\n.health-info-text[_ngcontent-%COMP%]:hover {\n text-decoration: underline;\n}\n\n.health-ok[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n color: #059669;\n font-weight: 500;\n font-size: 14px;\n}\n\n\n\n.kpi-row[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));\n gap: 16px;\n margin-bottom: 24px;\n}\n\n.kpi-card[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n padding: 16px 20px;\n background: var(--card-background, #ffffff);\n border-radius: 12px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);\n transition: transform 0.2s ease, box-shadow 0.2s ease;\n}\n\n.kpi-card.clickable[_ngcontent-%COMP%] {\n cursor: pointer;\n}\n\n.kpi-card.clickable[_ngcontent-%COMP%]:hover {\n transform: translateY(-2px);\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);\n}\n\n.kpi-card.active[_ngcontent-%COMP%] .kpi-icon[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, #10b981 0%, #059669 100%);\n}\n\n.kpi-card.warning[_ngcontent-%COMP%] .kpi-icon[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%);\n}\n\n.kpi-card.danger[_ngcontent-%COMP%] .kpi-icon[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, #ef4444 0%, #dc2626 100%);\n}\n\n.kpi-icon[_ngcontent-%COMP%] {\n width: 48px;\n height: 48px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%);\n border-radius: 10px;\n margin-right: 14px;\n flex-shrink: 0;\n}\n\n.kpi-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 20px;\n color: white;\n}\n\n.kpi-content[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n.kpi-value[_ngcontent-%COMP%] {\n font-size: 24px;\n font-weight: 700;\n color: var(--text-primary, #1f2937);\n line-height: 1.2;\n}\n\n.kpi-label[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--text-secondary, #6b7280);\n margin-top: 2px;\n white-space: nowrap;\n}\n\n.kpi-trend[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n margin-left: 8px;\n color: var(--text-tertiary, #9ca3af);\n}\n\n.kpi-trend.success[_ngcontent-%COMP%] {\n color: #10b981;\n}\n\n.kpi-trend.warning[_ngcontent-%COMP%] {\n color: #f59e0b;\n}\n\n.kpi-trend[_ngcontent-%COMP%] .percentage[_ngcontent-%COMP%] {\n font-size: 12px;\n font-weight: 600;\n}\n\n\n\n.content-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: 1fr 1fr;\n grid-template-rows: auto auto;\n gap: 20px;\n margin-bottom: 24px;\n}\n\n.keys-panel[_ngcontent-%COMP%] {\n grid-row: span 1;\n}\n\n.scope-panel[_ngcontent-%COMP%] {\n grid-row: span 1;\n}\n\n.activity-panel[_ngcontent-%COMP%] {\n grid-column: span 2;\n}\n\n.panel[_ngcontent-%COMP%] {\n background: var(--card-background, #ffffff);\n border-radius: 12px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);\n overflow: hidden;\n display: flex;\n flex-direction: column;\n}\n\n.panel-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px 20px;\n background: var(--header-background, #f9fafb);\n border-bottom: 1px solid var(--border-color, #e5e7eb);\n}\n\n.panel-title[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n font-weight: 600;\n font-size: 14px;\n color: var(--text-primary, #1f2937);\n}\n\n.panel-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: #f59e0b;\n}\n\n.panel-subtitle[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--text-tertiary, #9ca3af);\n}\n\n.panel-action[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 6px 12px;\n background: transparent;\n border: 1px solid var(--border-color, #e5e7eb);\n border-radius: 6px;\n font-size: 12px;\n font-weight: 500;\n color: var(--text-secondary, #6b7280);\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.panel-action[_ngcontent-%COMP%]:hover {\n background: #f59e0b;\n border-color: #f59e0b;\n color: white;\n}\n\n.panel-body[_ngcontent-%COMP%] {\n padding: 20px;\n flex: 1;\n overflow-y: auto;\n}\n\n\n\n.key-list[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n.key-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n padding: 14px 16px;\n background: var(--item-background, #f9fafb);\n border-radius: 10px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.key-item[_ngcontent-%COMP%]:hover {\n background: var(--item-hover, #f3f4f6);\n transform: translateX(4px);\n}\n\n.key-icon[_ngcontent-%COMP%] {\n width: 40px;\n height: 40px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: linear-gradient(135deg, #6b7280 0%, #4b5563 100%);\n border-radius: 8px;\n margin-right: 14px;\n flex-shrink: 0;\n}\n\n.key-icon.active[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%);\n}\n\n.key-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 16px;\n color: white;\n}\n\n.key-info[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n.key-label[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: 600;\n color: var(--text-primary, #1f2937);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.key-meta[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-top: 2px;\n font-size: 12px;\n color: var(--text-secondary, #6b7280);\n}\n\n.key-hash[_ngcontent-%COMP%] {\n font-family: monospace;\n background: var(--tag-background, #e5e7eb);\n padding: 2px 6px;\n border-radius: 4px;\n font-size: 11px;\n}\n\n.key-status[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: flex-end;\n gap: 4px;\n margin-left: 16px;\n}\n\n.last-used[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--text-secondary, #6b7280);\n}\n\n.expiration[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--text-tertiary, #9ca3af);\n}\n\n.expiration.expiring-soon[_ngcontent-%COMP%] {\n color: #f59e0b;\n font-weight: 500;\n}\n\n.expiration.expiring-critical[_ngcontent-%COMP%] {\n color: #ef4444;\n font-weight: 500;\n}\n\n.expiration.expired[_ngcontent-%COMP%] {\n color: #ef4444;\n font-weight: 600;\n}\n\n\n\n.scope-chart[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 24px;\n height: 100%;\n}\n\n.donut-chart-container[_ngcontent-%COMP%] {\n position: relative;\n width: 160px;\n height: 160px;\n margin: 0 auto;\n}\n\n.donut-chart[_ngcontent-%COMP%] {\n width: 100%;\n height: 100%;\n transform: rotate(-90deg);\n}\n\n.donut-segment[_ngcontent-%COMP%] {\n cursor: pointer;\n transition: opacity 0.2s ease;\n}\n\n.donut-segment[_ngcontent-%COMP%]:hover {\n opacity: 0.8;\n}\n\n.donut-center[_ngcontent-%COMP%] {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n text-align: center;\n}\n\n.donut-total[_ngcontent-%COMP%] {\n font-size: 28px;\n font-weight: 700;\n color: var(--text-primary, #1f2937);\n}\n\n.donut-label[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--text-secondary, #6b7280);\n}\n\n\n\n.scope-legend[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.legend-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n padding: 10px 12px;\n background: var(--item-background, #f9fafb);\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.legend-item[_ngcontent-%COMP%]:hover {\n background: var(--item-hover, #f3f4f6);\n transform: translateX(4px);\n}\n\n.legend-color[_ngcontent-%COMP%] {\n width: 12px;\n height: 12px;\n border-radius: 4px;\n margin-right: 12px;\n flex-shrink: 0;\n}\n\n.legend-info[_ngcontent-%COMP%] {\n flex: 1;\n}\n\n.legend-name[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: 500;\n color: var(--text-primary, #1f2937);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.legend-name[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--text-secondary, #6b7280);\n}\n\n.legend-value[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--text-secondary, #6b7280);\n}\n\n.legend-arrow[_ngcontent-%COMP%] {\n color: var(--text-tertiary, #9ca3af);\n font-size: 10px;\n}\n\n\n\n.activity-list[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));\n gap: 12px;\n}\n\n.activity-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n padding: 12px 14px;\n background: var(--item-background, #f9fafb);\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.activity-item[_ngcontent-%COMP%]:hover {\n background: var(--item-hover, #f3f4f6);\n}\n\n.activity-icon[_ngcontent-%COMP%] {\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--icon-background, #fef3c7);\n border-radius: 6px;\n margin-right: 12px;\n flex-shrink: 0;\n}\n\n.activity-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 12px;\n color: #f59e0b;\n}\n\n.activity-icon.action-created[_ngcontent-%COMP%] {\n background: #d1fae5;\n}\n\n.activity-icon.action-created[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: #059669;\n}\n\n.activity-icon.action-updated[_ngcontent-%COMP%] {\n background: #e0e7ff;\n}\n\n.activity-icon.action-updated[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: #6366f1;\n}\n\n.activity-icon.action-revoked[_ngcontent-%COMP%] {\n background: #fee2e2;\n}\n\n.activity-icon.action-revoked[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: #dc2626;\n}\n\n.activity-icon.action-used[_ngcontent-%COMP%] {\n background: #fef3c7;\n}\n\n.activity-icon.action-used[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: #d97706;\n}\n\n.activity-icon.action-extended[_ngcontent-%COMP%] {\n background: #dbeafe;\n}\n\n.activity-icon.action-extended[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: #3b82f6;\n}\n\n.activity-info[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n.activity-name[_ngcontent-%COMP%] {\n font-weight: 500;\n font-size: 13px;\n color: var(--text-primary, #1f2937);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.activity-meta[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n margin-top: 2px;\n font-size: 11px;\n color: var(--text-secondary, #6b7280);\n}\n\n.activity-action[_ngcontent-%COMP%] {\n font-weight: 500;\n text-transform: capitalize;\n}\n\n.activity-time[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--text-tertiary, #9ca3af);\n white-space: nowrap;\n}\n\n\n\n.quick-actions[_ngcontent-%COMP%] {\n margin-bottom: 24px;\n}\n\n.quick-actions-title[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: 600;\n color: var(--text-primary, #1f2937);\n margin-bottom: 12px;\n}\n\n.quick-actions-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));\n gap: 12px;\n}\n\n.quick-action[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 8px;\n padding: 16px;\n background: var(--card-background, #ffffff);\n border: 1px solid var(--border-color, #e5e7eb);\n border-radius: 10px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.quick-action[_ngcontent-%COMP%]:hover {\n border-color: #f59e0b;\n background: #fffbeb;\n transform: translateY(-2px);\n}\n\n.quick-action[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 20px;\n color: #f59e0b;\n}\n\n.quick-action[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n font-size: 12px;\n font-weight: 500;\n color: var(--text-secondary, #6b7280);\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;\n color: var(--text-secondary, #6b7280);\n text-align: center;\n}\n\n.empty-state[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 32px;\n margin-bottom: 12px;\n opacity: 0.5;\n}\n\n\n\n.security-notice[_ngcontent-%COMP%] {\n display: flex;\n align-items: flex-start;\n padding: 16px 20px;\n background: linear-gradient(135deg, #fffbeb 0%, #fef3c7 100%);\n border-radius: 12px;\n border: 1px solid #fcd34d;\n}\n\n.security-notice[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 20px;\n color: #f59e0b;\n margin-right: 12px;\n margin-top: 2px;\n}\n\n.notice-content[_ngcontent-%COMP%] {\n font-size: 13px;\n color: #92400e;\n line-height: 1.5;\n}\n\n.notice-content[_ngcontent-%COMP%] strong[_ngcontent-%COMP%] {\n font-weight: 600;\n}\n\n\n\n.mobile-nav-toggle[_ngcontent-%COMP%] {\n display: none;\n position: fixed;\n bottom: 20px;\n right: 20px;\n width: 56px;\n height: 56px;\n background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%);\n border: none;\n border-radius: 50%;\n color: white;\n font-size: 24px;\n box-shadow: 0 4px 16px rgba(245, 158, 11, 0.4);\n cursor: pointer;\n z-index: 50;\n transition: transform 0.2s ease;\n}\n\n.mobile-nav-toggle[_ngcontent-%COMP%]:hover {\n transform: scale(1.05);\n}\n\n\n\n.mobile-nav-overlay[_ngcontent-%COMP%] {\n display: none;\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n z-index: 90;\n}\n\n\n\n\n\n\n\n\n@media (max-width: 1024px) {\n .content-grid[_ngcontent-%COMP%] {\n grid-template-columns: 1fr;\n }\n\n .activity-panel[_ngcontent-%COMP%] {\n grid-column: span 1;\n }\n\n .scope-chart[_ngcontent-%COMP%] {\n flex-direction: row;\n align-items: center;\n }\n\n .donut-chart-container[_ngcontent-%COMP%] {\n width: 140px;\n height: 140px;\n }\n\n .scope-legend[_ngcontent-%COMP%] {\n flex: 1;\n }\n\n .dashboard-nav[_ngcontent-%COMP%] {\n width: 200px;\n }\n}\n\n\n\n@media (max-width: 768px) {\n .api-keys-dashboard[_ngcontent-%COMP%] {\n flex-direction: column;\n }\n\n .dashboard-nav[_ngcontent-%COMP%] {\n position: fixed;\n top: 0;\n left: -280px;\n width: 280px;\n height: 100%;\n z-index: 100;\n transition: left 0.3s ease;\n box-shadow: 4px 0 20px rgba(0, 0, 0, 0.15);\n }\n\n .api-keys-dashboard.nav-open[_ngcontent-%COMP%] .dashboard-nav[_ngcontent-%COMP%] {\n left: 0;\n }\n\n .mobile-nav-toggle[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .mobile-nav-overlay[_ngcontent-%COMP%] {\n display: block;\n opacity: 0;\n pointer-events: none;\n transition: opacity 0.3s ease;\n }\n\n .api-keys-dashboard.nav-open[_ngcontent-%COMP%] .mobile-nav-overlay[_ngcontent-%COMP%] {\n opacity: 1;\n pointer-events: auto;\n }\n\n .dashboard-content[_ngcontent-%COMP%] {\n width: 100%;\n }\n\n .content-wrapper[_ngcontent-%COMP%] {\n padding: 16px;\n }\n\n .overview-header[_ngcontent-%COMP%] {\n flex-direction: column;\n gap: 16px;\n }\n\n .header-actions[_ngcontent-%COMP%] {\n width: 100%;\n justify-content: flex-end;\n }\n\n .health-banner[_ngcontent-%COMP%] {\n flex-direction: column;\n text-align: center;\n }\n\n .health-score-container[_ngcontent-%COMP%] {\n margin-right: 0;\n margin-bottom: 16px;\n }\n\n .kpi-row[_ngcontent-%COMP%] {\n grid-template-columns: repeat(2, 1fr);\n }\n\n .scope-chart[_ngcontent-%COMP%] {\n flex-direction: column;\n }\n\n .quick-actions-grid[_ngcontent-%COMP%] {\n grid-template-columns: repeat(2, 1fr);\n }\n\n .activity-list[_ngcontent-%COMP%] {\n grid-template-columns: 1fr;\n }\n\n .key-item[_ngcontent-%COMP%] {\n flex-wrap: wrap;\n }\n\n .key-status[_ngcontent-%COMP%] {\n width: 100%;\n flex-direction: row;\n justify-content: flex-start;\n margin-left: 54px;\n margin-top: 8px;\n gap: 12px;\n }\n}\n\n\n\n@media (max-width: 480px) {\n .kpi-row[_ngcontent-%COMP%] {\n grid-template-columns: 1fr;\n }\n\n .quick-actions-grid[_ngcontent-%COMP%] {\n grid-template-columns: 1fr;\n }\n\n .kpi-card[_ngcontent-%COMP%] {\n padding: 12px 16px;\n }\n\n .kpi-icon[_ngcontent-%COMP%] {\n width: 40px;\n height: 40px;\n }\n\n .kpi-value[_ngcontent-%COMP%] {\n font-size: 20px;\n }\n\n .overview-title[_ngcontent-%COMP%] {\n font-size: 20px;\n }\n\n .btn-primary[_ngcontent-%COMP%] {\n padding: 8px 16px;\n font-size: 13px;\n }\n}"] });
1152
+ };
1153
+ APIKeysResourceComponent = __decorate([
1154
+ RegisterClass(BaseResourceComponent, 'APIKeysResource')
1155
+ ], APIKeysResourceComponent);
1156
+ export { APIKeysResourceComponent };
1157
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(APIKeysResourceComponent, [{
1158
+ type: Component,
1159
+ args: [{ selector: 'mj-api-keys-resource', template: "<div class=\"api-keys-dashboard\" [class.panel-open]=\"ShowCreateDialog || ShowEditPanel\" [class.nav-open]=\"NavOpen\">\n <mj-loading *ngIf=\"IsLoading\" text=\"Loading API Keys...\"></mj-loading>\n\n <ng-container *ngIf=\"!IsLoading\">\n <!-- Left Navigation Sidebar -->\n <div class=\"dashboard-nav\">\n <div class=\"nav-header\">\n <div class=\"nav-title\">\n <i class=\"fa-solid fa-key\"></i>\n <span>API Keys</span>\n </div>\n </div>\n <div class=\"nav-items\">\n <button class=\"nav-item\" [class.active]=\"MainTab === 'keys'\" (click)=\"switchTab('keys'); closeNav()\">\n <i class=\"fa-solid fa-key\"></i>\n <span class=\"nav-label\">API Keys</span>\n <span class=\"nav-badge\">{{TotalKeys}}</span>\n </button>\n <button class=\"nav-item\" [class.active]=\"MainTab === 'applications'\" (click)=\"switchTab('applications'); closeNav()\">\n <i class=\"fa-solid fa-cube\"></i>\n <span class=\"nav-label\">Applications</span>\n <span class=\"nav-badge\">{{ApplicationCount}}</span>\n </button>\n <button class=\"nav-item\" [class.active]=\"MainTab === 'scopes'\" (click)=\"switchTab('scopes'); closeNav()\">\n <i class=\"fa-solid fa-shield-halved\"></i>\n <span class=\"nav-label\">Scopes</span>\n <span class=\"nav-badge\">{{ScopeCount}}</span>\n </button>\n <button class=\"nav-item\" [class.active]=\"MainTab === 'usage'\" (click)=\"switchTab('usage'); closeNav()\">\n <i class=\"fa-solid fa-chart-line\"></i>\n <span class=\"nav-label\">Usage Analytics</span>\n </button>\n </div>\n </div>\n\n <!-- Main Content Area -->\n <div class=\"dashboard-content\">\n <div class=\"content-wrapper\">\n <!-- Keys Tab Content -->\n <ng-container *ngIf=\"MainTab === 'keys'\">\n <!-- Overview View -->\n <ng-container *ngIf=\"CurrentView === 'overview'\">\n <!-- Header with Actions -->\n <div class=\"overview-header\">\n <div class=\"header-left\">\n <h2 class=\"overview-title\">API Keys Management</h2>\n <p class=\"overview-subtitle\">Manage API keys for external integrations and services</p>\n </div>\n <div class=\"header-actions\">\n <button class=\"btn-refresh\" (click)=\"refresh()\" title=\"Refresh\">\n <i class=\"fa-solid fa-refresh\"></i>\n </button>\n <button class=\"btn-primary\" *ngIf=\"UserCanCreateKeys\" (click)=\"openCreateDialog()\">\n <i class=\"fa-solid fa-plus\"></i>\n <span>Generate New Key</span>\n </button>\n </div>\n </div>\n\n <!-- Health Score Banner -->\n <div class=\"health-banner\" [ngClass]=\"getHealthClass()\">\n <div class=\"health-score-container\">\n <div class=\"health-score-ring\">\n <svg viewBox=\"0 0 36 36\" class=\"circular-chart\">\n <path class=\"circle-bg\"\n d=\"M18 2.0845\n a 15.9155 15.9155 0 0 1 0 31.831\n a 15.9155 15.9155 0 0 1 0 -31.831\"\n />\n <path class=\"circle\"\n [attr.stroke-dasharray]=\"getHealthScore() + ', 100'\"\n d=\"M18 2.0845\n a 15.9155 15.9155 0 0 1 0 31.831\n a 15.9155 15.9155 0 0 1 0 -31.831\"\n />\n </svg>\n <div class=\"health-score-value\">{{getHealthScore()}}</div>\n </div>\n </div>\n <div class=\"health-info\">\n <div class=\"health-label\">{{getHealthLabel()}}</div>\n <div class=\"health-details\">\n <span *ngIf=\"ExpiredKeys > 0\" class=\"health-alert\" (click)=\"showListView('expired')\">\n <i class=\"fa-solid fa-circle-exclamation\"></i>\n {{ExpiredKeys}} expired\n </span>\n <span *ngIf=\"ExpiringSoonCount > 0\" class=\"health-warning-text\" (click)=\"showListView('expiring')\">\n <i class=\"fa-solid fa-clock\"></i>\n {{ExpiringSoonCount}} expiring soon\n </span>\n <span *ngIf=\"NeverUsedKeys > 0\" class=\"health-info-text\" (click)=\"showListView('never-used')\">\n <i class=\"fa-solid fa-question-circle\"></i>\n {{NeverUsedKeys}} never used\n </span>\n <span *ngIf=\"ExpiredKeys === 0 && ExpiringSoonCount === 0 && NeverUsedKeys === 0\" class=\"health-ok\">\n <i class=\"fa-solid fa-check-circle\"></i>\n All keys healthy\n </span>\n </div>\n </div>\n </div>\n\n <!-- KPI Cards Row -->\n <div class=\"kpi-row\">\n <div class=\"kpi-card clickable\" (click)=\"showListView('all')\">\n <div class=\"kpi-icon\">\n <i class=\"fa-solid fa-key\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">{{TotalKeys}}</div>\n <div class=\"kpi-label\">Total Keys</div>\n </div>\n <div class=\"kpi-trend\">\n <i class=\"fa-solid fa-arrow-right\"></i>\n </div>\n </div>\n\n <div class=\"kpi-card active clickable\" (click)=\"showListView('active')\">\n <div class=\"kpi-icon\">\n <i class=\"fa-solid fa-check-circle\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">{{ActiveKeys}}</div>\n <div class=\"kpi-label\">Active</div>\n </div>\n <div class=\"kpi-trend success\">\n <span class=\"percentage\">{{TotalKeys > 0 ? (ActiveKeys / TotalKeys * 100).toFixed(0) : 100}}%</span>\n </div>\n </div>\n\n <div class=\"kpi-card clickable\" [class.warning]=\"ExpiringSoonCount > 0\" (click)=\"showListView('expiring')\">\n <div class=\"kpi-icon\">\n <i class=\"fa-solid fa-clock\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">{{ExpiringSoonCount}}</div>\n <div class=\"kpi-label\">Expiring Soon</div>\n </div>\n <div class=\"kpi-trend warning\" *ngIf=\"ExpiringSoonCount > 0\">\n <i class=\"fa-solid fa-arrow-right\"></i>\n </div>\n </div>\n\n <div class=\"kpi-card clickable\" [class.danger]=\"RevokedKeys > 0\" (click)=\"showListView('revoked')\">\n <div class=\"kpi-icon\">\n <i class=\"fa-solid fa-ban\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">{{RevokedKeys}}</div>\n <div class=\"kpi-label\">Revoked</div>\n </div>\n </div>\n\n <div class=\"kpi-card clickable\" (click)=\"switchTab('scopes')\">\n <div class=\"kpi-icon\">\n <i class=\"fa-solid fa-shield-halved\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">{{ScopeStats.length}}</div>\n <div class=\"kpi-label\">Scope Categories</div>\n </div>\n </div>\n </div>\n\n <!-- Content Grid -->\n <div class=\"content-grid\">\n <!-- Recently Used Keys -->\n <div class=\"panel keys-panel\">\n <div class=\"panel-header\">\n <div class=\"panel-title\">\n <i class=\"fa-solid fa-key\"></i>\n <span>Recently Used Keys</span>\n </div>\n <button class=\"panel-action\" (click)=\"showListView('all')\">\n View All <i class=\"fa-solid fa-arrow-right\"></i>\n </button>\n </div>\n <div class=\"panel-body\">\n <div class=\"key-list\" *ngIf=\"TopUsedKeys.length > 0\">\n <div class=\"key-item\" *ngFor=\"let key of TopUsedKeys\" (click)=\"openEditPanel(key)\">\n <div class=\"key-icon\" [class.active]=\"key.Status === 'Active'\">\n <i class=\"fa-solid fa-key\"></i>\n </div>\n <div class=\"key-info\">\n <div class=\"key-label\">{{key.Label}}</div>\n <div class=\"key-meta\">\n <span class=\"key-user\">{{key.User}}</span>\n <span class=\"key-hash\">...{{key.Hash.slice(-8)}}</span>\n </div>\n </div>\n <div class=\"key-status\">\n <div class=\"last-used\">{{formatDate(key.LastUsedAt)}}</div>\n <div class=\"expiration\" [ngClass]=\"getExpirationClass(key)\">\n {{formatExpiration(key.ExpiresAt)}}\n </div>\n </div>\n </div>\n </div>\n <div class=\"empty-state\" *ngIf=\"TopUsedKeys.length === 0\">\n <i class=\"fa-solid fa-key\"></i>\n <span>No active keys with recent usage</span>\n </div>\n </div>\n </div>\n\n <!-- Scope Categories -->\n <div class=\"panel scope-panel\">\n <div class=\"panel-header\">\n <div class=\"panel-title\">\n <i class=\"fa-solid fa-shield-halved\"></i>\n <span>Permission Scopes</span>\n </div>\n <span class=\"panel-subtitle\">Available scope categories</span>\n </div>\n <div class=\"panel-body\">\n <div class=\"scope-chart\" *ngIf=\"ScopeStats.length > 0\">\n <!-- Visual Donut Chart -->\n <div class=\"donut-chart-container\">\n <svg viewBox=\"0 0 100 100\" class=\"donut-chart\">\n <circle cx=\"50\" cy=\"50\" r=\"40\" fill=\"none\" stroke=\"#e5e7eb\" stroke-width=\"12\"/>\n <ng-container *ngFor=\"let stat of ScopeStats; let i = index\">\n <circle\n cx=\"50\" cy=\"50\" r=\"40\"\n fill=\"none\"\n [attr.stroke]=\"stat.color\"\n stroke-width=\"12\"\n [attr.stroke-dasharray]=\"stat.percentage * 2.51 + ' ' + (251 - stat.percentage * 2.51)\"\n [attr.stroke-dashoffset]=\"getDonutOffset(i)\"\n class=\"donut-segment\"\n (click)=\"onScopeClick(stat)\"\n />\n </ng-container>\n </svg>\n <div class=\"donut-center\">\n <div class=\"donut-total\">{{ScopeStats.length}}</div>\n <div class=\"donut-label\">Categories</div>\n </div>\n </div>\n <!-- Legend -->\n <div class=\"scope-legend\">\n <div class=\"legend-item\" *ngFor=\"let stat of ScopeStats\" (click)=\"onScopeClick(stat)\">\n <div class=\"legend-color\" [style.backgroundColor]=\"stat.color\"></div>\n <div class=\"legend-info\">\n <div class=\"legend-name\">\n <i [class]=\"stat.iconClass\"></i>\n {{stat.category}}\n </div>\n <div class=\"legend-value\">{{stat.count}} scopes</div>\n </div>\n <i class=\"fa-solid fa-chevron-right legend-arrow\"></i>\n </div>\n </div>\n </div>\n <div class=\"empty-state\" *ngIf=\"ScopeStats.length === 0\">\n <i class=\"fa-solid fa-shield-halved\"></i>\n <span>No scopes configured</span>\n </div>\n </div>\n </div>\n\n <!-- Recent Activity -->\n <div class=\"panel activity-panel\">\n <div class=\"panel-header\">\n <div class=\"panel-title\">\n <i class=\"fa-solid fa-clock-rotate-left\"></i>\n <span>Recent Activity</span>\n </div>\n </div>\n <div class=\"panel-body\">\n <div class=\"activity-list\" *ngIf=\"RecentActivity.length > 0\">\n <div class=\"activity-item\" *ngFor=\"let activity of RecentActivity\" (click)=\"onActivityClick(activity)\">\n <div class=\"activity-icon\" [ngClass]=\"getActionClass(activity.action)\">\n <i [class]=\"getActionIcon(activity.action)\"></i>\n </div>\n <div class=\"activity-info\">\n <div class=\"activity-name\">{{activity.keyLabel}}</div>\n <div class=\"activity-meta\">\n <span class=\"activity-action\">{{activity.action}}</span>\n <span class=\"activity-user\" *ngIf=\"activity.user\">by {{activity.user}}</span>\n </div>\n </div>\n <div class=\"activity-time\">\n {{formatDate(activity.date)}}\n </div>\n </div>\n </div>\n <div class=\"empty-state\" *ngIf=\"RecentActivity.length === 0\">\n <i class=\"fa-solid fa-inbox\"></i>\n <span>No recent activity</span>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Quick Actions -->\n <div class=\"quick-actions\" *ngIf=\"UserCanCreateKeys\">\n <div class=\"quick-actions-title\">Quick Actions</div>\n <div class=\"quick-actions-grid\">\n <button class=\"quick-action\" (click)=\"openCreateDialog()\">\n <i class=\"fa-solid fa-plus\"></i>\n <span>Generate Key</span>\n </button>\n <button class=\"quick-action\" (click)=\"showListView('all')\">\n <i class=\"fa-solid fa-list\"></i>\n <span>View All Keys</span>\n </button>\n <button class=\"quick-action\" (click)=\"showListView('expiring')\">\n <i class=\"fa-solid fa-clock\"></i>\n <span>Expiring Keys</span>\n </button>\n <button class=\"quick-action\" (click)=\"showListView('never-used')\">\n <i class=\"fa-solid fa-question-circle\"></i>\n <span>Never Used</span>\n </button>\n </div>\n </div>\n\n <!-- Security Notice -->\n <div class=\"security-notice\">\n <i class=\"fa-solid fa-shield-check\"></i>\n <div class=\"notice-content\">\n <strong>Security Best Practices:</strong>\n API keys should be rotated regularly and revoked when no longer needed.\n Keys are hashed and stored securely - the raw key is only shown once at creation time.\n All API key usage is logged for audit purposes.\n </div>\n </div>\n </ng-container>\n\n <!-- List View -->\n <ng-container *ngIf=\"CurrentView === 'list'\">\n <div class=\"list-view-header\">\n <button class=\"back-btn\" (click)=\"showOverview()\">\n <i class=\"fa-solid fa-arrow-left\"></i>\n Back to Overview\n </button>\n </div>\n <mj-api-key-list #keyList\n [Filter]=\"ListFilter\"\n (KeySelected)=\"onKeySelected($event)\"\n (CreateRequested)=\"openCreateDialog()\">\n </mj-api-key-list>\n </ng-container>\n </ng-container>\n\n <!-- Applications Tab Content -->\n <ng-container *ngIf=\"MainTab === 'applications'\">\n <mj-api-applications-panel\n (ApplicationUpdated)=\"onDataUpdated()\">\n </mj-api-applications-panel>\n </ng-container>\n\n <!-- Scopes Tab Content -->\n <ng-container *ngIf=\"MainTab === 'scopes'\">\n <mj-api-scopes-panel\n (ScopeUpdated)=\"onDataUpdated()\">\n </mj-api-scopes-panel>\n </ng-container>\n\n <!-- Usage Tab Content -->\n <ng-container *ngIf=\"MainTab === 'usage'\">\n <mj-api-usage-panel></mj-api-usage-panel>\n </ng-container>\n </div><!-- /.content-wrapper -->\n </div><!-- /.dashboard-content -->\n\n <!-- Mobile Navigation Toggle -->\n <button class=\"mobile-nav-toggle\" (click)=\"toggleNav()\">\n <i class=\"fa-solid\" [class.fa-bars]=\"!NavOpen\" [class.fa-times]=\"NavOpen\"></i>\n </button>\n\n <!-- Mobile Navigation Overlay -->\n <div class=\"mobile-nav-overlay\" (click)=\"closeNav()\"></div>\n </ng-container>\n\n <!-- Create Dialog -->\n <mj-api-key-create-dialog\n [Visible]=\"ShowCreateDialog\"\n (Created)=\"onKeyCreated($event)\"\n (Closed)=\"onCreateDialogClosed()\">\n </mj-api-key-create-dialog>\n\n <!-- Edit Panel -->\n <mj-api-key-edit-panel\n [Visible]=\"ShowEditPanel\"\n [KeyId]=\"SelectedKeyId\"\n (Updated)=\"onKeyUpdated()\"\n (Revoked)=\"onKeyRevoked()\"\n (Closed)=\"onEditPanelClosed()\">\n </mj-api-key-edit-panel>\n</div>\n", styles: ["/* Main Dashboard Container */\n.api-keys-dashboard {\n display: flex;\n height: 100%;\n position: relative;\n overflow: hidden;\n}\n\n.api-keys-dashboard.panel-open .dashboard-content {\n overflow: hidden;\n}\n\n/* Left Navigation Sidebar */\n.dashboard-nav {\n width: 220px;\n background: var(--card-background, #ffffff);\n border-right: 1px solid var(--border-color, #e5e7eb);\n display: flex;\n flex-direction: column;\n flex-shrink: 0;\n}\n\n.nav-header {\n padding: 20px;\n border-bottom: 1px solid var(--border-color, #e5e7eb);\n}\n\n.nav-title {\n display: flex;\n align-items: center;\n gap: 10px;\n font-weight: 700;\n font-size: 16px;\n color: var(--text-primary, #1f2937);\n}\n\n.nav-title i {\n color: #f59e0b;\n font-size: 18px;\n}\n\n.nav-items {\n flex: 1;\n padding: 12px;\n overflow-y: auto;\n}\n\n.nav-item {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px 16px;\n margin-bottom: 4px;\n background: transparent;\n border: none;\n border-radius: 8px;\n font-size: 14px;\n font-weight: 500;\n color: var(--text-secondary, #6b7280);\n cursor: pointer;\n transition: all 0.2s ease;\n width: 100%;\n text-align: left;\n}\n\n.nav-item:hover {\n background: var(--item-hover, #f3f4f6);\n color: var(--text-primary, #1f2937);\n}\n\n.nav-item.active {\n background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%);\n color: white;\n box-shadow: 0 2px 8px rgba(245, 158, 11, 0.3);\n}\n\n.nav-item i {\n font-size: 16px;\n width: 20px;\n text-align: center;\n}\n\n.nav-item .nav-label {\n flex: 1;\n}\n\n.nav-badge {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 22px;\n height: 20px;\n padding: 0 6px;\n background: rgba(0, 0, 0, 0.1);\n border-radius: 10px;\n font-size: 11px;\n font-weight: 600;\n}\n\n.nav-item.active .nav-badge {\n background: rgba(255, 255, 255, 0.25);\n}\n\n/* Dashboard Content Area */\n.dashboard-content {\n flex: 1;\n display: flex;\n flex-direction: column;\n overflow-y: auto;\n min-width: 0;\n}\n\n.content-wrapper {\n flex: 1;\n padding: 24px;\n overflow-y: auto;\n}\n\n/* List View Header */\n.list-view-header {\n margin-bottom: 16px;\n}\n\n.back-btn {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n padding: 8px 16px;\n background: var(--card-background, #ffffff);\n border: 1px solid var(--border-color, #e5e7eb);\n border-radius: 8px;\n font-size: 14px;\n font-weight: 500;\n color: var(--text-secondary, #6b7280);\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.back-btn:hover {\n background: var(--item-hover, #f3f4f6);\n color: var(--text-primary, #1f2937);\n}\n\n/* Header */\n.overview-header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 24px;\n}\n\n.header-left {\n flex: 1;\n}\n\n.overview-title {\n font-size: 24px;\n font-weight: 700;\n color: var(--text-primary, #1f2937);\n margin: 0 0 4px 0;\n}\n\n.overview-subtitle {\n font-size: 14px;\n color: var(--text-secondary, #6b7280);\n margin: 0;\n}\n\n.header-actions {\n display: flex;\n gap: 12px;\n}\n\n.btn-refresh {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 40px;\n height: 40px;\n background: var(--card-background, #ffffff);\n border: 1px solid var(--border-color, #e5e7eb);\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.btn-refresh:hover {\n background: var(--item-hover, #f3f4f6);\n}\n\n.btn-refresh i {\n color: var(--text-secondary, #6b7280);\n}\n\n.btn-primary {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 20px;\n background: linear-gradient(135deg, #f59e0b 0%, #d97706 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-primary:hover {\n transform: translateY(-1px);\n box-shadow: 0 4px 12px rgba(245, 158, 11, 0.4);\n}\n\n/* Health Banner */\n.health-banner {\n display: flex;\n align-items: center;\n padding: 20px 24px;\n background: linear-gradient(135deg, #ecfdf5 0%, #d1fae5 100%);\n border: 1px solid #a7f3d0;\n border-radius: 16px;\n margin-bottom: 24px;\n}\n\n.health-banner.health-warning {\n background: linear-gradient(135deg, #fffbeb 0%, #fef3c7 100%);\n border-color: #fcd34d;\n}\n\n.health-banner.health-critical {\n background: linear-gradient(135deg, #fef2f2 0%, #fee2e2 100%);\n border-color: #fca5a5;\n}\n\n.health-score-container {\n margin-right: 24px;\n}\n\n.health-score-ring {\n position: relative;\n width: 80px;\n height: 80px;\n}\n\n.circular-chart {\n display: block;\n margin: 0 auto;\n max-height: 80px;\n transform: rotate(-90deg);\n}\n\n.circle-bg {\n fill: none;\n stroke: #e5e7eb;\n stroke-width: 3.8;\n}\n\n.circle {\n fill: none;\n stroke-width: 3.8;\n stroke-linecap: round;\n stroke: #10b981;\n animation: progress 1s ease-out forwards;\n}\n\n.health-banner.health-warning .circle {\n stroke: #f59e0b;\n}\n\n.health-banner.health-critical .circle {\n stroke: #ef4444;\n}\n\n@keyframes progress {\n 0% {\n stroke-dasharray: 0 100;\n }\n}\n\n.health-score-value {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n font-size: 20px;\n font-weight: 700;\n color: var(--text-primary, #1f2937);\n}\n\n.health-info {\n flex: 1;\n}\n\n.health-label {\n font-size: 18px;\n font-weight: 700;\n color: #059669;\n margin-bottom: 4px;\n}\n\n.health-banner.health-warning .health-label {\n color: #d97706;\n}\n\n.health-banner.health-critical .health-label {\n color: #dc2626;\n}\n\n.health-details {\n display: flex;\n gap: 16px;\n flex-wrap: wrap;\n}\n\n.health-alert {\n display: flex;\n align-items: center;\n gap: 6px;\n color: #dc2626;\n font-weight: 500;\n font-size: 14px;\n cursor: pointer;\n}\n\n.health-alert:hover {\n text-decoration: underline;\n}\n\n.health-warning-text {\n display: flex;\n align-items: center;\n gap: 6px;\n color: #d97706;\n font-weight: 500;\n font-size: 14px;\n cursor: pointer;\n}\n\n.health-warning-text:hover {\n text-decoration: underline;\n}\n\n.health-info-text {\n display: flex;\n align-items: center;\n gap: 6px;\n color: #6b7280;\n font-weight: 500;\n font-size: 14px;\n cursor: pointer;\n}\n\n.health-info-text:hover {\n text-decoration: underline;\n}\n\n.health-ok {\n display: flex;\n align-items: center;\n gap: 6px;\n color: #059669;\n font-weight: 500;\n font-size: 14px;\n}\n\n/* KPI Cards */\n.kpi-row {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));\n gap: 16px;\n margin-bottom: 24px;\n}\n\n.kpi-card {\n display: flex;\n align-items: center;\n padding: 16px 20px;\n background: var(--card-background, #ffffff);\n border-radius: 12px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);\n transition: transform 0.2s ease, box-shadow 0.2s ease;\n}\n\n.kpi-card.clickable {\n cursor: pointer;\n}\n\n.kpi-card.clickable:hover {\n transform: translateY(-2px);\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);\n}\n\n.kpi-card.active .kpi-icon {\n background: linear-gradient(135deg, #10b981 0%, #059669 100%);\n}\n\n.kpi-card.warning .kpi-icon {\n background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%);\n}\n\n.kpi-card.danger .kpi-icon {\n background: linear-gradient(135deg, #ef4444 0%, #dc2626 100%);\n}\n\n.kpi-icon {\n width: 48px;\n height: 48px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%);\n border-radius: 10px;\n margin-right: 14px;\n flex-shrink: 0;\n}\n\n.kpi-icon i {\n font-size: 20px;\n color: white;\n}\n\n.kpi-content {\n flex: 1;\n min-width: 0;\n}\n\n.kpi-value {\n font-size: 24px;\n font-weight: 700;\n color: var(--text-primary, #1f2937);\n line-height: 1.2;\n}\n\n.kpi-label {\n font-size: 12px;\n color: var(--text-secondary, #6b7280);\n margin-top: 2px;\n white-space: nowrap;\n}\n\n.kpi-trend {\n display: flex;\n align-items: center;\n margin-left: 8px;\n color: var(--text-tertiary, #9ca3af);\n}\n\n.kpi-trend.success {\n color: #10b981;\n}\n\n.kpi-trend.warning {\n color: #f59e0b;\n}\n\n.kpi-trend .percentage {\n font-size: 12px;\n font-weight: 600;\n}\n\n/* Content Grid */\n.content-grid {\n display: grid;\n grid-template-columns: 1fr 1fr;\n grid-template-rows: auto auto;\n gap: 20px;\n margin-bottom: 24px;\n}\n\n.keys-panel {\n grid-row: span 1;\n}\n\n.scope-panel {\n grid-row: span 1;\n}\n\n.activity-panel {\n grid-column: span 2;\n}\n\n.panel {\n background: var(--card-background, #ffffff);\n border-radius: 12px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);\n overflow: hidden;\n display: flex;\n flex-direction: column;\n}\n\n.panel-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px 20px;\n background: var(--header-background, #f9fafb);\n border-bottom: 1px solid var(--border-color, #e5e7eb);\n}\n\n.panel-title {\n display: flex;\n align-items: center;\n gap: 10px;\n font-weight: 600;\n font-size: 14px;\n color: var(--text-primary, #1f2937);\n}\n\n.panel-title i {\n color: #f59e0b;\n}\n\n.panel-subtitle {\n font-size: 12px;\n color: var(--text-tertiary, #9ca3af);\n}\n\n.panel-action {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 6px 12px;\n background: transparent;\n border: 1px solid var(--border-color, #e5e7eb);\n border-radius: 6px;\n font-size: 12px;\n font-weight: 500;\n color: var(--text-secondary, #6b7280);\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.panel-action:hover {\n background: #f59e0b;\n border-color: #f59e0b;\n color: white;\n}\n\n.panel-body {\n padding: 20px;\n flex: 1;\n overflow-y: auto;\n}\n\n/* Key List */\n.key-list {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n.key-item {\n display: flex;\n align-items: center;\n padding: 14px 16px;\n background: var(--item-background, #f9fafb);\n border-radius: 10px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.key-item:hover {\n background: var(--item-hover, #f3f4f6);\n transform: translateX(4px);\n}\n\n.key-icon {\n width: 40px;\n height: 40px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: linear-gradient(135deg, #6b7280 0%, #4b5563 100%);\n border-radius: 8px;\n margin-right: 14px;\n flex-shrink: 0;\n}\n\n.key-icon.active {\n background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%);\n}\n\n.key-icon i {\n font-size: 16px;\n color: white;\n}\n\n.key-info {\n flex: 1;\n min-width: 0;\n}\n\n.key-label {\n font-size: 14px;\n font-weight: 600;\n color: var(--text-primary, #1f2937);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.key-meta {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-top: 2px;\n font-size: 12px;\n color: var(--text-secondary, #6b7280);\n}\n\n.key-hash {\n font-family: monospace;\n background: var(--tag-background, #e5e7eb);\n padding: 2px 6px;\n border-radius: 4px;\n font-size: 11px;\n}\n\n.key-status {\n display: flex;\n flex-direction: column;\n align-items: flex-end;\n gap: 4px;\n margin-left: 16px;\n}\n\n.last-used {\n font-size: 12px;\n color: var(--text-secondary, #6b7280);\n}\n\n.expiration {\n font-size: 11px;\n color: var(--text-tertiary, #9ca3af);\n}\n\n.expiration.expiring-soon {\n color: #f59e0b;\n font-weight: 500;\n}\n\n.expiration.expiring-critical {\n color: #ef4444;\n font-weight: 500;\n}\n\n.expiration.expired {\n color: #ef4444;\n font-weight: 600;\n}\n\n/* Scope Chart */\n.scope-chart {\n display: flex;\n flex-direction: column;\n gap: 24px;\n height: 100%;\n}\n\n.donut-chart-container {\n position: relative;\n width: 160px;\n height: 160px;\n margin: 0 auto;\n}\n\n.donut-chart {\n width: 100%;\n height: 100%;\n transform: rotate(-90deg);\n}\n\n.donut-segment {\n cursor: pointer;\n transition: opacity 0.2s ease;\n}\n\n.donut-segment:hover {\n opacity: 0.8;\n}\n\n.donut-center {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n text-align: center;\n}\n\n.donut-total {\n font-size: 28px;\n font-weight: 700;\n color: var(--text-primary, #1f2937);\n}\n\n.donut-label {\n font-size: 11px;\n color: var(--text-secondary, #6b7280);\n}\n\n/* Scope Legend */\n.scope-legend {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.legend-item {\n display: flex;\n align-items: center;\n padding: 10px 12px;\n background: var(--item-background, #f9fafb);\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.legend-item:hover {\n background: var(--item-hover, #f3f4f6);\n transform: translateX(4px);\n}\n\n.legend-color {\n width: 12px;\n height: 12px;\n border-radius: 4px;\n margin-right: 12px;\n flex-shrink: 0;\n}\n\n.legend-info {\n flex: 1;\n}\n\n.legend-name {\n font-size: 14px;\n font-weight: 500;\n color: var(--text-primary, #1f2937);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.legend-name i {\n font-size: 12px;\n color: var(--text-secondary, #6b7280);\n}\n\n.legend-value {\n font-size: 12px;\n color: var(--text-secondary, #6b7280);\n}\n\n.legend-arrow {\n color: var(--text-tertiary, #9ca3af);\n font-size: 10px;\n}\n\n/* Activity List */\n.activity-list {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));\n gap: 12px;\n}\n\n.activity-item {\n display: flex;\n align-items: center;\n padding: 12px 14px;\n background: var(--item-background, #f9fafb);\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.activity-item:hover {\n background: var(--item-hover, #f3f4f6);\n}\n\n.activity-icon {\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--icon-background, #fef3c7);\n border-radius: 6px;\n margin-right: 12px;\n flex-shrink: 0;\n}\n\n.activity-icon i {\n font-size: 12px;\n color: #f59e0b;\n}\n\n.activity-icon.action-created {\n background: #d1fae5;\n}\n\n.activity-icon.action-created i {\n color: #059669;\n}\n\n.activity-icon.action-updated {\n background: #e0e7ff;\n}\n\n.activity-icon.action-updated i {\n color: #6366f1;\n}\n\n.activity-icon.action-revoked {\n background: #fee2e2;\n}\n\n.activity-icon.action-revoked i {\n color: #dc2626;\n}\n\n.activity-icon.action-used {\n background: #fef3c7;\n}\n\n.activity-icon.action-used i {\n color: #d97706;\n}\n\n.activity-icon.action-extended {\n background: #dbeafe;\n}\n\n.activity-icon.action-extended i {\n color: #3b82f6;\n}\n\n.activity-info {\n flex: 1;\n min-width: 0;\n}\n\n.activity-name {\n font-weight: 500;\n font-size: 13px;\n color: var(--text-primary, #1f2937);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.activity-meta {\n display: flex;\n align-items: center;\n gap: 6px;\n margin-top: 2px;\n font-size: 11px;\n color: var(--text-secondary, #6b7280);\n}\n\n.activity-action {\n font-weight: 500;\n text-transform: capitalize;\n}\n\n.activity-time {\n font-size: 11px;\n color: var(--text-tertiary, #9ca3af);\n white-space: nowrap;\n}\n\n/* Quick Actions */\n.quick-actions {\n margin-bottom: 24px;\n}\n\n.quick-actions-title {\n font-size: 14px;\n font-weight: 600;\n color: var(--text-primary, #1f2937);\n margin-bottom: 12px;\n}\n\n.quick-actions-grid {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));\n gap: 12px;\n}\n\n.quick-action {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 8px;\n padding: 16px;\n background: var(--card-background, #ffffff);\n border: 1px solid var(--border-color, #e5e7eb);\n border-radius: 10px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.quick-action:hover {\n border-color: #f59e0b;\n background: #fffbeb;\n transform: translateY(-2px);\n}\n\n.quick-action i {\n font-size: 20px;\n color: #f59e0b;\n}\n\n.quick-action span {\n font-size: 12px;\n font-weight: 500;\n color: var(--text-secondary, #6b7280);\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: 32px;\n color: var(--text-secondary, #6b7280);\n text-align: center;\n}\n\n.empty-state i {\n font-size: 32px;\n margin-bottom: 12px;\n opacity: 0.5;\n}\n\n/* Security Notice */\n.security-notice {\n display: flex;\n align-items: flex-start;\n padding: 16px 20px;\n background: linear-gradient(135deg, #fffbeb 0%, #fef3c7 100%);\n border-radius: 12px;\n border: 1px solid #fcd34d;\n}\n\n.security-notice i {\n font-size: 20px;\n color: #f59e0b;\n margin-right: 12px;\n margin-top: 2px;\n}\n\n.notice-content {\n font-size: 13px;\n color: #92400e;\n line-height: 1.5;\n}\n\n.notice-content strong {\n font-weight: 600;\n}\n\n/* Mobile Navigation Toggle */\n.mobile-nav-toggle {\n display: none;\n position: fixed;\n bottom: 20px;\n right: 20px;\n width: 56px;\n height: 56px;\n background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%);\n border: none;\n border-radius: 50%;\n color: white;\n font-size: 24px;\n box-shadow: 0 4px 16px rgba(245, 158, 11, 0.4);\n cursor: pointer;\n z-index: 50;\n transition: transform 0.2s ease;\n}\n\n.mobile-nav-toggle:hover {\n transform: scale(1.05);\n}\n\n/* Mobile Nav Overlay */\n.mobile-nav-overlay {\n display: none;\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n z-index: 90;\n}\n\n/* ========================================\n Responsive Styles\n ======================================== */\n\n/* Tablet */\n@media (max-width: 1024px) {\n .content-grid {\n grid-template-columns: 1fr;\n }\n\n .activity-panel {\n grid-column: span 1;\n }\n\n .scope-chart {\n flex-direction: row;\n align-items: center;\n }\n\n .donut-chart-container {\n width: 140px;\n height: 140px;\n }\n\n .scope-legend {\n flex: 1;\n }\n\n .dashboard-nav {\n width: 200px;\n }\n}\n\n/* Mobile */\n@media (max-width: 768px) {\n .api-keys-dashboard {\n flex-direction: column;\n }\n\n .dashboard-nav {\n position: fixed;\n top: 0;\n left: -280px;\n width: 280px;\n height: 100%;\n z-index: 100;\n transition: left 0.3s ease;\n box-shadow: 4px 0 20px rgba(0, 0, 0, 0.15);\n }\n\n .api-keys-dashboard.nav-open .dashboard-nav {\n left: 0;\n }\n\n .mobile-nav-toggle {\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .mobile-nav-overlay {\n display: block;\n opacity: 0;\n pointer-events: none;\n transition: opacity 0.3s ease;\n }\n\n .api-keys-dashboard.nav-open .mobile-nav-overlay {\n opacity: 1;\n pointer-events: auto;\n }\n\n .dashboard-content {\n width: 100%;\n }\n\n .content-wrapper {\n padding: 16px;\n }\n\n .overview-header {\n flex-direction: column;\n gap: 16px;\n }\n\n .header-actions {\n width: 100%;\n justify-content: flex-end;\n }\n\n .health-banner {\n flex-direction: column;\n text-align: center;\n }\n\n .health-score-container {\n margin-right: 0;\n margin-bottom: 16px;\n }\n\n .kpi-row {\n grid-template-columns: repeat(2, 1fr);\n }\n\n .scope-chart {\n flex-direction: column;\n }\n\n .quick-actions-grid {\n grid-template-columns: repeat(2, 1fr);\n }\n\n .activity-list {\n grid-template-columns: 1fr;\n }\n\n .key-item {\n flex-wrap: wrap;\n }\n\n .key-status {\n width: 100%;\n flex-direction: row;\n justify-content: flex-start;\n margin-left: 54px;\n margin-top: 8px;\n gap: 12px;\n }\n}\n\n/* Small Mobile */\n@media (max-width: 480px) {\n .kpi-row {\n grid-template-columns: 1fr;\n }\n\n .quick-actions-grid {\n grid-template-columns: 1fr;\n }\n\n .kpi-card {\n padding: 12px 16px;\n }\n\n .kpi-icon {\n width: 40px;\n height: 40px;\n }\n\n .kpi-value {\n font-size: 20px;\n }\n\n .overview-title {\n font-size: 20px;\n }\n\n .btn-primary {\n padding: 8px 16px;\n font-size: 13px;\n }\n}\n"] }]
1160
+ }], () => [{ type: i0.ChangeDetectorRef }], { keyListComponent: [{
1161
+ type: ViewChild,
1162
+ args: ['keyList']
1163
+ }] }); })();
1164
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(APIKeysResourceComponent, { className: "APIKeysResourceComponent", filePath: "src/APIKeys/api-keys-resource.component.ts", lineNumber: 56 }); })();
1165
+ //# sourceMappingURL=api-keys-resource.component.js.map