@memberjunction/ng-dashboards 5.35.0 → 5.37.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.
- package/dist/AI/components/agents/agent-configuration.component.js +3 -3
- package/dist/AI/components/agents/agent-configuration.component.js.map +1 -1
- package/dist/AI/components/analytics/ai-analytics-resource.component.d.ts +22 -1
- package/dist/AI/components/analytics/ai-analytics-resource.component.d.ts.map +1 -1
- package/dist/AI/components/analytics/ai-analytics-resource.component.js +157 -137
- package/dist/AI/components/analytics/ai-analytics-resource.component.js.map +1 -1
- package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.d.ts +28 -0
- package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.d.ts.map +1 -1
- package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.js +2075 -2068
- package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.js.map +1 -1
- package/dist/AI/components/models/model-management.component.js +4 -4
- package/dist/AI/components/models/model-management.component.js.map +1 -1
- package/dist/AI/components/prompts/prompt-management.component.js +3 -3
- package/dist/AI/components/prompts/prompt-management.component.js.map +1 -1
- package/dist/AI/components/tags/tags-resource.component.d.ts +15 -0
- package/dist/AI/components/tags/tags-resource.component.d.ts.map +1 -1
- package/dist/AI/components/tags/tags-resource.component.js +1411 -1424
- package/dist/AI/components/tags/tags-resource.component.js.map +1 -1
- package/dist/APIKeys/api-keys-resource.component.d.ts +12 -8
- package/dist/APIKeys/api-keys-resource.component.d.ts.map +1 -1
- package/dist/APIKeys/api-keys-resource.component.js +329 -371
- package/dist/APIKeys/api-keys-resource.component.js.map +1 -1
- package/dist/Actions/components/actions-overview.component.js +137 -142
- package/dist/Actions/components/actions-overview.component.js.map +1 -1
- package/dist/Actions/components/execution-monitoring.component.js +111 -116
- package/dist/Actions/components/execution-monitoring.component.js.map +1 -1
- package/dist/Admin/admin-data-schema.component.js +13 -65
- package/dist/Admin/admin-data-schema.component.js.map +1 -1
- package/dist/Admin/admin-dev-tools-resource.component.js +13 -65
- package/dist/Admin/admin-dev-tools-resource.component.js.map +1 -1
- package/dist/Admin/admin-identity-access.component.js +13 -65
- package/dist/Admin/admin-identity-access.component.js.map +1 -1
- package/dist/Admin/admin-monitoring.component.js +13 -65
- package/dist/Admin/admin-monitoring.component.js.map +1 -1
- package/dist/Admin/base-admin-container.component.d.ts +9 -7
- package/dist/Admin/base-admin-container.component.d.ts.map +1 -1
- package/dist/Admin/base-admin-container.component.js +26 -17
- package/dist/Admin/base-admin-container.component.js.map +1 -1
- package/dist/ApplicationRoles/application-roles-resource.component.js +74 -67
- package/dist/ApplicationRoles/application-roles-resource.component.js.map +1 -1
- package/dist/Communication/communication-new-message-resource.component.d.ts +93 -0
- package/dist/Communication/communication-new-message-resource.component.d.ts.map +1 -0
- package/dist/Communication/communication-new-message-resource.component.js +661 -0
- package/dist/Communication/communication-new-message-resource.component.js.map +1 -0
- package/dist/Credentials/components/credentials-categories-resource.component.js +152 -159
- package/dist/Credentials/components/credentials-categories-resource.component.js.map +1 -1
- package/dist/Credentials/components/credentials-types-resource.component.js +151 -155
- package/dist/Credentials/components/credentials-types-resource.component.js.map +1 -1
- package/dist/DatabaseDesigner/components/database-designer-dashboard.component.js +20 -21
- package/dist/DatabaseDesigner/components/database-designer-dashboard.component.js.map +1 -1
- package/dist/DatabaseDesigner/components/entity-list.component.d.ts +2 -0
- package/dist/DatabaseDesigner/components/entity-list.component.d.ts.map +1 -1
- package/dist/DatabaseDesigner/components/entity-list.component.js +131 -125
- package/dist/DatabaseDesigner/components/entity-list.component.js.map +1 -1
- package/dist/DatabaseDesigner/database-designer-dashboards.module.d.ts +1 -1
- package/dist/DatabaseDesigner/database-designer-dashboards.module.d.ts.map +1 -1
- package/dist/DatabaseDesigner/database-designer-dashboards.module.js +7 -1
- package/dist/DatabaseDesigner/database-designer-dashboards.module.js.map +1 -1
- package/dist/DevTools/app-state-inspector.component.d.ts +5 -0
- package/dist/DevTools/app-state-inspector.component.d.ts.map +1 -1
- package/dist/DevTools/app-state-inspector.component.js +46 -72
- package/dist/DevTools/app-state-inspector.component.js.map +1 -1
- package/dist/DevTools/class-registry.component.js +88 -100
- package/dist/DevTools/class-registry.component.js.map +1 -1
- package/dist/DevTools/event-monitor.component.js +158 -168
- package/dist/DevTools/event-monitor.component.js.map +1 -1
- package/dist/DevTools/graphql-console.component.js +257 -264
- package/dist/DevTools/graphql-console.component.js.map +1 -1
- package/dist/DevTools/layout-inspector.component.d.ts +5 -0
- package/dist/DevTools/layout-inspector.component.d.ts.map +1 -1
- package/dist/DevTools/layout-inspector.component.js +46 -64
- package/dist/DevTools/layout-inspector.component.js.map +1 -1
- package/dist/DevTools/lazy-module-status.component.js +75 -84
- package/dist/DevTools/lazy-module-status.component.js.map +1 -1
- package/dist/DevTools/settings-explorer.component.js +76 -85
- package/dist/DevTools/settings-explorer.component.js.map +1 -1
- package/dist/EntityAdmin/entity-admin-dashboard.component.d.ts +2 -0
- package/dist/EntityAdmin/entity-admin-dashboard.component.d.ts.map +1 -1
- package/dist/EntityAdmin/entity-admin-dashboard.component.js +7 -3
- package/dist/EntityAdmin/entity-admin-dashboard.component.js.map +1 -1
- package/dist/Integration/components/activity/activity.component.js +97 -99
- package/dist/Integration/components/activity/activity.component.js.map +1 -1
- package/dist/Integration/components/connections/connections.component.js +842 -855
- package/dist/Integration/components/connections/connections.component.js.map +1 -1
- package/dist/Integration/components/pipelines/pipelines.component.js +502 -517
- package/dist/Integration/components/pipelines/pipelines.component.js.map +1 -1
- package/dist/Integration/components/schedules/schedules.component.js +78 -89
- package/dist/Integration/components/schedules/schedules.component.js.map +1 -1
- package/dist/KnowledgeHub/components/analytics/analytics-resource.component.d.ts +5 -0
- package/dist/KnowledgeHub/components/analytics/analytics-resource.component.d.ts.map +1 -1
- package/dist/KnowledgeHub/components/analytics/analytics-resource.component.js +1120 -1128
- package/dist/KnowledgeHub/components/analytics/analytics-resource.component.js.map +1 -1
- package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.d.ts +11 -0
- package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.d.ts.map +1 -1
- package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.js +606 -661
- package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.js.map +1 -1
- package/dist/Lists/components/lists-browse-resource.component.d.ts +102 -0
- package/dist/Lists/components/lists-browse-resource.component.d.ts.map +1 -1
- package/dist/Lists/components/lists-browse-resource.component.js +1179 -504
- package/dist/Lists/components/lists-browse-resource.component.js.map +1 -1
- package/dist/Lists/components/lists-operations-resource.component.d.ts +133 -3
- package/dist/Lists/components/lists-operations-resource.component.d.ts.map +1 -1
- package/dist/Lists/components/lists-operations-resource.component.js +1527 -327
- package/dist/Lists/components/lists-operations-resource.component.js.map +1 -1
- package/dist/Lists/components/lists-shared-with-me-resource.component.d.ts +29 -0
- package/dist/Lists/components/lists-shared-with-me-resource.component.d.ts.map +1 -0
- package/dist/Lists/components/lists-shared-with-me-resource.component.js +77 -0
- package/dist/Lists/components/lists-shared-with-me-resource.component.js.map +1 -0
- package/dist/Lists/components/venn-diagram/venn-diagram.component.d.ts +6 -0
- package/dist/Lists/components/venn-diagram/venn-diagram.component.d.ts.map +1 -1
- package/dist/Lists/components/venn-diagram/venn-diagram.component.js +35 -7
- package/dist/Lists/components/venn-diagram/venn-diagram.component.js.map +1 -1
- package/dist/Lists/index.d.ts +1 -0
- package/dist/Lists/index.d.ts.map +1 -1
- package/dist/Lists/index.js +1 -0
- package/dist/Lists/index.js.map +1 -1
- package/dist/Lists/services/list-set-operations.service.d.ts +93 -2
- package/dist/Lists/services/list-set-operations.service.d.ts.map +1 -1
- package/dist/Lists/services/list-set-operations.service.js +236 -10
- package/dist/Lists/services/list-set-operations.service.js.map +1 -1
- package/dist/MCP/mcp-dashboard.component.js +19 -19
- package/dist/MCP/mcp-dashboard.component.js.map +1 -1
- package/dist/Scheduling/scheduling-dashboard.component.js +58 -60
- package/dist/Scheduling/scheduling-dashboard.component.js.map +1 -1
- package/dist/SystemDiagnostics/system-diagnostics.component.d.ts +13 -3
- package/dist/SystemDiagnostics/system-diagnostics.component.d.ts.map +1 -1
- package/dist/SystemDiagnostics/system-diagnostics.component.js +1007 -1252
- package/dist/SystemDiagnostics/system-diagnostics.component.js.map +1 -1
- package/dist/Testing/components/testing-explorer.component.d.ts +31 -6
- package/dist/Testing/components/testing-explorer.component.d.ts.map +1 -1
- package/dist/Testing/components/testing-explorer.component.js +543 -629
- package/dist/Testing/components/testing-explorer.component.js.map +1 -1
- package/dist/Testing/testing-dashboard.component.js +50 -49
- package/dist/Testing/testing-dashboard.component.js.map +1 -1
- package/dist/ai-dashboards.module.d.ts +1 -1
- package/dist/ai-dashboards.module.d.ts.map +1 -1
- package/dist/ai-dashboards.module.js +16 -1
- package/dist/ai-dashboards.module.js.map +1 -1
- package/dist/communication-dashboards.module.d.ts +9 -7
- package/dist/communication-dashboards.module.d.ts.map +1 -1
- package/dist/communication-dashboards.module.js +13 -4
- package/dist/communication-dashboards.module.js.map +1 -1
- package/dist/core-dashboards.module.d.ts +1 -1
- package/dist/core-dashboards.module.d.ts.map +1 -1
- package/dist/core-dashboards.module.js +16 -1
- package/dist/core-dashboards.module.js.map +1 -1
- package/dist/lists-dashboards.module.d.ts +10 -9
- package/dist/lists-dashboards.module.d.ts.map +1 -1
- package/dist/lists-dashboards.module.js +13 -2
- package/dist/lists-dashboards.module.js.map +1 -1
- package/dist/public-api.d.ts +1 -0
- package/dist/public-api.d.ts.map +1 -1
- package/dist/public-api.js +1 -0
- package/dist/public-api.js.map +1 -1
- package/dist/testing-dashboards.module.d.ts +1 -1
- package/dist/testing-dashboards.module.d.ts.map +1 -1
- package/dist/testing-dashboards.module.js +13 -1
- package/dist/testing-dashboards.module.js.map +1 -1
- package/package.json +53 -52
|
@@ -12,31 +12,33 @@ import { APIKeysEngineBase, parseAPIScopeUIConfig } from '@memberjunction/api-ke
|
|
|
12
12
|
import { Subject } from 'rxjs';
|
|
13
13
|
import * as i0 from "@angular/core";
|
|
14
14
|
import * as i1 from "@angular/common";
|
|
15
|
-
import * as i2 from "@memberjunction/ng-
|
|
16
|
-
import * as i3 from "
|
|
17
|
-
import * as i4 from "./api-key-
|
|
18
|
-
import * as i5 from "./api-key-
|
|
19
|
-
import * as i6 from "./api-
|
|
20
|
-
import * as i7 from "./api-
|
|
21
|
-
import * as i8 from "./api-
|
|
15
|
+
import * as i2 from "@memberjunction/ng-ui-components";
|
|
16
|
+
import * as i3 from "@memberjunction/ng-shared-generic";
|
|
17
|
+
import * as i4 from "./api-key-create-dialog.component";
|
|
18
|
+
import * as i5 from "./api-key-edit-panel.component";
|
|
19
|
+
import * as i6 from "./api-key-list.component";
|
|
20
|
+
import * as i7 from "./api-applications-panel.component";
|
|
21
|
+
import * as i8 from "./api-scopes-panel.component";
|
|
22
|
+
import * as i9 from "./api-usage-panel.component";
|
|
22
23
|
const _c0 = ["keyList"];
|
|
23
|
-
function
|
|
24
|
-
i0.ɵɵ
|
|
24
|
+
function APIKeysResourceComponent_Conditional_5_Template(rf, ctx) { if (rf & 1) {
|
|
25
|
+
const _r1 = i0.ɵɵgetCurrentView();
|
|
26
|
+
i0.ɵɵelementStart(0, "button", 10);
|
|
27
|
+
i0.ɵɵlistener("click", function APIKeysResourceComponent_Conditional_5_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.openCreateDialog()); });
|
|
28
|
+
i0.ɵɵelement(1, "i", 11);
|
|
29
|
+
i0.ɵɵtext(2, " Generate New Key ");
|
|
30
|
+
i0.ɵɵelementEnd();
|
|
25
31
|
} }
|
|
26
|
-
function
|
|
27
|
-
|
|
28
|
-
i0.ɵɵ
|
|
29
|
-
i0.ɵɵ
|
|
30
|
-
i0.ɵɵelement(1, "i", 77);
|
|
31
|
-
i0.ɵɵelementStart(2, "span");
|
|
32
|
-
i0.ɵɵtext(3, "Generate New Key");
|
|
33
|
-
i0.ɵɵelementEnd()();
|
|
32
|
+
function APIKeysResourceComponent_Conditional_6_Template(rf, ctx) { if (rf & 1) {
|
|
33
|
+
i0.ɵɵelementStart(0, "div", 7);
|
|
34
|
+
i0.ɵɵelement(1, "mj-loading", 12);
|
|
35
|
+
i0.ɵɵelementEnd();
|
|
34
36
|
} }
|
|
35
|
-
function
|
|
36
|
-
const
|
|
37
|
-
i0.ɵɵelementStart(0, "span",
|
|
38
|
-
i0.ɵɵlistener("click", function
|
|
39
|
-
i0.ɵɵelement(1, "i",
|
|
37
|
+
function APIKeysResourceComponent_Conditional_7_Conditional_1_Conditional_0_Conditional_12_Template(rf, ctx) { if (rf & 1) {
|
|
38
|
+
const _r4 = i0.ɵɵgetCurrentView();
|
|
39
|
+
i0.ɵɵelementStart(0, "span", 62);
|
|
40
|
+
i0.ɵɵlistener("click", function APIKeysResourceComponent_Conditional_7_Conditional_1_Conditional_0_Conditional_12_Template_span_click_0_listener() { i0.ɵɵrestoreView(_r4); const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.showListView("expired")); });
|
|
41
|
+
i0.ɵɵelement(1, "i", 63);
|
|
40
42
|
i0.ɵɵtext(2);
|
|
41
43
|
i0.ɵɵelementEnd();
|
|
42
44
|
} if (rf & 2) {
|
|
@@ -44,11 +46,11 @@ function APIKeysResourceComponent_Conditional_2_Conditional_31_Conditional_0_Con
|
|
|
44
46
|
i0.ɵɵadvance(2);
|
|
45
47
|
i0.ɵɵtextInterpolate1(" ", ctx_r1.ExpiredKeys, " expired ");
|
|
46
48
|
} }
|
|
47
|
-
function
|
|
48
|
-
const
|
|
49
|
-
i0.ɵɵelementStart(0, "span",
|
|
50
|
-
i0.ɵɵlistener("click", function
|
|
51
|
-
i0.ɵɵelement(1, "i",
|
|
49
|
+
function APIKeysResourceComponent_Conditional_7_Conditional_1_Conditional_0_Conditional_13_Template(rf, ctx) { if (rf & 1) {
|
|
50
|
+
const _r5 = i0.ɵɵgetCurrentView();
|
|
51
|
+
i0.ɵɵelementStart(0, "span", 64);
|
|
52
|
+
i0.ɵɵlistener("click", function APIKeysResourceComponent_Conditional_7_Conditional_1_Conditional_0_Conditional_13_Template_span_click_0_listener() { i0.ɵɵrestoreView(_r5); const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.showListView("expiring")); });
|
|
53
|
+
i0.ɵɵelement(1, "i", 40);
|
|
52
54
|
i0.ɵɵtext(2);
|
|
53
55
|
i0.ɵɵelementEnd();
|
|
54
56
|
} if (rf & 2) {
|
|
@@ -56,11 +58,11 @@ function APIKeysResourceComponent_Conditional_2_Conditional_31_Conditional_0_Con
|
|
|
56
58
|
i0.ɵɵadvance(2);
|
|
57
59
|
i0.ɵɵtextInterpolate1(" ", ctx_r1.ExpiringSoonCount, " expiring soon ");
|
|
58
60
|
} }
|
|
59
|
-
function
|
|
60
|
-
const
|
|
61
|
-
i0.ɵɵelementStart(0, "span",
|
|
62
|
-
i0.ɵɵlistener("click", function
|
|
63
|
-
i0.ɵɵelement(1, "i",
|
|
61
|
+
function APIKeysResourceComponent_Conditional_7_Conditional_1_Conditional_0_Conditional_14_Template(rf, ctx) { if (rf & 1) {
|
|
62
|
+
const _r6 = i0.ɵɵgetCurrentView();
|
|
63
|
+
i0.ɵɵelementStart(0, "span", 65);
|
|
64
|
+
i0.ɵɵlistener("click", function APIKeysResourceComponent_Conditional_7_Conditional_1_Conditional_0_Conditional_14_Template_span_click_0_listener() { i0.ɵɵrestoreView(_r6); const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.showListView("never-used")); });
|
|
65
|
+
i0.ɵɵelement(1, "i", 66);
|
|
64
66
|
i0.ɵɵtext(2);
|
|
65
67
|
i0.ɵɵelementEnd();
|
|
66
68
|
} if (rf & 2) {
|
|
@@ -68,129 +70,129 @@ function APIKeysResourceComponent_Conditional_2_Conditional_31_Conditional_0_Con
|
|
|
68
70
|
i0.ɵɵadvance(2);
|
|
69
71
|
i0.ɵɵtextInterpolate1(" ", ctx_r1.NeverUsedKeys, " never used ");
|
|
70
72
|
} }
|
|
71
|
-
function
|
|
72
|
-
i0.ɵɵelementStart(0, "span",
|
|
73
|
-
i0.ɵɵelement(1, "i",
|
|
73
|
+
function APIKeysResourceComponent_Conditional_7_Conditional_1_Conditional_0_Conditional_15_Template(rf, ctx) { if (rf & 1) {
|
|
74
|
+
i0.ɵɵelementStart(0, "span", 26);
|
|
75
|
+
i0.ɵɵelement(1, "i", 37);
|
|
74
76
|
i0.ɵɵtext(2, " All keys healthy ");
|
|
75
77
|
i0.ɵɵelementEnd();
|
|
76
78
|
} }
|
|
77
|
-
function
|
|
78
|
-
i0.ɵɵelementStart(0, "div",
|
|
79
|
-
i0.ɵɵelement(1, "i",
|
|
79
|
+
function APIKeysResourceComponent_Conditional_7_Conditional_1_Conditional_0_Conditional_46_Template(rf, ctx) { if (rf & 1) {
|
|
80
|
+
i0.ɵɵelementStart(0, "div", 41);
|
|
81
|
+
i0.ɵɵelement(1, "i", 35);
|
|
80
82
|
i0.ɵɵelementEnd();
|
|
81
83
|
} }
|
|
82
|
-
function
|
|
83
|
-
const
|
|
84
|
-
i0.ɵɵelementStart(0, "div",
|
|
85
|
-
i0.ɵɵlistener("click", function
|
|
86
|
-
i0.ɵɵelementStart(1, "div",
|
|
87
|
-
i0.ɵɵelement(2, "i",
|
|
84
|
+
function APIKeysResourceComponent_Conditional_7_Conditional_1_Conditional_0_Conditional_74_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
85
|
+
const _r7 = i0.ɵɵgetCurrentView();
|
|
86
|
+
i0.ɵɵelementStart(0, "div", 68);
|
|
87
|
+
i0.ɵɵlistener("click", function APIKeysResourceComponent_Conditional_7_Conditional_1_Conditional_0_Conditional_74_For_2_Template_div_click_0_listener() { const key_r8 = i0.ɵɵrestoreView(_r7).$implicit; const ctx_r1 = i0.ɵɵnextContext(5); return i0.ɵɵresetView(ctx_r1.openEditPanel(key_r8)); });
|
|
88
|
+
i0.ɵɵelementStart(1, "div", 69);
|
|
89
|
+
i0.ɵɵelement(2, "i", 30);
|
|
88
90
|
i0.ɵɵelementEnd();
|
|
89
|
-
i0.ɵɵelementStart(3, "div",
|
|
91
|
+
i0.ɵɵelementStart(3, "div", 70)(4, "div", 71);
|
|
90
92
|
i0.ɵɵtext(5);
|
|
91
93
|
i0.ɵɵelementEnd();
|
|
92
|
-
i0.ɵɵelementStart(6, "div",
|
|
94
|
+
i0.ɵɵelementStart(6, "div", 72)(7, "span", 73);
|
|
93
95
|
i0.ɵɵtext(8);
|
|
94
96
|
i0.ɵɵelementEnd();
|
|
95
|
-
i0.ɵɵelementStart(9, "span",
|
|
97
|
+
i0.ɵɵelementStart(9, "span", 74);
|
|
96
98
|
i0.ɵɵtext(10);
|
|
97
99
|
i0.ɵɵelementEnd()()();
|
|
98
|
-
i0.ɵɵelementStart(11, "div",
|
|
100
|
+
i0.ɵɵelementStart(11, "div", 75)(12, "div", 76);
|
|
99
101
|
i0.ɵɵtext(13);
|
|
100
102
|
i0.ɵɵelementEnd();
|
|
101
|
-
i0.ɵɵelementStart(14, "div",
|
|
103
|
+
i0.ɵɵelementStart(14, "div", 77);
|
|
102
104
|
i0.ɵɵtext(15);
|
|
103
105
|
i0.ɵɵelementEnd()()();
|
|
104
106
|
} if (rf & 2) {
|
|
105
|
-
const
|
|
107
|
+
const key_r8 = ctx.$implicit;
|
|
106
108
|
const ctx_r1 = i0.ɵɵnextContext(5);
|
|
107
109
|
i0.ɵɵadvance();
|
|
108
|
-
i0.ɵɵclassProp("active",
|
|
110
|
+
i0.ɵɵclassProp("active", key_r8.Status === "Active");
|
|
109
111
|
i0.ɵɵadvance(4);
|
|
110
|
-
i0.ɵɵtextInterpolate(
|
|
112
|
+
i0.ɵɵtextInterpolate(key_r8.Label);
|
|
111
113
|
i0.ɵɵadvance(3);
|
|
112
|
-
i0.ɵɵtextInterpolate(
|
|
114
|
+
i0.ɵɵtextInterpolate(key_r8.User);
|
|
113
115
|
i0.ɵɵadvance(2);
|
|
114
|
-
i0.ɵɵtextInterpolate1("...",
|
|
116
|
+
i0.ɵɵtextInterpolate1("...", key_r8.Hash.slice(-8));
|
|
115
117
|
i0.ɵɵadvance(3);
|
|
116
|
-
i0.ɵɵtextInterpolate(ctx_r1.formatDate(
|
|
118
|
+
i0.ɵɵtextInterpolate(ctx_r1.formatDate(key_r8.LastUsedAt));
|
|
117
119
|
i0.ɵɵadvance();
|
|
118
|
-
i0.ɵɵproperty("ngClass", ctx_r1.getExpirationClass(
|
|
120
|
+
i0.ɵɵproperty("ngClass", ctx_r1.getExpirationClass(key_r8));
|
|
119
121
|
i0.ɵɵadvance();
|
|
120
|
-
i0.ɵɵtextInterpolate1(" ", ctx_r1.formatExpiration(
|
|
122
|
+
i0.ɵɵtextInterpolate1(" ", ctx_r1.formatExpiration(key_r8.ExpiresAt), " ");
|
|
121
123
|
} }
|
|
122
|
-
function
|
|
123
|
-
i0.ɵɵelementStart(0, "div",
|
|
124
|
-
i0.ɵɵrepeaterCreate(1,
|
|
124
|
+
function APIKeysResourceComponent_Conditional_7_Conditional_1_Conditional_0_Conditional_74_Template(rf, ctx) { if (rf & 1) {
|
|
125
|
+
i0.ɵɵelementStart(0, "div", 50);
|
|
126
|
+
i0.ɵɵrepeaterCreate(1, APIKeysResourceComponent_Conditional_7_Conditional_1_Conditional_0_Conditional_74_For_2_Template, 16, 8, "div", 67, i0.ɵɵrepeaterTrackByIdentity);
|
|
125
127
|
i0.ɵɵelementEnd();
|
|
126
128
|
} if (rf & 2) {
|
|
127
129
|
const ctx_r1 = i0.ɵɵnextContext(4);
|
|
128
130
|
i0.ɵɵadvance();
|
|
129
131
|
i0.ɵɵrepeater(ctx_r1.TopUsedKeys);
|
|
130
132
|
} }
|
|
131
|
-
function
|
|
132
|
-
i0.ɵɵelementStart(0, "div",
|
|
133
|
-
i0.ɵɵelement(1, "i",
|
|
133
|
+
function APIKeysResourceComponent_Conditional_7_Conditional_1_Conditional_0_Conditional_75_Template(rf, ctx) { if (rf & 1) {
|
|
134
|
+
i0.ɵɵelementStart(0, "div", 51);
|
|
135
|
+
i0.ɵɵelement(1, "i", 30);
|
|
134
136
|
i0.ɵɵelementStart(2, "span");
|
|
135
137
|
i0.ɵɵtext(3, "No active keys with recent usage");
|
|
136
138
|
i0.ɵɵelementEnd()();
|
|
137
139
|
} }
|
|
138
|
-
function
|
|
139
|
-
const
|
|
140
|
+
function APIKeysResourceComponent_Conditional_7_Conditional_1_Conditional_0_Conditional_85_For_5_Template(rf, ctx) { if (rf & 1) {
|
|
141
|
+
const _r9 = i0.ɵɵgetCurrentView();
|
|
140
142
|
i0.ɵɵnamespaceSVG();
|
|
141
143
|
i0.ɵɵelementContainerStart(0);
|
|
142
|
-
i0.ɵɵelementStart(1, "circle",
|
|
143
|
-
i0.ɵɵlistener("click", function
|
|
144
|
+
i0.ɵɵelementStart(1, "circle", 86);
|
|
145
|
+
i0.ɵɵlistener("click", function APIKeysResourceComponent_Conditional_7_Conditional_1_Conditional_0_Conditional_85_For_5_Template_circle_click_1_listener() { const stat_r10 = i0.ɵɵrestoreView(_r9).$implicit; const ctx_r1 = i0.ɵɵnextContext(5); return i0.ɵɵresetView(ctx_r1.onScopeClick(stat_r10)); });
|
|
144
146
|
i0.ɵɵelementEnd();
|
|
145
147
|
i0.ɵɵelementContainerEnd();
|
|
146
148
|
} if (rf & 2) {
|
|
147
|
-
const
|
|
148
|
-
const ɵ$
|
|
149
|
+
const stat_r10 = ctx.$implicit;
|
|
150
|
+
const ɵ$index_243_r11 = ctx.$index;
|
|
149
151
|
const ctx_r1 = i0.ɵɵnextContext(5);
|
|
150
152
|
i0.ɵɵadvance();
|
|
151
|
-
i0.ɵɵattribute("stroke",
|
|
153
|
+
i0.ɵɵattribute("stroke", stat_r10.color)("stroke-dasharray", stat_r10.percentage * 2.51 + " " + (251 - stat_r10.percentage * 2.51))("stroke-dashoffset", ctx_r1.getDonutOffset(ɵ$index_243_r11));
|
|
152
154
|
} }
|
|
153
|
-
function
|
|
154
|
-
const
|
|
155
|
-
i0.ɵɵelementStart(0, "div",
|
|
156
|
-
i0.ɵɵlistener("click", function
|
|
157
|
-
i0.ɵɵelement(1, "div",
|
|
158
|
-
i0.ɵɵelementStart(2, "div",
|
|
155
|
+
function APIKeysResourceComponent_Conditional_7_Conditional_1_Conditional_0_Conditional_85_For_13_Template(rf, ctx) { if (rf & 1) {
|
|
156
|
+
const _r12 = i0.ɵɵgetCurrentView();
|
|
157
|
+
i0.ɵɵelementStart(0, "div", 87);
|
|
158
|
+
i0.ɵɵlistener("click", function APIKeysResourceComponent_Conditional_7_Conditional_1_Conditional_0_Conditional_85_For_13_Template_div_click_0_listener() { const stat_r13 = i0.ɵɵrestoreView(_r12).$implicit; const ctx_r1 = i0.ɵɵnextContext(5); return i0.ɵɵresetView(ctx_r1.onScopeClick(stat_r13)); });
|
|
159
|
+
i0.ɵɵelement(1, "div", 88);
|
|
160
|
+
i0.ɵɵelementStart(2, "div", 89)(3, "div", 90);
|
|
159
161
|
i0.ɵɵelement(4, "i");
|
|
160
162
|
i0.ɵɵtext(5);
|
|
161
163
|
i0.ɵɵelementEnd();
|
|
162
|
-
i0.ɵɵelementStart(6, "div",
|
|
164
|
+
i0.ɵɵelementStart(6, "div", 91);
|
|
163
165
|
i0.ɵɵtext(7);
|
|
164
166
|
i0.ɵɵelementEnd()();
|
|
165
|
-
i0.ɵɵelement(8, "i",
|
|
167
|
+
i0.ɵɵelement(8, "i", 92);
|
|
166
168
|
i0.ɵɵelementEnd();
|
|
167
169
|
} if (rf & 2) {
|
|
168
|
-
const
|
|
170
|
+
const stat_r13 = ctx.$implicit;
|
|
169
171
|
i0.ɵɵadvance();
|
|
170
|
-
i0.ɵɵstyleProp("background-color",
|
|
172
|
+
i0.ɵɵstyleProp("background-color", stat_r13.color);
|
|
171
173
|
i0.ɵɵadvance(3);
|
|
172
|
-
i0.ɵɵclassMap(
|
|
174
|
+
i0.ɵɵclassMap(stat_r13.iconClass);
|
|
173
175
|
i0.ɵɵadvance();
|
|
174
|
-
i0.ɵɵtextInterpolate1(" ",
|
|
176
|
+
i0.ɵɵtextInterpolate1(" ", stat_r13.category, " ");
|
|
175
177
|
i0.ɵɵadvance(2);
|
|
176
|
-
i0.ɵɵtextInterpolate1("",
|
|
178
|
+
i0.ɵɵtextInterpolate1("", stat_r13.count, " scopes");
|
|
177
179
|
} }
|
|
178
|
-
function
|
|
179
|
-
i0.ɵɵelementStart(0, "div",
|
|
180
|
+
function APIKeysResourceComponent_Conditional_7_Conditional_1_Conditional_0_Conditional_85_Template(rf, ctx) { if (rf & 1) {
|
|
181
|
+
i0.ɵɵelementStart(0, "div", 54)(1, "div", 78);
|
|
180
182
|
i0.ɵɵnamespaceSVG();
|
|
181
|
-
i0.ɵɵelementStart(2, "svg",
|
|
182
|
-
i0.ɵɵelement(3, "circle",
|
|
183
|
-
i0.ɵɵrepeaterCreate(4,
|
|
183
|
+
i0.ɵɵelementStart(2, "svg", 79);
|
|
184
|
+
i0.ɵɵelement(3, "circle", 80);
|
|
185
|
+
i0.ɵɵrepeaterCreate(4, APIKeysResourceComponent_Conditional_7_Conditional_1_Conditional_0_Conditional_85_For_5_Template, 2, 3, ":svg:ng-container", null, i0.ɵɵrepeaterTrackByIdentity);
|
|
184
186
|
i0.ɵɵelementEnd();
|
|
185
187
|
i0.ɵɵnamespaceHTML();
|
|
186
|
-
i0.ɵɵelementStart(6, "div",
|
|
188
|
+
i0.ɵɵelementStart(6, "div", 81)(7, "div", 82);
|
|
187
189
|
i0.ɵɵtext(8);
|
|
188
190
|
i0.ɵɵelementEnd();
|
|
189
|
-
i0.ɵɵelementStart(9, "div",
|
|
191
|
+
i0.ɵɵelementStart(9, "div", 83);
|
|
190
192
|
i0.ɵɵtext(10, "Categories");
|
|
191
193
|
i0.ɵɵelementEnd()()();
|
|
192
|
-
i0.ɵɵelementStart(11, "div",
|
|
193
|
-
i0.ɵɵrepeaterCreate(12,
|
|
194
|
+
i0.ɵɵelementStart(11, "div", 84);
|
|
195
|
+
i0.ɵɵrepeaterCreate(12, APIKeysResourceComponent_Conditional_7_Conditional_1_Conditional_0_Conditional_85_For_13_Template, 9, 6, "div", 85, i0.ɵɵrepeaterTrackByIdentity);
|
|
194
196
|
i0.ɵɵelementEnd()();
|
|
195
197
|
} if (rf & 2) {
|
|
196
198
|
const ctx_r1 = i0.ɵɵnextContext(4);
|
|
@@ -201,245 +203,230 @@ function APIKeysResourceComponent_Conditional_2_Conditional_31_Conditional_0_Con
|
|
|
201
203
|
i0.ɵɵadvance(4);
|
|
202
204
|
i0.ɵɵrepeater(ctx_r1.ScopeStats);
|
|
203
205
|
} }
|
|
204
|
-
function
|
|
205
|
-
i0.ɵɵelementStart(0, "div",
|
|
206
|
-
i0.ɵɵelement(1, "i",
|
|
206
|
+
function APIKeysResourceComponent_Conditional_7_Conditional_1_Conditional_0_Conditional_86_Template(rf, ctx) { if (rf & 1) {
|
|
207
|
+
i0.ɵɵelementStart(0, "div", 51);
|
|
208
|
+
i0.ɵɵelement(1, "i", 43);
|
|
207
209
|
i0.ɵɵelementStart(2, "span");
|
|
208
210
|
i0.ɵɵtext(3, "No scopes configured");
|
|
209
211
|
i0.ɵɵelementEnd()();
|
|
210
212
|
} }
|
|
211
|
-
function
|
|
212
|
-
i0.ɵɵelementStart(0, "span",
|
|
213
|
+
function APIKeysResourceComponent_Conditional_7_Conditional_1_Conditional_0_Conditional_94_For_2_Conditional_9_Template(rf, ctx) { if (rf & 1) {
|
|
214
|
+
i0.ɵɵelementStart(0, "span", 100);
|
|
213
215
|
i0.ɵɵtext(1);
|
|
214
216
|
i0.ɵɵelementEnd();
|
|
215
217
|
} if (rf & 2) {
|
|
216
|
-
const
|
|
218
|
+
const activity_r15 = i0.ɵɵnextContext().$implicit;
|
|
217
219
|
i0.ɵɵadvance();
|
|
218
|
-
i0.ɵɵtextInterpolate1("by ",
|
|
220
|
+
i0.ɵɵtextInterpolate1("by ", activity_r15.user);
|
|
219
221
|
} }
|
|
220
|
-
function
|
|
221
|
-
const
|
|
222
|
-
i0.ɵɵelementStart(0, "div",
|
|
223
|
-
i0.ɵɵlistener("click", function
|
|
224
|
-
i0.ɵɵelementStart(1, "div",
|
|
222
|
+
function APIKeysResourceComponent_Conditional_7_Conditional_1_Conditional_0_Conditional_94_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
223
|
+
const _r14 = i0.ɵɵgetCurrentView();
|
|
224
|
+
i0.ɵɵelementStart(0, "div", 94);
|
|
225
|
+
i0.ɵɵlistener("click", function APIKeysResourceComponent_Conditional_7_Conditional_1_Conditional_0_Conditional_94_For_2_Template_div_click_0_listener() { const activity_r15 = i0.ɵɵrestoreView(_r14).$implicit; const ctx_r1 = i0.ɵɵnextContext(5); return i0.ɵɵresetView(ctx_r1.onActivityClick(activity_r15)); });
|
|
226
|
+
i0.ɵɵelementStart(1, "div", 95);
|
|
225
227
|
i0.ɵɵelement(2, "i");
|
|
226
228
|
i0.ɵɵelementEnd();
|
|
227
|
-
i0.ɵɵelementStart(3, "div",
|
|
229
|
+
i0.ɵɵelementStart(3, "div", 96)(4, "div", 97);
|
|
228
230
|
i0.ɵɵtext(5);
|
|
229
231
|
i0.ɵɵelementEnd();
|
|
230
|
-
i0.ɵɵelementStart(6, "div",
|
|
232
|
+
i0.ɵɵelementStart(6, "div", 98)(7, "span", 99);
|
|
231
233
|
i0.ɵɵtext(8);
|
|
232
234
|
i0.ɵɵelementEnd();
|
|
233
|
-
i0.ɵɵconditionalCreate(9,
|
|
235
|
+
i0.ɵɵconditionalCreate(9, APIKeysResourceComponent_Conditional_7_Conditional_1_Conditional_0_Conditional_94_For_2_Conditional_9_Template, 2, 1, "span", 100);
|
|
234
236
|
i0.ɵɵelementEnd()();
|
|
235
|
-
i0.ɵɵelementStart(10, "div",
|
|
237
|
+
i0.ɵɵelementStart(10, "div", 101);
|
|
236
238
|
i0.ɵɵtext(11);
|
|
237
239
|
i0.ɵɵelementEnd()();
|
|
238
240
|
} if (rf & 2) {
|
|
239
|
-
const
|
|
241
|
+
const activity_r15 = ctx.$implicit;
|
|
240
242
|
const ctx_r1 = i0.ɵɵnextContext(5);
|
|
241
243
|
i0.ɵɵadvance();
|
|
242
|
-
i0.ɵɵproperty("ngClass", ctx_r1.getActionClass(
|
|
244
|
+
i0.ɵɵproperty("ngClass", ctx_r1.getActionClass(activity_r15.action));
|
|
243
245
|
i0.ɵɵadvance();
|
|
244
|
-
i0.ɵɵclassMap(ctx_r1.getActionIcon(
|
|
246
|
+
i0.ɵɵclassMap(ctx_r1.getActionIcon(activity_r15.action));
|
|
245
247
|
i0.ɵɵadvance(3);
|
|
246
|
-
i0.ɵɵtextInterpolate(
|
|
248
|
+
i0.ɵɵtextInterpolate(activity_r15.keyLabel);
|
|
247
249
|
i0.ɵɵadvance(3);
|
|
248
|
-
i0.ɵɵtextInterpolate(
|
|
250
|
+
i0.ɵɵtextInterpolate(activity_r15.action);
|
|
249
251
|
i0.ɵɵadvance();
|
|
250
|
-
i0.ɵɵconditional(
|
|
252
|
+
i0.ɵɵconditional(activity_r15.user ? 9 : -1);
|
|
251
253
|
i0.ɵɵadvance(2);
|
|
252
|
-
i0.ɵɵtextInterpolate1(" ", ctx_r1.formatDate(
|
|
254
|
+
i0.ɵɵtextInterpolate1(" ", ctx_r1.formatDate(activity_r15.date), " ");
|
|
253
255
|
} }
|
|
254
|
-
function
|
|
255
|
-
i0.ɵɵelementStart(0, "div",
|
|
256
|
-
i0.ɵɵrepeaterCreate(1,
|
|
256
|
+
function APIKeysResourceComponent_Conditional_7_Conditional_1_Conditional_0_Conditional_94_Template(rf, ctx) { if (rf & 1) {
|
|
257
|
+
i0.ɵɵelementStart(0, "div", 57);
|
|
258
|
+
i0.ɵɵrepeaterCreate(1, APIKeysResourceComponent_Conditional_7_Conditional_1_Conditional_0_Conditional_94_For_2_Template, 12, 7, "div", 93, i0.ɵɵrepeaterTrackByIdentity);
|
|
257
259
|
i0.ɵɵelementEnd();
|
|
258
260
|
} if (rf & 2) {
|
|
259
261
|
const ctx_r1 = i0.ɵɵnextContext(4);
|
|
260
262
|
i0.ɵɵadvance();
|
|
261
263
|
i0.ɵɵrepeater(ctx_r1.RecentActivity);
|
|
262
264
|
} }
|
|
263
|
-
function
|
|
264
|
-
i0.ɵɵelementStart(0, "div",
|
|
265
|
-
i0.ɵɵelement(1, "i",
|
|
265
|
+
function APIKeysResourceComponent_Conditional_7_Conditional_1_Conditional_0_Conditional_95_Template(rf, ctx) { if (rf & 1) {
|
|
266
|
+
i0.ɵɵelementStart(0, "div", 51);
|
|
267
|
+
i0.ɵɵelement(1, "i", 102);
|
|
266
268
|
i0.ɵɵelementStart(2, "span");
|
|
267
269
|
i0.ɵɵtext(3, "No recent activity");
|
|
268
270
|
i0.ɵɵelementEnd()();
|
|
269
271
|
} }
|
|
270
|
-
function
|
|
271
|
-
const
|
|
272
|
-
i0.ɵɵelementStart(0, "div",
|
|
272
|
+
function APIKeysResourceComponent_Conditional_7_Conditional_1_Conditional_0_Conditional_96_Template(rf, ctx) { if (rf & 1) {
|
|
273
|
+
const _r16 = i0.ɵɵgetCurrentView();
|
|
274
|
+
i0.ɵɵelementStart(0, "div", 58)(1, "div", 103);
|
|
273
275
|
i0.ɵɵtext(2, "Quick Actions");
|
|
274
276
|
i0.ɵɵelementEnd();
|
|
275
|
-
i0.ɵɵelementStart(3, "div",
|
|
276
|
-
i0.ɵɵlistener("click", function
|
|
277
|
-
i0.ɵɵelement(5, "i",
|
|
277
|
+
i0.ɵɵelementStart(3, "div", 104)(4, "button", 105);
|
|
278
|
+
i0.ɵɵlistener("click", function APIKeysResourceComponent_Conditional_7_Conditional_1_Conditional_0_Conditional_96_Template_button_click_4_listener() { i0.ɵɵrestoreView(_r16); const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.openCreateDialog()); });
|
|
279
|
+
i0.ɵɵelement(5, "i", 106);
|
|
278
280
|
i0.ɵɵelementStart(6, "span");
|
|
279
281
|
i0.ɵɵtext(7, "Generate Key");
|
|
280
282
|
i0.ɵɵelementEnd()();
|
|
281
|
-
i0.ɵɵelementStart(8, "button",
|
|
282
|
-
i0.ɵɵlistener("click", function
|
|
283
|
-
i0.ɵɵelement(9, "i",
|
|
283
|
+
i0.ɵɵelementStart(8, "button", 105);
|
|
284
|
+
i0.ɵɵlistener("click", function APIKeysResourceComponent_Conditional_7_Conditional_1_Conditional_0_Conditional_96_Template_button_click_8_listener() { i0.ɵɵrestoreView(_r16); const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.showListView("all")); });
|
|
285
|
+
i0.ɵɵelement(9, "i", 107);
|
|
284
286
|
i0.ɵɵelementStart(10, "span");
|
|
285
287
|
i0.ɵɵtext(11, "View All Keys");
|
|
286
288
|
i0.ɵɵelementEnd()();
|
|
287
|
-
i0.ɵɵelementStart(12, "button",
|
|
288
|
-
i0.ɵɵlistener("click", function
|
|
289
|
-
i0.ɵɵelement(13, "i",
|
|
289
|
+
i0.ɵɵelementStart(12, "button", 105);
|
|
290
|
+
i0.ɵɵlistener("click", function APIKeysResourceComponent_Conditional_7_Conditional_1_Conditional_0_Conditional_96_Template_button_click_12_listener() { i0.ɵɵrestoreView(_r16); const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.showListView("expiring")); });
|
|
291
|
+
i0.ɵɵelement(13, "i", 40);
|
|
290
292
|
i0.ɵɵelementStart(14, "span");
|
|
291
293
|
i0.ɵɵtext(15, "Expiring Keys");
|
|
292
294
|
i0.ɵɵelementEnd()();
|
|
293
|
-
i0.ɵɵelementStart(16, "button",
|
|
294
|
-
i0.ɵɵlistener("click", function
|
|
295
|
-
i0.ɵɵelement(17, "i",
|
|
295
|
+
i0.ɵɵelementStart(16, "button", 105);
|
|
296
|
+
i0.ɵɵlistener("click", function APIKeysResourceComponent_Conditional_7_Conditional_1_Conditional_0_Conditional_96_Template_button_click_16_listener() { i0.ɵɵrestoreView(_r16); const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.showListView("never-used")); });
|
|
297
|
+
i0.ɵɵelement(17, "i", 66);
|
|
296
298
|
i0.ɵɵelementStart(18, "span");
|
|
297
299
|
i0.ɵɵtext(19, "Never Used");
|
|
298
300
|
i0.ɵɵelementEnd()()()();
|
|
299
301
|
} }
|
|
300
|
-
function
|
|
302
|
+
function APIKeysResourceComponent_Conditional_7_Conditional_1_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
301
303
|
const _r3 = i0.ɵɵgetCurrentView();
|
|
302
|
-
i0.ɵɵelementStart(0, "div",
|
|
303
|
-
i0.ɵɵtext(3, "API Keys Management");
|
|
304
|
-
i0.ɵɵelementEnd();
|
|
305
|
-
i0.ɵɵelementStart(4, "p", 24);
|
|
306
|
-
i0.ɵɵtext(5, "Manage API keys for external integrations and services");
|
|
307
|
-
i0.ɵɵelementEnd()();
|
|
308
|
-
i0.ɵɵelementStart(6, "div", 25)(7, "button", 26);
|
|
309
|
-
i0.ɵɵlistener("click", function APIKeysResourceComponent_Conditional_2_Conditional_31_Conditional_0_Template_button_click_7_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.refresh()); });
|
|
310
|
-
i0.ɵɵelement(8, "i", 27);
|
|
311
|
-
i0.ɵɵelementEnd();
|
|
312
|
-
i0.ɵɵconditionalCreate(9, APIKeysResourceComponent_Conditional_2_Conditional_31_Conditional_0_Conditional_9_Template, 4, 0, "button", 28);
|
|
313
|
-
i0.ɵɵelementEnd()();
|
|
314
|
-
i0.ɵɵelementStart(10, "div", 29)(11, "div", 30)(12, "div", 31);
|
|
304
|
+
i0.ɵɵelementStart(0, "div", 13)(1, "div", 14)(2, "div", 15);
|
|
315
305
|
i0.ɵɵnamespaceSVG();
|
|
316
|
-
i0.ɵɵelementStart(
|
|
317
|
-
i0.ɵɵelement(
|
|
306
|
+
i0.ɵɵelementStart(3, "svg", 16);
|
|
307
|
+
i0.ɵɵelement(4, "path", 17)(5, "path", 18);
|
|
318
308
|
i0.ɵɵelementEnd();
|
|
319
309
|
i0.ɵɵnamespaceHTML();
|
|
320
|
-
i0.ɵɵelementStart(
|
|
321
|
-
i0.ɵɵtext(
|
|
310
|
+
i0.ɵɵelementStart(6, "div", 19);
|
|
311
|
+
i0.ɵɵtext(7);
|
|
322
312
|
i0.ɵɵelementEnd()()();
|
|
323
|
-
i0.ɵɵelementStart(
|
|
324
|
-
i0.ɵɵtext(
|
|
313
|
+
i0.ɵɵelementStart(8, "div", 20)(9, "div", 21);
|
|
314
|
+
i0.ɵɵtext(10);
|
|
325
315
|
i0.ɵɵelementEnd();
|
|
326
|
-
i0.ɵɵelementStart(
|
|
327
|
-
i0.ɵɵconditionalCreate(
|
|
328
|
-
i0.ɵɵconditionalCreate(
|
|
329
|
-
i0.ɵɵconditionalCreate(
|
|
330
|
-
i0.ɵɵconditionalCreate(
|
|
316
|
+
i0.ɵɵelementStart(11, "div", 22);
|
|
317
|
+
i0.ɵɵconditionalCreate(12, APIKeysResourceComponent_Conditional_7_Conditional_1_Conditional_0_Conditional_12_Template, 3, 1, "span", 23);
|
|
318
|
+
i0.ɵɵconditionalCreate(13, APIKeysResourceComponent_Conditional_7_Conditional_1_Conditional_0_Conditional_13_Template, 3, 1, "span", 24);
|
|
319
|
+
i0.ɵɵconditionalCreate(14, APIKeysResourceComponent_Conditional_7_Conditional_1_Conditional_0_Conditional_14_Template, 3, 1, "span", 25);
|
|
320
|
+
i0.ɵɵconditionalCreate(15, APIKeysResourceComponent_Conditional_7_Conditional_1_Conditional_0_Conditional_15_Template, 3, 0, "span", 26);
|
|
331
321
|
i0.ɵɵelementEnd()()();
|
|
332
|
-
i0.ɵɵelementStart(
|
|
333
|
-
i0.ɵɵlistener("click", function
|
|
334
|
-
i0.ɵɵelementStart(
|
|
335
|
-
i0.ɵɵelement(
|
|
322
|
+
i0.ɵɵelementStart(16, "div", 27)(17, "div", 28);
|
|
323
|
+
i0.ɵɵlistener("click", function APIKeysResourceComponent_Conditional_7_Conditional_1_Conditional_0_Template_div_click_17_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.showListView("all")); });
|
|
324
|
+
i0.ɵɵelementStart(18, "div", 29);
|
|
325
|
+
i0.ɵɵelement(19, "i", 30);
|
|
336
326
|
i0.ɵɵelementEnd();
|
|
337
|
-
i0.ɵɵelementStart(
|
|
338
|
-
i0.ɵɵtext(
|
|
327
|
+
i0.ɵɵelementStart(20, "div", 31)(21, "div", 32);
|
|
328
|
+
i0.ɵɵtext(22);
|
|
339
329
|
i0.ɵɵelementEnd();
|
|
340
|
-
i0.ɵɵelementStart(
|
|
341
|
-
i0.ɵɵtext(
|
|
330
|
+
i0.ɵɵelementStart(23, "div", 33);
|
|
331
|
+
i0.ɵɵtext(24, "Total Keys");
|
|
342
332
|
i0.ɵɵelementEnd()();
|
|
343
|
-
i0.ɵɵelementStart(
|
|
344
|
-
i0.ɵɵelement(
|
|
333
|
+
i0.ɵɵelementStart(25, "div", 34);
|
|
334
|
+
i0.ɵɵelement(26, "i", 35);
|
|
345
335
|
i0.ɵɵelementEnd()();
|
|
346
|
-
i0.ɵɵelementStart(
|
|
347
|
-
i0.ɵɵlistener("click", function
|
|
348
|
-
i0.ɵɵelementStart(
|
|
349
|
-
i0.ɵɵelement(
|
|
336
|
+
i0.ɵɵelementStart(27, "div", 36);
|
|
337
|
+
i0.ɵɵlistener("click", function APIKeysResourceComponent_Conditional_7_Conditional_1_Conditional_0_Template_div_click_27_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.showListView("active")); });
|
|
338
|
+
i0.ɵɵelementStart(28, "div", 29);
|
|
339
|
+
i0.ɵɵelement(29, "i", 37);
|
|
350
340
|
i0.ɵɵelementEnd();
|
|
351
|
-
i0.ɵɵelementStart(
|
|
352
|
-
i0.ɵɵtext(
|
|
341
|
+
i0.ɵɵelementStart(30, "div", 31)(31, "div", 32);
|
|
342
|
+
i0.ɵɵtext(32);
|
|
353
343
|
i0.ɵɵelementEnd();
|
|
354
|
-
i0.ɵɵelementStart(
|
|
355
|
-
i0.ɵɵtext(
|
|
344
|
+
i0.ɵɵelementStart(33, "div", 33);
|
|
345
|
+
i0.ɵɵtext(34, "Active");
|
|
356
346
|
i0.ɵɵelementEnd()();
|
|
357
|
-
i0.ɵɵelementStart(
|
|
358
|
-
i0.ɵɵtext(
|
|
347
|
+
i0.ɵɵelementStart(35, "div", 38)(36, "span", 39);
|
|
348
|
+
i0.ɵɵtext(37);
|
|
359
349
|
i0.ɵɵelementEnd()()();
|
|
360
|
-
i0.ɵɵelementStart(
|
|
361
|
-
i0.ɵɵlistener("click", function
|
|
362
|
-
i0.ɵɵelementStart(
|
|
363
|
-
i0.ɵɵelement(
|
|
350
|
+
i0.ɵɵelementStart(38, "div", 28);
|
|
351
|
+
i0.ɵɵlistener("click", function APIKeysResourceComponent_Conditional_7_Conditional_1_Conditional_0_Template_div_click_38_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.showListView("expiring")); });
|
|
352
|
+
i0.ɵɵelementStart(39, "div", 29);
|
|
353
|
+
i0.ɵɵelement(40, "i", 40);
|
|
364
354
|
i0.ɵɵelementEnd();
|
|
365
|
-
i0.ɵɵelementStart(
|
|
366
|
-
i0.ɵɵtext(
|
|
355
|
+
i0.ɵɵelementStart(41, "div", 31)(42, "div", 32);
|
|
356
|
+
i0.ɵɵtext(43);
|
|
367
357
|
i0.ɵɵelementEnd();
|
|
368
|
-
i0.ɵɵelementStart(
|
|
369
|
-
i0.ɵɵtext(
|
|
358
|
+
i0.ɵɵelementStart(44, "div", 33);
|
|
359
|
+
i0.ɵɵtext(45, "Expiring Soon");
|
|
370
360
|
i0.ɵɵelementEnd()();
|
|
371
|
-
i0.ɵɵconditionalCreate(
|
|
361
|
+
i0.ɵɵconditionalCreate(46, APIKeysResourceComponent_Conditional_7_Conditional_1_Conditional_0_Conditional_46_Template, 2, 0, "div", 41);
|
|
372
362
|
i0.ɵɵelementEnd();
|
|
373
|
-
i0.ɵɵelementStart(
|
|
374
|
-
i0.ɵɵlistener("click", function
|
|
375
|
-
i0.ɵɵelementStart(
|
|
376
|
-
i0.ɵɵelement(
|
|
363
|
+
i0.ɵɵelementStart(47, "div", 28);
|
|
364
|
+
i0.ɵɵlistener("click", function APIKeysResourceComponent_Conditional_7_Conditional_1_Conditional_0_Template_div_click_47_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.showListView("revoked")); });
|
|
365
|
+
i0.ɵɵelementStart(48, "div", 29);
|
|
366
|
+
i0.ɵɵelement(49, "i", 42);
|
|
377
367
|
i0.ɵɵelementEnd();
|
|
378
|
-
i0.ɵɵelementStart(
|
|
379
|
-
i0.ɵɵtext(
|
|
368
|
+
i0.ɵɵelementStart(50, "div", 31)(51, "div", 32);
|
|
369
|
+
i0.ɵɵtext(52);
|
|
380
370
|
i0.ɵɵelementEnd();
|
|
381
|
-
i0.ɵɵelementStart(
|
|
382
|
-
i0.ɵɵtext(
|
|
371
|
+
i0.ɵɵelementStart(53, "div", 33);
|
|
372
|
+
i0.ɵɵtext(54, "Revoked");
|
|
383
373
|
i0.ɵɵelementEnd()()();
|
|
384
|
-
i0.ɵɵelementStart(
|
|
385
|
-
i0.ɵɵlistener("click", function
|
|
386
|
-
i0.ɵɵelementStart(
|
|
387
|
-
i0.ɵɵelement(
|
|
374
|
+
i0.ɵɵelementStart(55, "div", 28);
|
|
375
|
+
i0.ɵɵlistener("click", function APIKeysResourceComponent_Conditional_7_Conditional_1_Conditional_0_Template_div_click_55_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.switchTab("scopes")); });
|
|
376
|
+
i0.ɵɵelementStart(56, "div", 29);
|
|
377
|
+
i0.ɵɵelement(57, "i", 43);
|
|
388
378
|
i0.ɵɵelementEnd();
|
|
389
|
-
i0.ɵɵelementStart(
|
|
390
|
-
i0.ɵɵtext(
|
|
379
|
+
i0.ɵɵelementStart(58, "div", 31)(59, "div", 32);
|
|
380
|
+
i0.ɵɵtext(60);
|
|
391
381
|
i0.ɵɵelementEnd();
|
|
392
|
-
i0.ɵɵelementStart(
|
|
393
|
-
i0.ɵɵtext(
|
|
382
|
+
i0.ɵɵelementStart(61, "div", 33);
|
|
383
|
+
i0.ɵɵtext(62, "Scope Categories");
|
|
394
384
|
i0.ɵɵelementEnd()()()();
|
|
395
|
-
i0.ɵɵelementStart(
|
|
396
|
-
i0.ɵɵelement(
|
|
397
|
-
i0.ɵɵelementStart(
|
|
398
|
-
i0.ɵɵtext(
|
|
385
|
+
i0.ɵɵelementStart(63, "div", 44)(64, "div", 45)(65, "div", 46)(66, "div", 47);
|
|
386
|
+
i0.ɵɵelement(67, "i", 30);
|
|
387
|
+
i0.ɵɵelementStart(68, "span");
|
|
388
|
+
i0.ɵɵtext(69, "Recently Used Keys");
|
|
399
389
|
i0.ɵɵelementEnd()();
|
|
400
|
-
i0.ɵɵelementStart(
|
|
401
|
-
i0.ɵɵlistener("click", function
|
|
402
|
-
i0.ɵɵtext(
|
|
403
|
-
i0.ɵɵelement(
|
|
390
|
+
i0.ɵɵelementStart(70, "button", 48);
|
|
391
|
+
i0.ɵɵlistener("click", function APIKeysResourceComponent_Conditional_7_Conditional_1_Conditional_0_Template_button_click_70_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.showListView("all")); });
|
|
392
|
+
i0.ɵɵtext(71, " View All ");
|
|
393
|
+
i0.ɵɵelement(72, "i", 35);
|
|
404
394
|
i0.ɵɵelementEnd()();
|
|
405
|
-
i0.ɵɵelementStart(
|
|
406
|
-
i0.ɵɵconditionalCreate(
|
|
407
|
-
i0.ɵɵconditionalCreate(
|
|
395
|
+
i0.ɵɵelementStart(73, "div", 49);
|
|
396
|
+
i0.ɵɵconditionalCreate(74, APIKeysResourceComponent_Conditional_7_Conditional_1_Conditional_0_Conditional_74_Template, 3, 0, "div", 50);
|
|
397
|
+
i0.ɵɵconditionalCreate(75, APIKeysResourceComponent_Conditional_7_Conditional_1_Conditional_0_Conditional_75_Template, 4, 0, "div", 51);
|
|
408
398
|
i0.ɵɵelementEnd()();
|
|
409
|
-
i0.ɵɵelementStart(
|
|
410
|
-
i0.ɵɵelement(
|
|
411
|
-
i0.ɵɵelementStart(
|
|
412
|
-
i0.ɵɵtext(
|
|
399
|
+
i0.ɵɵelementStart(76, "div", 52)(77, "div", 46)(78, "div", 47);
|
|
400
|
+
i0.ɵɵelement(79, "i", 43);
|
|
401
|
+
i0.ɵɵelementStart(80, "span");
|
|
402
|
+
i0.ɵɵtext(81, "Permission Scopes");
|
|
413
403
|
i0.ɵɵelementEnd()();
|
|
414
|
-
i0.ɵɵelementStart(
|
|
415
|
-
i0.ɵɵtext(
|
|
404
|
+
i0.ɵɵelementStart(82, "span", 53);
|
|
405
|
+
i0.ɵɵtext(83, "Available scope categories");
|
|
416
406
|
i0.ɵɵelementEnd()();
|
|
417
|
-
i0.ɵɵelementStart(
|
|
418
|
-
i0.ɵɵconditionalCreate(
|
|
419
|
-
i0.ɵɵconditionalCreate(
|
|
407
|
+
i0.ɵɵelementStart(84, "div", 49);
|
|
408
|
+
i0.ɵɵconditionalCreate(85, APIKeysResourceComponent_Conditional_7_Conditional_1_Conditional_0_Conditional_85_Template, 14, 1, "div", 54);
|
|
409
|
+
i0.ɵɵconditionalCreate(86, APIKeysResourceComponent_Conditional_7_Conditional_1_Conditional_0_Conditional_86_Template, 4, 0, "div", 51);
|
|
420
410
|
i0.ɵɵelementEnd()();
|
|
421
|
-
i0.ɵɵelementStart(
|
|
422
|
-
i0.ɵɵelement(
|
|
423
|
-
i0.ɵɵelementStart(
|
|
424
|
-
i0.ɵɵtext(
|
|
411
|
+
i0.ɵɵelementStart(87, "div", 55)(88, "div", 46)(89, "div", 47);
|
|
412
|
+
i0.ɵɵelement(90, "i", 56);
|
|
413
|
+
i0.ɵɵelementStart(91, "span");
|
|
414
|
+
i0.ɵɵtext(92, "Recent Activity");
|
|
425
415
|
i0.ɵɵelementEnd()()();
|
|
426
|
-
i0.ɵɵelementStart(
|
|
427
|
-
i0.ɵɵconditionalCreate(
|
|
428
|
-
i0.ɵɵconditionalCreate(
|
|
416
|
+
i0.ɵɵelementStart(93, "div", 49);
|
|
417
|
+
i0.ɵɵconditionalCreate(94, APIKeysResourceComponent_Conditional_7_Conditional_1_Conditional_0_Conditional_94_Template, 3, 0, "div", 57);
|
|
418
|
+
i0.ɵɵconditionalCreate(95, APIKeysResourceComponent_Conditional_7_Conditional_1_Conditional_0_Conditional_95_Template, 4, 0, "div", 51);
|
|
429
419
|
i0.ɵɵelementEnd()()();
|
|
430
|
-
i0.ɵɵconditionalCreate(
|
|
431
|
-
i0.ɵɵelementStart(
|
|
432
|
-
i0.ɵɵelement(
|
|
433
|
-
i0.ɵɵelementStart(
|
|
434
|
-
i0.ɵɵtext(
|
|
420
|
+
i0.ɵɵconditionalCreate(96, APIKeysResourceComponent_Conditional_7_Conditional_1_Conditional_0_Conditional_96_Template, 20, 0, "div", 58);
|
|
421
|
+
i0.ɵɵelementStart(97, "div", 59);
|
|
422
|
+
i0.ɵɵelement(98, "i", 60);
|
|
423
|
+
i0.ɵɵelementStart(99, "div", 61)(100, "strong");
|
|
424
|
+
i0.ɵɵtext(101, "Security Best Practices:");
|
|
435
425
|
i0.ɵɵelementEnd();
|
|
436
|
-
i0.ɵɵtext(
|
|
426
|
+
i0.ɵɵtext(102, " 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. ");
|
|
437
427
|
i0.ɵɵelementEnd()();
|
|
438
428
|
} if (rf & 2) {
|
|
439
429
|
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
440
|
-
i0.ɵɵadvance(9);
|
|
441
|
-
i0.ɵɵconditional(ctx_r1.UserCanCreateKeys ? 9 : -1);
|
|
442
|
-
i0.ɵɵadvance();
|
|
443
430
|
i0.ɵɵproperty("ngClass", ctx_r1.getHealthClass());
|
|
444
431
|
i0.ɵɵadvance(5);
|
|
445
432
|
i0.ɵɵattribute("stroke-dasharray", ctx_r1.getHealthScore() + ", 100");
|
|
@@ -448,13 +435,13 @@ function APIKeysResourceComponent_Conditional_2_Conditional_31_Conditional_0_Tem
|
|
|
448
435
|
i0.ɵɵadvance(3);
|
|
449
436
|
i0.ɵɵtextInterpolate(ctx_r1.getHealthLabel());
|
|
450
437
|
i0.ɵɵadvance(2);
|
|
451
|
-
i0.ɵɵconditional(ctx_r1.ExpiredKeys > 0 ?
|
|
438
|
+
i0.ɵɵconditional(ctx_r1.ExpiredKeys > 0 ? 12 : -1);
|
|
452
439
|
i0.ɵɵadvance();
|
|
453
|
-
i0.ɵɵconditional(ctx_r1.ExpiringSoonCount > 0 ?
|
|
440
|
+
i0.ɵɵconditional(ctx_r1.ExpiringSoonCount > 0 ? 13 : -1);
|
|
454
441
|
i0.ɵɵadvance();
|
|
455
|
-
i0.ɵɵconditional(ctx_r1.NeverUsedKeys > 0 ?
|
|
442
|
+
i0.ɵɵconditional(ctx_r1.NeverUsedKeys > 0 ? 14 : -1);
|
|
456
443
|
i0.ɵɵadvance();
|
|
457
|
-
i0.ɵɵconditional(ctx_r1.ExpiredKeys === 0 && ctx_r1.ExpiringSoonCount === 0 && ctx_r1.NeverUsedKeys === 0 ?
|
|
444
|
+
i0.ɵɵconditional(ctx_r1.ExpiredKeys === 0 && ctx_r1.ExpiringSoonCount === 0 && ctx_r1.NeverUsedKeys === 0 ? 15 : -1);
|
|
458
445
|
i0.ɵɵadvance(7);
|
|
459
446
|
i0.ɵɵtextInterpolate(ctx_r1.TotalKeys);
|
|
460
447
|
i0.ɵɵadvance(10);
|
|
@@ -466,7 +453,7 @@ function APIKeysResourceComponent_Conditional_2_Conditional_31_Conditional_0_Tem
|
|
|
466
453
|
i0.ɵɵadvance(5);
|
|
467
454
|
i0.ɵɵtextInterpolate(ctx_r1.ExpiringSoonCount);
|
|
468
455
|
i0.ɵɵadvance(3);
|
|
469
|
-
i0.ɵɵconditional(ctx_r1.ExpiringSoonCount > 0 ?
|
|
456
|
+
i0.ɵɵconditional(ctx_r1.ExpiringSoonCount > 0 ? 46 : -1);
|
|
470
457
|
i0.ɵɵadvance();
|
|
471
458
|
i0.ɵɵclassProp("danger", ctx_r1.RevokedKeys > 0);
|
|
472
459
|
i0.ɵɵadvance(5);
|
|
@@ -474,138 +461,76 @@ function APIKeysResourceComponent_Conditional_2_Conditional_31_Conditional_0_Tem
|
|
|
474
461
|
i0.ɵɵadvance(8);
|
|
475
462
|
i0.ɵɵtextInterpolate(ctx_r1.ScopeStats.length);
|
|
476
463
|
i0.ɵɵadvance(14);
|
|
477
|
-
i0.ɵɵconditional(ctx_r1.TopUsedKeys.length > 0 ?
|
|
464
|
+
i0.ɵɵconditional(ctx_r1.TopUsedKeys.length > 0 ? 74 : -1);
|
|
478
465
|
i0.ɵɵadvance();
|
|
479
|
-
i0.ɵɵconditional(ctx_r1.TopUsedKeys.length === 0 ?
|
|
466
|
+
i0.ɵɵconditional(ctx_r1.TopUsedKeys.length === 0 ? 75 : -1);
|
|
480
467
|
i0.ɵɵadvance(10);
|
|
481
|
-
i0.ɵɵconditional(ctx_r1.ScopeStats.length > 0 ?
|
|
468
|
+
i0.ɵɵconditional(ctx_r1.ScopeStats.length > 0 ? 85 : -1);
|
|
482
469
|
i0.ɵɵadvance();
|
|
483
|
-
i0.ɵɵconditional(ctx_r1.ScopeStats.length === 0 ?
|
|
470
|
+
i0.ɵɵconditional(ctx_r1.ScopeStats.length === 0 ? 86 : -1);
|
|
484
471
|
i0.ɵɵadvance(8);
|
|
485
|
-
i0.ɵɵconditional(ctx_r1.RecentActivity.length > 0 ?
|
|
472
|
+
i0.ɵɵconditional(ctx_r1.RecentActivity.length > 0 ? 94 : -1);
|
|
486
473
|
i0.ɵɵadvance();
|
|
487
|
-
i0.ɵɵconditional(ctx_r1.RecentActivity.length === 0 ?
|
|
474
|
+
i0.ɵɵconditional(ctx_r1.RecentActivity.length === 0 ? 95 : -1);
|
|
488
475
|
i0.ɵɵadvance();
|
|
489
|
-
i0.ɵɵconditional(ctx_r1.UserCanCreateKeys ?
|
|
476
|
+
i0.ɵɵconditional(ctx_r1.UserCanCreateKeys ? 96 : -1);
|
|
490
477
|
} }
|
|
491
|
-
function
|
|
492
|
-
const
|
|
493
|
-
i0.ɵɵelementStart(0, "div",
|
|
494
|
-
i0.ɵɵlistener("click", function
|
|
495
|
-
i0.ɵɵelement(2, "i",
|
|
478
|
+
function APIKeysResourceComponent_Conditional_7_Conditional_1_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
479
|
+
const _r17 = i0.ɵɵgetCurrentView();
|
|
480
|
+
i0.ɵɵelementStart(0, "div", 108)(1, "button", 109);
|
|
481
|
+
i0.ɵɵlistener("click", function APIKeysResourceComponent_Conditional_7_Conditional_1_Conditional_1_Template_button_click_1_listener() { i0.ɵɵrestoreView(_r17); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.showOverview()); });
|
|
482
|
+
i0.ɵɵelement(2, "i", 110);
|
|
496
483
|
i0.ɵɵtext(3, " Back to Overview ");
|
|
497
484
|
i0.ɵɵelementEnd()();
|
|
498
|
-
i0.ɵɵelementStart(4, "mj-api-key-list",
|
|
499
|
-
i0.ɵɵlistener("KeySelected", function
|
|
485
|
+
i0.ɵɵelementStart(4, "mj-api-key-list", 111, 0);
|
|
486
|
+
i0.ɵɵlistener("KeySelected", function APIKeysResourceComponent_Conditional_7_Conditional_1_Conditional_1_Template_mj_api_key_list_KeySelected_4_listener($event) { i0.ɵɵrestoreView(_r17); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.onKeySelected($event)); })("CreateRequested", function APIKeysResourceComponent_Conditional_7_Conditional_1_Conditional_1_Template_mj_api_key_list_CreateRequested_4_listener() { i0.ɵɵrestoreView(_r17); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.openCreateDialog()); });
|
|
500
487
|
i0.ɵɵelementEnd();
|
|
501
488
|
} if (rf & 2) {
|
|
502
489
|
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
503
490
|
i0.ɵɵadvance(4);
|
|
504
491
|
i0.ɵɵproperty("Filter", ctx_r1.ListFilter);
|
|
505
492
|
} }
|
|
506
|
-
function
|
|
507
|
-
i0.ɵɵconditionalCreate(0,
|
|
508
|
-
i0.ɵɵconditionalCreate(1,
|
|
493
|
+
function APIKeysResourceComponent_Conditional_7_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
494
|
+
i0.ɵɵconditionalCreate(0, APIKeysResourceComponent_Conditional_7_Conditional_1_Conditional_0_Template, 103, 26);
|
|
495
|
+
i0.ɵɵconditionalCreate(1, APIKeysResourceComponent_Conditional_7_Conditional_1_Conditional_1_Template, 6, 1);
|
|
509
496
|
} if (rf & 2) {
|
|
510
497
|
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
511
498
|
i0.ɵɵconditional(ctx_r1.CurrentView === "overview" ? 0 : -1);
|
|
512
499
|
i0.ɵɵadvance();
|
|
513
500
|
i0.ɵɵconditional(ctx_r1.CurrentView === "list" ? 1 : -1);
|
|
514
501
|
} }
|
|
515
|
-
function
|
|
516
|
-
const
|
|
517
|
-
i0.ɵɵelementStart(0, "mj-api-applications-panel",
|
|
518
|
-
i0.ɵɵlistener("ApplicationUpdated", function
|
|
502
|
+
function APIKeysResourceComponent_Conditional_7_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
503
|
+
const _r18 = i0.ɵɵgetCurrentView();
|
|
504
|
+
i0.ɵɵelementStart(0, "mj-api-applications-panel", 112);
|
|
505
|
+
i0.ɵɵlistener("ApplicationUpdated", function APIKeysResourceComponent_Conditional_7_Conditional_2_Template_mj_api_applications_panel_ApplicationUpdated_0_listener() { i0.ɵɵrestoreView(_r18); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onDataUpdated()); });
|
|
519
506
|
i0.ɵɵelementEnd();
|
|
520
507
|
} }
|
|
521
|
-
function
|
|
522
|
-
const
|
|
523
|
-
i0.ɵɵelementStart(0, "mj-api-scopes-panel",
|
|
524
|
-
i0.ɵɵlistener("ScopeUpdated", function
|
|
508
|
+
function APIKeysResourceComponent_Conditional_7_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
509
|
+
const _r19 = i0.ɵɵgetCurrentView();
|
|
510
|
+
i0.ɵɵelementStart(0, "mj-api-scopes-panel", 113);
|
|
511
|
+
i0.ɵɵlistener("ScopeUpdated", function APIKeysResourceComponent_Conditional_7_Conditional_3_Template_mj_api_scopes_panel_ScopeUpdated_0_listener() { i0.ɵɵrestoreView(_r19); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onDataUpdated()); });
|
|
525
512
|
i0.ɵɵelementEnd();
|
|
526
513
|
} }
|
|
527
|
-
function
|
|
514
|
+
function APIKeysResourceComponent_Conditional_7_Conditional_4_Template(rf, ctx) { if (rf & 1) {
|
|
528
515
|
i0.ɵɵelement(0, "mj-api-usage-panel");
|
|
529
516
|
} }
|
|
530
|
-
function
|
|
531
|
-
|
|
532
|
-
i0.ɵɵ
|
|
533
|
-
i0.ɵɵ
|
|
534
|
-
i0.ɵɵ
|
|
535
|
-
i0.ɵɵ
|
|
536
|
-
i0.ɵɵelementEnd()()();
|
|
537
|
-
i0.ɵɵelementStart(6, "div", 9)(7, "button", 10);
|
|
538
|
-
i0.ɵɵlistener("click", function APIKeysResourceComponent_Conditional_2_Template_button_click_7_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); ctx_r1.switchTab("keys"); return i0.ɵɵresetView(ctx_r1.closeNav()); });
|
|
539
|
-
i0.ɵɵelement(8, "i", 8);
|
|
540
|
-
i0.ɵɵelementStart(9, "span", 11);
|
|
541
|
-
i0.ɵɵtext(10, "API Keys");
|
|
542
|
-
i0.ɵɵelementEnd();
|
|
543
|
-
i0.ɵɵelementStart(11, "span", 12);
|
|
544
|
-
i0.ɵɵtext(12);
|
|
545
|
-
i0.ɵɵelementEnd()();
|
|
546
|
-
i0.ɵɵelementStart(13, "button", 10);
|
|
547
|
-
i0.ɵɵlistener("click", function APIKeysResourceComponent_Conditional_2_Template_button_click_13_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); ctx_r1.switchTab("applications"); return i0.ɵɵresetView(ctx_r1.closeNav()); });
|
|
548
|
-
i0.ɵɵelement(14, "i", 13);
|
|
549
|
-
i0.ɵɵelementStart(15, "span", 11);
|
|
550
|
-
i0.ɵɵtext(16, "Applications");
|
|
551
|
-
i0.ɵɵelementEnd();
|
|
552
|
-
i0.ɵɵelementStart(17, "span", 12);
|
|
553
|
-
i0.ɵɵtext(18);
|
|
554
|
-
i0.ɵɵelementEnd()();
|
|
555
|
-
i0.ɵɵelementStart(19, "button", 10);
|
|
556
|
-
i0.ɵɵlistener("click", function APIKeysResourceComponent_Conditional_2_Template_button_click_19_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); ctx_r1.switchTab("scopes"); return i0.ɵɵresetView(ctx_r1.closeNav()); });
|
|
557
|
-
i0.ɵɵelement(20, "i", 14);
|
|
558
|
-
i0.ɵɵelementStart(21, "span", 11);
|
|
559
|
-
i0.ɵɵtext(22, "Scopes");
|
|
560
|
-
i0.ɵɵelementEnd();
|
|
561
|
-
i0.ɵɵelementStart(23, "span", 12);
|
|
562
|
-
i0.ɵɵtext(24);
|
|
563
|
-
i0.ɵɵelementEnd()();
|
|
564
|
-
i0.ɵɵelementStart(25, "button", 10);
|
|
565
|
-
i0.ɵɵlistener("click", function APIKeysResourceComponent_Conditional_2_Template_button_click_25_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); ctx_r1.switchTab("usage"); return i0.ɵɵresetView(ctx_r1.closeNav()); });
|
|
566
|
-
i0.ɵɵelement(26, "i", 15);
|
|
567
|
-
i0.ɵɵelementStart(27, "span", 11);
|
|
568
|
-
i0.ɵɵtext(28, "Usage Analytics");
|
|
569
|
-
i0.ɵɵelementEnd()()()();
|
|
570
|
-
i0.ɵɵelementStart(29, "div", 16)(30, "div", 17);
|
|
571
|
-
i0.ɵɵconditionalCreate(31, APIKeysResourceComponent_Conditional_2_Conditional_31_Template, 2, 2);
|
|
572
|
-
i0.ɵɵconditionalCreate(32, APIKeysResourceComponent_Conditional_2_Conditional_32_Template, 1, 0, "mj-api-applications-panel");
|
|
573
|
-
i0.ɵɵconditionalCreate(33, APIKeysResourceComponent_Conditional_2_Conditional_33_Template, 1, 0, "mj-api-scopes-panel");
|
|
574
|
-
i0.ɵɵconditionalCreate(34, APIKeysResourceComponent_Conditional_2_Conditional_34_Template, 1, 0, "mj-api-usage-panel");
|
|
575
|
-
i0.ɵɵelementEnd()();
|
|
576
|
-
i0.ɵɵelementStart(35, "button", 18);
|
|
577
|
-
i0.ɵɵlistener("click", function APIKeysResourceComponent_Conditional_2_Template_button_click_35_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.toggleNav()); });
|
|
578
|
-
i0.ɵɵelement(36, "i", 19);
|
|
579
|
-
i0.ɵɵelementEnd();
|
|
580
|
-
i0.ɵɵelementStart(37, "div", 20);
|
|
581
|
-
i0.ɵɵlistener("click", function APIKeysResourceComponent_Conditional_2_Template_div_click_37_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.closeNav()); });
|
|
517
|
+
function APIKeysResourceComponent_Conditional_7_Template(rf, ctx) { if (rf & 1) {
|
|
518
|
+
i0.ɵɵelementStart(0, "mj-page-body-interior");
|
|
519
|
+
i0.ɵɵconditionalCreate(1, APIKeysResourceComponent_Conditional_7_Conditional_1_Template, 2, 2);
|
|
520
|
+
i0.ɵɵconditionalCreate(2, APIKeysResourceComponent_Conditional_7_Conditional_2_Template, 1, 0, "mj-api-applications-panel");
|
|
521
|
+
i0.ɵɵconditionalCreate(3, APIKeysResourceComponent_Conditional_7_Conditional_3_Template, 1, 0, "mj-api-scopes-panel");
|
|
522
|
+
i0.ɵɵconditionalCreate(4, APIKeysResourceComponent_Conditional_7_Conditional_4_Template, 1, 0, "mj-api-usage-panel");
|
|
582
523
|
i0.ɵɵelementEnd();
|
|
583
524
|
} if (rf & 2) {
|
|
584
525
|
const ctx_r1 = i0.ɵɵnextContext();
|
|
585
|
-
i0.ɵɵadvance(7);
|
|
586
|
-
i0.ɵɵclassProp("active", ctx_r1.MainTab === "keys");
|
|
587
|
-
i0.ɵɵadvance(5);
|
|
588
|
-
i0.ɵɵtextInterpolate(ctx_r1.TotalKeys);
|
|
589
526
|
i0.ɵɵadvance();
|
|
590
|
-
i0.ɵɵ
|
|
591
|
-
i0.ɵɵadvance(5);
|
|
592
|
-
i0.ɵɵtextInterpolate(ctx_r1.ApplicationCount);
|
|
527
|
+
i0.ɵɵconditional(ctx_r1.MainTab === "keys" ? 1 : -1);
|
|
593
528
|
i0.ɵɵadvance();
|
|
594
|
-
i0.ɵɵ
|
|
595
|
-
i0.ɵɵadvance(5);
|
|
596
|
-
i0.ɵɵtextInterpolate(ctx_r1.ScopeCount);
|
|
529
|
+
i0.ɵɵconditional(ctx_r1.MainTab === "applications" ? 2 : -1);
|
|
597
530
|
i0.ɵɵadvance();
|
|
598
|
-
i0.ɵɵ
|
|
599
|
-
i0.ɵɵadvance(6);
|
|
600
|
-
i0.ɵɵconditional(ctx_r1.MainTab === "keys" ? 31 : -1);
|
|
531
|
+
i0.ɵɵconditional(ctx_r1.MainTab === "scopes" ? 3 : -1);
|
|
601
532
|
i0.ɵɵadvance();
|
|
602
|
-
i0.ɵɵconditional(ctx_r1.MainTab === "
|
|
603
|
-
i0.ɵɵadvance();
|
|
604
|
-
i0.ɵɵconditional(ctx_r1.MainTab === "scopes" ? 33 : -1);
|
|
605
|
-
i0.ɵɵadvance();
|
|
606
|
-
i0.ɵɵconditional(ctx_r1.MainTab === "usage" ? 34 : -1);
|
|
607
|
-
i0.ɵɵadvance(2);
|
|
608
|
-
i0.ɵɵclassProp("fa-bars", !ctx_r1.NavOpen)("fa-times", ctx_r1.NavOpen);
|
|
533
|
+
i0.ɵɵconditional(ctx_r1.MainTab === "usage" ? 4 : -1);
|
|
609
534
|
} }
|
|
610
535
|
/**
|
|
611
536
|
* API Keys Resource Component
|
|
@@ -624,7 +549,6 @@ let APIKeysResourceComponent = class APIKeysResourceComponent extends BaseResour
|
|
|
624
549
|
CurrentView = 'overview';
|
|
625
550
|
ListFilter = 'all';
|
|
626
551
|
MainTab = 'keys';
|
|
627
|
-
NavOpen = false;
|
|
628
552
|
// Application and scope counts for tab badges
|
|
629
553
|
ApplicationCount = 0;
|
|
630
554
|
ScopeCount = 0;
|
|
@@ -1073,26 +997,50 @@ let APIKeysResourceComponent = class APIKeysResourceComponent extends BaseResour
|
|
|
1073
997
|
this.MainTab = 'scopes';
|
|
1074
998
|
}
|
|
1075
999
|
/**
|
|
1076
|
-
* Switch to a main tab
|
|
1000
|
+
* Switch to a main tab. Resets to the overview view when returning to the
|
|
1001
|
+
* Keys tab so the user always lands on the dashboard, not a stale list view.
|
|
1077
1002
|
*/
|
|
1078
1003
|
switchTab(tab) {
|
|
1079
1004
|
this.MainTab = tab;
|
|
1080
|
-
// Reset to overview when switching back to keys
|
|
1081
1005
|
if (tab === 'keys') {
|
|
1082
1006
|
this.CurrentView = 'overview';
|
|
1083
1007
|
}
|
|
1084
1008
|
}
|
|
1085
1009
|
/**
|
|
1086
|
-
*
|
|
1010
|
+
* L2 tabs rendered as `<mj-tab-nav>` in the interior chrome's [toolbar] slot.
|
|
1011
|
+
* Badges reflect live counts; Usage Analytics has no badge by design.
|
|
1087
1012
|
*/
|
|
1088
|
-
|
|
1089
|
-
|
|
1013
|
+
get tabsConfig() {
|
|
1014
|
+
return [
|
|
1015
|
+
{ key: 'keys', icon: 'fa-solid fa-key', label: 'API Keys', badge: this.TotalKeys },
|
|
1016
|
+
{ key: 'applications', icon: 'fa-solid fa-cube', label: 'Applications', badge: this.ApplicationCount },
|
|
1017
|
+
{ key: 'scopes', icon: 'fa-solid fa-shield-halved', label: 'Scopes', badge: this.ScopeCount },
|
|
1018
|
+
{ key: 'usage', icon: 'fa-solid fa-chart-line', label: 'Usage Analytics' }
|
|
1019
|
+
];
|
|
1090
1020
|
}
|
|
1091
|
-
/**
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1021
|
+
/** Adapter for `<mj-tab-nav>`'s string-typed `(TabChange)` output. */
|
|
1022
|
+
onTabChange(key) {
|
|
1023
|
+
if (key === 'keys' || key === 'applications' || key === 'scopes' || key === 'usage') {
|
|
1024
|
+
this.switchTab(key);
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
/** Title rendered in the interior chrome — varies per tab. */
|
|
1028
|
+
get currentTabTitle() {
|
|
1029
|
+
switch (this.MainTab) {
|
|
1030
|
+
case 'keys': return 'API Keys';
|
|
1031
|
+
case 'applications': return 'API Applications';
|
|
1032
|
+
case 'scopes': return 'API Scopes';
|
|
1033
|
+
case 'usage': return 'Usage Analytics';
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
/** Subtitle rendered in the interior chrome — varies per tab to give context. */
|
|
1037
|
+
get currentTabSubtitle() {
|
|
1038
|
+
switch (this.MainTab) {
|
|
1039
|
+
case 'keys': return 'Manage API keys for external integrations and services';
|
|
1040
|
+
case 'applications': return 'Register and manage API applications';
|
|
1041
|
+
case 'scopes': return 'Permission scopes that can be granted to API keys';
|
|
1042
|
+
case 'usage': return 'Track usage patterns and analytics across all API keys';
|
|
1043
|
+
}
|
|
1096
1044
|
}
|
|
1097
1045
|
/**
|
|
1098
1046
|
* Handle updates from child panels
|
|
@@ -1107,27 +1055,37 @@ let APIKeysResourceComponent = class APIKeysResourceComponent extends BaseResour
|
|
|
1107
1055
|
} if (rf & 2) {
|
|
1108
1056
|
let _t;
|
|
1109
1057
|
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.keyListComponent = _t.first);
|
|
1110
|
-
} }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls:
|
|
1111
|
-
i0.ɵɵelementStart(0, "
|
|
1112
|
-
i0.ɵɵ
|
|
1113
|
-
i0.ɵɵ
|
|
1114
|
-
i0.ɵɵelementStart(3, "mj-
|
|
1115
|
-
i0.ɵɵlistener("
|
|
1058
|
+
} }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 10, vars: 10, consts: [["keyList", ""], ["Role", "region", "AriaLabel", "API Keys", 3, "Title", "Subtitle"], ["toolbar", ""], [3, "TabChange", "Tabs", "ActiveKey"], ["actions", ""], [3, "Clicked", "Loading"], ["mjButton", "", "variant", "primary", "size", "sm", "aria-label", "Generate a new API key"], [1, "api-keys-loading"], [3, "Created", "Closed", "Visible"], [3, "Updated", "Revoked", "Closed", "Visible", "KeyId"], ["mjButton", "", "variant", "primary", "size", "sm", "aria-label", "Generate a new API key", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-plus"], ["text", "Loading API Keys..."], [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"], [1, "health-alert"], [1, "health-warning-text"], [1, "health-info-text"], [1, "health-ok"], [1, "kpi-row"], [1, "kpi-card", "clickable", 3, "click"], [1, "kpi-icon"], [1, "fa-solid", "fa-key"], [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"], [1, "kpi-trend", "warning"], [1, "fa-solid", "fa-ban"], [1, "fa-solid", "fa-shield-halved"], [1, "content-grid"], [1, "panel", "keys-panel"], [1, "panel-header"], [1, "panel-title"], [1, "panel-action", 3, "click"], [1, "panel-body"], [1, "key-list"], [1, "empty-state"], [1, "panel", "scope-panel"], [1, "panel-subtitle"], [1, "scope-chart"], [1, "panel", "activity-panel"], [1, "fa-solid", "fa-clock-rotate-left"], [1, "activity-list"], [1, "quick-actions"], [1, "security-notice"], [1, "fa-solid", "fa-shield-check"], [1, "notice-content"], [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, "key-item"], [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, "donut-chart-container"], ["viewBox", "0 0 100 100", 1, "donut-chart"], ["cx", "50", "cy", "50", "r", "40", "fill", "none", "stroke", "#e5e7eb", "stroke-width", "12"], [1, "donut-center"], [1, "donut-total"], [1, "donut-label"], [1, "scope-legend"], [1, "legend-item"], ["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-item"], [1, "activity-item", 3, "click"], [1, "activity-icon", 3, "ngClass"], [1, "activity-info"], [1, "activity-name"], [1, "activity-meta"], [1, "activity-action"], [1, "activity-user"], [1, "activity-time"], [1, "fa-solid", "fa-inbox"], [1, "quick-actions-title"], [1, "quick-actions-grid"], [1, "quick-action", 3, "click"], [1, "fa-solid", "fa-plus"], [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) {
|
|
1059
|
+
i0.ɵɵelementStart(0, "mj-page-header-interior", 1)(1, "div", 2)(2, "mj-tab-nav", 3);
|
|
1060
|
+
i0.ɵɵlistener("TabChange", function APIKeysResourceComponent_Template_mj_tab_nav_TabChange_2_listener($event) { return ctx.onTabChange($event); });
|
|
1061
|
+
i0.ɵɵelementEnd()();
|
|
1062
|
+
i0.ɵɵelementStart(3, "div", 4)(4, "mj-refresh-button", 5);
|
|
1063
|
+
i0.ɵɵlistener("Clicked", function APIKeysResourceComponent_Template_mj_refresh_button_Clicked_4_listener() { return ctx.refresh(); });
|
|
1116
1064
|
i0.ɵɵelementEnd();
|
|
1117
|
-
i0.ɵɵ
|
|
1118
|
-
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(); });
|
|
1065
|
+
i0.ɵɵconditionalCreate(5, APIKeysResourceComponent_Conditional_5_Template, 3, 0, "button", 6);
|
|
1119
1066
|
i0.ɵɵelementEnd()();
|
|
1067
|
+
i0.ɵɵconditionalCreate(6, APIKeysResourceComponent_Conditional_6_Template, 2, 0, "div", 7)(7, APIKeysResourceComponent_Conditional_7_Template, 5, 4, "mj-page-body-interior");
|
|
1068
|
+
i0.ɵɵelementStart(8, "mj-api-key-create-dialog", 8);
|
|
1069
|
+
i0.ɵɵlistener("Created", function APIKeysResourceComponent_Template_mj_api_key_create_dialog_Created_8_listener($event) { return ctx.onKeyCreated($event); })("Closed", function APIKeysResourceComponent_Template_mj_api_key_create_dialog_Closed_8_listener() { return ctx.onCreateDialogClosed(); });
|
|
1070
|
+
i0.ɵɵelementEnd();
|
|
1071
|
+
i0.ɵɵelementStart(9, "mj-api-key-edit-panel", 9);
|
|
1072
|
+
i0.ɵɵlistener("Updated", function APIKeysResourceComponent_Template_mj_api_key_edit_panel_Updated_9_listener() { return ctx.onKeyUpdated(); })("Revoked", function APIKeysResourceComponent_Template_mj_api_key_edit_panel_Revoked_9_listener() { return ctx.onKeyRevoked(); })("Closed", function APIKeysResourceComponent_Template_mj_api_key_edit_panel_Closed_9_listener() { return ctx.onEditPanelClosed(); });
|
|
1073
|
+
i0.ɵɵelementEnd();
|
|
1120
1074
|
} if (rf & 2) {
|
|
1121
|
-
i0.ɵɵ
|
|
1122
|
-
i0.ɵɵadvance();
|
|
1123
|
-
i0.ɵɵ
|
|
1075
|
+
i0.ɵɵproperty("Title", ctx.currentTabTitle)("Subtitle", ctx.currentTabSubtitle);
|
|
1076
|
+
i0.ɵɵadvance(2);
|
|
1077
|
+
i0.ɵɵproperty("Tabs", ctx.tabsConfig)("ActiveKey", ctx.MainTab);
|
|
1078
|
+
i0.ɵɵadvance(2);
|
|
1079
|
+
i0.ɵɵproperty("Loading", ctx.IsLoading);
|
|
1124
1080
|
i0.ɵɵadvance();
|
|
1125
|
-
i0.ɵɵconditional(
|
|
1081
|
+
i0.ɵɵconditional(ctx.MainTab === "keys" && ctx.CurrentView === "overview" && ctx.UserCanCreateKeys ? 5 : -1);
|
|
1126
1082
|
i0.ɵɵadvance();
|
|
1083
|
+
i0.ɵɵconditional(ctx.IsLoading ? 6 : 7);
|
|
1084
|
+
i0.ɵɵadvance(2);
|
|
1127
1085
|
i0.ɵɵproperty("Visible", ctx.ShowCreateDialog);
|
|
1128
1086
|
i0.ɵɵadvance();
|
|
1129
1087
|
i0.ɵɵproperty("Visible", ctx.ShowEditPanel)("KeyId", ctx.SelectedKeyId);
|
|
1130
|
-
} }, dependencies: [i1.NgClass, 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(--mj-bg-surface);\n border-right: 1px solid var(--mj-border-default);\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(--mj-border-default);\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(--mj-text-primary);\n}\n\n.nav-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\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(--mj-text-secondary);\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(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n\n.nav-item.active[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n box-shadow: var(--mj-shadow-brand-sm);\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: var(--mj-bg-surface-active);\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(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n font-size: 14px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.back-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\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(--mj-text-primary);\n margin: 0 0 4px 0;\n}\n\n.overview-subtitle[_ngcontent-%COMP%] {\n font-size: 14px;\n color: var(--mj-text-secondary);\n margin: 0;\n}\n\n.header-actions[_ngcontent-%COMP%] {\n display: flex;\n 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(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.btn-refresh[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.btn-refresh[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n}\n\n.btn-primary[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 20px;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border: none;\n border-radius: 8px;\n font-weight: 600;\n font-size: 14px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.btn-primary[_ngcontent-%COMP%]:hover {\n transform: translateY(-1px);\n box-shadow: var(--mj-shadow-brand-md);\n}\n\n\n\n.health-banner[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n padding: 20px 24px;\n background: var(--mj-status-success-bg);\n border: 1px solid var(--mj-status-success-border);\n border-radius: 16px;\n margin-bottom: 24px;\n}\n\n.health-banner.health-warning[_ngcontent-%COMP%] {\n background: var(--mj-status-warning-bg);\n border-color: var(--mj-color-accent-300);\n}\n\n.health-banner.health-critical[_ngcontent-%COMP%] {\n background: var(--mj-status-error-bg);\n border-color: var(--mj-status-error-border);\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: var(--mj-border-default);\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: var(--mj-status-success);\n animation: _ngcontent-%COMP%_progress 1s ease-out forwards;\n}\n\n.health-banner.health-warning[_ngcontent-%COMP%] .circle[_ngcontent-%COMP%] {\n stroke: var(--mj-color-warning-500);\n}\n\n.health-banner.health-critical[_ngcontent-%COMP%] .circle[_ngcontent-%COMP%] {\n stroke: var(--mj-status-error);\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(--mj-text-primary);\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: var(--mj-color-success-600);\n margin-bottom: 4px;\n}\n\n.health-banner.health-warning[_ngcontent-%COMP%] .health-label[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary-hover);\n}\n\n.health-banner.health-critical[_ngcontent-%COMP%] .health-label[_ngcontent-%COMP%] {\n color: var(--mj-color-error-600);\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: var(--mj-color-error-600);\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: var(--mj-brand-primary-hover);\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: var(--mj-text-secondary);\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: var(--mj-color-success-600);\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(--mj-bg-surface);\n border-radius: 12px;\n box-shadow: var(--mj-shadow-md);\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: var(--mj-shadow-lg);\n}\n\n.kpi-card.active[_ngcontent-%COMP%] .kpi-icon[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, var(--mj-status-success) 0%, var(--mj-color-success-600) 100%);\n}\n\n.kpi-card.warning[_ngcontent-%COMP%] .kpi-icon[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, var(--mj-color-warning-500) 0%, var(--mj-brand-primary-hover) 100%);\n}\n\n.kpi-card.danger[_ngcontent-%COMP%] .kpi-icon[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, var(--mj-status-error) 0%, var(--mj-color-error-600) 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: var(--mj-brand-primary);\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: var(--mj-text-inverse);\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(--mj-text-primary);\n line-height: 1.2;\n}\n\n.kpi-label[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-secondary);\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(--mj-text-muted);\n}\n\n.kpi-trend.success[_ngcontent-%COMP%] {\n color: var(--mj-status-success);\n}\n\n.kpi-trend.warning[_ngcontent-%COMP%] {\n color: var(--mj-color-warning-500);\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(--mj-bg-surface);\n border-radius: 12px;\n box-shadow: var(--mj-shadow-md);\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(--mj-bg-page);\n border-bottom: 1px solid var(--mj-border-default);\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(--mj-text-primary);\n}\n\n.panel-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n\n.panel-subtitle[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-muted);\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(--mj-border-default);\n border-radius: 6px;\n font-size: 12px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.panel-action[_ngcontent-%COMP%]:hover {\n background: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\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(--mj-bg-page);\n border-radius: 10px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.key-item[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\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, var(--mj-color-neutral-500) 0%, var(--mj-color-neutral-600) 100%);\n border-radius: 8px;\n margin-right: 14px;\n flex-shrink: 0;\n}\n\n.key-icon.active[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n}\n\n.key-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 16px;\n color: var(--mj-text-inverse);\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(--mj-text-primary);\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(--mj-text-secondary);\n}\n\n.key-hash[_ngcontent-%COMP%] {\n font-family: monospace;\n background: var(--mj-bg-surface-active);\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(--mj-text-secondary);\n}\n\n.expiration[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-muted);\n}\n\n.expiration.expiring-soon[_ngcontent-%COMP%] {\n color: var(--mj-color-warning-500);\n font-weight: 500;\n}\n\n.expiration.expiring-critical[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n font-weight: 500;\n}\n\n.expiration.expired[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\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(--mj-text-primary);\n}\n\n.donut-label[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-secondary);\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(--mj-bg-page);\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.legend-item[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\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(--mj-text-primary);\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(--mj-text-secondary);\n}\n\n.legend-value[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-secondary);\n}\n\n.legend-arrow[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\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(--mj-bg-page);\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.activity-item[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\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, var(--mj-color-brand-100));\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: var(--mj-brand-primary);\n}\n\n.activity-icon.action-created[_ngcontent-%COMP%] {\n background: var(--mj-color-success-100);\n}\n\n.activity-icon.action-created[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-color-success-600);\n}\n\n.activity-icon.action-updated[_ngcontent-%COMP%] {\n background: var(--mj-color-indigo-100);\n}\n\n.activity-icon.action-updated[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-color-indigo-500);\n}\n\n.activity-icon.action-revoked[_ngcontent-%COMP%] {\n background: var(--mj-color-error-100);\n}\n\n.activity-icon.action-revoked[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-color-error-600);\n}\n\n.activity-icon.action-used[_ngcontent-%COMP%] {\n background: var(--mj-color-brand-100);\n}\n\n.activity-icon.action-used[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary-hover);\n}\n\n.activity-icon.action-extended[_ngcontent-%COMP%] {\n background: var(--mj-color-info-100);\n}\n\n.activity-icon.action-extended[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-status-info);\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(--mj-text-primary);\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(--mj-text-secondary);\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(--mj-text-muted);\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(--mj-text-primary);\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(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 10px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.quick-action[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-brand-primary);\n background: var(--mj-color-brand-50);\n transform: translateY(-2px);\n}\n\n.quick-action[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 20px;\n color: var(--mj-brand-primary);\n}\n\n.quick-action[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n font-size: 12px;\n font-weight: 500;\n color: var(--mj-text-secondary);\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(--mj-text-secondary);\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, var(--mj-color-brand-50) 0%, var(--mj-color-brand-100) 100%);\n border-radius: 12px;\n border: 1px solid var(--mj-color-accent-300);\n}\n\n.security-notice[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 20px;\n color: var(--mj-brand-primary);\n margin-right: 12px;\n margin-top: 2px;\n}\n\n.notice-content[_ngcontent-%COMP%] {\n font-size: 13px;\n color: var(--mj-color-brand-800);\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: var(--mj-brand-primary);\n border: none;\n border-radius: 50%;\n color: var(--mj-text-inverse);\n font-size: 24px;\n box-shadow: var(--mj-shadow-brand-md);\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: var(--mj-bg-overlay);\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: var(--mj-shadow-xl);\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}"] });
|
|
1088
|
+
} }, dependencies: [i1.NgClass, i2.MJButtonDirective, i2.MJPageHeaderInteriorComponent, i2.MJPageBodyInteriorComponent, i2.MJRefreshButtonComponent, i2.MJTabNavComponent, i3.LoadingComponent, i4.APIKeyCreateDialogComponent, i5.APIKeyEditPanelComponent, i6.APIKeyListComponent, i7.APIApplicationsPanelComponent, i8.APIScopesPanelComponent, i9.APIUsagePanelComponent], styles: ["\n\n\n\n\n\n\n[_nghost-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n overflow: hidden;\n background: var(--mj-bg-page);\n}\n\n.api-keys-loading[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n align-items: center;\n justify-content: center;\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(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n font-size: 14px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.back-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n\n\n\n.health-banner[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n padding: 20px 24px;\n background: var(--mj-status-success-bg);\n border: 1px solid var(--mj-status-success-border);\n border-radius: 16px;\n margin-bottom: 24px;\n}\n\n.health-banner.health-warning[_ngcontent-%COMP%] {\n background: var(--mj-status-warning-bg);\n border-color: var(--mj-color-accent-300);\n}\n\n.health-banner.health-critical[_ngcontent-%COMP%] {\n background: var(--mj-status-error-bg);\n border-color: var(--mj-status-error-border);\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: var(--mj-border-default);\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: var(--mj-status-success);\n animation: _ngcontent-%COMP%_progress 1s ease-out forwards;\n}\n\n.health-banner.health-warning[_ngcontent-%COMP%] .circle[_ngcontent-%COMP%] {\n stroke: var(--mj-color-warning-500);\n}\n\n.health-banner.health-critical[_ngcontent-%COMP%] .circle[_ngcontent-%COMP%] {\n stroke: var(--mj-status-error);\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(--mj-text-primary);\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: var(--mj-color-success-600);\n margin-bottom: 4px;\n}\n\n.health-banner.health-warning[_ngcontent-%COMP%] .health-label[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary-hover);\n}\n\n.health-banner.health-critical[_ngcontent-%COMP%] .health-label[_ngcontent-%COMP%] {\n color: var(--mj-color-error-600);\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: var(--mj-color-error-600);\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: var(--mj-brand-primary-hover);\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: var(--mj-text-secondary);\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: var(--mj-color-success-600);\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(--mj-bg-surface);\n border-radius: 12px;\n box-shadow: var(--mj-shadow-md);\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: var(--mj-shadow-lg);\n}\n\n.kpi-card.active[_ngcontent-%COMP%] .kpi-icon[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, var(--mj-status-success) 0%, var(--mj-color-success-600) 100%);\n}\n\n.kpi-card.warning[_ngcontent-%COMP%] .kpi-icon[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, var(--mj-color-warning-500) 0%, var(--mj-brand-primary-hover) 100%);\n}\n\n.kpi-card.danger[_ngcontent-%COMP%] .kpi-icon[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, var(--mj-status-error) 0%, var(--mj-color-error-600) 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: var(--mj-brand-primary);\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: var(--mj-text-inverse);\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(--mj-text-primary);\n line-height: 1.2;\n}\n\n.kpi-label[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-secondary);\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(--mj-text-muted);\n}\n\n.kpi-trend.success[_ngcontent-%COMP%] {\n color: var(--mj-status-success);\n}\n\n.kpi-trend.warning[_ngcontent-%COMP%] {\n color: var(--mj-color-warning-500);\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(--mj-bg-surface);\n border-radius: 12px;\n box-shadow: var(--mj-shadow-md);\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(--mj-bg-page);\n border-bottom: 1px solid var(--mj-border-default);\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(--mj-text-primary);\n}\n\n.panel-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n\n.panel-subtitle[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-muted);\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(--mj-border-default);\n border-radius: 6px;\n font-size: 12px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.panel-action[_ngcontent-%COMP%]:hover {\n background: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\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(--mj-bg-page);\n border-radius: 10px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.key-item[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\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, var(--mj-color-neutral-500) 0%, var(--mj-color-neutral-600) 100%);\n border-radius: 8px;\n margin-right: 14px;\n flex-shrink: 0;\n}\n\n.key-icon.active[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n}\n\n.key-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 16px;\n color: var(--mj-text-inverse);\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(--mj-text-primary);\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(--mj-text-secondary);\n}\n\n.key-hash[_ngcontent-%COMP%] {\n font-family: monospace;\n background: var(--mj-bg-surface-active);\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(--mj-text-secondary);\n}\n\n.expiration[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-muted);\n}\n\n.expiration.expiring-soon[_ngcontent-%COMP%] {\n color: var(--mj-color-warning-500);\n font-weight: 500;\n}\n\n.expiration.expiring-critical[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n font-weight: 500;\n}\n\n.expiration.expired[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\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(--mj-text-primary);\n}\n\n.donut-label[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-secondary);\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(--mj-bg-page);\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.legend-item[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\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(--mj-text-primary);\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(--mj-text-secondary);\n}\n\n.legend-value[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-secondary);\n}\n\n.legend-arrow[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\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(--mj-bg-page);\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.activity-item[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\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, var(--mj-color-brand-100));\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: var(--mj-brand-primary);\n}\n\n.activity-icon.action-created[_ngcontent-%COMP%] {\n background: var(--mj-color-success-100);\n}\n\n.activity-icon.action-created[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-color-success-600);\n}\n\n.activity-icon.action-updated[_ngcontent-%COMP%] {\n background: var(--mj-color-indigo-100);\n}\n\n.activity-icon.action-updated[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-color-indigo-500);\n}\n\n.activity-icon.action-revoked[_ngcontent-%COMP%] {\n background: var(--mj-color-error-100);\n}\n\n.activity-icon.action-revoked[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-color-error-600);\n}\n\n.activity-icon.action-used[_ngcontent-%COMP%] {\n background: var(--mj-color-brand-100);\n}\n\n.activity-icon.action-used[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary-hover);\n}\n\n.activity-icon.action-extended[_ngcontent-%COMP%] {\n background: var(--mj-color-info-100);\n}\n\n.activity-icon.action-extended[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-status-info);\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(--mj-text-primary);\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(--mj-text-secondary);\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(--mj-text-muted);\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(--mj-text-primary);\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(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 10px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.quick-action[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-brand-primary);\n background: var(--mj-color-brand-50);\n transform: translateY(-2px);\n}\n\n.quick-action[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 20px;\n color: var(--mj-brand-primary);\n}\n\n.quick-action[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n font-size: 12px;\n font-weight: 500;\n color: var(--mj-text-secondary);\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(--mj-text-secondary);\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, var(--mj-color-brand-50) 0%, var(--mj-color-brand-100) 100%);\n border-radius: 12px;\n border: 1px solid var(--mj-color-accent-300);\n}\n\n.security-notice[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 20px;\n color: var(--mj-brand-primary);\n margin-right: 12px;\n margin-top: 2px;\n}\n\n.notice-content[_ngcontent-%COMP%] {\n font-size: 13px;\n color: var(--mj-color-brand-800);\n line-height: 1.5;\n}\n\n.notice-content[_ngcontent-%COMP%] strong[_ngcontent-%COMP%] {\n font-weight: 600;\n}\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\n\n\n@media (max-width: 768px) {\n .content-wrapper[_ngcontent-%COMP%] {\n padding: 16px;\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}"] });
|
|
1131
1089
|
};
|
|
1132
1090
|
APIKeysResourceComponent = __decorate([
|
|
1133
1091
|
RegisterClass(BaseResourceComponent, 'APIKeysResource')
|
|
@@ -1135,10 +1093,10 @@ APIKeysResourceComponent = __decorate([
|
|
|
1135
1093
|
export { APIKeysResourceComponent };
|
|
1136
1094
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(APIKeysResourceComponent, [{
|
|
1137
1095
|
type: Component,
|
|
1138
|
-
args: [{ standalone: false, selector: 'mj-api-keys-resource', template: "<div class=\"api-keys-dashboard\" [class.panel-open]=\"ShowCreateDialog || ShowEditPanel\" [class.nav-open]=\"NavOpen\">\n @if (IsLoading) {\n <mj-loading text=\"Loading API Keys...\"></mj-loading>\n }\n\n @if (!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 <!-- Main Content Area -->\n <div class=\"dashboard-content\">\n <div class=\"content-wrapper\">\n <!-- Keys Tab Content -->\n @if (MainTab === 'keys') {\n <!-- Overview View -->\n @if (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 @if (UserCanCreateKeys) {\n <button class=\"btn-primary\" (click)=\"openCreateDialog()\">\n <i class=\"fa-solid fa-plus\"></i>\n <span>Generate New Key</span>\n </button>\n }\n </div>\n </div>\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 @if (ExpiredKeys > 0) {\n <span class=\"health-alert\" (click)=\"showListView('expired')\">\n <i class=\"fa-solid fa-circle-exclamation\"></i>\n {{ExpiredKeys}} expired\n </span>\n }\n @if (ExpiringSoonCount > 0) {\n <span class=\"health-warning-text\" (click)=\"showListView('expiring')\">\n <i class=\"fa-solid fa-clock\"></i>\n {{ExpiringSoonCount}} expiring soon\n </span>\n }\n @if (NeverUsedKeys > 0) {\n <span class=\"health-info-text\" (click)=\"showListView('never-used')\">\n <i class=\"fa-solid fa-question-circle\"></i>\n {{NeverUsedKeys}} never used\n </span>\n }\n @if (ExpiredKeys === 0 && ExpiringSoonCount === 0 && NeverUsedKeys === 0) {\n <span class=\"health-ok\">\n <i class=\"fa-solid fa-check-circle\"></i>\n All keys healthy\n </span>\n }\n </div>\n </div>\n </div>\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 <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 <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 @if (ExpiringSoonCount > 0) {\n <div class=\"kpi-trend warning\">\n <i class=\"fa-solid fa-arrow-right\"></i>\n </div>\n }\n </div>\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 <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 <!-- 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 @if (TopUsedKeys.length > 0) {\n <div class=\"key-list\">\n @for (key of TopUsedKeys; track key) {\n <div class=\"key-item\" (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 }\n </div>\n }\n @if (TopUsedKeys.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-key\"></i>\n <span>No active keys with recent usage</span>\n </div>\n }\n </div>\n </div>\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 @if (ScopeStats.length > 0) {\n <div class=\"scope-chart\">\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 @for (stat of ScopeStats; track stat; let i = $index) {\n <ng-container>\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 }\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 @for (stat of ScopeStats; track stat) {\n <div class=\"legend-item\" (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 }\n </div>\n </div>\n }\n @if (ScopeStats.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-shield-halved\"></i>\n <span>No scopes configured</span>\n </div>\n }\n </div>\n </div>\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 @if (RecentActivity.length > 0) {\n <div class=\"activity-list\">\n @for (activity of RecentActivity; track activity) {\n <div class=\"activity-item\" (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 @if (activity.user) {\n <span class=\"activity-user\">by {{activity.user}}</span>\n }\n </div>\n </div>\n <div class=\"activity-time\">\n {{formatDate(activity.date)}}\n </div>\n </div>\n }\n </div>\n }\n @if (RecentActivity.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-inbox\"></i>\n <span>No recent activity</span>\n </div>\n }\n </div>\n </div>\n </div>\n <!-- Quick Actions -->\n @if (UserCanCreateKeys) {\n <div class=\"quick-actions\">\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 }\n <!-- List View -->\n @if (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 }\n }\n <!-- Applications Tab Content -->\n @if (MainTab === 'applications') {\n <mj-api-applications-panel\n (ApplicationUpdated)=\"onDataUpdated()\">\n </mj-api-applications-panel>\n }\n <!-- Scopes Tab Content -->\n @if (MainTab === 'scopes') {\n <mj-api-scopes-panel\n (ScopeUpdated)=\"onDataUpdated()\">\n </mj-api-scopes-panel>\n }\n <!-- Usage Tab Content -->\n @if (MainTab === 'usage') {\n <mj-api-usage-panel></mj-api-usage-panel>\n }\n </div><!-- /.content-wrapper -->\n </div><!-- /.dashboard-content -->\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 <!-- Mobile Navigation Overlay -->\n <div class=\"mobile-nav-overlay\" (click)=\"closeNav()\"></div>\n }\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(--mj-bg-surface);\n border-right: 1px solid var(--mj-border-default);\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(--mj-border-default);\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(--mj-text-primary);\n}\n\n.nav-title i {\n color: var(--mj-brand-primary);\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(--mj-text-secondary);\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(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n\n.nav-item.active {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n box-shadow: var(--mj-shadow-brand-sm);\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: var(--mj-bg-surface-active);\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(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n font-size: 14px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.back-btn:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\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(--mj-text-primary);\n margin: 0 0 4px 0;\n}\n\n.overview-subtitle {\n font-size: 14px;\n color: var(--mj-text-secondary);\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(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.btn-refresh:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.btn-refresh i {\n color: var(--mj-text-secondary);\n}\n\n.btn-primary {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 20px;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border: none;\n border-radius: 8px;\n font-weight: 600;\n font-size: 14px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.btn-primary:hover {\n transform: translateY(-1px);\n box-shadow: var(--mj-shadow-brand-md);\n}\n\n/* Health Banner */\n.health-banner {\n display: flex;\n align-items: center;\n padding: 20px 24px;\n background: var(--mj-status-success-bg);\n border: 1px solid var(--mj-status-success-border);\n border-radius: 16px;\n margin-bottom: 24px;\n}\n\n.health-banner.health-warning {\n background: var(--mj-status-warning-bg);\n border-color: var(--mj-color-accent-300);\n}\n\n.health-banner.health-critical {\n background: var(--mj-status-error-bg);\n border-color: var(--mj-status-error-border);\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: var(--mj-border-default);\n stroke-width: 3.8;\n}\n\n.circle {\n fill: none;\n stroke-width: 3.8;\n stroke-linecap: round;\n stroke: var(--mj-status-success);\n animation: progress 1s ease-out forwards;\n}\n\n.health-banner.health-warning .circle {\n stroke: var(--mj-color-warning-500);\n}\n\n.health-banner.health-critical .circle {\n stroke: var(--mj-status-error);\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(--mj-text-primary);\n}\n\n.health-info {\n flex: 1;\n}\n\n.health-label {\n font-size: 18px;\n font-weight: 700;\n color: var(--mj-color-success-600);\n margin-bottom: 4px;\n}\n\n.health-banner.health-warning .health-label {\n color: var(--mj-brand-primary-hover);\n}\n\n.health-banner.health-critical .health-label {\n color: var(--mj-color-error-600);\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: var(--mj-color-error-600);\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: var(--mj-brand-primary-hover);\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: var(--mj-text-secondary);\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: var(--mj-color-success-600);\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(--mj-bg-surface);\n border-radius: 12px;\n box-shadow: var(--mj-shadow-md);\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: var(--mj-shadow-lg);\n}\n\n.kpi-card.active .kpi-icon {\n background: linear-gradient(135deg, var(--mj-status-success) 0%, var(--mj-color-success-600) 100%);\n}\n\n.kpi-card.warning .kpi-icon {\n background: linear-gradient(135deg, var(--mj-color-warning-500) 0%, var(--mj-brand-primary-hover) 100%);\n}\n\n.kpi-card.danger .kpi-icon {\n background: linear-gradient(135deg, var(--mj-status-error) 0%, var(--mj-color-error-600) 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: var(--mj-brand-primary);\n border-radius: 10px;\n margin-right: 14px;\n flex-shrink: 0;\n}\n\n.kpi-icon i {\n font-size: 20px;\n color: var(--mj-text-inverse);\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(--mj-text-primary);\n line-height: 1.2;\n}\n\n.kpi-label {\n font-size: 12px;\n color: var(--mj-text-secondary);\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(--mj-text-muted);\n}\n\n.kpi-trend.success {\n color: var(--mj-status-success);\n}\n\n.kpi-trend.warning {\n color: var(--mj-color-warning-500);\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(--mj-bg-surface);\n border-radius: 12px;\n box-shadow: var(--mj-shadow-md);\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(--mj-bg-page);\n border-bottom: 1px solid var(--mj-border-default);\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(--mj-text-primary);\n}\n\n.panel-title i {\n color: var(--mj-brand-primary);\n}\n\n.panel-subtitle {\n font-size: 12px;\n color: var(--mj-text-muted);\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(--mj-border-default);\n border-radius: 6px;\n font-size: 12px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.panel-action:hover {\n background: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\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(--mj-bg-page);\n border-radius: 10px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.key-item:hover {\n background: var(--mj-bg-surface-hover);\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, var(--mj-color-neutral-500) 0%, var(--mj-color-neutral-600) 100%);\n border-radius: 8px;\n margin-right: 14px;\n flex-shrink: 0;\n}\n\n.key-icon.active {\n background: var(--mj-brand-primary);\n}\n\n.key-icon i {\n font-size: 16px;\n color: var(--mj-text-inverse);\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(--mj-text-primary);\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(--mj-text-secondary);\n}\n\n.key-hash {\n font-family: monospace;\n background: var(--mj-bg-surface-active);\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(--mj-text-secondary);\n}\n\n.expiration {\n font-size: 11px;\n color: var(--mj-text-muted);\n}\n\n.expiration.expiring-soon {\n color: var(--mj-color-warning-500);\n font-weight: 500;\n}\n\n.expiration.expiring-critical {\n color: var(--mj-status-error);\n font-weight: 500;\n}\n\n.expiration.expired {\n color: var(--mj-status-error);\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(--mj-text-primary);\n}\n\n.donut-label {\n font-size: 11px;\n color: var(--mj-text-secondary);\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(--mj-bg-page);\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.legend-item:hover {\n background: var(--mj-bg-surface-hover);\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(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.legend-name i {\n font-size: 12px;\n color: var(--mj-text-secondary);\n}\n\n.legend-value {\n font-size: 12px;\n color: var(--mj-text-secondary);\n}\n\n.legend-arrow {\n color: var(--mj-text-muted);\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(--mj-bg-page);\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.activity-item:hover {\n background: var(--mj-bg-surface-hover);\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, var(--mj-color-brand-100));\n border-radius: 6px;\n margin-right: 12px;\n flex-shrink: 0;\n}\n\n.activity-icon i {\n font-size: 12px;\n color: var(--mj-brand-primary);\n}\n\n.activity-icon.action-created {\n background: var(--mj-color-success-100);\n}\n\n.activity-icon.action-created i {\n color: var(--mj-color-success-600);\n}\n\n.activity-icon.action-updated {\n background: var(--mj-color-indigo-100);\n}\n\n.activity-icon.action-updated i {\n color: var(--mj-color-indigo-500);\n}\n\n.activity-icon.action-revoked {\n background: var(--mj-color-error-100);\n}\n\n.activity-icon.action-revoked i {\n color: var(--mj-color-error-600);\n}\n\n.activity-icon.action-used {\n background: var(--mj-color-brand-100);\n}\n\n.activity-icon.action-used i {\n color: var(--mj-brand-primary-hover);\n}\n\n.activity-icon.action-extended {\n background: var(--mj-color-info-100);\n}\n\n.activity-icon.action-extended i {\n color: var(--mj-status-info);\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(--mj-text-primary);\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(--mj-text-secondary);\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(--mj-text-muted);\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(--mj-text-primary);\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(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 10px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.quick-action:hover {\n border-color: var(--mj-brand-primary);\n background: var(--mj-color-brand-50);\n transform: translateY(-2px);\n}\n\n.quick-action i {\n font-size: 20px;\n color: var(--mj-brand-primary);\n}\n\n.quick-action span {\n font-size: 12px;\n font-weight: 500;\n color: var(--mj-text-secondary);\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(--mj-text-secondary);\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, var(--mj-color-brand-50) 0%, var(--mj-color-brand-100) 100%);\n border-radius: 12px;\n border: 1px solid var(--mj-color-accent-300);\n}\n\n.security-notice i {\n font-size: 20px;\n color: var(--mj-brand-primary);\n margin-right: 12px;\n margin-top: 2px;\n}\n\n.notice-content {\n font-size: 13px;\n color: var(--mj-color-brand-800);\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: var(--mj-brand-primary);\n border: none;\n border-radius: 50%;\n color: var(--mj-text-inverse);\n font-size: 24px;\n box-shadow: var(--mj-shadow-brand-md);\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: var(--mj-bg-overlay);\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: var(--mj-shadow-xl);\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"] }]
|
|
1096
|
+
args: [{ standalone: false, selector: 'mj-api-keys-resource', template: "<!--\n APIKeysResource is only ever loaded inside Admin \u2192 Identity & Access's\n left-nav shell. Per Section 9b/10 of plans/explorer-chrome-conventions.md,\n shell sub-pages must NOT render a page-level <mj-page-layout>+<mj-page-header>\n (that produces a doubled-header). Instead the body opens with an\n <mj-page-header-interior> card carrying the L2 tab nav and action chrome.\n-->\n<mj-page-header-interior\n Role=\"region\"\n AriaLabel=\"API Keys\"\n [Title]=\"currentTabTitle\"\n [Subtitle]=\"currentTabSubtitle\">\n <div toolbar>\n <mj-tab-nav\n [Tabs]=\"tabsConfig\"\n [ActiveKey]=\"MainTab\"\n (TabChange)=\"onTabChange($event)\">\n </mj-tab-nav>\n </div>\n <div actions>\n <mj-refresh-button [Loading]=\"IsLoading\" (Clicked)=\"refresh()\"></mj-refresh-button>\n @if (MainTab === 'keys' && CurrentView === 'overview' && UserCanCreateKeys) {\n <button mjButton variant=\"primary\" size=\"sm\" (click)=\"openCreateDialog()\" aria-label=\"Generate a new API key\">\n <i class=\"fa-solid fa-plus\" aria-hidden=\"true\"></i>\n Generate New Key\n </button>\n }\n </div>\n</mj-page-header-interior>\n\n@if (IsLoading) {\n <div class=\"api-keys-loading\">\n <mj-loading text=\"Loading API Keys...\"></mj-loading>\n </div>\n} @else {\n <mj-page-body-interior>\n <!-- Keys Tab Content -->\n @if (MainTab === 'keys') {\n <!-- Overview View \u2014 title + Refresh + Generate New Key now live in the page chrome above. -->\n @if (CurrentView === 'overview') {\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 @if (ExpiredKeys > 0) {\n <span class=\"health-alert\" (click)=\"showListView('expired')\">\n <i class=\"fa-solid fa-circle-exclamation\"></i>\n {{ExpiredKeys}} expired\n </span>\n }\n @if (ExpiringSoonCount > 0) {\n <span class=\"health-warning-text\" (click)=\"showListView('expiring')\">\n <i class=\"fa-solid fa-clock\"></i>\n {{ExpiringSoonCount}} expiring soon\n </span>\n }\n @if (NeverUsedKeys > 0) {\n <span class=\"health-info-text\" (click)=\"showListView('never-used')\">\n <i class=\"fa-solid fa-question-circle\"></i>\n {{NeverUsedKeys}} never used\n </span>\n }\n @if (ExpiredKeys === 0 && ExpiringSoonCount === 0 && NeverUsedKeys === 0) {\n <span class=\"health-ok\">\n <i class=\"fa-solid fa-check-circle\"></i>\n All keys healthy\n </span>\n }\n </div>\n </div>\n </div>\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 <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 <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 @if (ExpiringSoonCount > 0) {\n <div class=\"kpi-trend warning\">\n <i class=\"fa-solid fa-arrow-right\"></i>\n </div>\n }\n </div>\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 <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 <!-- 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 @if (TopUsedKeys.length > 0) {\n <div class=\"key-list\">\n @for (key of TopUsedKeys; track key) {\n <div class=\"key-item\" (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 }\n </div>\n }\n @if (TopUsedKeys.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-key\"></i>\n <span>No active keys with recent usage</span>\n </div>\n }\n </div>\n </div>\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 @if (ScopeStats.length > 0) {\n <div class=\"scope-chart\">\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 @for (stat of ScopeStats; track stat; let i = $index) {\n <ng-container>\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 }\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 @for (stat of ScopeStats; track stat) {\n <div class=\"legend-item\" (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 }\n </div>\n </div>\n }\n @if (ScopeStats.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-shield-halved\"></i>\n <span>No scopes configured</span>\n </div>\n }\n </div>\n </div>\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 @if (RecentActivity.length > 0) {\n <div class=\"activity-list\">\n @for (activity of RecentActivity; track activity) {\n <div class=\"activity-item\" (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 @if (activity.user) {\n <span class=\"activity-user\">by {{activity.user}}</span>\n }\n </div>\n </div>\n <div class=\"activity-time\">\n {{formatDate(activity.date)}}\n </div>\n </div>\n }\n </div>\n }\n @if (RecentActivity.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-inbox\"></i>\n <span>No recent activity</span>\n </div>\n }\n </div>\n </div>\n </div>\n <!-- Quick Actions -->\n @if (UserCanCreateKeys) {\n <div class=\"quick-actions\">\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 }\n <!-- List View -->\n @if (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 }\n }\n <!-- Applications Tab Content -->\n @if (MainTab === 'applications') {\n <mj-api-applications-panel\n (ApplicationUpdated)=\"onDataUpdated()\">\n </mj-api-applications-panel>\n }\n <!-- Scopes Tab Content -->\n @if (MainTab === 'scopes') {\n <mj-api-scopes-panel\n (ScopeUpdated)=\"onDataUpdated()\">\n </mj-api-scopes-panel>\n }\n <!-- Usage Tab Content -->\n @if (MainTab === 'usage') {\n <mj-api-usage-panel></mj-api-usage-panel>\n }\n </mj-page-body-interior>\n}\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", styles: ["/*\n APIKeysResource renders as a sub-page inside Admin \u2192 Identity & Access's\n left-nav shell. Host is a flex column so <mj-page-header-interior> pins at\n the top and <mj-page-body-interior> fills the rest. See Section 10 of\n plans/explorer-chrome-conventions.md.\n*/\n:host {\n display: flex;\n flex-direction: column;\n height: 100%;\n overflow: hidden;\n background: var(--mj-bg-page);\n}\n\n.api-keys-loading {\n flex: 1;\n display: flex;\n align-items: center;\n justify-content: center;\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(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n font-size: 14px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.back-btn:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n\n/* Health Banner */\n.health-banner {\n display: flex;\n align-items: center;\n padding: 20px 24px;\n background: var(--mj-status-success-bg);\n border: 1px solid var(--mj-status-success-border);\n border-radius: 16px;\n margin-bottom: 24px;\n}\n\n.health-banner.health-warning {\n background: var(--mj-status-warning-bg);\n border-color: var(--mj-color-accent-300);\n}\n\n.health-banner.health-critical {\n background: var(--mj-status-error-bg);\n border-color: var(--mj-status-error-border);\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: var(--mj-border-default);\n stroke-width: 3.8;\n}\n\n.circle {\n fill: none;\n stroke-width: 3.8;\n stroke-linecap: round;\n stroke: var(--mj-status-success);\n animation: progress 1s ease-out forwards;\n}\n\n.health-banner.health-warning .circle {\n stroke: var(--mj-color-warning-500);\n}\n\n.health-banner.health-critical .circle {\n stroke: var(--mj-status-error);\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(--mj-text-primary);\n}\n\n.health-info {\n flex: 1;\n}\n\n.health-label {\n font-size: 18px;\n font-weight: 700;\n color: var(--mj-color-success-600);\n margin-bottom: 4px;\n}\n\n.health-banner.health-warning .health-label {\n color: var(--mj-brand-primary-hover);\n}\n\n.health-banner.health-critical .health-label {\n color: var(--mj-color-error-600);\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: var(--mj-color-error-600);\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: var(--mj-brand-primary-hover);\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: var(--mj-text-secondary);\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: var(--mj-color-success-600);\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(--mj-bg-surface);\n border-radius: 12px;\n box-shadow: var(--mj-shadow-md);\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: var(--mj-shadow-lg);\n}\n\n.kpi-card.active .kpi-icon {\n background: linear-gradient(135deg, var(--mj-status-success) 0%, var(--mj-color-success-600) 100%);\n}\n\n.kpi-card.warning .kpi-icon {\n background: linear-gradient(135deg, var(--mj-color-warning-500) 0%, var(--mj-brand-primary-hover) 100%);\n}\n\n.kpi-card.danger .kpi-icon {\n background: linear-gradient(135deg, var(--mj-status-error) 0%, var(--mj-color-error-600) 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: var(--mj-brand-primary);\n border-radius: 10px;\n margin-right: 14px;\n flex-shrink: 0;\n}\n\n.kpi-icon i {\n font-size: 20px;\n color: var(--mj-text-inverse);\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(--mj-text-primary);\n line-height: 1.2;\n}\n\n.kpi-label {\n font-size: 12px;\n color: var(--mj-text-secondary);\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(--mj-text-muted);\n}\n\n.kpi-trend.success {\n color: var(--mj-status-success);\n}\n\n.kpi-trend.warning {\n color: var(--mj-color-warning-500);\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(--mj-bg-surface);\n border-radius: 12px;\n box-shadow: var(--mj-shadow-md);\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(--mj-bg-page);\n border-bottom: 1px solid var(--mj-border-default);\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(--mj-text-primary);\n}\n\n.panel-title i {\n color: var(--mj-brand-primary);\n}\n\n.panel-subtitle {\n font-size: 12px;\n color: var(--mj-text-muted);\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(--mj-border-default);\n border-radius: 6px;\n font-size: 12px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.panel-action:hover {\n background: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\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(--mj-bg-page);\n border-radius: 10px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.key-item:hover {\n background: var(--mj-bg-surface-hover);\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, var(--mj-color-neutral-500) 0%, var(--mj-color-neutral-600) 100%);\n border-radius: 8px;\n margin-right: 14px;\n flex-shrink: 0;\n}\n\n.key-icon.active {\n background: var(--mj-brand-primary);\n}\n\n.key-icon i {\n font-size: 16px;\n color: var(--mj-text-inverse);\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(--mj-text-primary);\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(--mj-text-secondary);\n}\n\n.key-hash {\n font-family: monospace;\n background: var(--mj-bg-surface-active);\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(--mj-text-secondary);\n}\n\n.expiration {\n font-size: 11px;\n color: var(--mj-text-muted);\n}\n\n.expiration.expiring-soon {\n color: var(--mj-color-warning-500);\n font-weight: 500;\n}\n\n.expiration.expiring-critical {\n color: var(--mj-status-error);\n font-weight: 500;\n}\n\n.expiration.expired {\n color: var(--mj-status-error);\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(--mj-text-primary);\n}\n\n.donut-label {\n font-size: 11px;\n color: var(--mj-text-secondary);\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(--mj-bg-page);\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.legend-item:hover {\n background: var(--mj-bg-surface-hover);\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(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.legend-name i {\n font-size: 12px;\n color: var(--mj-text-secondary);\n}\n\n.legend-value {\n font-size: 12px;\n color: var(--mj-text-secondary);\n}\n\n.legend-arrow {\n color: var(--mj-text-muted);\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(--mj-bg-page);\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.activity-item:hover {\n background: var(--mj-bg-surface-hover);\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, var(--mj-color-brand-100));\n border-radius: 6px;\n margin-right: 12px;\n flex-shrink: 0;\n}\n\n.activity-icon i {\n font-size: 12px;\n color: var(--mj-brand-primary);\n}\n\n.activity-icon.action-created {\n background: var(--mj-color-success-100);\n}\n\n.activity-icon.action-created i {\n color: var(--mj-color-success-600);\n}\n\n.activity-icon.action-updated {\n background: var(--mj-color-indigo-100);\n}\n\n.activity-icon.action-updated i {\n color: var(--mj-color-indigo-500);\n}\n\n.activity-icon.action-revoked {\n background: var(--mj-color-error-100);\n}\n\n.activity-icon.action-revoked i {\n color: var(--mj-color-error-600);\n}\n\n.activity-icon.action-used {\n background: var(--mj-color-brand-100);\n}\n\n.activity-icon.action-used i {\n color: var(--mj-brand-primary-hover);\n}\n\n.activity-icon.action-extended {\n background: var(--mj-color-info-100);\n}\n\n.activity-icon.action-extended i {\n color: var(--mj-status-info);\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(--mj-text-primary);\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(--mj-text-secondary);\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(--mj-text-muted);\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(--mj-text-primary);\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(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 10px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.quick-action:hover {\n border-color: var(--mj-brand-primary);\n background: var(--mj-color-brand-50);\n transform: translateY(-2px);\n}\n\n.quick-action i {\n font-size: 20px;\n color: var(--mj-brand-primary);\n}\n\n.quick-action span {\n font-size: 12px;\n font-weight: 500;\n color: var(--mj-text-secondary);\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(--mj-text-secondary);\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, var(--mj-color-brand-50) 0%, var(--mj-color-brand-100) 100%);\n border-radius: 12px;\n border: 1px solid var(--mj-color-accent-300);\n}\n\n.security-notice i {\n font-size: 20px;\n color: var(--mj-brand-primary);\n margin-right: 12px;\n margin-top: 2px;\n}\n\n.notice-content {\n font-size: 13px;\n color: var(--mj-color-brand-800);\n line-height: 1.5;\n}\n\n.notice-content strong {\n font-weight: 600;\n}\n\n/* ========================================\n Responsive Styles \u2014 chrome / nav responsiveness now owned by\n <mj-page-layout> + <mj-left-nav>; only inner content needs tuning here.\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\n/* Mobile */\n@media (max-width: 768px) {\n .content-wrapper {\n padding: 16px;\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"] }]
|
|
1139
1097
|
}], () => [{ type: i0.ChangeDetectorRef }], { keyListComponent: [{
|
|
1140
1098
|
type: ViewChild,
|
|
1141
1099
|
args: ['keyList']
|
|
1142
1100
|
}] }); })();
|
|
1143
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(APIKeysResourceComponent, { className: "APIKeysResourceComponent", filePath: "src/APIKeys/api-keys-resource.component.ts", lineNumber:
|
|
1101
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(APIKeysResourceComponent, { className: "APIKeysResourceComponent", filePath: "src/APIKeys/api-keys-resource.component.ts", lineNumber: 53 }); })();
|
|
1144
1102
|
//# sourceMappingURL=api-keys-resource.component.js.map
|