@memberjunction/ng-dashboards 3.2.0 → 3.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/APIKeys/api-applications-panel.component.d.ts +167 -0
- package/dist/APIKeys/api-applications-panel.component.d.ts.map +1 -0
- package/dist/APIKeys/api-applications-panel.component.js +1059 -0
- package/dist/APIKeys/api-applications-panel.component.js.map +1 -0
- package/dist/APIKeys/api-key-create-dialog.component.d.ts +124 -0
- package/dist/APIKeys/api-key-create-dialog.component.d.ts.map +1 -0
- package/dist/APIKeys/api-key-create-dialog.component.js +743 -0
- package/dist/APIKeys/api-key-create-dialog.component.js.map +1 -0
- package/dist/APIKeys/api-key-edit-panel.component.d.ts +149 -0
- package/dist/APIKeys/api-key-edit-panel.component.d.ts.map +1 -0
- package/dist/APIKeys/api-key-edit-panel.component.js +1061 -0
- package/dist/APIKeys/api-key-edit-panel.component.js.map +1 -0
- package/dist/APIKeys/api-key-list.component.d.ts +130 -0
- package/dist/APIKeys/api-key-list.component.d.ts.map +1 -0
- package/dist/APIKeys/api-key-list.component.js +814 -0
- package/dist/APIKeys/api-key-list.component.js.map +1 -0
- package/dist/APIKeys/api-keys-resource.component.d.ts +209 -0
- package/dist/APIKeys/api-keys-resource.component.d.ts.map +1 -0
- package/dist/APIKeys/api-keys-resource.component.js +1165 -0
- package/dist/APIKeys/api-keys-resource.component.js.map +1 -0
- package/dist/APIKeys/api-scopes-panel.component.d.ts +98 -0
- package/dist/APIKeys/api-scopes-panel.component.d.ts.map +1 -0
- package/dist/APIKeys/api-scopes-panel.component.js +652 -0
- package/dist/APIKeys/api-scopes-panel.component.js.map +1 -0
- package/dist/APIKeys/api-usage-panel.component.d.ts +174 -0
- package/dist/APIKeys/api-usage-panel.component.d.ts.map +1 -0
- package/dist/APIKeys/api-usage-panel.component.js +1013 -0
- package/dist/APIKeys/api-usage-panel.component.js.map +1 -0
- package/dist/APIKeys/index.d.ts +7 -0
- package/dist/APIKeys/index.d.ts.map +1 -0
- package/dist/APIKeys/index.js +8 -0
- package/dist/APIKeys/index.js.map +1 -0
- package/dist/DashboardBrowser/dashboard-browser-resource.component.d.ts.map +1 -1
- package/dist/DashboardBrowser/dashboard-browser-resource.component.js +4 -2
- package/dist/DashboardBrowser/dashboard-browser-resource.component.js.map +1 -1
- package/dist/DataExplorer/data-explorer-dashboard.component.d.ts +3 -3
- package/dist/DataExplorer/data-explorer-dashboard.component.d.ts.map +1 -1
- package/dist/DataExplorer/data-explorer-dashboard.component.js +22 -6
- package/dist/DataExplorer/data-explorer-dashboard.component.js.map +1 -1
- package/dist/EntityAdmin/entity-admin-dashboard.component.js +2 -2
- package/dist/module.d.ts +39 -32
- package/dist/module.d.ts.map +1 -1
- package/dist/module.js +44 -4
- package/dist/module.js.map +1 -1
- package/dist/public-api.d.ts +7 -0
- package/dist/public-api.d.ts.map +1 -1
- package/dist/public-api.js +24 -0
- package/dist/public-api.js.map +1 -1
- package/package.json +32 -32
|
@@ -0,0 +1,1059 @@
|
|
|
1
|
+
import { Component, EventEmitter, Output, HostListener } from '@angular/core';
|
|
2
|
+
import { Metadata, RunView } from '@memberjunction/core';
|
|
3
|
+
import { UserInfoEngine } from '@memberjunction/core-entities';
|
|
4
|
+
import * as i0 from "@angular/core";
|
|
5
|
+
import * as i1 from "@angular/common";
|
|
6
|
+
import * as i2 from "@angular/forms";
|
|
7
|
+
import * as i3 from "@progress/kendo-angular-dropdowns";
|
|
8
|
+
import * as i4 from "@progress/kendo-angular-inputs";
|
|
9
|
+
import * as i5 from "@progress/kendo-angular-buttons";
|
|
10
|
+
import * as i6 from "@memberjunction/ng-shared-generic";
|
|
11
|
+
const _c0 = () => ["Include", "Exclude"];
|
|
12
|
+
function APIApplicationsPanelComponent_mj_loading_1_Template(rf, ctx) { if (rf & 1) {
|
|
13
|
+
i0.ɵɵelement(0, "mj-loading", 32);
|
|
14
|
+
} }
|
|
15
|
+
function APIApplicationsPanelComponent_ng_container_2_div_11_Template(rf, ctx) { if (rf & 1) {
|
|
16
|
+
i0.ɵɵelementStart(0, "div", 44);
|
|
17
|
+
i0.ɵɵelement(1, "i", 45);
|
|
18
|
+
i0.ɵɵtext(2);
|
|
19
|
+
i0.ɵɵelementEnd();
|
|
20
|
+
} if (rf & 2) {
|
|
21
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
22
|
+
i0.ɵɵadvance(2);
|
|
23
|
+
i0.ɵɵtextInterpolate1(" ", ctx_r1.SuccessMessage, " ");
|
|
24
|
+
} }
|
|
25
|
+
function APIApplicationsPanelComponent_ng_container_2_div_12_Template(rf, ctx) { if (rf & 1) {
|
|
26
|
+
i0.ɵɵelementStart(0, "div", 46);
|
|
27
|
+
i0.ɵɵelement(1, "i", 47);
|
|
28
|
+
i0.ɵɵtext(2);
|
|
29
|
+
i0.ɵɵelementEnd();
|
|
30
|
+
} if (rf & 2) {
|
|
31
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
32
|
+
i0.ɵɵadvance(2);
|
|
33
|
+
i0.ɵɵtextInterpolate1(" ", ctx_r1.ErrorMessage, " ");
|
|
34
|
+
} }
|
|
35
|
+
function APIApplicationsPanelComponent_ng_container_2_div_14_div_10_Template(rf, ctx) { if (rf & 1) {
|
|
36
|
+
i0.ɵɵelementStart(0, "div", 62);
|
|
37
|
+
i0.ɵɵtext(1);
|
|
38
|
+
i0.ɵɵelementEnd();
|
|
39
|
+
} if (rf & 2) {
|
|
40
|
+
const appItem_r4 = i0.ɵɵnextContext().$implicit;
|
|
41
|
+
i0.ɵɵadvance();
|
|
42
|
+
i0.ɵɵtextInterpolate1(" ", appItem_r4.application.Description, " ");
|
|
43
|
+
} }
|
|
44
|
+
function APIApplicationsPanelComponent_ng_container_2_div_14_div_18_div_4_div_1_span_11_Template(rf, ctx) { if (rf & 1) {
|
|
45
|
+
i0.ɵɵelementStart(0, "span", 76);
|
|
46
|
+
i0.ɵɵtext(1);
|
|
47
|
+
i0.ɵɵelementEnd();
|
|
48
|
+
} if (rf & 2) {
|
|
49
|
+
const scope_r5 = i0.ɵɵnextContext().$implicit;
|
|
50
|
+
i0.ɵɵadvance();
|
|
51
|
+
i0.ɵɵtextInterpolate1(" Priority: ", scope_r5.Priority, " ");
|
|
52
|
+
} }
|
|
53
|
+
function APIApplicationsPanelComponent_ng_container_2_div_14_div_18_div_4_div_1_Template(rf, ctx) { if (rf & 1) {
|
|
54
|
+
i0.ɵɵelementStart(0, "div", 69)(1, "div", 70);
|
|
55
|
+
i0.ɵɵelement(2, "i");
|
|
56
|
+
i0.ɵɵelementEnd();
|
|
57
|
+
i0.ɵɵelementStart(3, "div", 71)(4, "div", 72);
|
|
58
|
+
i0.ɵɵtext(5);
|
|
59
|
+
i0.ɵɵelementEnd();
|
|
60
|
+
i0.ɵɵelementStart(6, "div", 73)(7, "code");
|
|
61
|
+
i0.ɵɵtext(8);
|
|
62
|
+
i0.ɵɵelementEnd();
|
|
63
|
+
i0.ɵɵelementStart(9, "span", 74);
|
|
64
|
+
i0.ɵɵtext(10);
|
|
65
|
+
i0.ɵɵelementEnd();
|
|
66
|
+
i0.ɵɵtemplate(11, APIApplicationsPanelComponent_ng_container_2_div_14_div_18_div_4_div_1_span_11_Template, 2, 1, "span", 75);
|
|
67
|
+
i0.ɵɵelementEnd()()();
|
|
68
|
+
} if (rf & 2) {
|
|
69
|
+
const scope_r5 = ctx.$implicit;
|
|
70
|
+
const ctx_r1 = i0.ɵɵnextContext(5);
|
|
71
|
+
i0.ɵɵadvance();
|
|
72
|
+
i0.ɵɵproperty("ngClass", ctx_r1.getPatternClass(scope_r5.PatternType, scope_r5.IsDeny));
|
|
73
|
+
i0.ɵɵadvance();
|
|
74
|
+
i0.ɵɵclassMap(ctx_r1.getPatternIcon(scope_r5.PatternType, scope_r5.IsDeny));
|
|
75
|
+
i0.ɵɵadvance(3);
|
|
76
|
+
i0.ɵɵtextInterpolate(ctx_r1.getScopeName(scope_r5.ScopeID));
|
|
77
|
+
i0.ɵɵadvance(3);
|
|
78
|
+
i0.ɵɵtextInterpolate(scope_r5.ResourcePattern);
|
|
79
|
+
i0.ɵɵadvance(2);
|
|
80
|
+
i0.ɵɵtextInterpolate(scope_r5.PatternType);
|
|
81
|
+
i0.ɵɵadvance();
|
|
82
|
+
i0.ɵɵproperty("ngIf", scope_r5.Priority > 0);
|
|
83
|
+
} }
|
|
84
|
+
function APIApplicationsPanelComponent_ng_container_2_div_14_div_18_div_4_Template(rf, ctx) { if (rf & 1) {
|
|
85
|
+
i0.ɵɵelementStart(0, "div", 67);
|
|
86
|
+
i0.ɵɵtemplate(1, APIApplicationsPanelComponent_ng_container_2_div_14_div_18_div_4_div_1_Template, 12, 7, "div", 68);
|
|
87
|
+
i0.ɵɵelementEnd();
|
|
88
|
+
} if (rf & 2) {
|
|
89
|
+
const appItem_r4 = i0.ɵɵnextContext(2).$implicit;
|
|
90
|
+
i0.ɵɵadvance();
|
|
91
|
+
i0.ɵɵproperty("ngForOf", appItem_r4.scopes);
|
|
92
|
+
} }
|
|
93
|
+
function APIApplicationsPanelComponent_ng_container_2_div_14_div_18_div_5_Template(rf, ctx) { if (rf & 1) {
|
|
94
|
+
i0.ɵɵelementStart(0, "div", 77);
|
|
95
|
+
i0.ɵɵelement(1, "i", 78);
|
|
96
|
+
i0.ɵɵelementStart(2, "span");
|
|
97
|
+
i0.ɵɵtext(3, "No scope rules defined - all access denied by default");
|
|
98
|
+
i0.ɵɵelementEnd()();
|
|
99
|
+
} }
|
|
100
|
+
function APIApplicationsPanelComponent_ng_container_2_div_14_div_18_Template(rf, ctx) { if (rf & 1) {
|
|
101
|
+
i0.ɵɵelementStart(0, "div", 63)(1, "div", 64)(2, "h4");
|
|
102
|
+
i0.ɵɵtext(3, "Scope Ceiling Rules");
|
|
103
|
+
i0.ɵɵelementEnd();
|
|
104
|
+
i0.ɵɵtemplate(4, APIApplicationsPanelComponent_ng_container_2_div_14_div_18_div_4_Template, 2, 1, "div", 65)(5, APIApplicationsPanelComponent_ng_container_2_div_14_div_18_div_5_Template, 4, 0, "div", 66);
|
|
105
|
+
i0.ɵɵelementEnd()();
|
|
106
|
+
} if (rf & 2) {
|
|
107
|
+
const appItem_r4 = i0.ɵɵnextContext().$implicit;
|
|
108
|
+
i0.ɵɵadvance(4);
|
|
109
|
+
i0.ɵɵproperty("ngIf", appItem_r4.scopes.length > 0);
|
|
110
|
+
i0.ɵɵadvance();
|
|
111
|
+
i0.ɵɵproperty("ngIf", appItem_r4.scopes.length === 0);
|
|
112
|
+
} }
|
|
113
|
+
function APIApplicationsPanelComponent_ng_container_2_div_14_Template(rf, ctx) { if (rf & 1) {
|
|
114
|
+
const _r3 = i0.ɵɵgetCurrentView();
|
|
115
|
+
i0.ɵɵelementStart(0, "div", 48)(1, "div", 49)(2, "div", 50);
|
|
116
|
+
i0.ɵɵlistener("click", function APIApplicationsPanelComponent_ng_container_2_div_14_Template_div_click_2_listener() { const appItem_r4 = i0.ɵɵrestoreView(_r3).$implicit; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.toggleExpanded(appItem_r4)); });
|
|
117
|
+
i0.ɵɵelementStart(3, "div", 51);
|
|
118
|
+
i0.ɵɵelement(4, "i", 23);
|
|
119
|
+
i0.ɵɵelementEnd();
|
|
120
|
+
i0.ɵɵelementStart(5, "div", 52)(6, "div", 53);
|
|
121
|
+
i0.ɵɵtext(7);
|
|
122
|
+
i0.ɵɵelementStart(8, "span", 54);
|
|
123
|
+
i0.ɵɵtext(9);
|
|
124
|
+
i0.ɵɵelementEnd()();
|
|
125
|
+
i0.ɵɵtemplate(10, APIApplicationsPanelComponent_ng_container_2_div_14_div_10_Template, 2, 1, "div", 55);
|
|
126
|
+
i0.ɵɵelementEnd();
|
|
127
|
+
i0.ɵɵelementStart(11, "div", 56)(12, "div", 57);
|
|
128
|
+
i0.ɵɵelement(13, "i", 28);
|
|
129
|
+
i0.ɵɵtext(14);
|
|
130
|
+
i0.ɵɵelementEnd();
|
|
131
|
+
i0.ɵɵelement(15, "i", 58);
|
|
132
|
+
i0.ɵɵelementEnd()();
|
|
133
|
+
i0.ɵɵelementStart(16, "button", 59);
|
|
134
|
+
i0.ɵɵlistener("click", function APIApplicationsPanelComponent_ng_container_2_div_14_Template_button_click_16_listener($event) { const appItem_r4 = i0.ɵɵrestoreView(_r3).$implicit; const ctx_r1 = i0.ɵɵnextContext(2); ctx_r1.openEditPanel(appItem_r4); return i0.ɵɵresetView($event.stopPropagation()); });
|
|
135
|
+
i0.ɵɵelement(17, "i", 60);
|
|
136
|
+
i0.ɵɵelementEnd()();
|
|
137
|
+
i0.ɵɵtemplate(18, APIApplicationsPanelComponent_ng_container_2_div_14_div_18_Template, 6, 2, "div", 61);
|
|
138
|
+
i0.ɵɵelementEnd();
|
|
139
|
+
} if (rf & 2) {
|
|
140
|
+
const appItem_r4 = ctx.$implicit;
|
|
141
|
+
i0.ɵɵclassProp("inactive", !appItem_r4.application.IsActive)("expanded", appItem_r4.expanded);
|
|
142
|
+
i0.ɵɵadvance(7);
|
|
143
|
+
i0.ɵɵtextInterpolate1(" ", appItem_r4.application.Name, " ");
|
|
144
|
+
i0.ɵɵadvance();
|
|
145
|
+
i0.ɵɵclassProp("active", appItem_r4.application.IsActive)("inactive", !appItem_r4.application.IsActive);
|
|
146
|
+
i0.ɵɵadvance();
|
|
147
|
+
i0.ɵɵtextInterpolate1(" ", appItem_r4.application.IsActive ? "Active" : "Inactive", " ");
|
|
148
|
+
i0.ɵɵadvance();
|
|
149
|
+
i0.ɵɵproperty("ngIf", appItem_r4.application.Description);
|
|
150
|
+
i0.ɵɵadvance(4);
|
|
151
|
+
i0.ɵɵtextInterpolate1(" ", appItem_r4.scopeCount, " scopes ");
|
|
152
|
+
i0.ɵɵadvance();
|
|
153
|
+
i0.ɵɵclassProp("fa-chevron-down", !appItem_r4.expanded)("fa-chevron-up", appItem_r4.expanded);
|
|
154
|
+
i0.ɵɵadvance(3);
|
|
155
|
+
i0.ɵɵproperty("ngIf", appItem_r4.expanded);
|
|
156
|
+
} }
|
|
157
|
+
function APIApplicationsPanelComponent_ng_container_2_div_15_Template(rf, ctx) { if (rf & 1) {
|
|
158
|
+
i0.ɵɵelementStart(0, "div", 79);
|
|
159
|
+
i0.ɵɵelement(1, "i", 23);
|
|
160
|
+
i0.ɵɵelementStart(2, "span");
|
|
161
|
+
i0.ɵɵtext(3, "No applications configured");
|
|
162
|
+
i0.ɵɵelementEnd();
|
|
163
|
+
i0.ɵɵelementStart(4, "p");
|
|
164
|
+
i0.ɵɵtext(5, "Create an application to define scope ceilings for API key access");
|
|
165
|
+
i0.ɵɵelementEnd()();
|
|
166
|
+
} }
|
|
167
|
+
function APIApplicationsPanelComponent_ng_container_2_Template(rf, ctx) { if (rf & 1) {
|
|
168
|
+
const _r1 = i0.ɵɵgetCurrentView();
|
|
169
|
+
i0.ɵɵelementContainerStart(0);
|
|
170
|
+
i0.ɵɵelementStart(1, "div", 33)(2, "div", 34)(3, "h3", 35);
|
|
171
|
+
i0.ɵɵelement(4, "i", 23);
|
|
172
|
+
i0.ɵɵtext(5, " API Applications ");
|
|
173
|
+
i0.ɵɵelementEnd();
|
|
174
|
+
i0.ɵɵelementStart(6, "p", 36);
|
|
175
|
+
i0.ɵɵtext(7, "Manage applications and their default scope permissions");
|
|
176
|
+
i0.ɵɵelementEnd()();
|
|
177
|
+
i0.ɵɵelementStart(8, "button", 37);
|
|
178
|
+
i0.ɵɵlistener("click", function APIApplicationsPanelComponent_ng_container_2_Template_button_click_8_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.openCreatePanel()); });
|
|
179
|
+
i0.ɵɵelement(9, "i", 38);
|
|
180
|
+
i0.ɵɵtext(10, " New Application ");
|
|
181
|
+
i0.ɵɵelementEnd()();
|
|
182
|
+
i0.ɵɵtemplate(11, APIApplicationsPanelComponent_ng_container_2_div_11_Template, 3, 1, "div", 39)(12, APIApplicationsPanelComponent_ng_container_2_div_12_Template, 3, 1, "div", 40);
|
|
183
|
+
i0.ɵɵelementStart(13, "div", 41);
|
|
184
|
+
i0.ɵɵtemplate(14, APIApplicationsPanelComponent_ng_container_2_div_14_Template, 19, 17, "div", 42)(15, APIApplicationsPanelComponent_ng_container_2_div_15_Template, 6, 0, "div", 43);
|
|
185
|
+
i0.ɵɵelementEnd();
|
|
186
|
+
i0.ɵɵelementContainerEnd();
|
|
187
|
+
} if (rf & 2) {
|
|
188
|
+
const ctx_r1 = i0.ɵɵnextContext();
|
|
189
|
+
i0.ɵɵadvance(11);
|
|
190
|
+
i0.ɵɵproperty("ngIf", ctx_r1.SuccessMessage);
|
|
191
|
+
i0.ɵɵadvance();
|
|
192
|
+
i0.ɵɵproperty("ngIf", ctx_r1.ErrorMessage);
|
|
193
|
+
i0.ɵɵadvance(2);
|
|
194
|
+
i0.ɵɵproperty("ngForOf", ctx_r1.Applications);
|
|
195
|
+
i0.ɵɵadvance();
|
|
196
|
+
i0.ɵɵproperty("ngIf", ctx_r1.Applications.length === 0);
|
|
197
|
+
} }
|
|
198
|
+
function APIApplicationsPanelComponent_div_3_Template(rf, ctx) { if (rf & 1) {
|
|
199
|
+
const _r6 = i0.ɵɵgetCurrentView();
|
|
200
|
+
i0.ɵɵelementStart(0, "div", 80);
|
|
201
|
+
i0.ɵɵlistener("click", function APIApplicationsPanelComponent_div_3_Template_div_click_0_listener() { i0.ɵɵrestoreView(_r6); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.closePanel()); });
|
|
202
|
+
i0.ɵɵelementEnd();
|
|
203
|
+
} }
|
|
204
|
+
function APIApplicationsPanelComponent_mj_loading_32_Template(rf, ctx) { if (rf & 1) {
|
|
205
|
+
i0.ɵɵelement(0, "mj-loading", 81);
|
|
206
|
+
} if (rf & 2) {
|
|
207
|
+
i0.ɵɵproperty("showText", false);
|
|
208
|
+
} }
|
|
209
|
+
function APIApplicationsPanelComponent_span_33_Template(rf, ctx) { if (rf & 1) {
|
|
210
|
+
i0.ɵɵelementStart(0, "span");
|
|
211
|
+
i0.ɵɵelement(1, "i", 82);
|
|
212
|
+
i0.ɵɵtext(2, " Create Application ");
|
|
213
|
+
i0.ɵɵelementEnd();
|
|
214
|
+
} }
|
|
215
|
+
function APIApplicationsPanelComponent_div_57_Template(rf, ctx) { if (rf & 1) {
|
|
216
|
+
const _r7 = i0.ɵɵgetCurrentView();
|
|
217
|
+
i0.ɵɵelementStart(0, "div", 83)(1, "div", 11)(2, "div", 12)(3, "label");
|
|
218
|
+
i0.ɵɵtext(4, "Application Name *");
|
|
219
|
+
i0.ɵɵelementEnd();
|
|
220
|
+
i0.ɵɵelementStart(5, "input", 13);
|
|
221
|
+
i0.ɵɵtwoWayListener("ngModelChange", function APIApplicationsPanelComponent_div_57_Template_input_ngModelChange_5_listener($event) { i0.ɵɵrestoreView(_r7); const ctx_r1 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r1.EditName, $event) || (ctx_r1.EditName = $event); return i0.ɵɵresetView($event); });
|
|
222
|
+
i0.ɵɵelementEnd()();
|
|
223
|
+
i0.ɵɵelementStart(6, "div", 12)(7, "label");
|
|
224
|
+
i0.ɵɵtext(8, "Description");
|
|
225
|
+
i0.ɵɵelementEnd();
|
|
226
|
+
i0.ɵɵelementStart(9, "textarea", 14);
|
|
227
|
+
i0.ɵɵtwoWayListener("ngModelChange", function APIApplicationsPanelComponent_div_57_Template_textarea_ngModelChange_9_listener($event) { i0.ɵɵrestoreView(_r7); const ctx_r1 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r1.EditDescription, $event) || (ctx_r1.EditDescription = $event); return i0.ɵɵresetView($event); });
|
|
228
|
+
i0.ɵɵelementEnd()();
|
|
229
|
+
i0.ɵɵelementStart(10, "div", 12)(11, "label", 15)(12, "input", 16);
|
|
230
|
+
i0.ɵɵtwoWayListener("ngModelChange", function APIApplicationsPanelComponent_div_57_Template_input_ngModelChange_12_listener($event) { i0.ɵɵrestoreView(_r7); const ctx_r1 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r1.EditIsActive, $event) || (ctx_r1.EditIsActive = $event); return i0.ɵɵresetView($event); });
|
|
231
|
+
i0.ɵɵelementEnd();
|
|
232
|
+
i0.ɵɵelementStart(13, "div")(14, "span");
|
|
233
|
+
i0.ɵɵtext(15, "Active");
|
|
234
|
+
i0.ɵɵelementEnd();
|
|
235
|
+
i0.ɵɵelementStart(16, "span", 17);
|
|
236
|
+
i0.ɵɵtext(17, "Inactive applications cannot be used with API keys");
|
|
237
|
+
i0.ɵɵelementEnd()()()()()();
|
|
238
|
+
} if (rf & 2) {
|
|
239
|
+
const ctx_r1 = i0.ɵɵnextContext();
|
|
240
|
+
i0.ɵɵadvance(5);
|
|
241
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx_r1.EditName);
|
|
242
|
+
i0.ɵɵadvance(4);
|
|
243
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx_r1.EditDescription);
|
|
244
|
+
i0.ɵɵproperty("rows", 4);
|
|
245
|
+
i0.ɵɵadvance(3);
|
|
246
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx_r1.EditIsActive);
|
|
247
|
+
} }
|
|
248
|
+
function APIApplicationsPanelComponent_div_58_div_6_div_14_div_1_span_6_Template(rf, ctx) { if (rf & 1) {
|
|
249
|
+
i0.ɵɵelementStart(0, "span", 109);
|
|
250
|
+
i0.ɵɵtext(1);
|
|
251
|
+
i0.ɵɵelementEnd();
|
|
252
|
+
} if (rf & 2) {
|
|
253
|
+
const selection_r11 = i0.ɵɵnextContext().$implicit;
|
|
254
|
+
i0.ɵɵadvance();
|
|
255
|
+
i0.ɵɵtextInterpolate1(" ", selection_r11.scope.Description, " ");
|
|
256
|
+
} }
|
|
257
|
+
function APIApplicationsPanelComponent_div_58_div_6_div_14_div_1_div_7_Template(rf, ctx) { if (rf & 1) {
|
|
258
|
+
i0.ɵɵelementStart(0, "div", 110)(1, "span", 111);
|
|
259
|
+
i0.ɵɵelement(2, "i", 112);
|
|
260
|
+
i0.ɵɵtext(3);
|
|
261
|
+
i0.ɵɵelementEnd()();
|
|
262
|
+
} if (rf & 2) {
|
|
263
|
+
const selection_r11 = i0.ɵɵnextContext().$implicit;
|
|
264
|
+
i0.ɵɵadvance();
|
|
265
|
+
i0.ɵɵclassProp("include", selection_r11.patternType === "Include")("exclude", selection_r11.patternType === "Exclude");
|
|
266
|
+
i0.ɵɵadvance();
|
|
267
|
+
i0.ɵɵclassProp("fa-check", selection_r11.patternType === "Include")("fa-minus", selection_r11.patternType === "Exclude");
|
|
268
|
+
i0.ɵɵadvance();
|
|
269
|
+
i0.ɵɵtextInterpolate1(" ", selection_r11.pattern || "*", " ");
|
|
270
|
+
} }
|
|
271
|
+
function APIApplicationsPanelComponent_div_58_div_6_div_14_div_1_div_8_Template(rf, ctx) { if (rf & 1) {
|
|
272
|
+
const _r12 = i0.ɵɵgetCurrentView();
|
|
273
|
+
i0.ɵɵelementStart(0, "div", 113)(1, "input", 114);
|
|
274
|
+
i0.ɵɵtwoWayListener("ngModelChange", function APIApplicationsPanelComponent_div_58_div_6_div_14_div_1_div_8_Template_input_ngModelChange_1_listener($event) { i0.ɵɵrestoreView(_r12); const selection_r11 = i0.ɵɵnextContext().$implicit; i0.ɵɵtwoWayBindingSet(selection_r11.pattern, $event) || (selection_r11.pattern = $event); return i0.ɵɵresetView($event); });
|
|
275
|
+
i0.ɵɵelementEnd();
|
|
276
|
+
i0.ɵɵelementStart(2, "kendo-dropdownlist", 115);
|
|
277
|
+
i0.ɵɵtwoWayListener("ngModelChange", function APIApplicationsPanelComponent_div_58_div_6_div_14_div_1_div_8_Template_kendo_dropdownlist_ngModelChange_2_listener($event) { i0.ɵɵrestoreView(_r12); const selection_r11 = i0.ɵɵnextContext().$implicit; i0.ɵɵtwoWayBindingSet(selection_r11.patternType, $event) || (selection_r11.patternType = $event); return i0.ɵɵresetView($event); });
|
|
278
|
+
i0.ɵɵelementEnd()();
|
|
279
|
+
} if (rf & 2) {
|
|
280
|
+
const selection_r11 = i0.ɵɵnextContext().$implicit;
|
|
281
|
+
i0.ɵɵadvance();
|
|
282
|
+
i0.ɵɵtwoWayProperty("ngModel", selection_r11.pattern);
|
|
283
|
+
i0.ɵɵadvance();
|
|
284
|
+
i0.ɵɵtwoWayProperty("ngModel", selection_r11.patternType);
|
|
285
|
+
i0.ɵɵproperty("data", i0.ɵɵpureFunction0(4, _c0))("valuePrimitive", true);
|
|
286
|
+
} }
|
|
287
|
+
function APIApplicationsPanelComponent_div_58_div_6_div_14_div_1_Template(rf, ctx) { if (rf & 1) {
|
|
288
|
+
const _r10 = i0.ɵɵgetCurrentView();
|
|
289
|
+
i0.ɵɵelementStart(0, "div", 101)(1, "label", 102)(2, "input", 103);
|
|
290
|
+
i0.ɵɵtwoWayListener("ngModelChange", function APIApplicationsPanelComponent_div_58_div_6_div_14_div_1_Template_input_ngModelChange_2_listener($event) { const selection_r11 = i0.ɵɵrestoreView(_r10).$implicit; i0.ɵɵtwoWayBindingSet(selection_r11.selected, $event) || (selection_r11.selected = $event); return i0.ɵɵresetView($event); });
|
|
291
|
+
i0.ɵɵlistener("change", function APIApplicationsPanelComponent_div_58_div_6_div_14_div_1_Template_input_change_2_listener() { i0.ɵɵrestoreView(_r10); const category_r9 = i0.ɵɵnextContext(2).$implicit; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.updateCategoryState(category_r9)); });
|
|
292
|
+
i0.ɵɵelementEnd();
|
|
293
|
+
i0.ɵɵelementStart(3, "div", 104)(4, "span", 105);
|
|
294
|
+
i0.ɵɵtext(5);
|
|
295
|
+
i0.ɵɵelementEnd();
|
|
296
|
+
i0.ɵɵtemplate(6, APIApplicationsPanelComponent_div_58_div_6_div_14_div_1_span_6_Template, 2, 1, "span", 106);
|
|
297
|
+
i0.ɵɵelementEnd()();
|
|
298
|
+
i0.ɵɵtemplate(7, APIApplicationsPanelComponent_div_58_div_6_div_14_div_1_div_7_Template, 4, 9, "div", 107)(8, APIApplicationsPanelComponent_div_58_div_6_div_14_div_1_div_8_Template, 3, 5, "div", 108);
|
|
299
|
+
i0.ɵɵelementEnd();
|
|
300
|
+
} if (rf & 2) {
|
|
301
|
+
const selection_r11 = ctx.$implicit;
|
|
302
|
+
i0.ɵɵclassProp("selected", selection_r11.selected);
|
|
303
|
+
i0.ɵɵadvance(2);
|
|
304
|
+
i0.ɵɵtwoWayProperty("ngModel", selection_r11.selected);
|
|
305
|
+
i0.ɵɵadvance(3);
|
|
306
|
+
i0.ɵɵtextInterpolate(selection_r11.displayName || "(unnamed scope)");
|
|
307
|
+
i0.ɵɵadvance();
|
|
308
|
+
i0.ɵɵproperty("ngIf", selection_r11.scope.Description);
|
|
309
|
+
i0.ɵɵadvance();
|
|
310
|
+
i0.ɵɵproperty("ngIf", selection_r11.selected);
|
|
311
|
+
i0.ɵɵadvance();
|
|
312
|
+
i0.ɵɵproperty("ngIf", selection_r11.selected);
|
|
313
|
+
} }
|
|
314
|
+
function APIApplicationsPanelComponent_div_58_div_6_div_14_Template(rf, ctx) { if (rf & 1) {
|
|
315
|
+
i0.ɵɵelementStart(0, "div", 99);
|
|
316
|
+
i0.ɵɵtemplate(1, APIApplicationsPanelComponent_div_58_div_6_div_14_div_1_Template, 9, 7, "div", 100);
|
|
317
|
+
i0.ɵɵelementEnd();
|
|
318
|
+
} if (rf & 2) {
|
|
319
|
+
const category_r9 = i0.ɵɵnextContext().$implicit;
|
|
320
|
+
i0.ɵɵadvance();
|
|
321
|
+
i0.ɵɵproperty("ngForOf", category_r9.scopes);
|
|
322
|
+
} }
|
|
323
|
+
function APIApplicationsPanelComponent_div_58_div_6_Template(rf, ctx) { if (rf & 1) {
|
|
324
|
+
const _r8 = i0.ɵɵgetCurrentView();
|
|
325
|
+
i0.ɵɵelementStart(0, "div", 89)(1, "div", 90);
|
|
326
|
+
i0.ɵɵlistener("click", function APIApplicationsPanelComponent_div_58_div_6_Template_div_click_1_listener() { const category_r9 = i0.ɵɵrestoreView(_r8).$implicit; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.toggleScopeCategory(category_r9)); });
|
|
327
|
+
i0.ɵɵelementStart(2, "div", 91);
|
|
328
|
+
i0.ɵɵelement(3, "i");
|
|
329
|
+
i0.ɵɵelementStart(4, "span", 92);
|
|
330
|
+
i0.ɵɵtext(5);
|
|
331
|
+
i0.ɵɵelementEnd();
|
|
332
|
+
i0.ɵɵelementStart(6, "span", 93);
|
|
333
|
+
i0.ɵɵtext(7);
|
|
334
|
+
i0.ɵɵelementEnd()();
|
|
335
|
+
i0.ɵɵelementStart(8, "div", 94)(9, "label", 95);
|
|
336
|
+
i0.ɵɵlistener("click", function APIApplicationsPanelComponent_div_58_div_6_Template_label_click_9_listener($event) { i0.ɵɵrestoreView(_r8); return i0.ɵɵresetView($event.stopPropagation()); });
|
|
337
|
+
i0.ɵɵelementStart(10, "input", 96);
|
|
338
|
+
i0.ɵɵlistener("change", function APIApplicationsPanelComponent_div_58_div_6_Template_input_change_10_listener() { const category_r9 = i0.ɵɵrestoreView(_r8).$implicit; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.toggleCategoryAll(category_r9)); });
|
|
339
|
+
i0.ɵɵelementEnd();
|
|
340
|
+
i0.ɵɵelementStart(11, "span");
|
|
341
|
+
i0.ɵɵtext(12, "All");
|
|
342
|
+
i0.ɵɵelementEnd()();
|
|
343
|
+
i0.ɵɵelement(13, "i", 97);
|
|
344
|
+
i0.ɵɵelementEnd()();
|
|
345
|
+
i0.ɵɵtemplate(14, APIApplicationsPanelComponent_div_58_div_6_div_14_Template, 2, 1, "div", 98);
|
|
346
|
+
i0.ɵɵelementEnd();
|
|
347
|
+
} if (rf & 2) {
|
|
348
|
+
const category_r9 = ctx.$implicit;
|
|
349
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
350
|
+
i0.ɵɵadvance(3);
|
|
351
|
+
i0.ɵɵclassMap(category_r9.icon);
|
|
352
|
+
i0.ɵɵstyleProp("color", category_r9.color);
|
|
353
|
+
i0.ɵɵadvance(2);
|
|
354
|
+
i0.ɵɵtextInterpolate(category_r9.name);
|
|
355
|
+
i0.ɵɵadvance(2);
|
|
356
|
+
i0.ɵɵtextInterpolate2(" ", ctx_r1.getCategorySelectedCount(category_r9), "/", category_r9.scopes.length, " ");
|
|
357
|
+
i0.ɵɵadvance(3);
|
|
358
|
+
i0.ɵɵproperty("checked", category_r9.allSelected);
|
|
359
|
+
i0.ɵɵadvance(3);
|
|
360
|
+
i0.ɵɵclassProp("fa-chevron-down", !category_r9.expanded)("fa-chevron-up", category_r9.expanded);
|
|
361
|
+
i0.ɵɵadvance();
|
|
362
|
+
i0.ɵɵproperty("ngIf", category_r9.expanded);
|
|
363
|
+
} }
|
|
364
|
+
function APIApplicationsPanelComponent_div_58_div_7_Template(rf, ctx) { if (rf & 1) {
|
|
365
|
+
i0.ɵɵelementStart(0, "div", 116);
|
|
366
|
+
i0.ɵɵelement(1, "i", 78);
|
|
367
|
+
i0.ɵɵelementStart(2, "span");
|
|
368
|
+
i0.ɵɵtext(3, "No scopes available");
|
|
369
|
+
i0.ɵɵelementEnd()();
|
|
370
|
+
} }
|
|
371
|
+
function APIApplicationsPanelComponent_div_58_Template(rf, ctx) { if (rf & 1) {
|
|
372
|
+
i0.ɵɵelementStart(0, "div", 84)(1, "div", 85);
|
|
373
|
+
i0.ɵɵelement(2, "i", 27);
|
|
374
|
+
i0.ɵɵelementStart(3, "span");
|
|
375
|
+
i0.ɵɵtext(4, "Define the maximum permissions this application can grant to API keys.");
|
|
376
|
+
i0.ɵɵelementEnd()();
|
|
377
|
+
i0.ɵɵelementStart(5, "div", 86);
|
|
378
|
+
i0.ɵɵtemplate(6, APIApplicationsPanelComponent_div_58_div_6_Template, 15, 13, "div", 87)(7, APIApplicationsPanelComponent_div_58_div_7_Template, 4, 0, "div", 88);
|
|
379
|
+
i0.ɵɵelementEnd()();
|
|
380
|
+
} if (rf & 2) {
|
|
381
|
+
const ctx_r1 = i0.ɵɵnextContext();
|
|
382
|
+
i0.ɵɵadvance(6);
|
|
383
|
+
i0.ɵɵproperty("ngForOf", ctx_r1.ScopeCategories);
|
|
384
|
+
i0.ɵɵadvance();
|
|
385
|
+
i0.ɵɵproperty("ngIf", ctx_r1.ScopeCategories.length === 0);
|
|
386
|
+
} }
|
|
387
|
+
function APIApplicationsPanelComponent_mj_loading_61_Template(rf, ctx) { if (rf & 1) {
|
|
388
|
+
i0.ɵɵelement(0, "mj-loading", 81);
|
|
389
|
+
} if (rf & 2) {
|
|
390
|
+
i0.ɵɵproperty("showText", false);
|
|
391
|
+
} }
|
|
392
|
+
function APIApplicationsPanelComponent_span_62_Template(rf, ctx) { if (rf & 1) {
|
|
393
|
+
i0.ɵɵelementStart(0, "span");
|
|
394
|
+
i0.ɵɵelement(1, "i", 82);
|
|
395
|
+
i0.ɵɵtext(2, " Save Changes ");
|
|
396
|
+
i0.ɵɵelementEnd();
|
|
397
|
+
} }
|
|
398
|
+
const PANEL_WIDTH_SETTING_KEY = 'APIKeys.ApplicationsPanelWidth';
|
|
399
|
+
const DEFAULT_PANEL_WIDTH = 570;
|
|
400
|
+
const MIN_PANEL_WIDTH = 400;
|
|
401
|
+
const MAX_PANEL_WIDTH = 800;
|
|
402
|
+
/** Tree shaking prevention function */
|
|
403
|
+
export function LoadAPIApplicationsPanel() {
|
|
404
|
+
// This function prevents tree shaking
|
|
405
|
+
}
|
|
406
|
+
/**
|
|
407
|
+
* API Applications Panel Component
|
|
408
|
+
* Manages API Applications and their scope assignments
|
|
409
|
+
*/
|
|
410
|
+
export class APIApplicationsPanelComponent {
|
|
411
|
+
ApplicationUpdated = new EventEmitter();
|
|
412
|
+
md = new Metadata();
|
|
413
|
+
cdr;
|
|
414
|
+
// Loading states
|
|
415
|
+
IsLoading = true;
|
|
416
|
+
IsSaving = false;
|
|
417
|
+
// Data
|
|
418
|
+
Applications = [];
|
|
419
|
+
AllScopes = [];
|
|
420
|
+
// Edit state
|
|
421
|
+
EditingApplication = null;
|
|
422
|
+
EditName = '';
|
|
423
|
+
EditDescription = '';
|
|
424
|
+
EditIsActive = true;
|
|
425
|
+
ScopeSelections = [];
|
|
426
|
+
// Panel states (slide-out panels)
|
|
427
|
+
ShowCreatePanel = false;
|
|
428
|
+
ShowEditPanel = false;
|
|
429
|
+
SelectedApplication = null;
|
|
430
|
+
EditTab = 'details';
|
|
431
|
+
// Panel width and resizing
|
|
432
|
+
PanelWidth = DEFAULT_PANEL_WIDTH;
|
|
433
|
+
IsResizing = false;
|
|
434
|
+
resizeStartX = 0;
|
|
435
|
+
resizeStartWidth = 0;
|
|
436
|
+
widthSaveTimeout = null;
|
|
437
|
+
// Track dirty state for unified save
|
|
438
|
+
DetailsChanged = false;
|
|
439
|
+
ScopesChanged = false;
|
|
440
|
+
// Scope categories for display
|
|
441
|
+
ScopeCategories = [];
|
|
442
|
+
// Messages
|
|
443
|
+
SuccessMessage = '';
|
|
444
|
+
ErrorMessage = '';
|
|
445
|
+
// Category configuration
|
|
446
|
+
categoryConfig = {
|
|
447
|
+
'Entities': { icon: 'fa-solid fa-database', color: '#6366f1' },
|
|
448
|
+
'Agents': { icon: 'fa-solid fa-robot', color: '#10b981' },
|
|
449
|
+
'Admin': { icon: 'fa-solid fa-shield-halved', color: '#f59e0b' },
|
|
450
|
+
'Actions': { icon: 'fa-solid fa-bolt', color: '#8b5cf6' },
|
|
451
|
+
'Queries': { icon: 'fa-solid fa-magnifying-glass', color: '#3b82f6' },
|
|
452
|
+
'Reports': { icon: 'fa-solid fa-chart-bar', color: '#ef4444' },
|
|
453
|
+
'Communication': { icon: 'fa-solid fa-envelope', color: '#ec4899' },
|
|
454
|
+
'Other': { icon: 'fa-solid fa-ellipsis', color: '#6b7280' }
|
|
455
|
+
};
|
|
456
|
+
constructor(cdr) {
|
|
457
|
+
this.cdr = cdr;
|
|
458
|
+
}
|
|
459
|
+
async ngOnInit() {
|
|
460
|
+
await this.loadPanelWidth();
|
|
461
|
+
await this.loadData();
|
|
462
|
+
}
|
|
463
|
+
ngOnDestroy() {
|
|
464
|
+
if (this.widthSaveTimeout) {
|
|
465
|
+
clearTimeout(this.widthSaveTimeout);
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
/**
|
|
469
|
+
* Handle mouse move during resize
|
|
470
|
+
*/
|
|
471
|
+
onMouseMove(event) {
|
|
472
|
+
if (!this.IsResizing)
|
|
473
|
+
return;
|
|
474
|
+
event.preventDefault();
|
|
475
|
+
const deltaX = this.resizeStartX - event.clientX;
|
|
476
|
+
const newWidth = Math.min(MAX_PANEL_WIDTH, Math.max(MIN_PANEL_WIDTH, this.resizeStartWidth + deltaX));
|
|
477
|
+
this.PanelWidth = newWidth;
|
|
478
|
+
this.cdr.markForCheck();
|
|
479
|
+
}
|
|
480
|
+
/**
|
|
481
|
+
* Handle mouse up to stop resize
|
|
482
|
+
*/
|
|
483
|
+
onMouseUp() {
|
|
484
|
+
if (this.IsResizing) {
|
|
485
|
+
this.IsResizing = false;
|
|
486
|
+
this.debouncedSavePanelWidth();
|
|
487
|
+
this.cdr.markForCheck();
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
/**
|
|
491
|
+
* Start resizing the panel
|
|
492
|
+
*/
|
|
493
|
+
startResize(event) {
|
|
494
|
+
event.preventDefault();
|
|
495
|
+
this.IsResizing = true;
|
|
496
|
+
this.resizeStartX = event.clientX;
|
|
497
|
+
this.resizeStartWidth = this.PanelWidth;
|
|
498
|
+
}
|
|
499
|
+
/**
|
|
500
|
+
* Load saved panel width from user settings
|
|
501
|
+
*/
|
|
502
|
+
async loadPanelWidth() {
|
|
503
|
+
try {
|
|
504
|
+
const engine = UserInfoEngine.Instance;
|
|
505
|
+
const setting = engine.UserSettings.find(s => s.Setting === PANEL_WIDTH_SETTING_KEY);
|
|
506
|
+
if (setting?.Value) {
|
|
507
|
+
const width = parseInt(setting.Value, 10);
|
|
508
|
+
if (!isNaN(width) && width >= MIN_PANEL_WIDTH && width <= MAX_PANEL_WIDTH) {
|
|
509
|
+
this.PanelWidth = width;
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
catch (error) {
|
|
514
|
+
console.warn('Failed to load panel width setting:', error);
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
/**
|
|
518
|
+
* Debounced save of panel width
|
|
519
|
+
*/
|
|
520
|
+
debouncedSavePanelWidth() {
|
|
521
|
+
if (this.widthSaveTimeout) {
|
|
522
|
+
clearTimeout(this.widthSaveTimeout);
|
|
523
|
+
}
|
|
524
|
+
this.widthSaveTimeout = setTimeout(() => {
|
|
525
|
+
this.savePanelWidth();
|
|
526
|
+
}, 500);
|
|
527
|
+
}
|
|
528
|
+
/**
|
|
529
|
+
* Save panel width to user settings
|
|
530
|
+
*/
|
|
531
|
+
async savePanelWidth() {
|
|
532
|
+
try {
|
|
533
|
+
const userId = this.md.CurrentUser?.ID;
|
|
534
|
+
if (!userId)
|
|
535
|
+
return;
|
|
536
|
+
const engine = UserInfoEngine.Instance;
|
|
537
|
+
let setting = engine.UserSettings.find(s => s.Setting === PANEL_WIDTH_SETTING_KEY);
|
|
538
|
+
if (!setting) {
|
|
539
|
+
setting = await this.md.GetEntityObject('MJ: User Settings');
|
|
540
|
+
setting.UserID = userId;
|
|
541
|
+
setting.Setting = PANEL_WIDTH_SETTING_KEY;
|
|
542
|
+
}
|
|
543
|
+
setting.Value = this.PanelWidth.toString();
|
|
544
|
+
await setting.Save();
|
|
545
|
+
}
|
|
546
|
+
catch (error) {
|
|
547
|
+
console.warn('Failed to save panel width setting:', error);
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
/**
|
|
551
|
+
* Load all applications and scopes
|
|
552
|
+
*/
|
|
553
|
+
async loadData() {
|
|
554
|
+
this.IsLoading = true;
|
|
555
|
+
try {
|
|
556
|
+
const rv = new RunView();
|
|
557
|
+
const [appsResult, scopesResult] = await rv.RunViews([
|
|
558
|
+
{
|
|
559
|
+
EntityName: 'MJ: API Applications',
|
|
560
|
+
OrderBy: 'Name',
|
|
561
|
+
ResultType: 'entity_object'
|
|
562
|
+
},
|
|
563
|
+
{
|
|
564
|
+
EntityName: 'MJ: API Scopes',
|
|
565
|
+
OrderBy: 'FullPath',
|
|
566
|
+
ResultType: 'entity_object'
|
|
567
|
+
}
|
|
568
|
+
]);
|
|
569
|
+
if (appsResult.Success) {
|
|
570
|
+
const apps = appsResult.Results;
|
|
571
|
+
this.AllScopes = (scopesResult.Success ? scopesResult.Results : []);
|
|
572
|
+
// Load scope assignments for each application
|
|
573
|
+
const appPromises = apps.map(async (app) => {
|
|
574
|
+
const scopeResult = await rv.RunView({
|
|
575
|
+
EntityName: 'MJ: API Application Scopes',
|
|
576
|
+
ExtraFilter: `ApplicationID='${app.ID}'`,
|
|
577
|
+
ResultType: 'entity_object'
|
|
578
|
+
});
|
|
579
|
+
return {
|
|
580
|
+
application: app,
|
|
581
|
+
scopeCount: scopeResult.Success ? scopeResult.Results.length : 0,
|
|
582
|
+
expanded: false,
|
|
583
|
+
scopes: scopeResult.Success ? scopeResult.Results : []
|
|
584
|
+
};
|
|
585
|
+
});
|
|
586
|
+
this.Applications = await Promise.all(appPromises);
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
catch (error) {
|
|
590
|
+
console.error('Error loading applications:', error);
|
|
591
|
+
this.ErrorMessage = 'Failed to load applications';
|
|
592
|
+
}
|
|
593
|
+
finally {
|
|
594
|
+
this.IsLoading = false;
|
|
595
|
+
this.cdr.markForCheck();
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
/**
|
|
599
|
+
* Open create panel (slide-out)
|
|
600
|
+
*/
|
|
601
|
+
openCreatePanel() {
|
|
602
|
+
this.EditName = '';
|
|
603
|
+
this.EditDescription = '';
|
|
604
|
+
this.EditIsActive = true;
|
|
605
|
+
this.EditingApplication = null;
|
|
606
|
+
this.DetailsChanged = false;
|
|
607
|
+
this.ScopesChanged = false;
|
|
608
|
+
this.ShowCreatePanel = true;
|
|
609
|
+
}
|
|
610
|
+
/**
|
|
611
|
+
* Save application (create only - for create panel)
|
|
612
|
+
*/
|
|
613
|
+
async saveApplication() {
|
|
614
|
+
this.IsSaving = true;
|
|
615
|
+
this.ErrorMessage = '';
|
|
616
|
+
try {
|
|
617
|
+
const app = await this.md.GetEntityObject('MJ: API Applications');
|
|
618
|
+
app.NewRecord();
|
|
619
|
+
app.Name = this.EditName.trim();
|
|
620
|
+
app.Description = this.EditDescription.trim() || null;
|
|
621
|
+
app.IsActive = this.EditIsActive;
|
|
622
|
+
const result = await app.Save();
|
|
623
|
+
if (result) {
|
|
624
|
+
this.SuccessMessage = 'Application created successfully';
|
|
625
|
+
this.closePanel();
|
|
626
|
+
await this.loadData();
|
|
627
|
+
this.ApplicationUpdated.emit();
|
|
628
|
+
setTimeout(() => this.SuccessMessage = '', 3000);
|
|
629
|
+
}
|
|
630
|
+
else {
|
|
631
|
+
this.ErrorMessage = 'Failed to create application';
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
catch (error) {
|
|
635
|
+
console.error('Error creating application:', error);
|
|
636
|
+
this.ErrorMessage = 'An error occurred while creating';
|
|
637
|
+
}
|
|
638
|
+
finally {
|
|
639
|
+
this.IsSaving = false;
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
/**
|
|
643
|
+
* Open edit panel (slide-out) with optional direct-to-scopes tab
|
|
644
|
+
*/
|
|
645
|
+
openEditPanel(appItem, goToScopes = false) {
|
|
646
|
+
this.EditingApplication = appItem.application;
|
|
647
|
+
this.SelectedApplication = appItem;
|
|
648
|
+
this.EditName = appItem.application.Name;
|
|
649
|
+
this.EditDescription = appItem.application.Description || '';
|
|
650
|
+
this.EditIsActive = appItem.application.IsActive;
|
|
651
|
+
this.EditTab = goToScopes ? 'scopes' : 'details';
|
|
652
|
+
this.DetailsChanged = false;
|
|
653
|
+
this.ScopesChanged = false;
|
|
654
|
+
this.buildScopeCategories(appItem);
|
|
655
|
+
this.ShowEditPanel = true;
|
|
656
|
+
}
|
|
657
|
+
/**
|
|
658
|
+
* Build scope categories with proper display names
|
|
659
|
+
*/
|
|
660
|
+
buildScopeCategories(appItem) {
|
|
661
|
+
const assignedScopeIds = new Map(appItem.scopes.map(s => [s.ScopeID, s]));
|
|
662
|
+
// Build a map for computing full paths
|
|
663
|
+
const scopeMap = new Map();
|
|
664
|
+
for (const scope of this.AllScopes) {
|
|
665
|
+
scopeMap.set(scope.ID, scope);
|
|
666
|
+
}
|
|
667
|
+
// Compute display name for each scope
|
|
668
|
+
const computeDisplayName = (scope) => {
|
|
669
|
+
// If FullPath is set and not empty, use it
|
|
670
|
+
if (scope.FullPath && scope.FullPath.trim()) {
|
|
671
|
+
return scope.FullPath;
|
|
672
|
+
}
|
|
673
|
+
// If Name is set, build the path by traversing parents
|
|
674
|
+
if (scope.Name && scope.Name.trim()) {
|
|
675
|
+
const parts = [scope.Name];
|
|
676
|
+
let currentScope = scope;
|
|
677
|
+
while (currentScope.ParentID) {
|
|
678
|
+
const parent = scopeMap.get(currentScope.ParentID);
|
|
679
|
+
if (parent && parent.Name) {
|
|
680
|
+
parts.unshift(parent.Name);
|
|
681
|
+
currentScope = parent;
|
|
682
|
+
}
|
|
683
|
+
else {
|
|
684
|
+
break;
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
return parts.join(':');
|
|
688
|
+
}
|
|
689
|
+
return `Scope-${scope.ID.slice(0, 8)}`;
|
|
690
|
+
};
|
|
691
|
+
// Create scope selections with computed display names
|
|
692
|
+
this.ScopeSelections = this.AllScopes
|
|
693
|
+
.filter(scope => {
|
|
694
|
+
// Filter out scopes with no name/path (shouldn't happen but be safe)
|
|
695
|
+
const displayName = computeDisplayName(scope);
|
|
696
|
+
return displayName && displayName.length > 0;
|
|
697
|
+
})
|
|
698
|
+
.map(scope => {
|
|
699
|
+
const assigned = assignedScopeIds.get(scope.ID);
|
|
700
|
+
return {
|
|
701
|
+
scope,
|
|
702
|
+
selected: !!assigned,
|
|
703
|
+
pattern: assigned?.ResourcePattern || '*',
|
|
704
|
+
patternType: (assigned?.PatternType || 'Include'),
|
|
705
|
+
isDeny: assigned?.IsDeny || false,
|
|
706
|
+
priority: assigned?.Priority || 0,
|
|
707
|
+
displayName: computeDisplayName(scope)
|
|
708
|
+
};
|
|
709
|
+
});
|
|
710
|
+
// Group by category
|
|
711
|
+
const categoryMap = new Map();
|
|
712
|
+
for (const selection of this.ScopeSelections) {
|
|
713
|
+
const category = selection.scope.Category || 'Other';
|
|
714
|
+
if (!categoryMap.has(category)) {
|
|
715
|
+
categoryMap.set(category, []);
|
|
716
|
+
}
|
|
717
|
+
categoryMap.get(category).push(selection);
|
|
718
|
+
}
|
|
719
|
+
// Build category objects - all collapsed by default
|
|
720
|
+
this.ScopeCategories = Array.from(categoryMap.entries()).map(([name, scopes]) => {
|
|
721
|
+
const config = this.categoryConfig[name] || this.categoryConfig['Other'];
|
|
722
|
+
const selectedCount = scopes.filter(s => s.selected).length;
|
|
723
|
+
return {
|
|
724
|
+
name,
|
|
725
|
+
icon: config.icon,
|
|
726
|
+
color: config.color,
|
|
727
|
+
scopes: scopes.sort((a, b) => a.displayName.localeCompare(b.displayName)),
|
|
728
|
+
expanded: false, // Always start collapsed - user can expand as needed
|
|
729
|
+
allSelected: selectedCount === scopes.length && scopes.length > 0
|
|
730
|
+
};
|
|
731
|
+
}).sort((a, b) => a.name.localeCompare(b.name));
|
|
732
|
+
}
|
|
733
|
+
/**
|
|
734
|
+
* Toggle category expansion
|
|
735
|
+
*/
|
|
736
|
+
toggleScopeCategory(category) {
|
|
737
|
+
category.expanded = !category.expanded;
|
|
738
|
+
}
|
|
739
|
+
/**
|
|
740
|
+
* Toggle all scopes in a category
|
|
741
|
+
*/
|
|
742
|
+
toggleCategoryAll(category) {
|
|
743
|
+
const newState = !category.allSelected;
|
|
744
|
+
for (const scope of category.scopes) {
|
|
745
|
+
scope.selected = newState;
|
|
746
|
+
}
|
|
747
|
+
category.allSelected = newState;
|
|
748
|
+
}
|
|
749
|
+
/**
|
|
750
|
+
* Update category state when individual scope changes
|
|
751
|
+
*/
|
|
752
|
+
updateCategoryState(category) {
|
|
753
|
+
const selectedCount = category.scopes.filter(s => s.selected).length;
|
|
754
|
+
category.allSelected = selectedCount === category.scopes.length && category.scopes.length > 0;
|
|
755
|
+
}
|
|
756
|
+
/**
|
|
757
|
+
* Get total selected scope count
|
|
758
|
+
*/
|
|
759
|
+
getSelectedScopeCount() {
|
|
760
|
+
return this.ScopeSelections.filter(s => s.selected).length;
|
|
761
|
+
}
|
|
762
|
+
/**
|
|
763
|
+
* Get selected scope count for a category
|
|
764
|
+
*/
|
|
765
|
+
getCategorySelectedCount(category) {
|
|
766
|
+
return category.scopes.filter(s => s.selected).length;
|
|
767
|
+
}
|
|
768
|
+
/**
|
|
769
|
+
* Save scope assignments (legacy - now handled by saveAll)
|
|
770
|
+
*/
|
|
771
|
+
async saveScopeAssignments() {
|
|
772
|
+
if (!this.SelectedApplication)
|
|
773
|
+
return;
|
|
774
|
+
this.IsSaving = true;
|
|
775
|
+
this.ErrorMessage = '';
|
|
776
|
+
try {
|
|
777
|
+
await this.saveScopeAssignmentsInternal();
|
|
778
|
+
this.SuccessMessage = 'Scope assignments saved successfully';
|
|
779
|
+
this.closePanel();
|
|
780
|
+
await this.loadData();
|
|
781
|
+
this.ApplicationUpdated.emit();
|
|
782
|
+
setTimeout(() => this.SuccessMessage = '', 3000);
|
|
783
|
+
}
|
|
784
|
+
catch (error) {
|
|
785
|
+
console.error('Error saving scope assignments:', error);
|
|
786
|
+
this.ErrorMessage = 'Failed to save scope assignments';
|
|
787
|
+
}
|
|
788
|
+
finally {
|
|
789
|
+
this.IsSaving = false;
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
/**
|
|
793
|
+
* Toggle application expansion
|
|
794
|
+
*/
|
|
795
|
+
toggleExpanded(appItem) {
|
|
796
|
+
appItem.expanded = !appItem.expanded;
|
|
797
|
+
}
|
|
798
|
+
/**
|
|
799
|
+
* Close all panels
|
|
800
|
+
*/
|
|
801
|
+
closePanel() {
|
|
802
|
+
this.ShowCreatePanel = false;
|
|
803
|
+
this.ShowEditPanel = false;
|
|
804
|
+
this.EditingApplication = null;
|
|
805
|
+
this.SelectedApplication = null;
|
|
806
|
+
this.ScopeSelections = [];
|
|
807
|
+
this.ScopeCategories = [];
|
|
808
|
+
this.EditTab = 'details';
|
|
809
|
+
this.DetailsChanged = false;
|
|
810
|
+
this.ScopesChanged = false;
|
|
811
|
+
}
|
|
812
|
+
/**
|
|
813
|
+
* Save all changes (both details and scopes)
|
|
814
|
+
*/
|
|
815
|
+
async saveAll() {
|
|
816
|
+
this.IsSaving = true;
|
|
817
|
+
this.ErrorMessage = '';
|
|
818
|
+
try {
|
|
819
|
+
// Save application details
|
|
820
|
+
if (this.EditingApplication) {
|
|
821
|
+
this.EditingApplication.Name = this.EditName.trim();
|
|
822
|
+
this.EditingApplication.Description = this.EditDescription.trim() || null;
|
|
823
|
+
this.EditingApplication.IsActive = this.EditIsActive;
|
|
824
|
+
const result = await this.EditingApplication.Save();
|
|
825
|
+
if (!result) {
|
|
826
|
+
this.ErrorMessage = 'Failed to save application details';
|
|
827
|
+
return;
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
// Save scope assignments
|
|
831
|
+
if (this.SelectedApplication) {
|
|
832
|
+
await this.saveScopeAssignmentsInternal();
|
|
833
|
+
}
|
|
834
|
+
this.SuccessMessage = 'Application saved successfully';
|
|
835
|
+
this.closePanel();
|
|
836
|
+
await this.loadData();
|
|
837
|
+
this.ApplicationUpdated.emit();
|
|
838
|
+
setTimeout(() => this.SuccessMessage = '', 3000);
|
|
839
|
+
}
|
|
840
|
+
catch (error) {
|
|
841
|
+
console.error('Error saving application:', error);
|
|
842
|
+
this.ErrorMessage = 'An error occurred while saving';
|
|
843
|
+
}
|
|
844
|
+
finally {
|
|
845
|
+
this.IsSaving = false;
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
/**
|
|
849
|
+
* Internal method to save scope assignments
|
|
850
|
+
*/
|
|
851
|
+
async saveScopeAssignmentsInternal() {
|
|
852
|
+
if (!this.SelectedApplication)
|
|
853
|
+
return;
|
|
854
|
+
const appId = this.SelectedApplication.application.ID;
|
|
855
|
+
const existingScopes = new Map(this.SelectedApplication.scopes.map(s => [s.ScopeID, s]));
|
|
856
|
+
for (const selection of this.ScopeSelections) {
|
|
857
|
+
const existing = existingScopes.get(selection.scope.ID);
|
|
858
|
+
if (selection.selected && !existing) {
|
|
859
|
+
// Create new assignment
|
|
860
|
+
const appScope = await this.md.GetEntityObject('MJ: API Application Scopes');
|
|
861
|
+
appScope.NewRecord();
|
|
862
|
+
appScope.ApplicationID = appId;
|
|
863
|
+
appScope.ScopeID = selection.scope.ID;
|
|
864
|
+
appScope.ResourcePattern = selection.pattern;
|
|
865
|
+
appScope.PatternType = selection.patternType;
|
|
866
|
+
appScope.IsDeny = selection.isDeny;
|
|
867
|
+
appScope.Priority = selection.priority;
|
|
868
|
+
await appScope.Save();
|
|
869
|
+
}
|
|
870
|
+
else if (selection.selected && existing) {
|
|
871
|
+
// Update existing
|
|
872
|
+
if (existing.ResourcePattern !== selection.pattern ||
|
|
873
|
+
existing.PatternType !== selection.patternType ||
|
|
874
|
+
existing.IsDeny !== selection.isDeny ||
|
|
875
|
+
existing.Priority !== selection.priority) {
|
|
876
|
+
existing.ResourcePattern = selection.pattern;
|
|
877
|
+
existing.PatternType = selection.patternType;
|
|
878
|
+
existing.IsDeny = selection.isDeny;
|
|
879
|
+
existing.Priority = selection.priority;
|
|
880
|
+
await existing.Save();
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
else if (!selection.selected && existing) {
|
|
884
|
+
// Delete assignment
|
|
885
|
+
await existing.Delete();
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
/**
|
|
890
|
+
* Get icon for pattern type
|
|
891
|
+
*/
|
|
892
|
+
getPatternIcon(patternType, isDeny) {
|
|
893
|
+
if (isDeny)
|
|
894
|
+
return 'fa-solid fa-ban';
|
|
895
|
+
return patternType === 'Include' ? 'fa-solid fa-check' : 'fa-solid fa-minus';
|
|
896
|
+
}
|
|
897
|
+
/**
|
|
898
|
+
* Get class for pattern type
|
|
899
|
+
*/
|
|
900
|
+
getPatternClass(patternType, isDeny) {
|
|
901
|
+
if (isDeny)
|
|
902
|
+
return 'pattern-deny';
|
|
903
|
+
return patternType === 'Include' ? 'pattern-include' : 'pattern-exclude';
|
|
904
|
+
}
|
|
905
|
+
/**
|
|
906
|
+
* Get scope name by ID
|
|
907
|
+
*/
|
|
908
|
+
getScopeName(scopeId) {
|
|
909
|
+
const scope = this.AllScopes.find(s => s.ID === scopeId);
|
|
910
|
+
return scope?.FullPath || scope?.Name || 'Unknown';
|
|
911
|
+
}
|
|
912
|
+
static ɵfac = function APIApplicationsPanelComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || APIApplicationsPanelComponent)(i0.ɵɵdirectiveInject(i0.ChangeDetectorRef)); };
|
|
913
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: APIApplicationsPanelComponent, selectors: [["mj-api-applications-panel"]], hostBindings: function APIApplicationsPanelComponent_HostBindings(rf, ctx) { if (rf & 1) {
|
|
914
|
+
i0.ɵɵlistener("mousemove", function APIApplicationsPanelComponent_mousemove_HostBindingHandler($event) { return ctx.onMouseMove($event); }, false, i0.ɵɵresolveDocument)("mouseup", function APIApplicationsPanelComponent_mouseup_HostBindingHandler() { return ctx.onMouseUp(); }, false, i0.ɵɵresolveDocument);
|
|
915
|
+
} }, outputs: { ApplicationUpdated: "ApplicationUpdated" }, decls: 65, vars: 36, consts: [[1, "applications-panel"], ["text", "Loading applications...", 4, "ngIf"], [4, "ngIf"], ["class", "slideout-backdrop", 3, "click", 4, "ngIf"], [1, "slideout-panel"], [1, "slideout-header"], [1, "slideout-title"], [1, "fa-solid", "fa-plus-circle"], ["title", "Close", 1, "slideout-close", 3, "click"], [1, "fa-solid", "fa-times"], [1, "slideout-content"], [1, "form-section"], [1, "form-field"], ["kendoTextBox", "", "placeholder", "e.g., MJAPI, MCP Server, Portal", 1, "form-input", 3, "ngModelChange", "ngModel"], ["kendoTextArea", "", "placeholder", "Describe the application's purpose...", 1, "form-textarea", 3, "ngModelChange", "ngModel", "rows"], [1, "checkbox-label"], ["type", "checkbox", "kendoCheckBox", "", 3, "ngModelChange", "ngModel"], [1, "checkbox-hint"], [1, "slideout-footer"], ["kendoButton", "", 3, "click", "themeColor", "disabled"], ["size", "small", 3, "showText", 4, "ngIf"], ["kendoButton", "", 3, "click"], [1, "slideout-resize-handle", 3, "mousedown"], [1, "fa-solid", "fa-cube"], [1, "status-pill"], [1, "slideout-tabs"], [1, "slideout-tab", 3, "click"], [1, "fa-solid", "fa-info-circle"], [1, "fa-solid", "fa-shield-halved"], [1, "tab-badge"], ["class", "tab-panel", 4, "ngIf"], ["class", "tab-panel scopes-panel", 4, "ngIf"], ["text", "Loading applications..."], [1, "panel-header"], [1, "header-left"], [1, "panel-title"], [1, "panel-subtitle"], [1, "btn-create", 3, "click"], [1, "fa-solid", "fa-plus"], ["class", "message success", 4, "ngIf"], ["class", "message error", 4, "ngIf"], [1, "applications-grid"], ["class", "app-card", 3, "inactive", "expanded", 4, "ngFor", "ngForOf"], ["class", "empty-state", 4, "ngIf"], [1, "message", "success"], [1, "fa-solid", "fa-check-circle"], [1, "message", "error"], [1, "fa-solid", "fa-circle-exclamation"], [1, "app-card"], [1, "app-header"], [1, "app-header-main", 3, "click"], [1, "app-icon"], [1, "app-info"], [1, "app-name"], [1, "status-badge"], ["class", "app-description", 4, "ngIf"], [1, "app-stats"], [1, "scope-count"], [1, "fa-solid", "expand-icon"], ["title", "Edit Application", 1, "app-edit-btn", 3, "click"], [1, "fa-solid", "fa-pencil"], ["class", "app-details", 4, "ngIf"], [1, "app-description"], [1, "app-details"], [1, "details-section"], ["class", "scope-rules", 4, "ngIf"], ["class", "empty-scopes", 4, "ngIf"], [1, "scope-rules"], ["class", "scope-rule", 4, "ngFor", "ngForOf"], [1, "scope-rule"], [1, "rule-icon", 3, "ngClass"], [1, "rule-info"], [1, "rule-scope"], [1, "rule-pattern"], [1, "pattern-type"], ["class", "priority", 4, "ngIf"], [1, "priority"], [1, "empty-scopes"], [1, "fa-solid", "fa-shield-xmark"], [1, "empty-state"], [1, "slideout-backdrop", 3, "click"], ["size", "small", 3, "showText"], [1, "fa-solid", "fa-save"], [1, "tab-panel"], [1, "tab-panel", "scopes-panel"], [1, "scopes-intro"], [1, "scope-categories-list"], ["class", "scope-category-card", 4, "ngFor", "ngForOf"], ["class", "empty-scopes-message", 4, "ngIf"], [1, "scope-category-card"], [1, "category-header", 3, "click"], [1, "category-left"], [1, "category-name"], [1, "category-count-badge"], [1, "category-right"], [1, "category-all-toggle", 3, "click"], ["type", "checkbox", "kendoCheckBox", "", 3, "change", "checked"], [1, "fa-solid", "category-chevron"], ["class", "category-scopes-list", 4, "ngIf"], [1, "category-scopes-list"], ["class", "scope-row", 3, "selected", 4, "ngFor", "ngForOf"], [1, "scope-row"], [1, "scope-select"], ["type", "checkbox", "kendoCheckBox", "", 3, "ngModelChange", "change", "ngModel"], [1, "scope-label"], [1, "scope-path"], ["class", "scope-description", 4, "ngIf"], ["class", "scope-pattern-display", 4, "ngIf"], ["class", "scope-pattern-config", 4, "ngIf"], [1, "scope-description"], [1, "scope-pattern-display"], [1, "pattern-tag"], [1, "fa-solid"], [1, "scope-pattern-config"], ["kendoTextBox", "", "placeholder", "*", "title", "Resource Pattern", 1, "pattern-field", 3, "ngModelChange", "ngModel"], ["title", "Pattern Type", 1, "type-field", 3, "ngModelChange", "ngModel", "data", "valuePrimitive"], [1, "empty-scopes-message"]], template: function APIApplicationsPanelComponent_Template(rf, ctx) { if (rf & 1) {
|
|
916
|
+
i0.ɵɵelementStart(0, "div", 0);
|
|
917
|
+
i0.ɵɵtemplate(1, APIApplicationsPanelComponent_mj_loading_1_Template, 1, 0, "mj-loading", 1)(2, APIApplicationsPanelComponent_ng_container_2_Template, 16, 4, "ng-container", 2)(3, APIApplicationsPanelComponent_div_3_Template, 1, 0, "div", 3);
|
|
918
|
+
i0.ɵɵelementStart(4, "div", 4)(5, "div", 5)(6, "div", 6);
|
|
919
|
+
i0.ɵɵelement(7, "i", 7);
|
|
920
|
+
i0.ɵɵelementStart(8, "span");
|
|
921
|
+
i0.ɵɵtext(9, "New Application");
|
|
922
|
+
i0.ɵɵelementEnd()();
|
|
923
|
+
i0.ɵɵelementStart(10, "button", 8);
|
|
924
|
+
i0.ɵɵlistener("click", function APIApplicationsPanelComponent_Template_button_click_10_listener() { return ctx.closePanel(); });
|
|
925
|
+
i0.ɵɵelement(11, "i", 9);
|
|
926
|
+
i0.ɵɵelementEnd()();
|
|
927
|
+
i0.ɵɵelementStart(12, "div", 10)(13, "div", 11)(14, "div", 12)(15, "label");
|
|
928
|
+
i0.ɵɵtext(16, "Application Name *");
|
|
929
|
+
i0.ɵɵelementEnd();
|
|
930
|
+
i0.ɵɵelementStart(17, "input", 13);
|
|
931
|
+
i0.ɵɵtwoWayListener("ngModelChange", function APIApplicationsPanelComponent_Template_input_ngModelChange_17_listener($event) { i0.ɵɵtwoWayBindingSet(ctx.EditName, $event) || (ctx.EditName = $event); return $event; });
|
|
932
|
+
i0.ɵɵelementEnd()();
|
|
933
|
+
i0.ɵɵelementStart(18, "div", 12)(19, "label");
|
|
934
|
+
i0.ɵɵtext(20, "Description");
|
|
935
|
+
i0.ɵɵelementEnd();
|
|
936
|
+
i0.ɵɵelementStart(21, "textarea", 14);
|
|
937
|
+
i0.ɵɵtwoWayListener("ngModelChange", function APIApplicationsPanelComponent_Template_textarea_ngModelChange_21_listener($event) { i0.ɵɵtwoWayBindingSet(ctx.EditDescription, $event) || (ctx.EditDescription = $event); return $event; });
|
|
938
|
+
i0.ɵɵelementEnd()();
|
|
939
|
+
i0.ɵɵelementStart(22, "div", 12)(23, "label", 15)(24, "input", 16);
|
|
940
|
+
i0.ɵɵtwoWayListener("ngModelChange", function APIApplicationsPanelComponent_Template_input_ngModelChange_24_listener($event) { i0.ɵɵtwoWayBindingSet(ctx.EditIsActive, $event) || (ctx.EditIsActive = $event); return $event; });
|
|
941
|
+
i0.ɵɵelementEnd();
|
|
942
|
+
i0.ɵɵelementStart(25, "div")(26, "span");
|
|
943
|
+
i0.ɵɵtext(27, "Active");
|
|
944
|
+
i0.ɵɵelementEnd();
|
|
945
|
+
i0.ɵɵelementStart(28, "span", 17);
|
|
946
|
+
i0.ɵɵtext(29, "Inactive applications cannot be used with API keys");
|
|
947
|
+
i0.ɵɵelementEnd()()()()()();
|
|
948
|
+
i0.ɵɵelementStart(30, "div", 18)(31, "button", 19);
|
|
949
|
+
i0.ɵɵlistener("click", function APIApplicationsPanelComponent_Template_button_click_31_listener() { return ctx.saveApplication(); });
|
|
950
|
+
i0.ɵɵtemplate(32, APIApplicationsPanelComponent_mj_loading_32_Template, 1, 1, "mj-loading", 20)(33, APIApplicationsPanelComponent_span_33_Template, 3, 0, "span", 2);
|
|
951
|
+
i0.ɵɵelementEnd();
|
|
952
|
+
i0.ɵɵelementStart(34, "button", 21);
|
|
953
|
+
i0.ɵɵlistener("click", function APIApplicationsPanelComponent_Template_button_click_34_listener() { return ctx.closePanel(); });
|
|
954
|
+
i0.ɵɵtext(35, "Cancel");
|
|
955
|
+
i0.ɵɵelementEnd()()();
|
|
956
|
+
i0.ɵɵelementStart(36, "div", 4)(37, "div", 22);
|
|
957
|
+
i0.ɵɵlistener("mousedown", function APIApplicationsPanelComponent_Template_div_mousedown_37_listener($event) { return ctx.startResize($event); });
|
|
958
|
+
i0.ɵɵelementEnd();
|
|
959
|
+
i0.ɵɵelementStart(38, "div", 5)(39, "div", 6);
|
|
960
|
+
i0.ɵɵelement(40, "i", 23);
|
|
961
|
+
i0.ɵɵelementStart(41, "span");
|
|
962
|
+
i0.ɵɵtext(42);
|
|
963
|
+
i0.ɵɵelementEnd();
|
|
964
|
+
i0.ɵɵelementStart(43, "span", 24);
|
|
965
|
+
i0.ɵɵtext(44);
|
|
966
|
+
i0.ɵɵelementEnd()();
|
|
967
|
+
i0.ɵɵelementStart(45, "button", 8);
|
|
968
|
+
i0.ɵɵlistener("click", function APIApplicationsPanelComponent_Template_button_click_45_listener() { return ctx.closePanel(); });
|
|
969
|
+
i0.ɵɵelement(46, "i", 9);
|
|
970
|
+
i0.ɵɵelementEnd()();
|
|
971
|
+
i0.ɵɵelementStart(47, "div", 25)(48, "button", 26);
|
|
972
|
+
i0.ɵɵlistener("click", function APIApplicationsPanelComponent_Template_button_click_48_listener() { return ctx.EditTab = "details"; });
|
|
973
|
+
i0.ɵɵelement(49, "i", 27);
|
|
974
|
+
i0.ɵɵtext(50, " Details ");
|
|
975
|
+
i0.ɵɵelementEnd();
|
|
976
|
+
i0.ɵɵelementStart(51, "button", 26);
|
|
977
|
+
i0.ɵɵlistener("click", function APIApplicationsPanelComponent_Template_button_click_51_listener() { return ctx.EditTab = "scopes"; });
|
|
978
|
+
i0.ɵɵelement(52, "i", 28);
|
|
979
|
+
i0.ɵɵtext(53, " Scopes ");
|
|
980
|
+
i0.ɵɵelementStart(54, "span", 29);
|
|
981
|
+
i0.ɵɵtext(55);
|
|
982
|
+
i0.ɵɵelementEnd()()();
|
|
983
|
+
i0.ɵɵelementStart(56, "div", 10);
|
|
984
|
+
i0.ɵɵtemplate(57, APIApplicationsPanelComponent_div_57_Template, 18, 4, "div", 30)(58, APIApplicationsPanelComponent_div_58_Template, 8, 2, "div", 31);
|
|
985
|
+
i0.ɵɵelementEnd();
|
|
986
|
+
i0.ɵɵelementStart(59, "div", 18)(60, "button", 19);
|
|
987
|
+
i0.ɵɵlistener("click", function APIApplicationsPanelComponent_Template_button_click_60_listener() { return ctx.saveAll(); });
|
|
988
|
+
i0.ɵɵtemplate(61, APIApplicationsPanelComponent_mj_loading_61_Template, 1, 1, "mj-loading", 20)(62, APIApplicationsPanelComponent_span_62_Template, 3, 0, "span", 2);
|
|
989
|
+
i0.ɵɵelementEnd();
|
|
990
|
+
i0.ɵɵelementStart(63, "button", 21);
|
|
991
|
+
i0.ɵɵlistener("click", function APIApplicationsPanelComponent_Template_button_click_63_listener() { return ctx.closePanel(); });
|
|
992
|
+
i0.ɵɵtext(64, "Cancel");
|
|
993
|
+
i0.ɵɵelementEnd()()()();
|
|
994
|
+
} if (rf & 2) {
|
|
995
|
+
i0.ɵɵclassProp("panel-open", ctx.ShowEditPanel || ctx.ShowCreatePanel);
|
|
996
|
+
i0.ɵɵadvance();
|
|
997
|
+
i0.ɵɵproperty("ngIf", ctx.IsLoading);
|
|
998
|
+
i0.ɵɵadvance();
|
|
999
|
+
i0.ɵɵproperty("ngIf", !ctx.IsLoading);
|
|
1000
|
+
i0.ɵɵadvance();
|
|
1001
|
+
i0.ɵɵproperty("ngIf", ctx.ShowEditPanel || ctx.ShowCreatePanel);
|
|
1002
|
+
i0.ɵɵadvance();
|
|
1003
|
+
i0.ɵɵclassProp("open", ctx.ShowCreatePanel);
|
|
1004
|
+
i0.ɵɵadvance(13);
|
|
1005
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx.EditName);
|
|
1006
|
+
i0.ɵɵadvance(4);
|
|
1007
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx.EditDescription);
|
|
1008
|
+
i0.ɵɵproperty("rows", 3);
|
|
1009
|
+
i0.ɵɵadvance(3);
|
|
1010
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx.EditIsActive);
|
|
1011
|
+
i0.ɵɵadvance(7);
|
|
1012
|
+
i0.ɵɵproperty("themeColor", "primary")("disabled", !ctx.EditName.trim() || ctx.IsSaving);
|
|
1013
|
+
i0.ɵɵadvance();
|
|
1014
|
+
i0.ɵɵproperty("ngIf", ctx.IsSaving);
|
|
1015
|
+
i0.ɵɵadvance();
|
|
1016
|
+
i0.ɵɵproperty("ngIf", !ctx.IsSaving);
|
|
1017
|
+
i0.ɵɵadvance(3);
|
|
1018
|
+
i0.ɵɵstyleProp("width", ctx.PanelWidth, "px");
|
|
1019
|
+
i0.ɵɵclassProp("open", ctx.ShowEditPanel);
|
|
1020
|
+
i0.ɵɵadvance();
|
|
1021
|
+
i0.ɵɵclassProp("resizing", ctx.IsResizing);
|
|
1022
|
+
i0.ɵɵadvance(5);
|
|
1023
|
+
i0.ɵɵtextInterpolate(ctx.EditingApplication == null ? null : ctx.EditingApplication.Name);
|
|
1024
|
+
i0.ɵɵadvance();
|
|
1025
|
+
i0.ɵɵclassProp("active", ctx.EditIsActive);
|
|
1026
|
+
i0.ɵɵadvance();
|
|
1027
|
+
i0.ɵɵtextInterpolate1(" ", ctx.EditIsActive ? "Active" : "Inactive", " ");
|
|
1028
|
+
i0.ɵɵadvance(4);
|
|
1029
|
+
i0.ɵɵclassProp("active", ctx.EditTab === "details");
|
|
1030
|
+
i0.ɵɵadvance(3);
|
|
1031
|
+
i0.ɵɵclassProp("active", ctx.EditTab === "scopes");
|
|
1032
|
+
i0.ɵɵadvance(4);
|
|
1033
|
+
i0.ɵɵtextInterpolate(ctx.getSelectedScopeCount());
|
|
1034
|
+
i0.ɵɵadvance(2);
|
|
1035
|
+
i0.ɵɵproperty("ngIf", ctx.EditTab === "details");
|
|
1036
|
+
i0.ɵɵadvance();
|
|
1037
|
+
i0.ɵɵproperty("ngIf", ctx.EditTab === "scopes");
|
|
1038
|
+
i0.ɵɵadvance(2);
|
|
1039
|
+
i0.ɵɵproperty("themeColor", "primary")("disabled", !ctx.EditName.trim() || ctx.IsSaving);
|
|
1040
|
+
i0.ɵɵadvance();
|
|
1041
|
+
i0.ɵɵproperty("ngIf", ctx.IsSaving);
|
|
1042
|
+
i0.ɵɵadvance();
|
|
1043
|
+
i0.ɵɵproperty("ngIf", !ctx.IsSaving);
|
|
1044
|
+
} }, dependencies: [i1.NgClass, i1.NgForOf, i1.NgIf, i2.DefaultValueAccessor, i2.CheckboxControlValueAccessor, i2.NgControlStatus, i2.NgModel, i3.DropDownListComponent, i4.TextAreaDirective, i4.TextBoxDirective, i4.CheckBoxDirective, i5.ButtonComponent, i6.LoadingComponent], styles: [".applications-panel[_ngcontent-%COMP%] {\n height: 100%;\n display: flex;\n flex-direction: column;\n position: relative;\n}\n\n.applications-panel.panel-open[_ngcontent-%COMP%] {\n overflow: hidden;\n}\n\n\n\n.panel-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 24px;\n}\n\n.header-left[_ngcontent-%COMP%] {\n flex: 1;\n}\n\n.panel-title[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n font-size: 18px;\n font-weight: 600;\n color: var(--text-primary, #1f2937);\n margin: 0 0 4px 0;\n}\n\n.panel-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: #8b5cf6;\n}\n\n.panel-subtitle[_ngcontent-%COMP%] {\n font-size: 14px;\n color: var(--text-secondary, #6b7280);\n margin: 0;\n}\n\n.btn-create[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 20px;\n background: linear-gradient(135deg, #8b5cf6 0%, #7c3aed 100%);\n color: white;\n border: none;\n border-radius: 8px;\n font-weight: 600;\n font-size: 14px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.btn-create[_ngcontent-%COMP%]:hover {\n transform: translateY(-1px);\n box-shadow: 0 4px 12px rgba(139, 92, 246, 0.4);\n}\n\n\n\n.message[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 12px 16px;\n border-radius: 8px;\n margin-bottom: 16px;\n font-size: 14px;\n}\n\n.message.success[_ngcontent-%COMP%] {\n background: #d1fae5;\n color: #065f46;\n border: 1px solid #a7f3d0;\n}\n\n.message.error[_ngcontent-%COMP%] {\n background: #fee2e2;\n color: #991b1b;\n border: 1px solid #fca5a5;\n}\n\n\n\n.applications-grid[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 16px;\n flex: 1;\n overflow-y: auto;\n}\n\n.app-card[_ngcontent-%COMP%] {\n background: var(--card-background, #ffffff);\n border-radius: 12px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);\n overflow: hidden;\n transition: box-shadow 0.2s ease;\n}\n\n.app-card[_ngcontent-%COMP%]:hover {\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);\n}\n\n.app-card.inactive[_ngcontent-%COMP%] {\n opacity: 0.7;\n}\n\n.app-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n padding: 16px 20px;\n gap: 12px;\n}\n\n.app-header-main[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n flex: 1;\n cursor: pointer;\n transition: background 0.2s ease;\n border-radius: 8px;\n padding: 4px;\n margin: -4px;\n}\n\n.app-header-main[_ngcontent-%COMP%]:hover {\n background: var(--item-hover, #f9fafb);\n}\n\n.app-edit-btn[_ngcontent-%COMP%] {\n width: 36px;\n height: 36px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: transparent;\n border: 1px solid var(--border-color, #e5e7eb);\n border-radius: 8px;\n color: var(--text-secondary, #6b7280);\n cursor: pointer;\n transition: all 0.2s ease;\n flex-shrink: 0;\n}\n\n.app-edit-btn[_ngcontent-%COMP%]:hover {\n background: #8b5cf6;\n border-color: #8b5cf6;\n color: white;\n}\n\n.app-icon[_ngcontent-%COMP%] {\n width: 48px;\n height: 48px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: linear-gradient(135deg, #8b5cf6 0%, #7c3aed 100%);\n border-radius: 10px;\n margin-right: 16px;\n flex-shrink: 0;\n}\n\n.app-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 20px;\n color: white;\n}\n\n.app-info[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n.app-name[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n font-size: 16px;\n font-weight: 600;\n color: var(--text-primary, #1f2937);\n}\n\n.status-badge[_ngcontent-%COMP%] {\n font-size: 11px;\n font-weight: 500;\n padding: 2px 8px;\n border-radius: 10px;\n}\n\n.status-badge.active[_ngcontent-%COMP%] {\n background: #d1fae5;\n color: #065f46;\n}\n\n.status-badge.inactive[_ngcontent-%COMP%] {\n background: #f3f4f6;\n color: #6b7280;\n}\n\n.app-description[_ngcontent-%COMP%] {\n font-size: 13px;\n color: var(--text-secondary, #6b7280);\n margin-top: 4px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.app-stats[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 16px;\n margin-left: 16px;\n}\n\n.scope-count[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 13px;\n color: var(--text-secondary, #6b7280);\n}\n\n.scope-count[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: #8b5cf6;\n}\n\n.expand-icon[_ngcontent-%COMP%] {\n color: var(--text-tertiary, #9ca3af);\n transition: transform 0.2s ease;\n}\n\n\n\n.app-details[_ngcontent-%COMP%] {\n padding: 0 20px 20px 20px;\n border-top: 1px solid var(--border-color, #e5e7eb);\n margin-top: 0;\n}\n\n.details-section[_ngcontent-%COMP%] {\n margin-top: 16px;\n}\n\n.details-section[_ngcontent-%COMP%] h4[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: 600;\n color: var(--text-primary, #1f2937);\n margin: 0 0 12px 0;\n}\n\n.scope-rules[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.scope-rule[_ngcontent-%COMP%] {\n display: flex;\n align-items: flex-start;\n padding: 10px 12px;\n background: var(--item-background, #f9fafb);\n border-radius: 8px;\n}\n\n.rule-icon[_ngcontent-%COMP%] {\n width: 28px;\n height: 28px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 6px;\n margin-right: 12px;\n flex-shrink: 0;\n}\n\n.rule-icon.pattern-include[_ngcontent-%COMP%] {\n background: #d1fae5;\n color: #059669;\n}\n\n.rule-icon.pattern-exclude[_ngcontent-%COMP%] {\n background: #fef3c7;\n color: #d97706;\n}\n\n.rule-icon.pattern-deny[_ngcontent-%COMP%] {\n background: #fee2e2;\n color: #dc2626;\n}\n\n.rule-info[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n.rule-scope[_ngcontent-%COMP%] {\n font-size: 13px;\n font-weight: 500;\n color: var(--text-primary, #1f2937);\n}\n\n.rule-pattern[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-top: 4px;\n flex-wrap: wrap;\n}\n\n.rule-pattern[_ngcontent-%COMP%] code[_ngcontent-%COMP%] {\n font-family: monospace;\n font-size: 12px;\n background: var(--tag-background, #e5e7eb);\n padding: 2px 6px;\n border-radius: 4px;\n color: var(--text-primary, #1f2937);\n}\n\n.pattern-type[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--text-secondary, #6b7280);\n}\n\n.priority[_ngcontent-%COMP%] {\n font-size: 11px;\n color: #8b5cf6;\n}\n\n.empty-scopes[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n padding: 24px;\n color: var(--text-secondary, #6b7280);\n text-align: center;\n background: var(--item-background, #f9fafb);\n border-radius: 8px;\n}\n\n.empty-scopes[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 24px;\n margin-bottom: 8px;\n opacity: 0.5;\n}\n\n\n\n\n\n\n.empty-state[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 48px;\n color: var(--text-secondary, #6b7280);\n text-align: center;\n}\n\n.empty-state[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 48px;\n margin-bottom: 16px;\n opacity: 0.5;\n}\n\n.empty-state[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n font-size: 16px;\n font-weight: 500;\n}\n\n.empty-state[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n font-size: 14px;\n margin-top: 8px;\n}\n\n\n\n\n\n\n\n\n.slideout-backdrop[_ngcontent-%COMP%] {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.3);\n z-index: 100;\n animation: _ngcontent-%COMP%_fadeIn 0.2s ease;\n}\n\n@keyframes _ngcontent-%COMP%_fadeIn {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n\n\n\n.slideout-panel[_ngcontent-%COMP%] {\n position: absolute;\n top: 0;\n right: 0;\n width: 570px;\n height: 100%;\n max-height: 100%;\n background: var(--card-background, #ffffff);\n box-shadow: -8px 0 32px rgba(0, 0, 0, 0.15);\n z-index: 101;\n display: flex;\n flex-direction: column;\n transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n overflow: hidden;\n transform: translateX(100%);\n}\n\n.slideout-panel.open[_ngcontent-%COMP%] {\n transform: translateX(0);\n}\n\n\n\n.slideout-resize-handle[_ngcontent-%COMP%] {\n position: absolute;\n top: 0;\n left: 0;\n width: 6px;\n height: 100%;\n cursor: ew-resize;\n background: transparent;\n z-index: 10;\n transition: background 0.2s ease;\n}\n\n.slideout-resize-handle[_ngcontent-%COMP%]:hover, \n.slideout-resize-handle.resizing[_ngcontent-%COMP%] {\n background: rgba(139, 92, 246, 0.3);\n}\n\n.slideout-resize-handle[_ngcontent-%COMP%]::after {\n content: '';\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 2px;\n height: 40px;\n background: #d1d5db;\n border-radius: 2px;\n opacity: 0;\n transition: opacity 0.2s ease;\n}\n\n.slideout-resize-handle[_ngcontent-%COMP%]:hover::after {\n opacity: 1;\n}\n\n\n\n.slideout-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 20px 24px;\n background: linear-gradient(135deg, #fafafa 0%, #f3f4f6 100%);\n border-bottom: 1px solid #e5e7eb;\n flex-shrink: 0;\n}\n\n.slideout-title[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n font-weight: 600;\n font-size: 17px;\n color: #1f2937;\n flex: 1;\n min-width: 0;\n}\n\n.slideout-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: #8b5cf6;\n font-size: 18px;\n flex-shrink: 0;\n}\n\n.slideout-title[_ngcontent-%COMP%] span[_ngcontent-%COMP%]:first-of-type {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.status-pill[_ngcontent-%COMP%] {\n font-size: 11px;\n font-weight: 500;\n padding: 3px 10px;\n border-radius: 12px;\n background: #f3f4f6;\n color: #6b7280;\n flex-shrink: 0;\n}\n\n.status-pill.active[_ngcontent-%COMP%] {\n background: #d1fae5;\n color: #065f46;\n}\n\n.slideout-close[_ngcontent-%COMP%] {\n width: 36px;\n height: 36px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: transparent;\n border: none;\n border-radius: 8px;\n color: #9ca3af;\n cursor: pointer;\n transition: all 0.2s ease;\n flex-shrink: 0;\n}\n\n.slideout-close[_ngcontent-%COMP%]:hover {\n background: rgba(0, 0, 0, 0.05);\n color: #374151;\n}\n\n\n\n.slideout-tabs[_ngcontent-%COMP%] {\n display: flex;\n gap: 4px;\n padding: 12px 24px;\n background: #f9fafb;\n border-bottom: 1px solid #e5e7eb;\n flex-shrink: 0;\n}\n\n.slideout-tab[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 18px;\n background: transparent;\n border: none;\n border-radius: 8px;\n font-size: 14px;\n font-weight: 500;\n color: #6b7280;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.slideout-tab[_ngcontent-%COMP%]:hover {\n background: #e5e7eb;\n color: #374151;\n}\n\n.slideout-tab.active[_ngcontent-%COMP%] {\n background: #8b5cf6;\n color: white;\n}\n\n.slideout-tab[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n}\n\n.tab-badge[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 20px;\n height: 20px;\n padding: 0 6px;\n background: rgba(255, 255, 255, 0.2);\n border-radius: 10px;\n font-size: 11px;\n font-weight: 600;\n}\n\n.slideout-tab[_ngcontent-%COMP%]:not(.active) .tab-badge[_ngcontent-%COMP%] {\n background: #e5e7eb;\n color: #374151;\n}\n\n\n\n.slideout-content[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n padding: 24px;\n}\n\n.tab-panel[_ngcontent-%COMP%] {\n height: 100%;\n display: flex;\n flex-direction: column;\n}\n\n.scopes-panel[_ngcontent-%COMP%] {\n height: 100%;\n}\n\n\n\n.form-section[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 20px;\n}\n\n\n\n.form-field[_ngcontent-%COMP%] {\n margin-bottom: 20px;\n}\n\n.form-field[_ngcontent-%COMP%]:last-of-type {\n margin-bottom: 0;\n}\n\n.form-field[_ngcontent-%COMP%] label[_ngcontent-%COMP%] {\n display: block;\n font-size: 13px;\n font-weight: 600;\n color: #374151;\n margin-bottom: 8px;\n letter-spacing: 0.01em;\n}\n\n.form-input[_ngcontent-%COMP%] {\n width: 100%;\n}\n\n.form-textarea[_ngcontent-%COMP%] {\n width: 100%;\n resize: vertical;\n min-height: 80px;\n}\n\n[_nghost-%COMP%] .form-input .k-input, \n[_nghost-%COMP%] .form-textarea .k-input-inner {\n padding: 10px 14px;\n border-radius: 8px;\n font-size: 14px;\n border-color: #e5e7eb;\n transition: all 0.2s ease;\n}\n\n[_nghost-%COMP%] .form-input:focus-within, \n[_nghost-%COMP%] .form-textarea:focus-within {\n box-shadow: 0 0 0 3px rgba(139, 92, 246, 0.1);\n}\n\n\n\n.slideout-footer[_ngcontent-%COMP%] {\n display: flex;\n gap: 12px;\n padding: 16px 24px;\n background: #f9fafb;\n border-top: 1px solid #e5e7eb;\n flex-shrink: 0;\n}\n\n[_nghost-%COMP%] .slideout-footer .k-button {\n min-width: 100px;\n padding: 10px 20px;\n font-weight: 600;\n border-radius: 8px;\n transition: all 0.2s ease;\n}\n\n[_nghost-%COMP%] .slideout-footer .k-button-solid-primary {\n background: linear-gradient(135deg, #8b5cf6 0%, #7c3aed 100%);\n border: none;\n box-shadow: 0 2px 8px rgba(139, 92, 246, 0.3);\n}\n\n[_nghost-%COMP%] .slideout-footer .k-button-solid-primary:hover {\n transform: translateY(-1px);\n box-shadow: 0 4px 12px rgba(139, 92, 246, 0.4);\n}\n\n.checkbox-label[_ngcontent-%COMP%] {\n display: flex;\n align-items: flex-start;\n gap: 12px;\n cursor: pointer;\n padding: 12px 16px;\n background: #f9fafb;\n border-radius: 10px;\n border: 1px solid #e5e7eb;\n transition: all 0.2s ease;\n}\n\n.checkbox-label[_ngcontent-%COMP%]:hover {\n background: #f3f4f6;\n border-color: #d1d5db;\n}\n\n.checkbox-label[_ngcontent-%COMP%] input[_ngcontent-%COMP%] {\n margin-top: 2px;\n flex-shrink: 0;\n}\n\n.checkbox-label[_ngcontent-%COMP%] span[_ngcontent-%COMP%]:first-of-type {\n font-weight: 600;\n color: #374151;\n font-size: 14px;\n}\n\n.checkbox-hint[_ngcontent-%COMP%] {\n display: block;\n font-size: 12px;\n color: #6b7280;\n margin-top: 4px;\n line-height: 1.4;\n}\n\n\n\n\n\n\n\n\n\n.scopes-intro[_ngcontent-%COMP%] {\n display: flex;\n align-items: flex-start;\n gap: 12px;\n padding: 12px 16px;\n background: linear-gradient(135deg, #eff6ff 0%, #dbeafe 100%);\n border: 1px solid #bfdbfe;\n border-radius: 10px;\n font-size: 13px;\n color: #1e40af;\n margin-bottom: 16px;\n line-height: 1.4;\n}\n\n.scopes-intro[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: #3b82f6;\n font-size: 14px;\n flex-shrink: 0;\n margin-top: 1px;\n}\n\n.scope-categories-list[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n.scope-category-card[_ngcontent-%COMP%] {\n background: #fff;\n border: 1px solid #e5e7eb;\n border-radius: 10px;\n overflow: hidden;\n}\n\n.scope-category-card[_ngcontent-%COMP%] .category-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 16px;\n cursor: pointer;\n transition: background 0.2s ease;\n}\n\n.scope-category-card[_ngcontent-%COMP%] .category-header[_ngcontent-%COMP%]:hover {\n background: #f9fafb;\n}\n\n.scope-category-card[_ngcontent-%COMP%] .category-left[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n}\n\n.scope-category-card[_ngcontent-%COMP%] .category-left[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n}\n\n.scope-category-card[_ngcontent-%COMP%] .category-name[_ngcontent-%COMP%] {\n font-size: 13px;\n font-weight: 600;\n color: #1f2937;\n}\n\n.category-count-badge[_ngcontent-%COMP%] {\n font-size: 11px;\n color: #6b7280;\n background: #f3f4f6;\n padding: 2px 8px;\n border-radius: 10px;\n}\n\n.scope-category-card[_ngcontent-%COMP%] .category-right[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 14px;\n}\n\n.category-all-toggle[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 12px;\n color: #6b7280;\n cursor: pointer;\n}\n\n.category-chevron[_ngcontent-%COMP%] {\n color: #9ca3af;\n font-size: 11px;\n}\n\n.category-scopes-list[_ngcontent-%COMP%] {\n border-top: 1px solid #e5e7eb;\n padding: 8px;\n max-height: 280px;\n overflow-y: auto;\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.scope-row[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 10px 12px;\n border-radius: 8px;\n background: #f9fafb;\n transition: all 0.2s ease;\n}\n\n.scope-row[_ngcontent-%COMP%]:hover {\n background: #f3f4f6;\n}\n\n.scope-row.selected[_ngcontent-%COMP%] {\n background: #ede9fe;\n border: 1px solid #c4b5fd;\n}\n\n.scope-select[_ngcontent-%COMP%] {\n display: flex;\n align-items: flex-start;\n gap: 10px;\n flex: 1;\n min-width: 0;\n cursor: pointer;\n}\n\n.scope-select[_ngcontent-%COMP%] input[_ngcontent-%COMP%] {\n margin-top: 2px;\n flex-shrink: 0;\n}\n\n.scope-label[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n.scope-path[_ngcontent-%COMP%] {\n font-size: 12px;\n font-weight: 500;\n color: #1f2937;\n font-family: 'SF Mono', 'Consolas', monospace;\n word-break: break-word;\n}\n\n.scope-description[_ngcontent-%COMP%] {\n display: block;\n font-size: 11px;\n color: #6b7280;\n margin-top: 2px;\n line-height: 1.3;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n\n\n.scope-pattern-display[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n margin-left: auto;\n flex-shrink: 0;\n font-size: 11px;\n color: #6b7280;\n}\n\n.pattern-tag[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 3px 8px;\n background: #f3f4f6;\n border-radius: 4px;\n font-family: 'SF Mono', 'Consolas', monospace;\n font-size: 11px;\n color: #374151;\n}\n\n.pattern-tag.include[_ngcontent-%COMP%] {\n background: #d1fae5;\n color: #065f46;\n}\n\n.pattern-tag.exclude[_ngcontent-%COMP%] {\n background: #fee2e2;\n color: #991b1b;\n}\n\n.pattern-tag[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 10px;\n}\n\n\n\n.scope-pattern-config[_ngcontent-%COMP%] {\n display: none;\n gap: 6px;\n margin-left: auto;\n flex-shrink: 0;\n}\n\n.scope-row[_ngcontent-%COMP%]:hover .scope-pattern-config[_ngcontent-%COMP%], \n.scope-row.editing[_ngcontent-%COMP%] .scope-pattern-config[_ngcontent-%COMP%] {\n display: flex;\n}\n\n.scope-row[_ngcontent-%COMP%]:hover .scope-pattern-display[_ngcontent-%COMP%], \n.scope-row.editing[_ngcontent-%COMP%] .scope-pattern-display[_ngcontent-%COMP%] {\n display: none;\n}\n\n.pattern-field[_ngcontent-%COMP%] {\n width: 60px;\n}\n\n[_nghost-%COMP%] .pattern-field .k-input {\n padding: 3px 6px;\n font-size: 11px;\n border-radius: 4px;\n height: 26px;\n}\n\n.type-field[_ngcontent-%COMP%] {\n width: 75px;\n}\n\n[_nghost-%COMP%] .type-field .k-dropdownlist {\n font-size: 11px;\n height: 26px;\n}\n\n[_nghost-%COMP%] .type-field .k-input-inner {\n padding: 2px 6px;\n font-size: 11px;\n}\n\n.empty-scopes-message[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n padding: 32px;\n color: #9ca3af;\n text-align: center;\n}\n\n.empty-scopes-message[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 32px;\n margin-bottom: 12px;\n opacity: 0.5;\n}\n\n\n"] });
|
|
1045
|
+
}
|
|
1046
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(APIApplicationsPanelComponent, [{
|
|
1047
|
+
type: Component,
|
|
1048
|
+
args: [{ selector: 'mj-api-applications-panel', template: "<div class=\"applications-panel\" [class.panel-open]=\"ShowEditPanel || ShowCreatePanel\">\n <mj-loading *ngIf=\"IsLoading\" text=\"Loading applications...\"></mj-loading>\n\n <ng-container *ngIf=\"!IsLoading\">\n <!-- Header -->\n <div class=\"panel-header\">\n <div class=\"header-left\">\n <h3 class=\"panel-title\">\n <i class=\"fa-solid fa-cube\"></i>\n API Applications\n </h3>\n <p class=\"panel-subtitle\">Manage applications and their default scope permissions</p>\n </div>\n <button class=\"btn-create\" (click)=\"openCreatePanel()\">\n <i class=\"fa-solid fa-plus\"></i>\n New Application\n </button>\n </div>\n\n <!-- Messages -->\n <div class=\"message success\" *ngIf=\"SuccessMessage\">\n <i class=\"fa-solid fa-check-circle\"></i>\n {{SuccessMessage}}\n </div>\n <div class=\"message error\" *ngIf=\"ErrorMessage\">\n <i class=\"fa-solid fa-circle-exclamation\"></i>\n {{ErrorMessage}}\n </div>\n\n <!-- Applications Grid -->\n <div class=\"applications-grid\">\n <div class=\"app-card\" *ngFor=\"let appItem of Applications\"\n [class.inactive]=\"!appItem.application.IsActive\"\n [class.expanded]=\"appItem.expanded\">\n <div class=\"app-header\">\n <div class=\"app-header-main\" (click)=\"toggleExpanded(appItem)\">\n <div class=\"app-icon\">\n <i class=\"fa-solid fa-cube\"></i>\n </div>\n <div class=\"app-info\">\n <div class=\"app-name\">\n {{appItem.application.Name}}\n <span class=\"status-badge\" [class.active]=\"appItem.application.IsActive\"\n [class.inactive]=\"!appItem.application.IsActive\">\n {{appItem.application.IsActive ? 'Active' : 'Inactive'}}\n </span>\n </div>\n <div class=\"app-description\" *ngIf=\"appItem.application.Description\">\n {{appItem.application.Description}}\n </div>\n </div>\n <div class=\"app-stats\">\n <div class=\"scope-count\">\n <i class=\"fa-solid fa-shield-halved\"></i>\n {{appItem.scopeCount}} scopes\n </div>\n <i class=\"fa-solid expand-icon\"\n [class.fa-chevron-down]=\"!appItem.expanded\"\n [class.fa-chevron-up]=\"appItem.expanded\"></i>\n </div>\n </div>\n <button class=\"app-edit-btn\" (click)=\"openEditPanel(appItem); $event.stopPropagation()\" title=\"Edit Application\">\n <i class=\"fa-solid fa-pencil\"></i>\n </button>\n </div>\n\n <!-- Expanded Content -->\n <div class=\"app-details\" *ngIf=\"appItem.expanded\">\n <div class=\"details-section\">\n <h4>Scope Ceiling Rules</h4>\n <div class=\"scope-rules\" *ngIf=\"appItem.scopes.length > 0\">\n <div class=\"scope-rule\" *ngFor=\"let scope of appItem.scopes\">\n <div class=\"rule-icon\" [ngClass]=\"getPatternClass(scope.PatternType, scope.IsDeny)\">\n <i [class]=\"getPatternIcon(scope.PatternType, scope.IsDeny)\"></i>\n </div>\n <div class=\"rule-info\">\n <div class=\"rule-scope\">{{getScopeName(scope.ScopeID)}}</div>\n <div class=\"rule-pattern\">\n <code>{{scope.ResourcePattern}}</code>\n <span class=\"pattern-type\">{{scope.PatternType}}</span>\n <span class=\"priority\" *ngIf=\"scope.Priority > 0\">\n Priority: {{scope.Priority}}\n </span>\n </div>\n </div>\n </div>\n </div>\n <div class=\"empty-scopes\" *ngIf=\"appItem.scopes.length === 0\">\n <i class=\"fa-solid fa-shield-xmark\"></i>\n <span>No scope rules defined - all access denied by default</span>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Empty State -->\n <div class=\"empty-state\" *ngIf=\"Applications.length === 0\">\n <i class=\"fa-solid fa-cube\"></i>\n <span>No applications configured</span>\n <p>Create an application to define scope ceilings for API key access</p>\n </div>\n </div>\n </ng-container>\n\n <!-- Slide-out Backdrop -->\n <div class=\"slideout-backdrop\" *ngIf=\"ShowEditPanel || ShowCreatePanel\" (click)=\"closePanel()\"></div>\n\n <!-- Create Panel (Slide-out) -->\n <div class=\"slideout-panel\" [class.open]=\"ShowCreatePanel\">\n <div class=\"slideout-header\">\n <div class=\"slideout-title\">\n <i class=\"fa-solid fa-plus-circle\"></i>\n <span>New Application</span>\n </div>\n <button class=\"slideout-close\" (click)=\"closePanel()\" title=\"Close\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n\n <div class=\"slideout-content\">\n <div class=\"form-section\">\n <div class=\"form-field\">\n <label>Application Name *</label>\n <input kendoTextBox [(ngModel)]=\"EditName\"\n placeholder=\"e.g., MJAPI, MCP Server, Portal\"\n class=\"form-input\" />\n </div>\n\n <div class=\"form-field\">\n <label>Description</label>\n <textarea kendoTextArea [(ngModel)]=\"EditDescription\"\n placeholder=\"Describe the application's purpose...\"\n [rows]=\"3\"\n class=\"form-textarea\"></textarea>\n </div>\n\n <div class=\"form-field\">\n <label class=\"checkbox-label\">\n <input type=\"checkbox\" kendoCheckBox [(ngModel)]=\"EditIsActive\" />\n <div>\n <span>Active</span>\n <span class=\"checkbox-hint\">Inactive applications cannot be used with API keys</span>\n </div>\n </label>\n </div>\n </div>\n </div>\n\n <div class=\"slideout-footer\">\n <button kendoButton [themeColor]=\"'primary'\"\n [disabled]=\"!EditName.trim() || IsSaving\"\n (click)=\"saveApplication()\">\n <mj-loading *ngIf=\"IsSaving\" [showText]=\"false\" size=\"small\"></mj-loading>\n <span *ngIf=\"!IsSaving\">\n <i class=\"fa-solid fa-save\"></i>\n Create Application\n </span>\n </button>\n <button kendoButton (click)=\"closePanel()\">Cancel</button>\n </div>\n </div>\n\n <!-- Edit Panel (Slide-out) -->\n <div class=\"slideout-panel\" [class.open]=\"ShowEditPanel\" [style.width.px]=\"PanelWidth\">\n <!-- Resize Handle -->\n <div class=\"slideout-resize-handle\"\n [class.resizing]=\"IsResizing\"\n (mousedown)=\"startResize($event)\"></div>\n <div class=\"slideout-header\">\n <div class=\"slideout-title\">\n <i class=\"fa-solid fa-cube\"></i>\n <span>{{EditingApplication?.Name}}</span>\n <span class=\"status-pill\" [class.active]=\"EditIsActive\">\n {{EditIsActive ? 'Active' : 'Inactive'}}\n </span>\n </div>\n <button class=\"slideout-close\" (click)=\"closePanel()\" title=\"Close\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n\n <!-- Tab Bar -->\n <div class=\"slideout-tabs\">\n <button class=\"slideout-tab\" [class.active]=\"EditTab === 'details'\"\n (click)=\"EditTab = 'details'\">\n <i class=\"fa-solid fa-info-circle\"></i>\n Details\n </button>\n <button class=\"slideout-tab\" [class.active]=\"EditTab === 'scopes'\"\n (click)=\"EditTab = 'scopes'\">\n <i class=\"fa-solid fa-shield-halved\"></i>\n Scopes\n <span class=\"tab-badge\">{{getSelectedScopeCount()}}</span>\n </button>\n </div>\n\n <div class=\"slideout-content\">\n <!-- Details Tab -->\n <div class=\"tab-panel\" *ngIf=\"EditTab === 'details'\">\n <div class=\"form-section\">\n <div class=\"form-field\">\n <label>Application Name *</label>\n <input kendoTextBox [(ngModel)]=\"EditName\"\n placeholder=\"e.g., MJAPI, MCP Server, Portal\"\n class=\"form-input\" />\n </div>\n\n <div class=\"form-field\">\n <label>Description</label>\n <textarea kendoTextArea [(ngModel)]=\"EditDescription\"\n placeholder=\"Describe the application's purpose...\"\n [rows]=\"4\"\n class=\"form-textarea\"></textarea>\n </div>\n\n <div class=\"form-field\">\n <label class=\"checkbox-label\">\n <input type=\"checkbox\" kendoCheckBox [(ngModel)]=\"EditIsActive\" />\n <div>\n <span>Active</span>\n <span class=\"checkbox-hint\">Inactive applications cannot be used with API keys</span>\n </div>\n </label>\n </div>\n </div>\n </div>\n\n <!-- Scopes Tab -->\n <div class=\"tab-panel scopes-panel\" *ngIf=\"EditTab === 'scopes'\">\n <div class=\"scopes-intro\">\n <i class=\"fa-solid fa-info-circle\"></i>\n <span>Define the maximum permissions this application can grant to API keys.</span>\n </div>\n\n <div class=\"scope-categories-list\">\n <div class=\"scope-category-card\" *ngFor=\"let category of ScopeCategories\">\n <div class=\"category-header\" (click)=\"toggleScopeCategory(category)\">\n <div class=\"category-left\">\n <i [class]=\"category.icon\" [style.color]=\"category.color\"></i>\n <span class=\"category-name\">{{category.name}}</span>\n <span class=\"category-count-badge\">\n {{getCategorySelectedCount(category)}}/{{category.scopes.length}}\n </span>\n </div>\n <div class=\"category-right\">\n <label class=\"category-all-toggle\" (click)=\"$event.stopPropagation()\">\n <input type=\"checkbox\" kendoCheckBox\n [checked]=\"category.allSelected\"\n (change)=\"toggleCategoryAll(category)\" />\n <span>All</span>\n </label>\n <i class=\"fa-solid category-chevron\"\n [class.fa-chevron-down]=\"!category.expanded\"\n [class.fa-chevron-up]=\"category.expanded\"></i>\n </div>\n </div>\n\n <div class=\"category-scopes-list\" *ngIf=\"category.expanded\">\n <div class=\"scope-row\" *ngFor=\"let selection of category.scopes\"\n [class.selected]=\"selection.selected\">\n <label class=\"scope-select\">\n <input type=\"checkbox\" kendoCheckBox\n [(ngModel)]=\"selection.selected\"\n (change)=\"updateCategoryState(category)\" />\n <div class=\"scope-label\">\n <span class=\"scope-path\">{{selection.displayName || '(unnamed scope)'}}</span>\n <span class=\"scope-description\" *ngIf=\"selection.scope.Description\">\n {{selection.scope.Description}}\n </span>\n </div>\n </label>\n\n <!-- Read-only pattern display -->\n <div class=\"scope-pattern-display\" *ngIf=\"selection.selected\">\n <span class=\"pattern-tag\" [class.include]=\"selection.patternType === 'Include'\"\n [class.exclude]=\"selection.patternType === 'Exclude'\">\n <i class=\"fa-solid\" [class.fa-check]=\"selection.patternType === 'Include'\"\n [class.fa-minus]=\"selection.patternType === 'Exclude'\"></i>\n {{selection.pattern || '*'}}\n </span>\n </div>\n <!-- Editable pattern config - shown on hover -->\n <div class=\"scope-pattern-config\" *ngIf=\"selection.selected\">\n <input kendoTextBox [(ngModel)]=\"selection.pattern\"\n placeholder=\"*\"\n class=\"pattern-field\"\n title=\"Resource Pattern\" />\n <kendo-dropdownlist [(ngModel)]=\"selection.patternType\"\n [data]=\"['Include', 'Exclude']\"\n [valuePrimitive]=\"true\"\n class=\"type-field\"\n title=\"Pattern Type\">\n </kendo-dropdownlist>\n </div>\n </div>\n </div>\n </div>\n\n <div class=\"empty-scopes-message\" *ngIf=\"ScopeCategories.length === 0\">\n <i class=\"fa-solid fa-shield-xmark\"></i>\n <span>No scopes available</span>\n </div>\n </div>\n </div>\n </div>\n\n <div class=\"slideout-footer\">\n <button kendoButton [themeColor]=\"'primary'\"\n [disabled]=\"!EditName.trim() || IsSaving\"\n (click)=\"saveAll()\">\n <mj-loading *ngIf=\"IsSaving\" [showText]=\"false\" size=\"small\"></mj-loading>\n <span *ngIf=\"!IsSaving\">\n <i class=\"fa-solid fa-save\"></i>\n Save Changes\n </span>\n </button>\n <button kendoButton (click)=\"closePanel()\">Cancel</button>\n </div>\n </div>\n</div>\n", styles: [".applications-panel {\n height: 100%;\n display: flex;\n flex-direction: column;\n position: relative;\n}\n\n.applications-panel.panel-open {\n overflow: hidden;\n}\n\n/* Panel Header */\n.panel-header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 24px;\n}\n\n.header-left {\n flex: 1;\n}\n\n.panel-title {\n display: flex;\n align-items: center;\n gap: 10px;\n font-size: 18px;\n font-weight: 600;\n color: var(--text-primary, #1f2937);\n margin: 0 0 4px 0;\n}\n\n.panel-title i {\n color: #8b5cf6;\n}\n\n.panel-subtitle {\n font-size: 14px;\n color: var(--text-secondary, #6b7280);\n margin: 0;\n}\n\n.btn-create {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 20px;\n background: linear-gradient(135deg, #8b5cf6 0%, #7c3aed 100%);\n color: white;\n border: none;\n border-radius: 8px;\n font-weight: 600;\n font-size: 14px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.btn-create:hover {\n transform: translateY(-1px);\n box-shadow: 0 4px 12px rgba(139, 92, 246, 0.4);\n}\n\n/* Messages */\n.message {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 12px 16px;\n border-radius: 8px;\n margin-bottom: 16px;\n font-size: 14px;\n}\n\n.message.success {\n background: #d1fae5;\n color: #065f46;\n border: 1px solid #a7f3d0;\n}\n\n.message.error {\n background: #fee2e2;\n color: #991b1b;\n border: 1px solid #fca5a5;\n}\n\n/* Applications Grid */\n.applications-grid {\n display: flex;\n flex-direction: column;\n gap: 16px;\n flex: 1;\n overflow-y: auto;\n}\n\n.app-card {\n background: var(--card-background, #ffffff);\n border-radius: 12px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);\n overflow: hidden;\n transition: box-shadow 0.2s ease;\n}\n\n.app-card:hover {\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);\n}\n\n.app-card.inactive {\n opacity: 0.7;\n}\n\n.app-header {\n display: flex;\n align-items: center;\n padding: 16px 20px;\n gap: 12px;\n}\n\n.app-header-main {\n display: flex;\n align-items: center;\n flex: 1;\n cursor: pointer;\n transition: background 0.2s ease;\n border-radius: 8px;\n padding: 4px;\n margin: -4px;\n}\n\n.app-header-main:hover {\n background: var(--item-hover, #f9fafb);\n}\n\n.app-edit-btn {\n width: 36px;\n height: 36px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: transparent;\n border: 1px solid var(--border-color, #e5e7eb);\n border-radius: 8px;\n color: var(--text-secondary, #6b7280);\n cursor: pointer;\n transition: all 0.2s ease;\n flex-shrink: 0;\n}\n\n.app-edit-btn:hover {\n background: #8b5cf6;\n border-color: #8b5cf6;\n color: white;\n}\n\n.app-icon {\n width: 48px;\n height: 48px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: linear-gradient(135deg, #8b5cf6 0%, #7c3aed 100%);\n border-radius: 10px;\n margin-right: 16px;\n flex-shrink: 0;\n}\n\n.app-icon i {\n font-size: 20px;\n color: white;\n}\n\n.app-info {\n flex: 1;\n min-width: 0;\n}\n\n.app-name {\n display: flex;\n align-items: center;\n gap: 10px;\n font-size: 16px;\n font-weight: 600;\n color: var(--text-primary, #1f2937);\n}\n\n.status-badge {\n font-size: 11px;\n font-weight: 500;\n padding: 2px 8px;\n border-radius: 10px;\n}\n\n.status-badge.active {\n background: #d1fae5;\n color: #065f46;\n}\n\n.status-badge.inactive {\n background: #f3f4f6;\n color: #6b7280;\n}\n\n.app-description {\n font-size: 13px;\n color: var(--text-secondary, #6b7280);\n margin-top: 4px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.app-stats {\n display: flex;\n align-items: center;\n gap: 16px;\n margin-left: 16px;\n}\n\n.scope-count {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 13px;\n color: var(--text-secondary, #6b7280);\n}\n\n.scope-count i {\n color: #8b5cf6;\n}\n\n.expand-icon {\n color: var(--text-tertiary, #9ca3af);\n transition: transform 0.2s ease;\n}\n\n/* Expanded Details */\n.app-details {\n padding: 0 20px 20px 20px;\n border-top: 1px solid var(--border-color, #e5e7eb);\n margin-top: 0;\n}\n\n.details-section {\n margin-top: 16px;\n}\n\n.details-section h4 {\n font-size: 14px;\n font-weight: 600;\n color: var(--text-primary, #1f2937);\n margin: 0 0 12px 0;\n}\n\n.scope-rules {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.scope-rule {\n display: flex;\n align-items: flex-start;\n padding: 10px 12px;\n background: var(--item-background, #f9fafb);\n border-radius: 8px;\n}\n\n.rule-icon {\n width: 28px;\n height: 28px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 6px;\n margin-right: 12px;\n flex-shrink: 0;\n}\n\n.rule-icon.pattern-include {\n background: #d1fae5;\n color: #059669;\n}\n\n.rule-icon.pattern-exclude {\n background: #fef3c7;\n color: #d97706;\n}\n\n.rule-icon.pattern-deny {\n background: #fee2e2;\n color: #dc2626;\n}\n\n.rule-info {\n flex: 1;\n min-width: 0;\n}\n\n.rule-scope {\n font-size: 13px;\n font-weight: 500;\n color: var(--text-primary, #1f2937);\n}\n\n.rule-pattern {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-top: 4px;\n flex-wrap: wrap;\n}\n\n.rule-pattern code {\n font-family: monospace;\n font-size: 12px;\n background: var(--tag-background, #e5e7eb);\n padding: 2px 6px;\n border-radius: 4px;\n color: var(--text-primary, #1f2937);\n}\n\n.pattern-type {\n font-size: 11px;\n color: var(--text-secondary, #6b7280);\n}\n\n.priority {\n font-size: 11px;\n color: #8b5cf6;\n}\n\n.empty-scopes {\n display: flex;\n flex-direction: column;\n align-items: center;\n padding: 24px;\n color: var(--text-secondary, #6b7280);\n text-align: center;\n background: var(--item-background, #f9fafb);\n border-radius: 8px;\n}\n\n.empty-scopes i {\n font-size: 24px;\n margin-bottom: 8px;\n opacity: 0.5;\n}\n\n/* Legacy .details-actions removed - buttons now in header */\n\n/* Empty State */\n.empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 48px;\n color: var(--text-secondary, #6b7280);\n text-align: center;\n}\n\n.empty-state i {\n font-size: 48px;\n margin-bottom: 16px;\n opacity: 0.5;\n}\n\n.empty-state span {\n font-size: 16px;\n font-weight: 500;\n}\n\n.empty-state p {\n font-size: 14px;\n margin-top: 8px;\n}\n\n/* ========================================\n Slide-out Panel Styles\n ======================================== */\n\n/* Backdrop */\n.slideout-backdrop {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.3);\n z-index: 100;\n animation: fadeIn 0.2s ease;\n}\n\n@keyframes fadeIn {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n\n/* Slide-out Panel */\n.slideout-panel {\n position: absolute;\n top: 0;\n right: 0;\n width: 570px;\n height: 100%;\n max-height: 100%;\n background: var(--card-background, #ffffff);\n box-shadow: -8px 0 32px rgba(0, 0, 0, 0.15);\n z-index: 101;\n display: flex;\n flex-direction: column;\n transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n overflow: hidden;\n transform: translateX(100%);\n}\n\n.slideout-panel.open {\n transform: translateX(0);\n}\n\n/* Resize handle */\n.slideout-resize-handle {\n position: absolute;\n top: 0;\n left: 0;\n width: 6px;\n height: 100%;\n cursor: ew-resize;\n background: transparent;\n z-index: 10;\n transition: background 0.2s ease;\n}\n\n.slideout-resize-handle:hover,\n.slideout-resize-handle.resizing {\n background: rgba(139, 92, 246, 0.3);\n}\n\n.slideout-resize-handle::after {\n content: '';\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 2px;\n height: 40px;\n background: #d1d5db;\n border-radius: 2px;\n opacity: 0;\n transition: opacity 0.2s ease;\n}\n\n.slideout-resize-handle:hover::after {\n opacity: 1;\n}\n\n/* Panel Header */\n.slideout-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 20px 24px;\n background: linear-gradient(135deg, #fafafa 0%, #f3f4f6 100%);\n border-bottom: 1px solid #e5e7eb;\n flex-shrink: 0;\n}\n\n.slideout-title {\n display: flex;\n align-items: center;\n gap: 12px;\n font-weight: 600;\n font-size: 17px;\n color: #1f2937;\n flex: 1;\n min-width: 0;\n}\n\n.slideout-title i {\n color: #8b5cf6;\n font-size: 18px;\n flex-shrink: 0;\n}\n\n.slideout-title span:first-of-type {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.status-pill {\n font-size: 11px;\n font-weight: 500;\n padding: 3px 10px;\n border-radius: 12px;\n background: #f3f4f6;\n color: #6b7280;\n flex-shrink: 0;\n}\n\n.status-pill.active {\n background: #d1fae5;\n color: #065f46;\n}\n\n.slideout-close {\n width: 36px;\n height: 36px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: transparent;\n border: none;\n border-radius: 8px;\n color: #9ca3af;\n cursor: pointer;\n transition: all 0.2s ease;\n flex-shrink: 0;\n}\n\n.slideout-close:hover {\n background: rgba(0, 0, 0, 0.05);\n color: #374151;\n}\n\n/* Panel Tabs */\n.slideout-tabs {\n display: flex;\n gap: 4px;\n padding: 12px 24px;\n background: #f9fafb;\n border-bottom: 1px solid #e5e7eb;\n flex-shrink: 0;\n}\n\n.slideout-tab {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 18px;\n background: transparent;\n border: none;\n border-radius: 8px;\n font-size: 14px;\n font-weight: 500;\n color: #6b7280;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.slideout-tab:hover {\n background: #e5e7eb;\n color: #374151;\n}\n\n.slideout-tab.active {\n background: #8b5cf6;\n color: white;\n}\n\n.slideout-tab i {\n font-size: 14px;\n}\n\n.tab-badge {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 20px;\n height: 20px;\n padding: 0 6px;\n background: rgba(255, 255, 255, 0.2);\n border-radius: 10px;\n font-size: 11px;\n font-weight: 600;\n}\n\n.slideout-tab:not(.active) .tab-badge {\n background: #e5e7eb;\n color: #374151;\n}\n\n/* Panel Content */\n.slideout-content {\n flex: 1;\n overflow-y: auto;\n padding: 24px;\n}\n\n.tab-panel {\n height: 100%;\n display: flex;\n flex-direction: column;\n}\n\n.scopes-panel {\n height: 100%;\n}\n\n/* Form Section */\n.form-section {\n display: flex;\n flex-direction: column;\n gap: 20px;\n}\n\n/* Form Fields */\n.form-field {\n margin-bottom: 20px;\n}\n\n.form-field:last-of-type {\n margin-bottom: 0;\n}\n\n.form-field label {\n display: block;\n font-size: 13px;\n font-weight: 600;\n color: #374151;\n margin-bottom: 8px;\n letter-spacing: 0.01em;\n}\n\n.form-input {\n width: 100%;\n}\n\n.form-textarea {\n width: 100%;\n resize: vertical;\n min-height: 80px;\n}\n\n:host ::ng-deep .form-input .k-input,\n:host ::ng-deep .form-textarea .k-input-inner {\n padding: 10px 14px;\n border-radius: 8px;\n font-size: 14px;\n border-color: #e5e7eb;\n transition: all 0.2s ease;\n}\n\n:host ::ng-deep .form-input:focus-within,\n:host ::ng-deep .form-textarea:focus-within {\n box-shadow: 0 0 0 3px rgba(139, 92, 246, 0.1);\n}\n\n/* Slideout Footer */\n.slideout-footer {\n display: flex;\n gap: 12px;\n padding: 16px 24px;\n background: #f9fafb;\n border-top: 1px solid #e5e7eb;\n flex-shrink: 0;\n}\n\n:host ::ng-deep .slideout-footer .k-button {\n min-width: 100px;\n padding: 10px 20px;\n font-weight: 600;\n border-radius: 8px;\n transition: all 0.2s ease;\n}\n\n:host ::ng-deep .slideout-footer .k-button-solid-primary {\n background: linear-gradient(135deg, #8b5cf6 0%, #7c3aed 100%);\n border: none;\n box-shadow: 0 2px 8px rgba(139, 92, 246, 0.3);\n}\n\n:host ::ng-deep .slideout-footer .k-button-solid-primary:hover {\n transform: translateY(-1px);\n box-shadow: 0 4px 12px rgba(139, 92, 246, 0.4);\n}\n\n.checkbox-label {\n display: flex;\n align-items: flex-start;\n gap: 12px;\n cursor: pointer;\n padding: 12px 16px;\n background: #f9fafb;\n border-radius: 10px;\n border: 1px solid #e5e7eb;\n transition: all 0.2s ease;\n}\n\n.checkbox-label:hover {\n background: #f3f4f6;\n border-color: #d1d5db;\n}\n\n.checkbox-label input {\n margin-top: 2px;\n flex-shrink: 0;\n}\n\n.checkbox-label span:first-of-type {\n font-weight: 600;\n color: #374151;\n font-size: 14px;\n}\n\n.checkbox-hint {\n display: block;\n font-size: 12px;\n color: #6b7280;\n margin-top: 4px;\n line-height: 1.4;\n}\n\n/* Legacy dialog-actions removed - now using slideout-footer */\n\n/* ========================================\n Scopes Panel - Slide-out Layout\n ======================================== */\n\n.scopes-intro {\n display: flex;\n align-items: flex-start;\n gap: 12px;\n padding: 12px 16px;\n background: linear-gradient(135deg, #eff6ff 0%, #dbeafe 100%);\n border: 1px solid #bfdbfe;\n border-radius: 10px;\n font-size: 13px;\n color: #1e40af;\n margin-bottom: 16px;\n line-height: 1.4;\n}\n\n.scopes-intro i {\n color: #3b82f6;\n font-size: 14px;\n flex-shrink: 0;\n margin-top: 1px;\n}\n\n.scope-categories-list {\n flex: 1;\n overflow-y: auto;\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n.scope-category-card {\n background: #fff;\n border: 1px solid #e5e7eb;\n border-radius: 10px;\n overflow: hidden;\n}\n\n.scope-category-card .category-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 16px;\n cursor: pointer;\n transition: background 0.2s ease;\n}\n\n.scope-category-card .category-header:hover {\n background: #f9fafb;\n}\n\n.scope-category-card .category-left {\n display: flex;\n align-items: center;\n gap: 10px;\n}\n\n.scope-category-card .category-left i {\n font-size: 14px;\n}\n\n.scope-category-card .category-name {\n font-size: 13px;\n font-weight: 600;\n color: #1f2937;\n}\n\n.category-count-badge {\n font-size: 11px;\n color: #6b7280;\n background: #f3f4f6;\n padding: 2px 8px;\n border-radius: 10px;\n}\n\n.scope-category-card .category-right {\n display: flex;\n align-items: center;\n gap: 14px;\n}\n\n.category-all-toggle {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 12px;\n color: #6b7280;\n cursor: pointer;\n}\n\n.category-chevron {\n color: #9ca3af;\n font-size: 11px;\n}\n\n.category-scopes-list {\n border-top: 1px solid #e5e7eb;\n padding: 8px;\n max-height: 280px;\n overflow-y: auto;\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.scope-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 10px 12px;\n border-radius: 8px;\n background: #f9fafb;\n transition: all 0.2s ease;\n}\n\n.scope-row:hover {\n background: #f3f4f6;\n}\n\n.scope-row.selected {\n background: #ede9fe;\n border: 1px solid #c4b5fd;\n}\n\n.scope-select {\n display: flex;\n align-items: flex-start;\n gap: 10px;\n flex: 1;\n min-width: 0;\n cursor: pointer;\n}\n\n.scope-select input {\n margin-top: 2px;\n flex-shrink: 0;\n}\n\n.scope-label {\n flex: 1;\n min-width: 0;\n}\n\n.scope-path {\n font-size: 12px;\n font-weight: 500;\n color: #1f2937;\n font-family: 'SF Mono', 'Consolas', monospace;\n word-break: break-word;\n}\n\n.scope-description {\n display: block;\n font-size: 11px;\n color: #6b7280;\n margin-top: 2px;\n line-height: 1.3;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n/* Pattern config for selected scopes - read-only display */\n.scope-pattern-display {\n display: flex;\n align-items: center;\n gap: 6px;\n margin-left: auto;\n flex-shrink: 0;\n font-size: 11px;\n color: #6b7280;\n}\n\n.pattern-tag {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 3px 8px;\n background: #f3f4f6;\n border-radius: 4px;\n font-family: 'SF Mono', 'Consolas', monospace;\n font-size: 11px;\n color: #374151;\n}\n\n.pattern-tag.include {\n background: #d1fae5;\n color: #065f46;\n}\n\n.pattern-tag.exclude {\n background: #fee2e2;\n color: #991b1b;\n}\n\n.pattern-tag i {\n font-size: 10px;\n}\n\n/* Editable pattern config - shown on hover/edit */\n.scope-pattern-config {\n display: none;\n gap: 6px;\n margin-left: auto;\n flex-shrink: 0;\n}\n\n.scope-row:hover .scope-pattern-config,\n.scope-row.editing .scope-pattern-config {\n display: flex;\n}\n\n.scope-row:hover .scope-pattern-display,\n.scope-row.editing .scope-pattern-display {\n display: none;\n}\n\n.pattern-field {\n width: 60px;\n}\n\n:host ::ng-deep .pattern-field .k-input {\n padding: 3px 6px;\n font-size: 11px;\n border-radius: 4px;\n height: 26px;\n}\n\n.type-field {\n width: 75px;\n}\n\n:host ::ng-deep .type-field .k-dropdownlist {\n font-size: 11px;\n height: 26px;\n}\n\n:host ::ng-deep .type-field .k-input-inner {\n padding: 2px 6px;\n font-size: 11px;\n}\n\n.empty-scopes-message {\n display: flex;\n flex-direction: column;\n align-items: center;\n padding: 32px;\n color: #9ca3af;\n text-align: center;\n}\n\n.empty-scopes-message i {\n font-size: 32px;\n margin-bottom: 12px;\n opacity: 0.5;\n}\n\n/* Legacy dialog styles removed - now using slide-out panels */\n"] }]
|
|
1049
|
+
}], () => [{ type: i0.ChangeDetectorRef }], { ApplicationUpdated: [{
|
|
1050
|
+
type: Output
|
|
1051
|
+
}], onMouseMove: [{
|
|
1052
|
+
type: HostListener,
|
|
1053
|
+
args: ['document:mousemove', ['$event']]
|
|
1054
|
+
}], onMouseUp: [{
|
|
1055
|
+
type: HostListener,
|
|
1056
|
+
args: ['document:mouseup']
|
|
1057
|
+
}] }); })();
|
|
1058
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(APIApplicationsPanelComponent, { className: "APIApplicationsPanelComponent", filePath: "src/APIKeys/api-applications-panel.component.ts", lineNumber: 53 }); })();
|
|
1059
|
+
//# sourceMappingURL=api-applications-panel.component.js.map
|