@memberjunction/ng-dashboards 5.22.0 → 5.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +51 -0
- package/dist/AI/components/agents/agent-configuration.component.d.ts.map +1 -1
- package/dist/AI/components/agents/agent-configuration.component.js +364 -362
- package/dist/AI/components/agents/agent-configuration.component.js.map +1 -1
- package/dist/AI/components/agents/agent-editor.component.js +2 -2
- package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.d.ts +275 -64
- package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.d.ts.map +1 -1
- package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.js +2645 -436
- package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.js.map +1 -1
- package/dist/AI/components/duplicates/duplicate-detection-resource.component.d.ts +240 -6
- package/dist/AI/components/duplicates/duplicate-detection-resource.component.d.ts.map +1 -1
- package/dist/AI/components/duplicates/duplicate-detection-resource.component.js +2166 -256
- package/dist/AI/components/duplicates/duplicate-detection-resource.component.js.map +1 -1
- package/dist/AI/components/execution-monitoring.component.d.ts.map +1 -1
- package/dist/AI/components/execution-monitoring.component.js +191 -197
- package/dist/AI/components/execution-monitoring.component.js.map +1 -1
- package/dist/AI/components/models/model-management.component.js +9 -8
- package/dist/AI/components/models/model-management.component.js.map +1 -1
- package/dist/AI/components/prompts/prompt-management.component.js +305 -299
- package/dist/AI/components/prompts/prompt-management.component.js.map +1 -1
- package/dist/AI/components/system/system-configuration.component.js +319 -313
- package/dist/AI/components/system/system-configuration.component.js.map +1 -1
- package/dist/AI/components/vectors/vector-management-resource.component.d.ts +1 -2
- package/dist/AI/components/vectors/vector-management-resource.component.d.ts.map +1 -1
- package/dist/AI/components/vectors/vector-management-resource.component.js +12 -27
- package/dist/AI/components/vectors/vector-management-resource.component.js.map +1 -1
- package/dist/APIKeys/api-applications-panel.component.js +10 -12
- package/dist/APIKeys/api-applications-panel.component.js.map +1 -1
- package/dist/APIKeys/api-key-create-dialog.component.js +13 -19
- package/dist/APIKeys/api-key-create-dialog.component.js.map +1 -1
- package/dist/APIKeys/api-key-edit-panel.component.js +12 -14
- package/dist/APIKeys/api-key-edit-panel.component.js.map +1 -1
- package/dist/APIKeys/api-scopes-panel.component.js +61 -68
- package/dist/APIKeys/api-scopes-panel.component.js.map +1 -1
- package/dist/APIKeys/api-usage-panel.component.js +10 -11
- package/dist/APIKeys/api-usage-panel.component.js.map +1 -1
- package/dist/Actions/components/actions-list-view.component.js +82 -96
- package/dist/Actions/components/actions-list-view.component.js.map +1 -1
- package/dist/Actions/components/actions-overview.component.js +130 -134
- package/dist/Actions/components/actions-overview.component.js.map +1 -1
- package/dist/Actions/components/categories-list-view.component.d.ts.map +1 -1
- package/dist/Actions/components/categories-list-view.component.js +40 -46
- package/dist/Actions/components/categories-list-view.component.js.map +1 -1
- package/dist/Actions/components/code-management.component.js +2 -2
- package/dist/Actions/components/code-management.component.js.map +1 -1
- package/dist/Actions/components/entity-integration.component.js +2 -2
- package/dist/Actions/components/entity-integration.component.js.map +1 -1
- package/dist/Actions/components/execution-monitoring.component.js +127 -132
- package/dist/Actions/components/execution-monitoring.component.js.map +1 -1
- package/dist/Actions/components/executions-list-view.component.js +2 -2
- package/dist/Actions/components/executions-list-view.component.js.map +1 -1
- package/dist/Actions/components/explorer/action-card.component.js +11 -17
- package/dist/Actions/components/explorer/action-card.component.js.map +1 -1
- package/dist/Actions/components/explorer/action-explorer.component.js +5 -11
- package/dist/Actions/components/explorer/action-explorer.component.js.map +1 -1
- package/dist/Actions/components/explorer/action-list-item.component.js +8 -10
- package/dist/Actions/components/explorer/action-list-item.component.js.map +1 -1
- package/dist/Actions/components/explorer/action-toolbar.component.js +112 -133
- package/dist/Actions/components/explorer/action-toolbar.component.js.map +1 -1
- package/dist/Actions/components/explorer/action-tree-panel.component.js +63 -83
- package/dist/Actions/components/explorer/action-tree-panel.component.js.map +1 -1
- package/dist/Actions/components/explorer/new-action-panel.component.js +17 -21
- package/dist/Actions/components/explorer/new-action-panel.component.js.map +1 -1
- package/dist/Actions/components/explorer/new-category-panel.component.js +17 -21
- package/dist/Actions/components/explorer/new-category-panel.component.js.map +1 -1
- package/dist/Actions/components/scheduled-actions.component.js +2 -2
- package/dist/Actions/components/scheduled-actions.component.js.map +1 -1
- package/dist/Actions/components/security-permissions.component.js +2 -2
- package/dist/Actions/components/security-permissions.component.js.map +1 -1
- package/dist/ComponentStudio/component-studio-dashboard.component.d.ts +13 -5
- package/dist/ComponentStudio/component-studio-dashboard.component.d.ts.map +1 -1
- package/dist/ComponentStudio/component-studio-dashboard.component.js +168 -145
- package/dist/ComponentStudio/component-studio-dashboard.component.js.map +1 -1
- package/dist/ComponentStudio/components/artifact-load-dialog.component.d.ts +4 -5
- package/dist/ComponentStudio/components/artifact-load-dialog.component.d.ts.map +1 -1
- package/dist/ComponentStudio/components/artifact-load-dialog.component.js +197 -200
- package/dist/ComponentStudio/components/artifact-load-dialog.component.js.map +1 -1
- package/dist/ComponentStudio/components/artifact-selection-dialog.component.d.ts +5 -7
- package/dist/ComponentStudio/components/artifact-selection-dialog.component.d.ts.map +1 -1
- package/dist/ComponentStudio/components/artifact-selection-dialog.component.js +142 -148
- package/dist/ComponentStudio/components/artifact-selection-dialog.component.js.map +1 -1
- package/dist/ComponentStudio/components/browser/component-browser.component.js +153 -166
- package/dist/ComponentStudio/components/browser/component-browser.component.js.map +1 -1
- package/dist/ComponentStudio/components/editors/code-editor-panel.component.js +15 -20
- package/dist/ComponentStudio/components/editors/code-editor-panel.component.js.map +1 -1
- package/dist/ComponentStudio/components/editors/data-requirements-editor.component.js +16 -21
- package/dist/ComponentStudio/components/editors/data-requirements-editor.component.js.map +1 -1
- package/dist/ComponentStudio/components/editors/requirements-editor.component.js +18 -23
- package/dist/ComponentStudio/components/editors/requirements-editor.component.js.map +1 -1
- package/dist/ComponentStudio/components/editors/spec-editor.component.js +25 -30
- package/dist/ComponentStudio/components/editors/spec-editor.component.js.map +1 -1
- package/dist/ComponentStudio/components/new-component-dialog/new-component-dialog.component.js +10 -11
- package/dist/ComponentStudio/components/new-component-dialog/new-component-dialog.component.js.map +1 -1
- package/dist/ComponentStudio/components/save-version-dialog/save-version-dialog.component.d.ts.map +1 -1
- package/dist/ComponentStudio/components/save-version-dialog/save-version-dialog.component.js +24 -35
- package/dist/ComponentStudio/components/save-version-dialog/save-version-dialog.component.js.map +1 -1
- package/dist/ComponentStudio/components/text-import-dialog.component.js +15 -17
- package/dist/ComponentStudio/components/text-import-dialog.component.js.map +1 -1
- package/dist/Credentials/components/credentials-categories-resource.component.js +7 -6
- package/dist/Credentials/components/credentials-categories-resource.component.js.map +1 -1
- package/dist/Credentials/components/credentials-list-resource.component.js +6 -5
- package/dist/Credentials/components/credentials-list-resource.component.js.map +1 -1
- package/dist/Credentials/components/credentials-types-resource.component.js +7 -6
- package/dist/Credentials/components/credentials-types-resource.component.js.map +1 -1
- package/dist/DashboardBrowser/dashboard-share-dialog.component.js +9 -9
- package/dist/DashboardBrowser/dashboard-share-dialog.component.js.map +1 -1
- package/dist/Home/home-dashboard.component.js +4 -4
- package/dist/Home/home-dashboard.component.js.map +1 -1
- package/dist/Integration/components/connections/connections.component.js +4 -4
- package/dist/Integration/components/connections/connections.component.js.map +1 -1
- package/dist/Integration/components/mapping-workspace/mapping-workspace.component.js +246 -259
- package/dist/Integration/components/mapping-workspace/mapping-workspace.component.js.map +1 -1
- package/dist/Integration/components/widgets/integration-card.component.js +7 -9
- package/dist/Integration/components/widgets/integration-card.component.js.map +1 -1
- package/dist/Integration/integration.module.d.ts +6 -10
- package/dist/Integration/integration.module.d.ts.map +1 -1
- package/dist/Integration/integration.module.js +12 -20
- package/dist/Integration/integration.module.js.map +1 -1
- package/dist/KnowledgeHub/components/clusters/cluster-visualization-resource.component.d.ts +106 -0
- package/dist/KnowledgeHub/components/clusters/cluster-visualization-resource.component.d.ts.map +1 -0
- package/dist/KnowledgeHub/components/clusters/cluster-visualization-resource.component.js +607 -0
- package/dist/KnowledgeHub/components/clusters/cluster-visualization-resource.component.js.map +1 -0
- package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.d.ts +7 -2
- package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.d.ts.map +1 -1
- package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.js +59 -31
- package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.js.map +1 -1
- package/dist/KnowledgeHub/index.d.ts +1 -0
- package/dist/KnowledgeHub/index.d.ts.map +1 -1
- package/dist/KnowledgeHub/index.js +1 -0
- package/dist/KnowledgeHub/index.js.map +1 -1
- package/dist/Lists/components/lists-browse-resource.component.d.ts.map +1 -1
- package/dist/Lists/components/lists-browse-resource.component.js +9 -7
- package/dist/Lists/components/lists-browse-resource.component.js.map +1 -1
- package/dist/Lists/components/lists-my-lists-resource.component.js +5 -4
- package/dist/Lists/components/lists-my-lists-resource.component.js.map +1 -1
- package/dist/Lists/components/lists-operations-resource.component.js +10 -9
- package/dist/Lists/components/lists-operations-resource.component.js.map +1 -1
- package/dist/MCP/components/mcp-connection-dialog.component.js +141 -132
- package/dist/MCP/components/mcp-connection-dialog.component.js.map +1 -1
- package/dist/MCP/components/mcp-log-detail-panel.component.js +4 -4
- package/dist/MCP/components/mcp-log-detail-panel.component.js.map +1 -1
- package/dist/MCP/components/mcp-server-dialog.component.js +141 -128
- package/dist/MCP/components/mcp-server-dialog.component.js.map +1 -1
- package/dist/MCP/components/mcp-test-tool-dialog.component.js +210 -218
- package/dist/MCP/components/mcp-test-tool-dialog.component.js.map +1 -1
- package/dist/MCP/mcp-dashboard.component.js +2 -2
- package/dist/MCP/mcp-dashboard.component.js.map +1 -1
- package/dist/MCP/mcp.module.d.ts +6 -9
- package/dist/MCP/mcp.module.d.ts.map +1 -1
- package/dist/MCP/mcp.module.js +20 -22
- package/dist/MCP/mcp.module.js.map +1 -1
- package/dist/Scheduling/components/scheduling-activity.component.js +5 -4
- package/dist/Scheduling/components/scheduling-activity.component.js.map +1 -1
- package/dist/Scheduling/components/scheduling-jobs.component.js +6 -5
- package/dist/Scheduling/components/scheduling-jobs.component.js.map +1 -1
- package/dist/Scheduling/components/scheduling-overview.component.js +93 -92
- package/dist/Scheduling/components/scheduling-overview.component.js.map +1 -1
- package/dist/Testing/testing-dashboard.component.js +9 -10
- package/dist/Testing/testing-dashboard.component.js.map +1 -1
- package/dist/actions-dashboards.module.d.ts +8 -13
- package/dist/actions-dashboards.module.d.ts.map +1 -1
- package/dist/actions-dashboards.module.js +6 -27
- package/dist/actions-dashboards.module.js.map +1 -1
- package/dist/ai-dashboards.module.d.ts +16 -20
- package/dist/ai-dashboards.module.d.ts.map +1 -1
- package/dist/ai-dashboards.module.js +23 -44
- package/dist/ai-dashboards.module.js.map +1 -1
- package/dist/communication-dashboards.module.d.ts +4 -8
- package/dist/communication-dashboards.module.d.ts.map +1 -1
- package/dist/communication-dashboards.module.js +0 -19
- package/dist/communication-dashboards.module.js.map +1 -1
- package/dist/component-studio-dashboards.module.d.ts +7 -11
- package/dist/component-studio-dashboards.module.d.ts.map +1 -1
- package/dist/component-studio-dashboards.module.js +22 -34
- package/dist/component-studio-dashboards.module.js.map +1 -1
- package/dist/core-dashboards.module.d.ts +12 -18
- package/dist/core-dashboards.module.d.ts.map +1 -1
- package/dist/core-dashboards.module.js +15 -31
- package/dist/core-dashboards.module.js.map +1 -1
- package/dist/credentials-dashboards.module.d.ts +5 -8
- package/dist/credentials-dashboards.module.d.ts.map +1 -1
- package/dist/credentials-dashboards.module.js +3 -19
- package/dist/credentials-dashboards.module.js.map +1 -1
- package/dist/data-explorer-dashboards.module.d.ts +7 -13
- package/dist/data-explorer-dashboards.module.d.ts.map +1 -1
- package/dist/data-explorer-dashboards.module.js +0 -27
- package/dist/data-explorer-dashboards.module.js.map +1 -1
- package/dist/lists-dashboards.module.d.ts +5 -8
- package/dist/lists-dashboards.module.d.ts.map +1 -1
- package/dist/lists-dashboards.module.js +3 -19
- package/dist/lists-dashboards.module.js.map +1 -1
- package/dist/public-api.d.ts +1 -0
- package/dist/public-api.d.ts.map +1 -1
- package/dist/public-api.js +1 -0
- package/dist/public-api.js.map +1 -1
- package/dist/scheduling-dashboards.module.d.ts +6 -10
- package/dist/scheduling-dashboards.module.d.ts.map +1 -1
- package/dist/scheduling-dashboards.module.js +3 -23
- package/dist/scheduling-dashboards.module.js.map +1 -1
- package/dist/testing-dashboards.module.d.ts +7 -13
- package/dist/testing-dashboards.module.d.ts.map +1 -1
- package/dist/testing-dashboards.module.js +0 -27
- package/dist/testing-dashboards.module.js.map +1 -1
- package/package.json +47 -55
|
@@ -4,11 +4,8 @@ import { UUIDsEqual } from '@memberjunction/global';
|
|
|
4
4
|
import * as i0 from "@angular/core";
|
|
5
5
|
import * as i1 from "@angular/common";
|
|
6
6
|
import * as i2 from "@angular/forms";
|
|
7
|
-
import * as i3 from "@
|
|
8
|
-
import * as i4 from "@
|
|
9
|
-
import * as i5 from "@progress/kendo-angular-inputs";
|
|
10
|
-
import * as i6 from "@progress/kendo-angular-dialog";
|
|
11
|
-
import * as i7 from "@memberjunction/ng-shared-generic";
|
|
7
|
+
import * as i3 from "@memberjunction/ng-ui-components";
|
|
8
|
+
import * as i4 from "@memberjunction/ng-shared-generic";
|
|
12
9
|
const _c0 = a0 => ({ node: a0 });
|
|
13
10
|
const _c1 = () => ({ FullPath: "(No Parent - Root Level)", ID: null });
|
|
14
11
|
function APIScopesPanelComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
@@ -233,8 +230,8 @@ function APIScopesPanelComponent_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
|
233
230
|
i0.ɵɵadvance(2);
|
|
234
231
|
i0.ɵɵconditional(ctx_r1.ScopeTree.length === 0 ? 28 : -1);
|
|
235
232
|
} }
|
|
236
|
-
function
|
|
237
|
-
i0.ɵɵelementStart(0, "span",
|
|
233
|
+
function APIScopesPanelComponent_Conditional_3_Conditional_17_Template(rf, ctx) { if (rf & 1) {
|
|
234
|
+
i0.ɵɵelementStart(0, "span", 54);
|
|
238
235
|
i0.ɵɵtext(1, " Full path will be: ");
|
|
239
236
|
i0.ɵɵelementStart(2, "code");
|
|
240
237
|
i0.ɵɵtext(3);
|
|
@@ -244,14 +241,14 @@ function APIScopesPanelComponent_Conditional_3_Conditional_19_Template(rf, ctx)
|
|
|
244
241
|
i0.ɵɵadvance(3);
|
|
245
242
|
i0.ɵɵtextInterpolate2("", ctx_r1.SelectedParentScope.FullPath, ":", ctx_r1.EditName || "...");
|
|
246
243
|
} }
|
|
247
|
-
function
|
|
248
|
-
i0.ɵɵelement(0, "mj-loading",
|
|
244
|
+
function APIScopesPanelComponent_Conditional_3_Conditional_41_Template(rf, ctx) { if (rf & 1) {
|
|
245
|
+
i0.ɵɵelement(0, "mj-loading", 66);
|
|
249
246
|
} if (rf & 2) {
|
|
250
247
|
i0.ɵɵproperty("showText", false);
|
|
251
248
|
} }
|
|
252
|
-
function
|
|
249
|
+
function APIScopesPanelComponent_Conditional_3_Conditional_42_Template(rf, ctx) { if (rf & 1) {
|
|
253
250
|
i0.ɵɵelementStart(0, "span");
|
|
254
|
-
i0.ɵɵelement(1, "i",
|
|
251
|
+
i0.ɵɵelement(1, "i", 68);
|
|
255
252
|
i0.ɵɵtext(2);
|
|
256
253
|
i0.ɵɵelementEnd();
|
|
257
254
|
} if (rf & 2) {
|
|
@@ -261,99 +258,95 @@ function APIScopesPanelComponent_Conditional_3_Conditional_44_Template(rf, ctx)
|
|
|
261
258
|
} }
|
|
262
259
|
function APIScopesPanelComponent_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
263
260
|
const _r9 = i0.ɵɵgetCurrentView();
|
|
264
|
-
i0.ɵɵelementStart(0, "
|
|
265
|
-
i0.ɵɵlistener("
|
|
266
|
-
i0.ɵɵelementStart(1, "
|
|
261
|
+
i0.ɵɵelementStart(0, "mj-window", 49);
|
|
262
|
+
i0.ɵɵlistener("Close", function APIScopesPanelComponent_Conditional_3_Template_mj_window_Close_0_listener() { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.closeDialogs()); });
|
|
263
|
+
i0.ɵɵelementStart(1, "mj-window-titlebar")(2, "div", 50);
|
|
267
264
|
i0.ɵɵelement(3, "i", 7);
|
|
268
265
|
i0.ɵɵelementStart(4, "span");
|
|
269
266
|
i0.ɵɵtext(5);
|
|
270
|
-
i0.ɵɵelementEnd()();
|
|
271
|
-
i0.ɵɵelementStart(6, "
|
|
272
|
-
i0.ɵɵ
|
|
273
|
-
i0.ɵɵelement(7, "i", 52);
|
|
274
|
-
i0.ɵɵelementEnd()();
|
|
275
|
-
i0.ɵɵelementStart(8, "div", 53)(9, "div", 54)(10, "label");
|
|
276
|
-
i0.ɵɵtext(11, "Scope Name *");
|
|
267
|
+
i0.ɵɵelementEnd()()();
|
|
268
|
+
i0.ɵɵelementStart(6, "div", 51)(7, "div", 52)(8, "label");
|
|
269
|
+
i0.ɵɵtext(9, "Scope Name *");
|
|
277
270
|
i0.ɵɵelementEnd();
|
|
278
|
-
i0.ɵɵelementStart(
|
|
279
|
-
i0.ɵɵtwoWayListener("ngModelChange", function
|
|
271
|
+
i0.ɵɵelementStart(10, "input", 53);
|
|
272
|
+
i0.ɵɵtwoWayListener("ngModelChange", function APIScopesPanelComponent_Conditional_3_Template_input_ngModelChange_10_listener($event) { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r1.EditName, $event) || (ctx_r1.EditName = $event); return i0.ɵɵresetView($event); });
|
|
280
273
|
i0.ɵɵelementEnd();
|
|
281
|
-
i0.ɵɵelementStart(
|
|
282
|
-
i0.ɵɵtext(
|
|
274
|
+
i0.ɵɵelementStart(11, "span", 54);
|
|
275
|
+
i0.ɵɵtext(12, "Use lowercase, single word. Will be combined with parent for full path.");
|
|
283
276
|
i0.ɵɵelementEnd()();
|
|
284
|
-
i0.ɵɵelementStart(
|
|
285
|
-
i0.ɵɵtext(
|
|
277
|
+
i0.ɵɵelementStart(13, "div", 52)(14, "label");
|
|
278
|
+
i0.ɵɵtext(15, "Parent Scope");
|
|
286
279
|
i0.ɵɵelementEnd();
|
|
287
|
-
i0.ɵɵelementStart(
|
|
288
|
-
i0.ɵɵtwoWayListener("ngModelChange", function
|
|
280
|
+
i0.ɵɵelementStart(16, "mj-dropdown", 55);
|
|
281
|
+
i0.ɵɵtwoWayListener("ngModelChange", function APIScopesPanelComponent_Conditional_3_Template_mj_dropdown_ngModelChange_16_listener($event) { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r1.EditParentId, $event) || (ctx_r1.EditParentId = $event); return i0.ɵɵresetView($event); });
|
|
289
282
|
i0.ɵɵelementEnd();
|
|
290
|
-
i0.ɵɵconditionalCreate(
|
|
283
|
+
i0.ɵɵconditionalCreate(17, APIScopesPanelComponent_Conditional_3_Conditional_17_Template, 4, 2, "span", 54);
|
|
291
284
|
i0.ɵɵelementEnd();
|
|
292
|
-
i0.ɵɵelementStart(
|
|
293
|
-
i0.ɵɵtext(
|
|
285
|
+
i0.ɵɵelementStart(18, "div", 56)(19, "div", 57)(20, "label");
|
|
286
|
+
i0.ɵɵtext(21, "Category");
|
|
294
287
|
i0.ɵɵelementEnd();
|
|
295
|
-
i0.ɵɵelementStart(
|
|
296
|
-
i0.ɵɵtwoWayListener("ngModelChange", function
|
|
288
|
+
i0.ɵɵelementStart(22, "mj-dropdown", 58);
|
|
289
|
+
i0.ɵɵtwoWayListener("ngModelChange", function APIScopesPanelComponent_Conditional_3_Template_mj_dropdown_ngModelChange_22_listener($event) { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r1.EditCategory, $event) || (ctx_r1.EditCategory = $event); return i0.ɵɵresetView($event); });
|
|
297
290
|
i0.ɵɵelementEnd()();
|
|
298
|
-
i0.ɵɵelementStart(
|
|
299
|
-
i0.ɵɵtext(
|
|
291
|
+
i0.ɵɵelementStart(23, "div", 57)(24, "label");
|
|
292
|
+
i0.ɵɵtext(25, "Resource Type");
|
|
300
293
|
i0.ɵɵelementEnd();
|
|
301
|
-
i0.ɵɵelementStart(
|
|
302
|
-
i0.ɵɵtwoWayListener("ngModelChange", function
|
|
294
|
+
i0.ɵɵelementStart(26, "mj-dropdown", 59);
|
|
295
|
+
i0.ɵɵtwoWayListener("ngModelChange", function APIScopesPanelComponent_Conditional_3_Template_mj_dropdown_ngModelChange_26_listener($event) { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r1.EditResourceType, $event) || (ctx_r1.EditResourceType = $event); return i0.ɵɵresetView($event); });
|
|
303
296
|
i0.ɵɵelementEnd()()();
|
|
304
|
-
i0.ɵɵelementStart(
|
|
305
|
-
i0.ɵɵtext(
|
|
297
|
+
i0.ɵɵelementStart(27, "div", 52)(28, "label");
|
|
298
|
+
i0.ɵɵtext(29, "Description");
|
|
306
299
|
i0.ɵɵelementEnd();
|
|
307
|
-
i0.ɵɵelementStart(
|
|
308
|
-
i0.ɵɵtwoWayListener("ngModelChange", function
|
|
300
|
+
i0.ɵɵelementStart(30, "textarea", 60);
|
|
301
|
+
i0.ɵɵtwoWayListener("ngModelChange", function APIScopesPanelComponent_Conditional_3_Template_textarea_ngModelChange_30_listener($event) { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r1.EditDescription, $event) || (ctx_r1.EditDescription = $event); return i0.ɵɵresetView($event); });
|
|
309
302
|
i0.ɵɵelementEnd()();
|
|
310
|
-
i0.ɵɵelementStart(
|
|
311
|
-
i0.ɵɵtwoWayListener("ngModelChange", function
|
|
303
|
+
i0.ɵɵelementStart(31, "div", 52)(32, "label", 61)(33, "input", 62);
|
|
304
|
+
i0.ɵɵtwoWayListener("ngModelChange", function APIScopesPanelComponent_Conditional_3_Template_input_ngModelChange_33_listener($event) { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r1.EditIsActive, $event) || (ctx_r1.EditIsActive = $event); return i0.ɵɵresetView($event); });
|
|
312
305
|
i0.ɵɵelementEnd();
|
|
313
|
-
i0.ɵɵelementStart(
|
|
314
|
-
i0.ɵɵtext(
|
|
306
|
+
i0.ɵɵelementStart(34, "div")(35, "span");
|
|
307
|
+
i0.ɵɵtext(36, "Active");
|
|
315
308
|
i0.ɵɵelementEnd();
|
|
316
|
-
i0.ɵɵelementStart(
|
|
317
|
-
i0.ɵɵtext(
|
|
309
|
+
i0.ɵɵelementStart(37, "span", 63);
|
|
310
|
+
i0.ɵɵtext(38, "Inactive scopes cannot be assigned to keys or applications");
|
|
318
311
|
i0.ɵɵelementEnd()()()();
|
|
319
|
-
i0.ɵɵelementStart(
|
|
320
|
-
i0.ɵɵlistener("click", function
|
|
321
|
-
i0.ɵɵconditionalCreate(
|
|
322
|
-
i0.ɵɵconditionalCreate(
|
|
312
|
+
i0.ɵɵelementStart(39, "div", 64)(40, "button", 65);
|
|
313
|
+
i0.ɵɵlistener("click", function APIScopesPanelComponent_Conditional_3_Template_button_click_40_listener() { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.saveScope()); });
|
|
314
|
+
i0.ɵɵconditionalCreate(41, APIScopesPanelComponent_Conditional_3_Conditional_41_Template, 1, 1, "mj-loading", 66);
|
|
315
|
+
i0.ɵɵconditionalCreate(42, APIScopesPanelComponent_Conditional_3_Conditional_42_Template, 3, 1, "span");
|
|
323
316
|
i0.ɵɵelementEnd();
|
|
324
|
-
i0.ɵɵelementStart(
|
|
325
|
-
i0.ɵɵlistener("click", function
|
|
326
|
-
i0.ɵɵtext(
|
|
317
|
+
i0.ɵɵelementStart(43, "button", 67);
|
|
318
|
+
i0.ɵɵlistener("click", function APIScopesPanelComponent_Conditional_3_Template_button_click_43_listener() { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.closeDialogs()); });
|
|
319
|
+
i0.ɵɵtext(44, "Cancel");
|
|
327
320
|
i0.ɵɵelementEnd()()()();
|
|
328
321
|
} if (rf & 2) {
|
|
329
322
|
const ctx_r1 = i0.ɵɵnextContext();
|
|
330
|
-
i0.ɵɵproperty("
|
|
323
|
+
i0.ɵɵproperty("Width", 560)("MinWidth", 420)("MinHeight", 480)("Resizable", true)("Draggable", true)("Visible", true)("Top", 80);
|
|
331
324
|
i0.ɵɵadvance(5);
|
|
332
325
|
i0.ɵɵtextInterpolate(ctx_r1.EditingScope ? "Edit Scope" : "New Scope");
|
|
333
|
-
i0.ɵɵadvance(
|
|
326
|
+
i0.ɵɵadvance(5);
|
|
334
327
|
i0.ɵɵtwoWayProperty("ngModel", ctx_r1.EditName);
|
|
335
328
|
i0.ɵɵadvance(6);
|
|
336
329
|
i0.ɵɵtwoWayProperty("ngModel", ctx_r1.EditParentId);
|
|
337
|
-
i0.ɵɵproperty("
|
|
330
|
+
i0.ɵɵproperty("Data", ctx_r1.getParentOptions())("ValuePrimitive", true)("DefaultItem", i0.ɵɵpureFunction0(27, _c1));
|
|
338
331
|
i0.ɵɵadvance();
|
|
339
|
-
i0.ɵɵconditional(ctx_r1.SelectedParentScope ?
|
|
332
|
+
i0.ɵɵconditional(ctx_r1.SelectedParentScope ? 17 : -1);
|
|
340
333
|
i0.ɵɵadvance(5);
|
|
341
334
|
i0.ɵɵtwoWayProperty("ngModel", ctx_r1.EditCategory);
|
|
342
|
-
i0.ɵɵproperty("
|
|
335
|
+
i0.ɵɵproperty("Data", ctx_r1.Categories)("ValuePrimitive", true);
|
|
343
336
|
i0.ɵɵadvance(4);
|
|
344
337
|
i0.ɵɵtwoWayProperty("ngModel", ctx_r1.EditResourceType);
|
|
345
|
-
i0.ɵɵproperty("
|
|
338
|
+
i0.ɵɵproperty("Data", ctx_r1.ResourceTypes)("ValuePrimitive", true)("DefaultItem", "");
|
|
346
339
|
i0.ɵɵadvance(4);
|
|
347
340
|
i0.ɵɵtwoWayProperty("ngModel", ctx_r1.EditDescription);
|
|
348
341
|
i0.ɵɵproperty("rows", 3);
|
|
349
342
|
i0.ɵɵadvance(3);
|
|
350
343
|
i0.ɵɵtwoWayProperty("ngModel", ctx_r1.EditIsActive);
|
|
351
344
|
i0.ɵɵadvance(7);
|
|
352
|
-
i0.ɵɵproperty("
|
|
345
|
+
i0.ɵɵproperty("disabled", !ctx_r1.EditName.trim() || ctx_r1.IsSaving);
|
|
353
346
|
i0.ɵɵadvance();
|
|
354
|
-
i0.ɵɵconditional(ctx_r1.IsSaving ?
|
|
347
|
+
i0.ɵɵconditional(ctx_r1.IsSaving ? 41 : -1);
|
|
355
348
|
i0.ɵɵadvance();
|
|
356
|
-
i0.ɵɵconditional(!ctx_r1.IsSaving ?
|
|
349
|
+
i0.ɵɵconditional(!ctx_r1.IsSaving ? 42 : -1);
|
|
357
350
|
} }
|
|
358
351
|
/**
|
|
359
352
|
* API Scopes Panel Component
|
|
@@ -624,11 +617,11 @@ export class APIScopesPanelComponent {
|
|
|
624
617
|
return this.FlatScopes.filter(s => s.IsActive).length;
|
|
625
618
|
}
|
|
626
619
|
static ɵfac = function APIScopesPanelComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || APIScopesPanelComponent)(i0.ɵɵdirectiveInject(i0.ChangeDetectorRef)); };
|
|
627
|
-
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: APIScopesPanelComponent, selectors: [["mj-api-scopes-panel"]], outputs: { ScopeUpdated: "ScopeUpdated" }, standalone: false, decls: 4, vars: 3, consts: [["scopeNode", ""], [1, "scopes-panel"], ["text", "Loading scopes..."], [3, "
|
|
620
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: APIScopesPanelComponent, selectors: [["mj-api-scopes-panel"]], outputs: { ScopeUpdated: "ScopeUpdated" }, standalone: false, decls: 4, vars: 3, consts: [["scopeNode", ""], [1, "scopes-panel"], ["text", "Loading scopes..."], [3, "Width", "MinWidth", "MinHeight", "Resizable", "Draggable", "Visible", "Top"], [1, "panel-header"], [1, "header-left"], [1, "panel-title"], [1, "fa-solid", "fa-shield-halved"], [1, "panel-subtitle"], [1, "header-actions"], [1, "scope-stats"], [1, "stat"], [1, "fa-solid", "fa-shield"], [1, "stat", "active"], [1, "fa-solid", "fa-check-circle"], [1, "tree-controls"], ["title", "Expand All", 1, "btn-icon", 3, "click"], [1, "fa-solid", "fa-plus-square"], ["title", "Collapse All", 1, "btn-icon", 3, "click"], [1, "fa-solid", "fa-minus-square"], [1, "btn-create", 3, "click"], [1, "fa-solid", "fa-plus"], [1, "message", "success"], [1, "message", "error"], [1, "scope-tree"], [1, "empty-state"], [1, "fa-solid", "fa-circle-exclamation"], [4, "ngTemplateOutlet", "ngTemplateOutletContext"], [1, "scope-node"], [1, "node-content"], [1, "expand-btn"], [1, "expand-placeholder"], [1, "scope-info", 3, "click"], [1, "scope-icon"], [1, "scope-details"], [1, "scope-name"], [1, "full-path"], [1, "status-badge"], [1, "scope-meta"], [1, "category"], [1, "resource-type"], [1, "description"], [1, "node-actions"], ["title", "Add Child Scope", 1, "btn-node-action", 3, "click"], ["title", "Edit Scope", 1, "btn-node-action", 3, "click"], [1, "fa-solid", "fa-pencil"], [1, "children"], [1, "expand-btn", 3, "click"], [1, "fa-solid"], [3, "Close", "Width", "MinWidth", "MinHeight", "Resizable", "Draggable", "Visible", "Top"], [1, "dialog-title"], [1, "dialog-content"], [1, "form-field"], ["placeholder", "e.g., runview, create, execute", 1, "mj-input", "form-input", 3, "ngModelChange", "ngModel"], [1, "field-hint"], ["TextField", "FullPath", "ValueField", "ID", 3, "ngModelChange", "ngModel", "Data", "ValuePrimitive", "DefaultItem"], [1, "form-row"], [1, "form-field", "half"], [3, "ngModelChange", "ngModel", "Data", "ValuePrimitive"], [3, "ngModelChange", "ngModel", "Data", "ValuePrimitive", "DefaultItem"], ["placeholder", "Describe what this scope allows...", 1, "mj-textarea", "form-textarea", 3, "ngModelChange", "ngModel", "rows"], [1, "checkbox-label"], ["type", "checkbox", 1, "mj-checkbox", 3, "ngModelChange", "ngModel"], [1, "checkbox-hint"], [1, "dialog-actions"], ["mjButton", "", "variant", "primary", 3, "click", "disabled"], ["size", "small", 3, "showText"], ["mjButton", "", 3, "click"], [1, "fa-solid", "fa-save"]], template: function APIScopesPanelComponent_Template(rf, ctx) { if (rf & 1) {
|
|
628
621
|
i0.ɵɵelementStart(0, "div", 1);
|
|
629
622
|
i0.ɵɵconditionalCreate(1, APIScopesPanelComponent_Conditional_1_Template, 1, 0, "mj-loading", 2);
|
|
630
623
|
i0.ɵɵconditionalCreate(2, APIScopesPanelComponent_Conditional_2_Template, 31, 5);
|
|
631
|
-
i0.ɵɵconditionalCreate(3, APIScopesPanelComponent_Conditional_3_Template,
|
|
624
|
+
i0.ɵɵconditionalCreate(3, APIScopesPanelComponent_Conditional_3_Template, 45, 28, "mj-window", 3);
|
|
632
625
|
i0.ɵɵelementEnd();
|
|
633
626
|
} if (rf & 2) {
|
|
634
627
|
i0.ɵɵadvance();
|
|
@@ -637,11 +630,11 @@ export class APIScopesPanelComponent {
|
|
|
637
630
|
i0.ɵɵconditional(!ctx.IsLoading ? 2 : -1);
|
|
638
631
|
i0.ɵɵadvance();
|
|
639
632
|
i0.ɵɵconditional(ctx.ShowCreateDialog || ctx.ShowEditDialog ? 3 : -1);
|
|
640
|
-
} }, dependencies: [i1.NgTemplateOutlet, i2.DefaultValueAccessor, i2.CheckboxControlValueAccessor, i2.NgControlStatus, i2.NgModel, i3.ButtonComponent, i4.DropDownListComponent, i5.TextBoxDirective, i5.TextAreaDirective, i5.CheckBoxDirective, i6.WindowComponent, i6.WindowTitleBarComponent, i7.LoadingComponent], styles: [".scopes-panel[_ngcontent-%COMP%] {\n height: 100%;\n display: flex;\n flex-direction: column;\n}\n\n\n\n.panel-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 24px;\n flex-wrap: wrap;\n gap: 16px;\n}\n\n.header-left[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 200px;\n}\n\n.panel-title[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n font-size: 18px;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0 0 4px 0;\n}\n\n.panel-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-status-success);\n}\n\n.panel-subtitle[_ngcontent-%COMP%] {\n font-size: 14px;\n color: var(--mj-text-secondary);\n margin: 0;\n}\n\n.header-actions[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 16px;\n}\n\n.scope-stats[_ngcontent-%COMP%] {\n display: flex;\n gap: 16px;\n}\n\n.stat[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 13px;\n color: var(--mj-text-secondary);\n}\n\n.stat.active[_ngcontent-%COMP%] {\n color: var(--mj-status-success);\n}\n\n.stat[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n}\n\n.tree-controls[_ngcontent-%COMP%] {\n display: flex;\n gap: 4px;\n}\n\n.btn-icon[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.btn-icon[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.btn-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n color: var(--mj-text-secondary);\n}\n\n.btn-create[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 20px;\n background: linear-gradient(135deg, var(--mj-status-success) 0%, var(--mj-color-success-600) 100%);\n color: var(--mj-text-inverse);\n border: none;\n border-radius: 8px;\n font-weight: 600;\n font-size: 14px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.btn-create[_ngcontent-%COMP%]:hover {\n transform: translateY(-1px);\n box-shadow: 0 4px 12px color-mix(in srgb, var(--mj-status-success) 40%, transparent);\n}\n\n\n\n.message[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 12px 16px;\n border-radius: 8px;\n margin-bottom: 16px;\n font-size: 14px;\n}\n\n.message.success[_ngcontent-%COMP%] {\n background: var(--mj-color-success-100);\n color: var(--mj-color-success-800);\n border: 1px solid var(--mj-status-success-border);\n}\n\n.message.error[_ngcontent-%COMP%] {\n background: var(--mj-color-error-100);\n color: var(--mj-status-error);\n border: 1px solid var(--mj-status-error-border);\n}\n\n\n\n.scope-tree[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n background: var(--mj-bg-surface);\n border-radius: 12px;\n box-shadow: var(--mj-shadow-md);\n}\n\n.scope-node[_ngcontent-%COMP%] {\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.scope-node[_ngcontent-%COMP%]:last-child {\n border-bottom: none;\n}\n\n.node-content[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n padding: 12px 16px;\n transition: background 0.2s ease;\n}\n\n.node-content[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.node-content.inactive[_ngcontent-%COMP%] {\n opacity: 0.6;\n}\n\n.expand-btn[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n background: none;\n border: none;\n cursor: pointer;\n color: var(--mj-text-muted);\n transition: transform 0.2s ease;\n flex-shrink: 0;\n}\n\n.expand-btn[_ngcontent-%COMP%]:hover {\n color: var(--mj-text-secondary);\n}\n\n.expand-placeholder[_ngcontent-%COMP%] {\n width: 24px;\n flex-shrink: 0;\n}\n\n.scope-info[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n flex: 1;\n min-width: 0;\n cursor: pointer;\n}\n\n.scope-icon[_ngcontent-%COMP%] {\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 8px;\n margin-right: 12px;\n flex-shrink: 0;\n}\n\n.scope-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n color: var(--mj-text-inverse);\n}\n\n.scope-details[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n.scope-name[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 14px;\n font-weight: 500;\n color: var(--mj-text-primary);\n flex-wrap: wrap;\n}\n\n.full-path[_ngcontent-%COMP%] {\n font-family: monospace;\n font-size: 12px;\n color: var(--mj-text-muted);\n background: var(--mj-bg-surface-sunken);\n padding: 2px 6px;\n border-radius: 4px;\n}\n\n.status-badge[_ngcontent-%COMP%] {\n font-size: 10px;\n font-weight: 500;\n padding: 2px 6px;\n border-radius: 4px;\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-secondary);\n}\n\n.scope-meta[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n margin-top: 4px;\n font-size: 12px;\n flex-wrap: wrap;\n}\n\n.category[_ngcontent-%COMP%] {\n font-weight: 500;\n}\n\n.resource-type[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface-sunken);\n padding: 2px 6px;\n border-radius: 4px;\n}\n\n.description[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n max-width: 300px;\n}\n\n.node-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 4px;\n margin-left: 12px;\n opacity: 0;\n transition: opacity 0.2s ease;\n}\n\n.node-content[_ngcontent-%COMP%]:hover .node-actions[_ngcontent-%COMP%] {\n opacity: 1;\n}\n\n.btn-node-action[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.btn-node-action[_ngcontent-%COMP%]:hover {\n background: var(--mj-status-success);\n border-color: var(--mj-status-success);\n color: var(--mj-text-inverse);\n}\n\n.btn-node-action[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 12px;\n}\n\n.children[_ngcontent-%COMP%] {\n margin-left: 0;\n}\n\n\n\n.empty-state[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 48px;\n color: var(--mj-text-secondary);\n text-align: center;\n}\n\n.empty-state[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 48px;\n margin-bottom: 16px;\n opacity: 0.5;\n}\n\n.empty-state[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n font-size: 16px;\n font-weight: 500;\n}\n\n.empty-state[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n font-size: 14px;\n margin-top: 8px;\n}\n\n\n\n\n\n\n\n\n[_nghost-%COMP%] kendo-window {\n border-radius: 16px !important;\n overflow: hidden;\n box-shadow: var(--mj-shadow-2xl) !important;\n background: var(--mj-bg-surface) !important;\n}\n\n[_nghost-%COMP%] kendo-window .k-window-content {\n padding: 0 !important;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n background: var(--mj-bg-surface) !important;\n}\n\n[_nghost-%COMP%] kendo-window-titlebar {\n display: flex !important;\n align-items: center;\n justify-content: space-between;\n padding: 18px 24px !important;\n background: var(--mj-bg-page) !important;\n border-bottom: 1px solid var(--mj-border-default) !important;\n}\n\n.dialog-title[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n font-weight: 600;\n font-size: 17px;\n color: var(--mj-text-primary);\n}\n\n.dialog-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-status-success);\n font-size: 18px;\n}\n\n.window-close-btn[_ngcontent-%COMP%] {\n margin-left: auto;\n color: var(--mj-text-muted);\n transition: all 0.2s ease;\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 8px;\n}\n\n.window-close-btn[_ngcontent-%COMP%]:hover {\n color: var(--mj-text-primary);\n background: var(--mj-bg-surface-hover);\n}\n\n.window-close-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 16px;\n}\n\n\n\n.dialog-content[_ngcontent-%COMP%] {\n padding: 24px;\n flex: 1;\n overflow-y: auto;\n}\n\n\n\n.form-field[_ngcontent-%COMP%] {\n margin-bottom: 20px;\n}\n\n.form-field[_ngcontent-%COMP%]:last-of-type {\n margin-bottom: 0;\n}\n\n.form-field[_ngcontent-%COMP%] label[_ngcontent-%COMP%] {\n display: block;\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin-bottom: 8px;\n letter-spacing: 0.01em;\n}\n\n.form-input[_ngcontent-%COMP%] {\n width: 100%;\n}\n\n.form-textarea[_ngcontent-%COMP%] {\n width: 100%;\n resize: vertical;\n min-height: 80px;\n}\n\n[_nghost-%COMP%] .form-input .k-input, \n[_nghost-%COMP%] .form-textarea .k-input-inner, \n[_nghost-%COMP%] .form-field .k-dropdownlist {\n padding: 10px 14px;\n border-radius: 8px;\n font-size: 14px;\n border-color: var(--mj-border-default);\n background: var(--mj-bg-surface) !important;\n color: var(--mj-text-primary) !important;\n transition: all 0.2s ease;\n}\n\n[_nghost-%COMP%] .form-input:focus-within, \n[_nghost-%COMP%] .form-textarea:focus-within, \n[_nghost-%COMP%] .form-field .k-dropdownlist.k-focus {\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-status-success) 10%, transparent);\n}\n\n.field-hint[_ngcontent-%COMP%] {\n display: block;\n font-size: 12px;\n color: var(--mj-text-secondary);\n margin-top: 6px;\n line-height: 1.4;\n}\n\n.form-row[_ngcontent-%COMP%] {\n display: flex;\n gap: 16px;\n}\n\n.form-field.half[_ngcontent-%COMP%] {\n flex: 1;\n}\n\n.checkbox-label[_ngcontent-%COMP%] {\n display: flex;\n align-items: flex-start;\n gap: 12px;\n cursor: pointer;\n padding: 12px 16px;\n background: var(--mj-bg-page);\n border-radius: 10px;\n border: 1px solid var(--mj-border-default);\n transition: all 0.2s ease;\n}\n\n.checkbox-label[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n border-color: var(--mj-border-strong);\n}\n\n.checkbox-label[_ngcontent-%COMP%] input[_ngcontent-%COMP%] {\n margin-top: 2px;\n flex-shrink: 0;\n}\n\n.checkbox-label[_ngcontent-%COMP%] span[_ngcontent-%COMP%]:first-of-type {\n font-weight: 600;\n color: var(--mj-text-primary);\n font-size: 14px;\n}\n\n.checkbox-hint[_ngcontent-%COMP%] {\n display: block;\n font-size: 12px;\n color: var(--mj-text-secondary);\n margin-top: 4px;\n line-height: 1.4;\n}\n\n\n\n.dialog-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 12px;\n padding: 20px 24px;\n background: var(--mj-bg-page);\n border-top: 1px solid var(--mj-border-default);\n margin: 0 -24px -24px -24px;\n}\n\n[_nghost-%COMP%] .dialog-actions .k-button {\n min-width: 100px;\n padding: 10px 20px;\n font-weight: 600;\n border-radius: 8px;\n transition: all 0.2s ease;\n}\n\n[_nghost-%COMP%] .dialog-actions .k-button-solid-primary {\n background: linear-gradient(135deg, var(--mj-status-success) 0%, var(--mj-color-success-600) 100%);\n border: none;\n box-shadow: 0 2px 8px color-mix(in srgb, var(--mj-status-success) 30%, transparent);\n}\n\n[_nghost-%COMP%] .dialog-actions .k-button-solid-primary:hover {\n transform: translateY(-1px);\n box-shadow: 0 4px 12px color-mix(in srgb, var(--mj-status-success) 40%, transparent);\n}"] });
|
|
633
|
+
} }, dependencies: [i1.NgTemplateOutlet, i2.DefaultValueAccessor, i2.CheckboxControlValueAccessor, i2.NgControlStatus, i2.NgModel, i3.MJButtonDirective, i3.MJWindowComponent, i3.MJWindowTitlebarComponent, i3.MJDropdownComponent, i4.LoadingComponent], styles: [".scopes-panel[_ngcontent-%COMP%] {\n height: 100%;\n display: flex;\n flex-direction: column;\n}\n\n\n\n.panel-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 24px;\n flex-wrap: wrap;\n gap: 16px;\n}\n\n.header-left[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 200px;\n}\n\n.panel-title[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n font-size: 18px;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0 0 4px 0;\n}\n\n.panel-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-status-success);\n}\n\n.panel-subtitle[_ngcontent-%COMP%] {\n font-size: 14px;\n color: var(--mj-text-secondary);\n margin: 0;\n}\n\n.header-actions[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 16px;\n}\n\n.scope-stats[_ngcontent-%COMP%] {\n display: flex;\n gap: 16px;\n}\n\n.stat[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 13px;\n color: var(--mj-text-secondary);\n}\n\n.stat.active[_ngcontent-%COMP%] {\n color: var(--mj-status-success);\n}\n\n.stat[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n}\n\n.tree-controls[_ngcontent-%COMP%] {\n display: flex;\n gap: 4px;\n}\n\n.btn-icon[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.btn-icon[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.btn-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n color: var(--mj-text-secondary);\n}\n\n.btn-create[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 20px;\n background: linear-gradient(135deg, var(--mj-status-success) 0%, var(--mj-color-success-600) 100%);\n color: var(--mj-text-inverse);\n border: none;\n border-radius: 8px;\n font-weight: 600;\n font-size: 14px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.btn-create[_ngcontent-%COMP%]:hover {\n transform: translateY(-1px);\n box-shadow: 0 4px 12px color-mix(in srgb, var(--mj-status-success) 40%, transparent);\n}\n\n\n\n.message[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 12px 16px;\n border-radius: 8px;\n margin-bottom: 16px;\n font-size: 14px;\n}\n\n.message.success[_ngcontent-%COMP%] {\n background: var(--mj-color-success-100);\n color: var(--mj-color-success-800);\n border: 1px solid var(--mj-status-success-border);\n}\n\n.message.error[_ngcontent-%COMP%] {\n background: var(--mj-color-error-100);\n color: var(--mj-status-error);\n border: 1px solid var(--mj-status-error-border);\n}\n\n\n\n.scope-tree[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n background: var(--mj-bg-surface);\n border-radius: 12px;\n box-shadow: var(--mj-shadow-md);\n}\n\n.scope-node[_ngcontent-%COMP%] {\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.scope-node[_ngcontent-%COMP%]:last-child {\n border-bottom: none;\n}\n\n.node-content[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n padding: 12px 16px;\n transition: background 0.2s ease;\n}\n\n.node-content[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.node-content.inactive[_ngcontent-%COMP%] {\n opacity: 0.6;\n}\n\n.expand-btn[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n background: none;\n border: none;\n cursor: pointer;\n color: var(--mj-text-muted);\n transition: transform 0.2s ease;\n flex-shrink: 0;\n}\n\n.expand-btn[_ngcontent-%COMP%]:hover {\n color: var(--mj-text-secondary);\n}\n\n.expand-placeholder[_ngcontent-%COMP%] {\n width: 24px;\n flex-shrink: 0;\n}\n\n.scope-info[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n flex: 1;\n min-width: 0;\n cursor: pointer;\n}\n\n.scope-icon[_ngcontent-%COMP%] {\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 8px;\n margin-right: 12px;\n flex-shrink: 0;\n}\n\n.scope-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n color: var(--mj-text-inverse);\n}\n\n.scope-details[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n.scope-name[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 14px;\n font-weight: 500;\n color: var(--mj-text-primary);\n flex-wrap: wrap;\n}\n\n.full-path[_ngcontent-%COMP%] {\n font-family: monospace;\n font-size: 12px;\n color: var(--mj-text-muted);\n background: var(--mj-bg-surface-sunken);\n padding: 2px 6px;\n border-radius: 4px;\n}\n\n.status-badge[_ngcontent-%COMP%] {\n font-size: 10px;\n font-weight: 500;\n padding: 2px 6px;\n border-radius: 4px;\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-secondary);\n}\n\n.scope-meta[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n margin-top: 4px;\n font-size: 12px;\n flex-wrap: wrap;\n}\n\n.category[_ngcontent-%COMP%] {\n font-weight: 500;\n}\n\n.resource-type[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface-sunken);\n padding: 2px 6px;\n border-radius: 4px;\n}\n\n.description[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n max-width: 300px;\n}\n\n.node-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 4px;\n margin-left: 12px;\n opacity: 0;\n transition: opacity 0.2s ease;\n}\n\n.node-content[_ngcontent-%COMP%]:hover .node-actions[_ngcontent-%COMP%] {\n opacity: 1;\n}\n\n.btn-node-action[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.btn-node-action[_ngcontent-%COMP%]:hover {\n background: var(--mj-status-success);\n border-color: var(--mj-status-success);\n color: var(--mj-text-inverse);\n}\n\n.btn-node-action[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 12px;\n}\n\n.children[_ngcontent-%COMP%] {\n margin-left: 0;\n}\n\n\n\n.empty-state[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 48px;\n color: var(--mj-text-secondary);\n text-align: center;\n}\n\n.empty-state[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 48px;\n margin-bottom: 16px;\n opacity: 0.5;\n}\n\n.empty-state[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n font-size: 16px;\n font-weight: 500;\n}\n\n.empty-state[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n font-size: 14px;\n margin-top: 8px;\n}\n\n\n\n\n\n\n\n\n[_nghost-%COMP%] .mj-window {\n border-radius: 16px !important;\n overflow: hidden;\n box-shadow: var(--mj-shadow-2xl) !important;\n background: var(--mj-bg-surface) !important;\n}\n\n[_nghost-%COMP%] .mj-window-body {\n padding: 0 !important;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n background: var(--mj-bg-surface) !important;\n}\n\n[_nghost-%COMP%] .mj-window-titlebar {\n display: flex !important;\n align-items: center;\n justify-content: space-between;\n padding: 18px 24px !important;\n background: var(--mj-bg-page) !important;\n border-bottom: 1px solid var(--mj-border-default) !important;\n}\n\n.dialog-title[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n font-weight: 600;\n font-size: 17px;\n color: var(--mj-text-primary);\n}\n\n.dialog-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-status-success);\n font-size: 18px;\n}\n\n.window-close-btn[_ngcontent-%COMP%] {\n margin-left: auto;\n color: var(--mj-text-muted);\n transition: all 0.2s ease;\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 8px;\n}\n\n.window-close-btn[_ngcontent-%COMP%]:hover {\n color: var(--mj-text-primary);\n background: var(--mj-bg-surface-hover);\n}\n\n.window-close-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 16px;\n}\n\n\n\n.dialog-content[_ngcontent-%COMP%] {\n padding: 24px;\n flex: 1;\n overflow-y: auto;\n}\n\n\n\n.form-field[_ngcontent-%COMP%] {\n margin-bottom: 20px;\n}\n\n.form-field[_ngcontent-%COMP%]:last-of-type {\n margin-bottom: 0;\n}\n\n.form-field[_ngcontent-%COMP%] label[_ngcontent-%COMP%] {\n display: block;\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin-bottom: 8px;\n letter-spacing: 0.01em;\n}\n\n.form-input[_ngcontent-%COMP%] {\n width: 100%;\n}\n\n.form-textarea[_ngcontent-%COMP%] {\n width: 100%;\n resize: vertical;\n min-height: 80px;\n}\n\n[_nghost-%COMP%] .form-input.mj-input, \n[_nghost-%COMP%] .form-textarea.mj-textarea, \n[_nghost-%COMP%] .form-field .mj-dropdown {\n padding: 10px 14px;\n border-radius: 8px;\n font-size: 14px;\n border-color: var(--mj-border-default);\n background: var(--mj-bg-surface) !important;\n color: var(--mj-text-primary) !important;\n transition: all 0.2s ease;\n}\n\n[_nghost-%COMP%] .form-input.mj-input:focus-within, \n[_nghost-%COMP%] .form-textarea.mj-textarea:focus-within, \n[_nghost-%COMP%] .form-field .mj-dropdown:focus-within {\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-status-success) 10%, transparent);\n}\n\n.field-hint[_ngcontent-%COMP%] {\n display: block;\n font-size: 12px;\n color: var(--mj-text-secondary);\n margin-top: 6px;\n line-height: 1.4;\n}\n\n.form-row[_ngcontent-%COMP%] {\n display: flex;\n gap: 16px;\n}\n\n.form-field.half[_ngcontent-%COMP%] {\n flex: 1;\n}\n\n.checkbox-label[_ngcontent-%COMP%] {\n display: flex;\n align-items: flex-start;\n gap: 12px;\n cursor: pointer;\n padding: 12px 16px;\n background: var(--mj-bg-page);\n border-radius: 10px;\n border: 1px solid var(--mj-border-default);\n transition: all 0.2s ease;\n}\n\n.checkbox-label[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n border-color: var(--mj-border-strong);\n}\n\n.checkbox-label[_ngcontent-%COMP%] input[_ngcontent-%COMP%] {\n margin-top: 2px;\n flex-shrink: 0;\n}\n\n.checkbox-label[_ngcontent-%COMP%] span[_ngcontent-%COMP%]:first-of-type {\n font-weight: 600;\n color: var(--mj-text-primary);\n font-size: 14px;\n}\n\n.checkbox-hint[_ngcontent-%COMP%] {\n display: block;\n font-size: 12px;\n color: var(--mj-text-secondary);\n margin-top: 4px;\n line-height: 1.4;\n}\n\n\n\n.dialog-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 12px;\n padding: 20px 24px;\n background: var(--mj-bg-page);\n border-top: 1px solid var(--mj-border-default);\n margin: 0 -24px -24px -24px;\n}\n\n[_nghost-%COMP%] .dialog-actions .mj-button {\n min-width: 100px;\n padding: 10px 20px;\n font-weight: 600;\n border-radius: 8px;\n transition: all 0.2s ease;\n}\n\n[_nghost-%COMP%] .dialog-actions .mj-button-primary {\n background: linear-gradient(135deg, var(--mj-status-success) 0%, var(--mj-color-success-600) 100%);\n border: none;\n box-shadow: 0 2px 8px color-mix(in srgb, var(--mj-status-success) 30%, transparent);\n}\n\n[_nghost-%COMP%] .dialog-actions .mj-button-primary:hover {\n transform: translateY(-1px);\n box-shadow: 0 4px 12px color-mix(in srgb, var(--mj-status-success) 40%, transparent);\n}"] });
|
|
641
634
|
}
|
|
642
635
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(APIScopesPanelComponent, [{
|
|
643
636
|
type: Component,
|
|
644
|
-
args: [{ standalone: false, selector: 'mj-api-scopes-panel', template: "<div class=\"scopes-panel\">\n @if (IsLoading) {\n <mj-loading text=\"Loading scopes...\"></mj-loading>\n }\n\n @if (!IsLoading) {\n <!-- Header -->\n <div class=\"panel-header\">\n <div class=\"header-left\">\n <h3 class=\"panel-title\">\n <i class=\"fa-solid fa-shield-halved\"></i>\n API Scopes\n </h3>\n <p class=\"panel-subtitle\">Manage hierarchical permission scopes for API access</p>\n </div>\n <div class=\"header-actions\">\n <div class=\"scope-stats\">\n <span class=\"stat\">\n <i class=\"fa-solid fa-shield\"></i>\n {{getTotalCount()}} total\n </span>\n <span class=\"stat active\">\n <i class=\"fa-solid fa-check-circle\"></i>\n {{getActiveCount()}} active\n </span>\n </div>\n <div class=\"tree-controls\">\n <button class=\"btn-icon\" (click)=\"expandAll()\" title=\"Expand All\">\n <i class=\"fa-solid fa-plus-square\"></i>\n </button>\n <button class=\"btn-icon\" (click)=\"collapseAll()\" title=\"Collapse All\">\n <i class=\"fa-solid fa-minus-square\"></i>\n </button>\n </div>\n <button class=\"btn-create\" (click)=\"openCreateDialog()\">\n <i class=\"fa-solid fa-plus\"></i>\n New Scope\n </button>\n </div>\n </div>\n <!-- Messages -->\n @if (SuccessMessage) {\n <div class=\"message success\">\n <i class=\"fa-solid fa-check-circle\"></i>\n {{SuccessMessage}}\n </div>\n }\n @if (ErrorMessage) {\n <div class=\"message error\">\n <i class=\"fa-solid fa-circle-exclamation\"></i>\n {{ErrorMessage}}\n </div>\n }\n <!-- Scope Tree -->\n <div class=\"scope-tree\">\n @for (node of ScopeTree; track node) {\n <ng-container *ngTemplateOutlet=\"scopeNode; context: { node: node }\"></ng-container>\n }\n <!-- Empty State -->\n @if (ScopeTree.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-shield-halved\"></i>\n <span>No scopes configured</span>\n <p>Create scopes to define API access permissions</p>\n </div>\n }\n </div>\n <!-- Recursive Node Template -->\n <ng-template #scopeNode let-node=\"node\">\n <div class=\"scope-node\" [style.padding-left.px]=\"node.level * 24\">\n <div class=\"node-content\" [class.inactive]=\"!node.scope.IsActive\">\n @if (node.children.length > 0) {\n <button class=\"expand-btn\"\n (click)=\"toggleExpanded(node)\">\n <i class=\"fa-solid\"\n [class.fa-chevron-right]=\"!node.expanded\"\n [class.fa-chevron-down]=\"node.expanded\"></i>\n </button>\n }\n @if (node.children.length === 0) {\n <span class=\"expand-placeholder\"></span>\n }\n <div class=\"scope-info\" (click)=\"openEditDialog(node.scope)\">\n <div class=\"scope-icon\" [style.backgroundColor]=\"getCategoryColor(node.scope.Category)\">\n <i class=\"fa-solid fa-shield\"></i>\n </div>\n <div class=\"scope-details\">\n <div class=\"scope-name\">\n {{node.scope.Name}}\n @if (node.scope.FullPath && node.scope.FullPath !== node.scope.Name) {\n <span class=\"full-path\">\n {{node.scope.FullPath}}\n </span>\n }\n @if (!node.scope.IsActive) {\n <span class=\"status-badge\">Inactive</span>\n }\n </div>\n <div class=\"scope-meta\">\n <span class=\"category\" [style.color]=\"getCategoryColor(node.scope.Category)\">\n {{node.scope.Category}}\n </span>\n @if (node.scope.ResourceType) {\n <span class=\"resource-type\">\n {{node.scope.ResourceType}}\n </span>\n }\n @if (node.scope.Description) {\n <span class=\"description\">\n {{node.scope.Description}}\n </span>\n }\n </div>\n </div>\n </div>\n <div class=\"node-actions\">\n <button class=\"btn-node-action\" (click)=\"openCreateDialog(node.scope)\" title=\"Add Child Scope\">\n <i class=\"fa-solid fa-plus\"></i>\n </button>\n <button class=\"btn-node-action\" (click)=\"openEditDialog(node.scope)\" title=\"Edit Scope\">\n <i class=\"fa-solid fa-pencil\"></i>\n </button>\n </div>\n </div>\n @if (node.expanded && node.children.length > 0) {\n <div class=\"children\">\n @for (child of node.children; track child) {\n <ng-container *ngTemplateOutlet=\"scopeNode; context: { node: child }\"></ng-container>\n }\n </div>\n }\n </div>\n </ng-template>\n }\n\n <!-- Create/Edit Dialog -->\n @if (ShowCreateDialog || ShowEditDialog) {\n <kendo-window\n [width]=\"560\"\n [minWidth]=\"420\"\n [minHeight]=\"480\"\n [resizable]=\"true\"\n [draggable]=\"true\"\n [top]=\"80\"\n (close)=\"closeDialogs()\">\n <kendo-window-titlebar>\n <div class=\"dialog-title\">\n <i class=\"fa-solid fa-shield-halved\"></i>\n <span>{{EditingScope ? 'Edit Scope' : 'New Scope'}}</span>\n </div>\n <button kendoButton fillMode=\"flat\" (click)=\"closeDialogs()\" class=\"window-close-btn\" title=\"Close (Esc)\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </kendo-window-titlebar>\n <div class=\"dialog-content\">\n <div class=\"form-field\">\n <label>Scope Name *</label>\n <input kendoTextBox [(ngModel)]=\"EditName\"\n placeholder=\"e.g., runview, create, execute\"\n class=\"form-input\" />\n <span class=\"field-hint\">Use lowercase, single word. Will be combined with parent for full path.</span>\n </div>\n <div class=\"form-field\">\n <label>Parent Scope</label>\n <kendo-dropdownlist [(ngModel)]=\"EditParentId\"\n [data]=\"getParentOptions()\"\n [textField]=\"'FullPath'\"\n [valueField]=\"'ID'\"\n [valuePrimitive]=\"true\"\n [defaultItem]=\"{ FullPath: '(No Parent - Root Level)', ID: null }\">\n </kendo-dropdownlist>\n @if (SelectedParentScope) {\n <span class=\"field-hint\">\n Full path will be: <code>{{SelectedParentScope.FullPath}}:{{EditName || '...'}}</code>\n </span>\n }\n </div>\n <div class=\"form-row\">\n <div class=\"form-field half\">\n <label>Category</label>\n <kendo-dropdownlist [(ngModel)]=\"EditCategory\"\n [data]=\"Categories\"\n [valuePrimitive]=\"true\">\n </kendo-dropdownlist>\n </div>\n <div class=\"form-field half\">\n <label>Resource Type</label>\n <kendo-dropdownlist [(ngModel)]=\"EditResourceType\"\n [data]=\"ResourceTypes\"\n [valuePrimitive]=\"true\"\n [defaultItem]=\"''\">\n </kendo-dropdownlist>\n </div>\n </div>\n <div class=\"form-field\">\n <label>Description</label>\n <textarea kendoTextArea [(ngModel)]=\"EditDescription\"\n placeholder=\"Describe what this scope allows...\"\n [rows]=\"3\"\n class=\"form-textarea\"></textarea>\n </div>\n <div class=\"form-field\">\n <label class=\"checkbox-label\">\n <input type=\"checkbox\" kendoCheckBox [(ngModel)]=\"EditIsActive\" />\n <div>\n <span>Active</span>\n <span class=\"checkbox-hint\">Inactive scopes cannot be assigned to keys or applications</span>\n </div>\n </label>\n </div>\n <div class=\"dialog-actions\">\n <button kendoButton [themeColor]=\"'primary'\"\n [disabled]=\"!EditName.trim() || IsSaving\"\n (click)=\"saveScope()\">\n @if (IsSaving) {\n <mj-loading [showText]=\"false\" size=\"small\"></mj-loading>\n }\n @if (!IsSaving) {\n <span>\n <i class=\"fa-solid fa-save\"></i>\n {{EditingScope ? 'Update' : 'Create'}}\n </span>\n }\n </button>\n <button kendoButton (click)=\"closeDialogs()\">Cancel</button>\n </div>\n </div>\n </kendo-window>\n }\n</div>\n", styles: [".scopes-panel {\n height: 100%;\n display: flex;\n flex-direction: column;\n}\n\n/* Panel Header */\n.panel-header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 24px;\n flex-wrap: wrap;\n gap: 16px;\n}\n\n.header-left {\n flex: 1;\n min-width: 200px;\n}\n\n.panel-title {\n display: flex;\n align-items: center;\n gap: 10px;\n font-size: 18px;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0 0 4px 0;\n}\n\n.panel-title i {\n color: var(--mj-status-success);\n}\n\n.panel-subtitle {\n font-size: 14px;\n color: var(--mj-text-secondary);\n margin: 0;\n}\n\n.header-actions {\n display: flex;\n align-items: center;\n gap: 16px;\n}\n\n.scope-stats {\n display: flex;\n gap: 16px;\n}\n\n.stat {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 13px;\n color: var(--mj-text-secondary);\n}\n\n.stat.active {\n color: var(--mj-status-success);\n}\n\n.stat i {\n font-size: 14px;\n}\n\n.tree-controls {\n display: flex;\n gap: 4px;\n}\n\n.btn-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.btn-icon:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.btn-icon i {\n font-size: 14px;\n color: var(--mj-text-secondary);\n}\n\n.btn-create {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 20px;\n background: linear-gradient(135deg, var(--mj-status-success) 0%, var(--mj-color-success-600) 100%);\n color: var(--mj-text-inverse);\n border: none;\n border-radius: 8px;\n font-weight: 600;\n font-size: 14px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.btn-create:hover {\n transform: translateY(-1px);\n box-shadow: 0 4px 12px color-mix(in srgb, var(--mj-status-success) 40%, transparent);\n}\n\n/* Messages */\n.message {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 12px 16px;\n border-radius: 8px;\n margin-bottom: 16px;\n font-size: 14px;\n}\n\n.message.success {\n background: var(--mj-color-success-100);\n color: var(--mj-color-success-800);\n border: 1px solid var(--mj-status-success-border);\n}\n\n.message.error {\n background: var(--mj-color-error-100);\n color: var(--mj-status-error);\n border: 1px solid var(--mj-status-error-border);\n}\n\n/* Scope Tree */\n.scope-tree {\n flex: 1;\n overflow-y: auto;\n background: var(--mj-bg-surface);\n border-radius: 12px;\n box-shadow: var(--mj-shadow-md);\n}\n\n.scope-node {\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.scope-node:last-child {\n border-bottom: none;\n}\n\n.node-content {\n display: flex;\n align-items: center;\n padding: 12px 16px;\n transition: background 0.2s ease;\n}\n\n.node-content:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.node-content.inactive {\n opacity: 0.6;\n}\n\n.expand-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n background: none;\n border: none;\n cursor: pointer;\n color: var(--mj-text-muted);\n transition: transform 0.2s ease;\n flex-shrink: 0;\n}\n\n.expand-btn:hover {\n color: var(--mj-text-secondary);\n}\n\n.expand-placeholder {\n width: 24px;\n flex-shrink: 0;\n}\n\n.scope-info {\n display: flex;\n align-items: center;\n flex: 1;\n min-width: 0;\n cursor: pointer;\n}\n\n.scope-icon {\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 8px;\n margin-right: 12px;\n flex-shrink: 0;\n}\n\n.scope-icon i {\n font-size: 14px;\n color: var(--mj-text-inverse);\n}\n\n.scope-details {\n flex: 1;\n min-width: 0;\n}\n\n.scope-name {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 14px;\n font-weight: 500;\n color: var(--mj-text-primary);\n flex-wrap: wrap;\n}\n\n.full-path {\n font-family: monospace;\n font-size: 12px;\n color: var(--mj-text-muted);\n background: var(--mj-bg-surface-sunken);\n padding: 2px 6px;\n border-radius: 4px;\n}\n\n.status-badge {\n font-size: 10px;\n font-weight: 500;\n padding: 2px 6px;\n border-radius: 4px;\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-secondary);\n}\n\n.scope-meta {\n display: flex;\n align-items: center;\n gap: 12px;\n margin-top: 4px;\n font-size: 12px;\n flex-wrap: wrap;\n}\n\n.category {\n font-weight: 500;\n}\n\n.resource-type {\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface-sunken);\n padding: 2px 6px;\n border-radius: 4px;\n}\n\n.description {\n color: var(--mj-text-muted);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n max-width: 300px;\n}\n\n.node-actions {\n display: flex;\n gap: 4px;\n margin-left: 12px;\n opacity: 0;\n transition: opacity 0.2s ease;\n}\n\n.node-content:hover .node-actions {\n opacity: 1;\n}\n\n.btn-node-action {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.btn-node-action:hover {\n background: var(--mj-status-success);\n border-color: var(--mj-status-success);\n color: var(--mj-text-inverse);\n}\n\n.btn-node-action i {\n font-size: 12px;\n}\n\n.children {\n margin-left: 0;\n}\n\n/* Empty State */\n.empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 48px;\n color: var(--mj-text-secondary);\n text-align: center;\n}\n\n.empty-state i {\n font-size: 48px;\n margin-bottom: 16px;\n opacity: 0.5;\n}\n\n.empty-state span {\n font-size: 16px;\n font-weight: 500;\n}\n\n.empty-state p {\n font-size: 14px;\n margin-top: 8px;\n}\n\n/* ========================================\n Dialog Styles - Polished & Professional\n ======================================== */\n\n/* Window styling */\n:host ::ng-deep kendo-window {\n border-radius: 16px !important;\n overflow: hidden;\n box-shadow: var(--mj-shadow-2xl) !important;\n background: var(--mj-bg-surface) !important;\n}\n\n:host ::ng-deep kendo-window .k-window-content {\n padding: 0 !important;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n background: var(--mj-bg-surface) !important;\n}\n\n:host ::ng-deep kendo-window-titlebar {\n display: flex !important;\n align-items: center;\n justify-content: space-between;\n padding: 18px 24px !important;\n background: var(--mj-bg-page) !important;\n border-bottom: 1px solid var(--mj-border-default) !important;\n}\n\n.dialog-title {\n display: flex;\n align-items: center;\n gap: 12px;\n font-weight: 600;\n font-size: 17px;\n color: var(--mj-text-primary);\n}\n\n.dialog-title i {\n color: var(--mj-status-success);\n font-size: 18px;\n}\n\n.window-close-btn {\n margin-left: auto;\n color: var(--mj-text-muted);\n transition: all 0.2s ease;\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 8px;\n}\n\n.window-close-btn:hover {\n color: var(--mj-text-primary);\n background: var(--mj-bg-surface-hover);\n}\n\n.window-close-btn i {\n font-size: 16px;\n}\n\n/* Dialog Content */\n.dialog-content {\n padding: 24px;\n flex: 1;\n overflow-y: auto;\n}\n\n/* Form Fields */\n.form-field {\n margin-bottom: 20px;\n}\n\n.form-field:last-of-type {\n margin-bottom: 0;\n}\n\n.form-field label {\n display: block;\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin-bottom: 8px;\n letter-spacing: 0.01em;\n}\n\n.form-input {\n width: 100%;\n}\n\n.form-textarea {\n width: 100%;\n resize: vertical;\n min-height: 80px;\n}\n\n:host ::ng-deep .form-input .k-input,\n:host ::ng-deep .form-textarea .k-input-inner,\n:host ::ng-deep .form-field .k-dropdownlist {\n padding: 10px 14px;\n border-radius: 8px;\n font-size: 14px;\n border-color: var(--mj-border-default);\n background: var(--mj-bg-surface) !important;\n color: var(--mj-text-primary) !important;\n transition: all 0.2s ease;\n}\n\n:host ::ng-deep .form-input:focus-within,\n:host ::ng-deep .form-textarea:focus-within,\n:host ::ng-deep .form-field .k-dropdownlist.k-focus {\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-status-success) 10%, transparent);\n}\n\n.field-hint {\n display: block;\n font-size: 12px;\n color: var(--mj-text-secondary);\n margin-top: 6px;\n line-height: 1.4;\n}\n\n.form-row {\n display: flex;\n gap: 16px;\n}\n\n.form-field.half {\n flex: 1;\n}\n\n.checkbox-label {\n display: flex;\n align-items: flex-start;\n gap: 12px;\n cursor: pointer;\n padding: 12px 16px;\n background: var(--mj-bg-page);\n border-radius: 10px;\n border: 1px solid var(--mj-border-default);\n transition: all 0.2s ease;\n}\n\n.checkbox-label:hover {\n background: var(--mj-bg-surface-sunken);\n border-color: var(--mj-border-strong);\n}\n\n.checkbox-label input {\n margin-top: 2px;\n flex-shrink: 0;\n}\n\n.checkbox-label span:first-of-type {\n font-weight: 600;\n color: var(--mj-text-primary);\n font-size: 14px;\n}\n\n.checkbox-hint {\n display: block;\n font-size: 12px;\n color: var(--mj-text-secondary);\n margin-top: 4px;\n line-height: 1.4;\n}\n\n/* Dialog Actions */\n.dialog-actions {\n display: flex;\n gap: 12px;\n padding: 20px 24px;\n background: var(--mj-bg-page);\n border-top: 1px solid var(--mj-border-default);\n margin: 0 -24px -24px -24px;\n}\n\n:host ::ng-deep .dialog-actions .k-button {\n min-width: 100px;\n padding: 10px 20px;\n font-weight: 600;\n border-radius: 8px;\n transition: all 0.2s ease;\n}\n\n:host ::ng-deep .dialog-actions .k-button-solid-primary {\n background: linear-gradient(135deg, var(--mj-status-success) 0%, var(--mj-color-success-600) 100%);\n border: none;\n box-shadow: 0 2px 8px color-mix(in srgb, var(--mj-status-success) 30%, transparent);\n}\n\n:host ::ng-deep .dialog-actions .k-button-solid-primary:hover {\n transform: translateY(-1px);\n box-shadow: 0 4px 12px color-mix(in srgb, var(--mj-status-success) 40%, transparent);\n}\n"] }]
|
|
637
|
+
args: [{ standalone: false, selector: 'mj-api-scopes-panel', template: "<div class=\"scopes-panel\">\n @if (IsLoading) {\n <mj-loading text=\"Loading scopes...\"></mj-loading>\n }\n\n @if (!IsLoading) {\n <!-- Header -->\n <div class=\"panel-header\">\n <div class=\"header-left\">\n <h3 class=\"panel-title\">\n <i class=\"fa-solid fa-shield-halved\"></i>\n API Scopes\n </h3>\n <p class=\"panel-subtitle\">Manage hierarchical permission scopes for API access</p>\n </div>\n <div class=\"header-actions\">\n <div class=\"scope-stats\">\n <span class=\"stat\">\n <i class=\"fa-solid fa-shield\"></i>\n {{getTotalCount()}} total\n </span>\n <span class=\"stat active\">\n <i class=\"fa-solid fa-check-circle\"></i>\n {{getActiveCount()}} active\n </span>\n </div>\n <div class=\"tree-controls\">\n <button class=\"btn-icon\" (click)=\"expandAll()\" title=\"Expand All\">\n <i class=\"fa-solid fa-plus-square\"></i>\n </button>\n <button class=\"btn-icon\" (click)=\"collapseAll()\" title=\"Collapse All\">\n <i class=\"fa-solid fa-minus-square\"></i>\n </button>\n </div>\n <button class=\"btn-create\" (click)=\"openCreateDialog()\">\n <i class=\"fa-solid fa-plus\"></i>\n New Scope\n </button>\n </div>\n </div>\n <!-- Messages -->\n @if (SuccessMessage) {\n <div class=\"message success\">\n <i class=\"fa-solid fa-check-circle\"></i>\n {{SuccessMessage}}\n </div>\n }\n @if (ErrorMessage) {\n <div class=\"message error\">\n <i class=\"fa-solid fa-circle-exclamation\"></i>\n {{ErrorMessage}}\n </div>\n }\n <!-- Scope Tree -->\n <div class=\"scope-tree\">\n @for (node of ScopeTree; track node) {\n <ng-container *ngTemplateOutlet=\"scopeNode; context: { node: node }\"></ng-container>\n }\n <!-- Empty State -->\n @if (ScopeTree.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-shield-halved\"></i>\n <span>No scopes configured</span>\n <p>Create scopes to define API access permissions</p>\n </div>\n }\n </div>\n <!-- Recursive Node Template -->\n <ng-template #scopeNode let-node=\"node\">\n <div class=\"scope-node\" [style.padding-left.px]=\"node.level * 24\">\n <div class=\"node-content\" [class.inactive]=\"!node.scope.IsActive\">\n @if (node.children.length > 0) {\n <button class=\"expand-btn\"\n (click)=\"toggleExpanded(node)\">\n <i class=\"fa-solid\"\n [class.fa-chevron-right]=\"!node.expanded\"\n [class.fa-chevron-down]=\"node.expanded\"></i>\n </button>\n }\n @if (node.children.length === 0) {\n <span class=\"expand-placeholder\"></span>\n }\n <div class=\"scope-info\" (click)=\"openEditDialog(node.scope)\">\n <div class=\"scope-icon\" [style.backgroundColor]=\"getCategoryColor(node.scope.Category)\">\n <i class=\"fa-solid fa-shield\"></i>\n </div>\n <div class=\"scope-details\">\n <div class=\"scope-name\">\n {{node.scope.Name}}\n @if (node.scope.FullPath && node.scope.FullPath !== node.scope.Name) {\n <span class=\"full-path\">\n {{node.scope.FullPath}}\n </span>\n }\n @if (!node.scope.IsActive) {\n <span class=\"status-badge\">Inactive</span>\n }\n </div>\n <div class=\"scope-meta\">\n <span class=\"category\" [style.color]=\"getCategoryColor(node.scope.Category)\">\n {{node.scope.Category}}\n </span>\n @if (node.scope.ResourceType) {\n <span class=\"resource-type\">\n {{node.scope.ResourceType}}\n </span>\n }\n @if (node.scope.Description) {\n <span class=\"description\">\n {{node.scope.Description}}\n </span>\n }\n </div>\n </div>\n </div>\n <div class=\"node-actions\">\n <button class=\"btn-node-action\" (click)=\"openCreateDialog(node.scope)\" title=\"Add Child Scope\">\n <i class=\"fa-solid fa-plus\"></i>\n </button>\n <button class=\"btn-node-action\" (click)=\"openEditDialog(node.scope)\" title=\"Edit Scope\">\n <i class=\"fa-solid fa-pencil\"></i>\n </button>\n </div>\n </div>\n @if (node.expanded && node.children.length > 0) {\n <div class=\"children\">\n @for (child of node.children; track child) {\n <ng-container *ngTemplateOutlet=\"scopeNode; context: { node: child }\"></ng-container>\n }\n </div>\n }\n </div>\n </ng-template>\n }\n\n <!-- Create/Edit Dialog -->\n @if (ShowCreateDialog || ShowEditDialog) {\n <mj-window\n [Width]=\"560\"\n [MinWidth]=\"420\"\n [MinHeight]=\"480\"\n [Resizable]=\"true\"\n [Draggable]=\"true\"\n [Visible]=\"true\"\n [Top]=\"80\"\n (Close)=\"closeDialogs()\">\n <mj-window-titlebar>\n <div class=\"dialog-title\">\n <i class=\"fa-solid fa-shield-halved\"></i>\n <span>{{EditingScope ? 'Edit Scope' : 'New Scope'}}</span>\n </div>\n </mj-window-titlebar>\n <div class=\"dialog-content\">\n <div class=\"form-field\">\n <label>Scope Name *</label>\n <input class=\"mj-input form-input\" [(ngModel)]=\"EditName\"\n placeholder=\"e.g., runview, create, execute\" />\n <span class=\"field-hint\">Use lowercase, single word. Will be combined with parent for full path.</span>\n </div>\n <div class=\"form-field\">\n <label>Parent Scope</label>\n <mj-dropdown [(ngModel)]=\"EditParentId\"\n [Data]=\"getParentOptions()\"\n TextField=\"FullPath\"\n ValueField=\"ID\"\n [ValuePrimitive]=\"true\"\n [DefaultItem]=\"{ FullPath: '(No Parent - Root Level)', ID: null }\">\n </mj-dropdown>\n @if (SelectedParentScope) {\n <span class=\"field-hint\">\n Full path will be: <code>{{SelectedParentScope.FullPath}}:{{EditName || '...'}}</code>\n </span>\n }\n </div>\n <div class=\"form-row\">\n <div class=\"form-field half\">\n <label>Category</label>\n <mj-dropdown [(ngModel)]=\"EditCategory\"\n [Data]=\"Categories\"\n [ValuePrimitive]=\"true\">\n </mj-dropdown>\n </div>\n <div class=\"form-field half\">\n <label>Resource Type</label>\n <mj-dropdown [(ngModel)]=\"EditResourceType\"\n [Data]=\"ResourceTypes\"\n [ValuePrimitive]=\"true\"\n [DefaultItem]=\"''\">\n </mj-dropdown>\n </div>\n </div>\n <div class=\"form-field\">\n <label>Description</label>\n <textarea class=\"mj-textarea form-textarea\" [(ngModel)]=\"EditDescription\"\n placeholder=\"Describe what this scope allows...\"\n [rows]=\"3\"></textarea>\n </div>\n <div class=\"form-field\">\n <label class=\"checkbox-label\">\n <input type=\"checkbox\" class=\"mj-checkbox\" [(ngModel)]=\"EditIsActive\" />\n <div>\n <span>Active</span>\n <span class=\"checkbox-hint\">Inactive scopes cannot be assigned to keys or applications</span>\n </div>\n </label>\n </div>\n <div class=\"dialog-actions\">\n <button mjButton variant=\"primary\"\n [disabled]=\"!EditName.trim() || IsSaving\"\n (click)=\"saveScope()\">\n @if (IsSaving) {\n <mj-loading [showText]=\"false\" size=\"small\"></mj-loading>\n }\n @if (!IsSaving) {\n <span>\n <i class=\"fa-solid fa-save\"></i>\n {{EditingScope ? 'Update' : 'Create'}}\n </span>\n }\n </button>\n <button mjButton (click)=\"closeDialogs()\">Cancel</button>\n </div>\n </div>\n </mj-window>\n }\n</div>\n", styles: [".scopes-panel {\n height: 100%;\n display: flex;\n flex-direction: column;\n}\n\n/* Panel Header */\n.panel-header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 24px;\n flex-wrap: wrap;\n gap: 16px;\n}\n\n.header-left {\n flex: 1;\n min-width: 200px;\n}\n\n.panel-title {\n display: flex;\n align-items: center;\n gap: 10px;\n font-size: 18px;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0 0 4px 0;\n}\n\n.panel-title i {\n color: var(--mj-status-success);\n}\n\n.panel-subtitle {\n font-size: 14px;\n color: var(--mj-text-secondary);\n margin: 0;\n}\n\n.header-actions {\n display: flex;\n align-items: center;\n gap: 16px;\n}\n\n.scope-stats {\n display: flex;\n gap: 16px;\n}\n\n.stat {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 13px;\n color: var(--mj-text-secondary);\n}\n\n.stat.active {\n color: var(--mj-status-success);\n}\n\n.stat i {\n font-size: 14px;\n}\n\n.tree-controls {\n display: flex;\n gap: 4px;\n}\n\n.btn-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.btn-icon:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.btn-icon i {\n font-size: 14px;\n color: var(--mj-text-secondary);\n}\n\n.btn-create {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 20px;\n background: linear-gradient(135deg, var(--mj-status-success) 0%, var(--mj-color-success-600) 100%);\n color: var(--mj-text-inverse);\n border: none;\n border-radius: 8px;\n font-weight: 600;\n font-size: 14px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.btn-create:hover {\n transform: translateY(-1px);\n box-shadow: 0 4px 12px color-mix(in srgb, var(--mj-status-success) 40%, transparent);\n}\n\n/* Messages */\n.message {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 12px 16px;\n border-radius: 8px;\n margin-bottom: 16px;\n font-size: 14px;\n}\n\n.message.success {\n background: var(--mj-color-success-100);\n color: var(--mj-color-success-800);\n border: 1px solid var(--mj-status-success-border);\n}\n\n.message.error {\n background: var(--mj-color-error-100);\n color: var(--mj-status-error);\n border: 1px solid var(--mj-status-error-border);\n}\n\n/* Scope Tree */\n.scope-tree {\n flex: 1;\n overflow-y: auto;\n background: var(--mj-bg-surface);\n border-radius: 12px;\n box-shadow: var(--mj-shadow-md);\n}\n\n.scope-node {\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.scope-node:last-child {\n border-bottom: none;\n}\n\n.node-content {\n display: flex;\n align-items: center;\n padding: 12px 16px;\n transition: background 0.2s ease;\n}\n\n.node-content:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.node-content.inactive {\n opacity: 0.6;\n}\n\n.expand-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n background: none;\n border: none;\n cursor: pointer;\n color: var(--mj-text-muted);\n transition: transform 0.2s ease;\n flex-shrink: 0;\n}\n\n.expand-btn:hover {\n color: var(--mj-text-secondary);\n}\n\n.expand-placeholder {\n width: 24px;\n flex-shrink: 0;\n}\n\n.scope-info {\n display: flex;\n align-items: center;\n flex: 1;\n min-width: 0;\n cursor: pointer;\n}\n\n.scope-icon {\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 8px;\n margin-right: 12px;\n flex-shrink: 0;\n}\n\n.scope-icon i {\n font-size: 14px;\n color: var(--mj-text-inverse);\n}\n\n.scope-details {\n flex: 1;\n min-width: 0;\n}\n\n.scope-name {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 14px;\n font-weight: 500;\n color: var(--mj-text-primary);\n flex-wrap: wrap;\n}\n\n.full-path {\n font-family: monospace;\n font-size: 12px;\n color: var(--mj-text-muted);\n background: var(--mj-bg-surface-sunken);\n padding: 2px 6px;\n border-radius: 4px;\n}\n\n.status-badge {\n font-size: 10px;\n font-weight: 500;\n padding: 2px 6px;\n border-radius: 4px;\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-secondary);\n}\n\n.scope-meta {\n display: flex;\n align-items: center;\n gap: 12px;\n margin-top: 4px;\n font-size: 12px;\n flex-wrap: wrap;\n}\n\n.category {\n font-weight: 500;\n}\n\n.resource-type {\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface-sunken);\n padding: 2px 6px;\n border-radius: 4px;\n}\n\n.description {\n color: var(--mj-text-muted);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n max-width: 300px;\n}\n\n.node-actions {\n display: flex;\n gap: 4px;\n margin-left: 12px;\n opacity: 0;\n transition: opacity 0.2s ease;\n}\n\n.node-content:hover .node-actions {\n opacity: 1;\n}\n\n.btn-node-action {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.btn-node-action:hover {\n background: var(--mj-status-success);\n border-color: var(--mj-status-success);\n color: var(--mj-text-inverse);\n}\n\n.btn-node-action i {\n font-size: 12px;\n}\n\n.children {\n margin-left: 0;\n}\n\n/* Empty State */\n.empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 48px;\n color: var(--mj-text-secondary);\n text-align: center;\n}\n\n.empty-state i {\n font-size: 48px;\n margin-bottom: 16px;\n opacity: 0.5;\n}\n\n.empty-state span {\n font-size: 16px;\n font-weight: 500;\n}\n\n.empty-state p {\n font-size: 14px;\n margin-top: 8px;\n}\n\n/* ========================================\n Dialog Styles - Polished & Professional\n ======================================== */\n\n/* Window styling */\n:host ::ng-deep .mj-window {\n border-radius: 16px !important;\n overflow: hidden;\n box-shadow: var(--mj-shadow-2xl) !important;\n background: var(--mj-bg-surface) !important;\n}\n\n:host ::ng-deep .mj-window-body {\n padding: 0 !important;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n background: var(--mj-bg-surface) !important;\n}\n\n:host ::ng-deep .mj-window-titlebar {\n display: flex !important;\n align-items: center;\n justify-content: space-between;\n padding: 18px 24px !important;\n background: var(--mj-bg-page) !important;\n border-bottom: 1px solid var(--mj-border-default) !important;\n}\n\n.dialog-title {\n display: flex;\n align-items: center;\n gap: 12px;\n font-weight: 600;\n font-size: 17px;\n color: var(--mj-text-primary);\n}\n\n.dialog-title i {\n color: var(--mj-status-success);\n font-size: 18px;\n}\n\n.window-close-btn {\n margin-left: auto;\n color: var(--mj-text-muted);\n transition: all 0.2s ease;\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 8px;\n}\n\n.window-close-btn:hover {\n color: var(--mj-text-primary);\n background: var(--mj-bg-surface-hover);\n}\n\n.window-close-btn i {\n font-size: 16px;\n}\n\n/* Dialog Content */\n.dialog-content {\n padding: 24px;\n flex: 1;\n overflow-y: auto;\n}\n\n/* Form Fields */\n.form-field {\n margin-bottom: 20px;\n}\n\n.form-field:last-of-type {\n margin-bottom: 0;\n}\n\n.form-field label {\n display: block;\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin-bottom: 8px;\n letter-spacing: 0.01em;\n}\n\n.form-input {\n width: 100%;\n}\n\n.form-textarea {\n width: 100%;\n resize: vertical;\n min-height: 80px;\n}\n\n:host ::ng-deep .form-input.mj-input,\n:host ::ng-deep .form-textarea.mj-textarea,\n:host ::ng-deep .form-field .mj-dropdown {\n padding: 10px 14px;\n border-radius: 8px;\n font-size: 14px;\n border-color: var(--mj-border-default);\n background: var(--mj-bg-surface) !important;\n color: var(--mj-text-primary) !important;\n transition: all 0.2s ease;\n}\n\n:host ::ng-deep .form-input.mj-input:focus-within,\n:host ::ng-deep .form-textarea.mj-textarea:focus-within,\n:host ::ng-deep .form-field .mj-dropdown:focus-within {\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-status-success) 10%, transparent);\n}\n\n.field-hint {\n display: block;\n font-size: 12px;\n color: var(--mj-text-secondary);\n margin-top: 6px;\n line-height: 1.4;\n}\n\n.form-row {\n display: flex;\n gap: 16px;\n}\n\n.form-field.half {\n flex: 1;\n}\n\n.checkbox-label {\n display: flex;\n align-items: flex-start;\n gap: 12px;\n cursor: pointer;\n padding: 12px 16px;\n background: var(--mj-bg-page);\n border-radius: 10px;\n border: 1px solid var(--mj-border-default);\n transition: all 0.2s ease;\n}\n\n.checkbox-label:hover {\n background: var(--mj-bg-surface-sunken);\n border-color: var(--mj-border-strong);\n}\n\n.checkbox-label input {\n margin-top: 2px;\n flex-shrink: 0;\n}\n\n.checkbox-label span:first-of-type {\n font-weight: 600;\n color: var(--mj-text-primary);\n font-size: 14px;\n}\n\n.checkbox-hint {\n display: block;\n font-size: 12px;\n color: var(--mj-text-secondary);\n margin-top: 4px;\n line-height: 1.4;\n}\n\n/* Dialog Actions */\n.dialog-actions {\n display: flex;\n gap: 12px;\n padding: 20px 24px;\n background: var(--mj-bg-page);\n border-top: 1px solid var(--mj-border-default);\n margin: 0 -24px -24px -24px;\n}\n\n:host ::ng-deep .dialog-actions .mj-button {\n min-width: 100px;\n padding: 10px 20px;\n font-weight: 600;\n border-radius: 8px;\n transition: all 0.2s ease;\n}\n\n:host ::ng-deep .dialog-actions .mj-button-primary {\n background: linear-gradient(135deg, var(--mj-status-success) 0%, var(--mj-color-success-600) 100%);\n border: none;\n box-shadow: 0 2px 8px color-mix(in srgb, var(--mj-status-success) 30%, transparent);\n}\n\n:host ::ng-deep .dialog-actions .mj-button-primary:hover {\n transform: translateY(-1px);\n box-shadow: 0 4px 12px color-mix(in srgb, var(--mj-status-success) 40%, transparent);\n}\n"] }]
|
|
645
638
|
}], () => [{ type: i0.ChangeDetectorRef }], { ScopeUpdated: [{
|
|
646
639
|
type: Output
|
|
647
640
|
}] }); })();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api-scopes-panel.component.js","sourceRoot":"","sources":["../../src/APIKeys/api-scopes-panel.component.ts","../../src/APIKeys/api-scopes-panel.component.html"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAU,YAAY,EAAE,MAAM,EAAqB,MAAM,eAAe,CAAC;AAC3F,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAEzD,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;;;;;;;;;;;;ICDhD,gCAAkD;;;IAwChD,+BAA6B;IAC3B,wBAAwC;IACxC,YACF;IAAA,iBAAM;;;IADJ,eACF;IADE,sDACF;;;IAGA,+BAA2B;IACzB,wBAA8C;IAC9C,YACF;IAAA,iBAAM;;;IADJ,eACF;IADE,oDACF;;;IAKE,wBAAoF;;;IAApF,gHAAqE;;;;;IAAzB,AAA7B,+CAA6B,gEAAuB;;;IAInE,+BAAyB;IACvB,uBAAyC;IACzC,4BAAM;IAAA,oCAAoB;IAAA,iBAAO;IACjC,yBAAG;IAAA,8DAA8C;IACnD,AADmD,iBAAI,EACjD;;;;IAQF,kCACiC;IAA/B,kQAAS,8BAAoB,KAAC;IAC9B,wBAE4C;IAC9C,iBAAS;;;IAFL,cAAyC;IAC3C,AADE,qDAAyC,qCACJ;;;IAIzC,2BAAwC;;;IAUlC,gCAAwB;IACtB,YACF;IAAA,iBAAO;;;IADL,cACF;IADE,uDACF;;;IAGA,gCAA2B;IAAA,wBAAQ;IAAA,iBAAO;;;IAQ1C,gCAA4B;IAC1B,YACF;IAAA,iBAAO;;;IADL,cACF;IADE,2DACF;;;IAGA,gCAA0B;IACxB,YACF;IAAA,iBAAO;;;IADL,cACF;IADE,0DACF;;;IAiBJ,wBAAqF;;;IAArF,6IAAsE;;;;;IAA1B,AAA7B,+CAA6B,iEAAwB;;;IAFxE,+BAAsB;IACpB,oKAEC;IACH,iBAAM;;;IAHJ,cAEC;IAFD,+BAEC;;;;IA1DL,AADF,+BAAkE,cACE;IAChE,0HAAgC;IAQhC,wHAAkC;IAGlC,+BAA6D;IAArC,6NAAS,oCAA0B,KAAC;IAC1D,+BAAwF;IACtF,wBAAkC;IACpC,iBAAM;IAEJ,AADF,+BAA2B,cACD;IACtB,YACA;IAAA,0HAAsE;IAKtE,0HAA4B;IAG9B,iBAAM;IAEJ,AADF,gCAAwB,gBACuD;IAC3E,aACF;IAAA,iBAAO;IACP,0HAA+B;IAK/B,0HAA8B;IAOpC,AADE,AADE,iBAAM,EACF,EACF;IAEJ,AADF,gCAA0B,kBACuE;IAA/D,iOAAS,sCAA4B,KAAC;IACpE,yBAAgC;IAClC,iBAAS;IACT,mCAAwF;IAAxD,iOAAS,oCAA0B,KAAC;IAClE,yBAAkC;IAGxC,AADE,AADE,iBAAS,EACL,EACF;IACN,yHAAiD;IAOnD,iBAAM;;;;IA9DkB,wDAAyC;IACrC,cAAuC;IAAvC,mDAAuC;IAC/D,cAOC;IAPD,sDAOC;IACD,cAEC;IAFD,wDAEC;IAEyB,eAA+D;IAA/D,mFAA+D;IAKnF,eACA;IADA,mDACA;IAAA,cAIC;IAJD,mGAIC;IACD,cAEC;IAFD,mDAEC;IAGsB,eAAqD;IAArD,wEAAqD;IAC1E,cACF;IADE,uDACF;IACA,cAIC;IAJD,sDAIC;IACD,cAIC;IAJD,qDAIC;IAaT,eAMC;IAND,2EAMC;;;;IAzHD,AADF,AADF,8BAA0B,aACC,YACC;IACtB,uBAAyC;IACzC,4BACF;IAAA,iBAAK;IACL,4BAA0B;IAAA,oEAAoD;IAChF,AADgF,iBAAI,EAC9E;IAGF,AADF,AADF,8BAA4B,cACD,eACJ;IACjB,yBAAkC;IAClC,aACF;IAAA,iBAAO;IACP,iCAA0B;IACxB,yBAAwC;IACxC,aACF;IACF,AADE,iBAAO,EACH;IAEJ,AADF,gCAA2B,kBACyC;IAAzC,4LAAS,kBAAW,KAAC;IAC5C,yBAAuC;IACzC,iBAAS;IACT,mCAAsE;IAA7C,4LAAS,oBAAa,KAAC;IAC9C,yBAAwC;IAE5C,AADE,iBAAS,EACL;IACN,mCAAwD;IAA7B,4LAAS,yBAAkB,KAAC;IACrD,yBAAgC;IAChC,4BACF;IAEJ,AADE,AADE,iBAAS,EACL,EACF;IAEN,0GAAsB;IAMtB,0GAAoB;IAOpB,gCAAwB;IACtB,wIAEC;IAED,0GAA8B;IAOhC,iBAAM;IAEN,2IAAwC;;;IAjDhC,gBACF;IADE,6DACF;IAGE,eACF;IADE,+DACF;IAiBN,eAKC;IALD,iDAKC;IACD,cAKC;IALD,+CAKC;IAGC,eAEC;IAFD,+BAEC;IAED,eAMC;IAND,yDAMC;;;IA2GK,gCAAyB;IACvB,oCAAmB;IAAA,4BAAM;IAAA,YAAsD;IACjF,AADiF,iBAAO,EACjF;;;IADoB,eAAsD;IAAtD,6FAAsD;;;IA0C/E,iCAAyD;;IAA7C,gCAAkB;;;IAG9B,4BAAM;IACJ,wBAAgC;IAChC,YACF;IAAA,iBAAO;;;IADL,eACF;IADE,0EACF;;;;IApFV,wCAO2B;IAAzB,iMAAS,qBAAc,KAAC;IAEtB,AADF,6CAAuB,cACK;IACxB,uBAAyC;IACzC,4BAAM;IAAA,YAA6C;IACrD,AADqD,iBAAO,EACtD;IACN,kCAA0G;IAAtE,2LAAS,qBAAc,KAAC;IAC1D,wBAAiC;IAErC,AADE,iBAAS,EACa;IAGpB,AADF,AADF,+BAA4B,cACF,aACf;IAAA,6BAAY;IAAA,iBAAQ;IAC3B,kCAEuB;IAFH,gTAAsB;IAA1C,iBAEuB;IACvB,iCAAyB;IAAA,wFAAuE;IAClG,AADkG,iBAAO,EACnG;IAEJ,AADF,gCAAwB,aACf;IAAA,6BAAY;IAAA,iBAAQ;IAC3B,+CAKqE;IALjD,qUAA0B;IAM9C,iBAAqB;IACrB,2GAA2B;IAK7B,iBAAM;IAGF,AADF,AADF,gCAAsB,eACS,aACpB;IAAA,yBAAQ;IAAA,iBAAQ;IACvB,+CAE0B;IAFN,qUAA0B;IAIhD,AADE,iBAAqB,EACjB;IAEJ,AADF,gCAA6B,aACpB;IAAA,8BAAa;IAAA,iBAAQ;IAC5B,+CAGqB;IAHD,6UAA8B;IAMtD,AADE,AADE,iBAAqB,EACjB,EACF;IAEJ,AADF,gCAAwB,aACf;IAAA,4BAAW;IAAA,iBAAQ;IAC1B,qCAGsB;IAHE,iUAA6B;IAIvD,AADwB,iBAAW,EAC7B;IAGF,AADF,AADF,gCAAwB,iBACQ,iBACsC;IAA7B,wTAA0B;IAA/D,iBAAkE;IAEhE,AADF,4BAAK,YACG;IAAA,uBAAM;IAAA,iBAAO;IACnB,iCAA4B;IAAA,2EAA0D;IAG5F,AADE,AADE,AADwF,iBAAO,EACzF,EACA,EACJ;IAEJ,AADF,gCAA4B,kBAGF;IAAtB,4LAAS,kBAAW,KAAC;IACrB,iHAAgB;IAGhB,uGAAiB;IAMnB,iBAAS;IACT,mCAA6C;IAAzB,4LAAS,qBAAc,KAAC;IAAC,uBAAM;IAGzD,AADE,AADE,AADqD,iBAAS,EACxD,EACF,EACO;;;IApFb,AADA,AADA,AADA,AADA,AADA,2BAAa,iBACG,kBACC,mBACC,mBACA,WACR;IAKA,eAA6C;IAA7C,sEAA6C;IAS/B,eAAsB;IAAtB,+CAAsB;IAOtB,eAA0B;IAA1B,mDAA0B;IAK5C,AADA,AADA,AADA,AADA,gDAA2B,yBACH,oBACL,wBACI,4CAC2C;IAEpE,cAIC;IAJD,sDAIC;IAKqB,eAA0B;IAA1B,mDAA0B;IAE5C,AADA,wCAAmB,wBACI;IAKL,eAA8B;IAA9B,uDAA8B;IAGhD,AADA,AADA,2CAAsB,wBACC,mBACL;IAME,eAA6B;IAA7B,sDAA6B;IAEnD,wBAAU;IAK2B,eAA0B;IAA1B,mDAA0B;IAQ7C,eAAwB;IAC1C,AADkB,sCAAwB,wDACD;IAEzC,cAEC;IAFD,2CAEC;IACD,cAKC;IALD,4CAKC;;ADlNb;;;GAGG;AAOH,MAAM,OAAO,uBAAuB;IACtB,YAAY,GAAG,IAAI,YAAY,EAAQ,CAAC;IAE1C,EAAE,GAAG,IAAI,QAAQ,EAAE,CAAC;IACpB,GAAG,CAAoB;IAE/B,iBAAiB;IACV,SAAS,GAAG,IAAI,CAAC;IACjB,QAAQ,GAAG,KAAK,CAAC;IAExB,OAAO;IACA,SAAS,GAAoB,EAAE,CAAC;IAChC,UAAU,GAAuB,EAAE,CAAC;IAE3C,aAAa;IACN,YAAY,GAA4B,IAAI,CAAC;IAC7C,QAAQ,GAAG,EAAE,CAAC;IACd,eAAe,GAAG,EAAE,CAAC;IACrB,YAAY,GAAG,EAAE,CAAC;IAClB,gBAAgB,GAAG,EAAE,CAAC;IACtB,YAAY,GAAkB,IAAI,CAAC;IACnC,YAAY,GAAG,IAAI,CAAC;IAE3B,gBAAgB;IACT,gBAAgB,GAAG,KAAK,CAAC;IACzB,cAAc,GAAG,KAAK,CAAC;IACvB,mBAAmB,GAA4B,IAAI,CAAC;IAE3D,WAAW;IACJ,cAAc,GAAG,EAAE,CAAC;IACpB,YAAY,GAAG,EAAE,CAAC;IAEzB,kBAAkB;IACF,cAAc,GAA2B;QACrD,UAAU,EAAE,SAAS;QACrB,QAAQ,EAAE,SAAS;QACnB,OAAO,EAAE,SAAS;QAClB,SAAS,EAAE,SAAS;QACpB,SAAS,EAAE,SAAS;QACpB,SAAS,EAAE,SAAS;QACpB,eAAe,EAAE,SAAS;QAC1B,OAAO,EAAE,SAAS;KACrB,CAAC;IAEF,wBAAwB;IACR,aAAa,GAAG,CAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IAC/F,UAAU,GAAG,CAAC,UAAU,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,eAAe,EAAE,OAAO,CAAC,CAAC;IAExH,YAAY,GAAsB;QAC9B,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;IACnB,CAAC;IAED,KAAK,CAAC,QAAQ;QACV,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC;IAC1B,CAAC;IAED;;OAEG;IACI,KAAK,CAAC,QAAQ;QACjB,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACtB,IAAI,CAAC;YACD,MAAM,EAAE,GAAG,IAAI,OAAO,EAAE,CAAC;YACzB,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,OAAO,CAAmB;gBAC9C,UAAU,EAAE,gBAAgB;gBAC5B,OAAO,EAAE,UAAU;gBACnB,UAAU,EAAE,eAAe;aAC9B,CAAC,CAAC;YAEH,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;gBACjB,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC;gBACjC,IAAI,CAAC,SAAS,EAAE,CAAC;YACrB,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,uBAAuB,EAAE,KAAK,CAAC,CAAC;YAC9C,IAAI,CAAC,YAAY,GAAG,uBAAuB,CAAC;QAChD,CAAC;gBAAS,CAAC;YACP,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;YACvB,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC;QAC5B,CAAC;IACL,CAAC;IAED;;OAEG;IACK,SAAS;QACb,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAyB,CAAC;QAClD,MAAM,SAAS,GAAoB,EAAE,CAAC;QAEtC,eAAe;QACf,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YAClC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE;gBACnB,KAAK;gBACL,QAAQ,EAAE,EAAE;gBACZ,QAAQ,EAAE,IAAI;gBACd,KAAK,EAAE,CAAC;aACX,CAAC,CAAC;QACP,CAAC;QAED,kBAAkB;QAClB,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YAClC,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAE,CAAC;YACrC,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;gBACjB,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;gBAC5C,IAAI,MAAM,EAAE,CAAC;oBACT,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;oBAC3B,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC;gBAClC,CAAC;qBAAM,CAAC;oBACJ,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACzB,CAAC;YACL,CAAC;iBAAM,CAAC;gBACJ,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACzB,CAAC;QACL,CAAC;QAED,+BAA+B;QAC/B,MAAM,eAAe,GAAG,CAAC,KAAsB,EAAE,KAAa,EAAE,EAAE;YAC9D,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;gBACvB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;gBACnB,eAAe,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;YAC9C,CAAC;QACL,CAAC,CAAC;QACF,eAAe,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;QAE9B,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;IAC/B,CAAC;IAED;;OAEG;IACI,gBAAgB,CAAC,cAAuC,IAAI;QAC/D,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAC;QACnB,IAAI,CAAC,eAAe,GAAG,EAAE,CAAC;QAC1B,IAAI,CAAC,YAAY,GAAG,WAAW,EAAE,QAAQ,IAAI,UAAU,CAAC;QACxD,IAAI,CAAC,gBAAgB,GAAG,EAAE,CAAC;QAC3B,IAAI,CAAC,YAAY,GAAG,WAAW,EAAE,EAAE,IAAI,IAAI,CAAC;QAC5C,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;QACzB,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;QACzB,IAAI,CAAC,mBAAmB,GAAG,WAAW,CAAC;QACvC,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;IACjC,CAAC;IAED;;OAEG;IACI,cAAc,CAAC,KAAuB;QACzC,IAAI,CAAC,YAAY,GAAG,KAAK,CAAC;QAC1B,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC;QAC3B,IAAI,CAAC,eAAe,GAAG,KAAK,CAAC,WAAW,IAAI,EAAE,CAAC;QAC/C,IAAI,CAAC,YAAY,GAAG,KAAK,CAAC,QAAQ,IAAI,UAAU,CAAC;QACjD,IAAI,CAAC,gBAAgB,GAAG,KAAK,CAAC,YAAY,IAAI,EAAE,CAAC;QACjD,IAAI,CAAC,YAAY,GAAG,KAAK,CAAC,QAAQ,CAAC;QACnC,IAAI,CAAC,YAAY,GAAG,KAAK,CAAC,QAAQ,CAAC;QACnC,IAAI,CAAC,mBAAmB,GAAG,KAAK,CAAC,QAAQ;YACrC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC,IAAI,IAAI;YACrE,CAAC,CAAC,IAAI,CAAC;QACX,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC;IAC/B,CAAC;IAED;;OAEG;IACI,KAAK,CAAC,SAAS;QAClB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACrB,IAAI,CAAC,YAAY,GAAG,EAAE,CAAC;QAEvB,IAAI,CAAC;YACD,IAAI,KAAuB,CAAC;YAE5B,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;gBACpB,KAAK,GAAG,IAAI,CAAC,YAAY,CAAC;YAC9B,CAAC;iBAAM,CAAC;gBACJ,KAAK,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,eAAe,CAAmB,gBAAgB,CAAC,CAAC;gBAC1E,KAAK,CAAC,SAAS,EAAE,CAAC;YACtB,CAAC;YAED,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;YAClC,KAAK,CAAC,WAAW,GAAG,IAAI,CAAC,eAAe,CAAC,IAAI,EAAE,IAAI,IAAI,CAAC;YACxD,KAAK,CAAC,QAAQ,GAAG,IAAI,CAAC,YAAY,CAAC;YACnC,KAAK,CAAC,YAAY,GAAG,IAAI,CAAC,gBAAgB,IAAI,IAAI,CAAC;YACnD,KAAK,CAAC,QAAQ,GAAG,IAAI,CAAC,YAAY,CAAC;YACnC,KAAK,CAAC,QAAQ,GAAG,IAAI,CAAC,YAAY,CAAC;YACnC,2CAA2C;YAE3C,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC;YAClC,IAAI,MAAM,EAAE,CAAC;gBACT,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,YAAY;oBACnC,CAAC,CAAC,4BAA4B;oBAC9B,CAAC,CAAC,4BAA4B,CAAC;gBACnC,IAAI,CAAC,YAAY,EAAE,CAAC;gBACpB,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACtB,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC;gBACzB,UAAU,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,cAAc,GAAG,EAAE,EAAE,IAAI,CAAC,CAAC;YACrD,CAAC;iBAAM,CAAC;gBACJ,IAAI,CAAC,YAAY,GAAG,sBAAsB,CAAC;YAC/C,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,qBAAqB,EAAE,KAAK,CAAC,CAAC;YAC5C,IAAI,CAAC,YAAY,GAAG,gCAAgC,CAAC;QACzD,CAAC;gBAAS,CAAC;YACP,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;QAC1B,CAAC;IACL,CAAC;IAED;;OAEG;IACI,cAAc,CAAC,IAAmB;QACrC,IAAI,CAAC,QAAQ,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC;IACnC,CAAC;IAED;;OAEG;IACI,SAAS;QACZ,MAAM,MAAM,GAAG,CAAC,KAAsB,EAAE,EAAE;YACtC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;gBACvB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;gBACrB,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAC1B,CAAC;QACL,CAAC,CAAC;QACF,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC3B,CAAC;IAED;;OAEG;IACI,WAAW;QACd,MAAM,QAAQ,GAAG,CAAC,KAAsB,EAAE,EAAE;YACxC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;gBACvB,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;gBACtB,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAC5B,CAAC;QACL,CAAC,CAAC;QACF,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC7B,CAAC;IAED;;OAEG;IACI,YAAY;QACf,IAAI,CAAC,gBAAgB,GAAG,KAAK,CAAC;QAC9B,IAAI,CAAC,cAAc,GAAG,KAAK,CAAC;QAC5B,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;QACzB,IAAI,CAAC,mBAAmB,GAAG,IAAI,CAAC;IACpC,CAAC;IAED;;OAEG;IACI,gBAAgB;QACnB,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC;YACrB,OAAO,IAAI,CAAC,UAAU,CAAC;QAC3B,CAAC;QAED,mCAAmC;QACnC,MAAM,UAAU,GAAG,IAAI,GAAG,CAAS,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,CAAC;QAC3D,MAAM,cAAc,GAAG,CAAC,QAAgB,EAAE,EAAE;YACxC,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;gBAClC,IAAI,UAAU,CAAC,KAAK,CAAC,QAAQ,EAAE,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC;oBACpE,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;oBACzB,cAAc,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;gBAC7B,CAAC;YACL,CAAC;QACL,CAAC,CAAC;QACF,cAAc,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;QAErC,OAAO,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC9D,CAAC;IAED;;OAEG;IACI,gBAAgB,CAAC,QAAuB;QAC3C,OAAO,IAAI,CAAC,cAAc,CAAC,QAAQ,IAAI,OAAO,CAAC,IAAI,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;IACpF,CAAC;IAED;;OAEG;IACI,aAAa;QAChB,OAAO,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC;IAClC,CAAC;IAED;;OAEG;IACI,cAAc;QACjB,OAAO,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC;IAC1D,CAAC;iHAjSQ,uBAAuB;6DAAvB,uBAAuB;YCtBpC,8BAA0B;YACxB,gGAAiB;YAIjB,gFAAkB;YAmIlB,oGAA0C;YA6F5C,iBAAM;;YApOJ,cAEC;YAFD,wCAEC;YAED,cAgIC;YAhID,yCAgIC;YAGD,cA4FC;YA5FD,qEA4FC;;;iFD9MU,uBAAuB;cANnC,SAAS;6BACI,KAAK,YACL,qBAAqB;;kBAK9B,MAAM;;kFADE,uBAAuB","sourcesContent":["import { Component, OnInit, EventEmitter, Output, ChangeDetectorRef } from '@angular/core';\nimport { Metadata, RunView } from '@memberjunction/core';\nimport { MJAPIScopeEntity } from '@memberjunction/core-entities';\nimport { UUIDsEqual } from '@memberjunction/global';\n/** Scope tree node structure */\ninterface ScopeTreeNode {\n scope: MJAPIScopeEntity;\n children: ScopeTreeNode[];\n expanded: boolean;\n level: number;\n}\n\n/**\n * API Scopes Panel Component\n * Manages API Scopes in a hierarchical tree structure\n */\n@Component({\n standalone: false,\n selector: 'mj-api-scopes-panel',\n templateUrl: './api-scopes-panel.component.html',\n styleUrls: ['./api-scopes-panel.component.css']\n})\nexport class APIScopesPanelComponent implements OnInit {\n @Output() ScopeUpdated = new EventEmitter<void>();\n\n private md = new Metadata();\n private cdr: ChangeDetectorRef;\n\n // Loading states\n public IsLoading = true;\n public IsSaving = false;\n\n // Data\n public ScopeTree: ScopeTreeNode[] = [];\n public FlatScopes: MJAPIScopeEntity[] = [];\n\n // Edit state\n public EditingScope: MJAPIScopeEntity | null = null;\n public EditName = '';\n public EditDescription = '';\n public EditCategory = '';\n public EditResourceType = '';\n public EditParentId: string | null = null;\n public EditIsActive = true;\n\n // Dialog states\n public ShowCreateDialog = false;\n public ShowEditDialog = false;\n public SelectedParentScope: MJAPIScopeEntity | null = null;\n\n // Messages\n public SuccessMessage = '';\n public ErrorMessage = '';\n\n // Category colors\n public readonly CategoryColors: Record<string, string> = {\n 'Entities': '#6366f1',\n 'Agents': '#10b981',\n 'Admin': '#f59e0b',\n 'Actions': '#8b5cf6',\n 'Queries': '#3b82f6',\n 'Reports': '#ef4444',\n 'Communication': '#ec4899',\n 'Other': '#6b7280'\n };\n\n // Resource type options\n public readonly ResourceTypes = ['Entity', 'Agent', 'Query', 'Mutation', 'Action', 'Report', 'Admin', 'Other'];\n public readonly Categories = ['Entities', 'Agents', 'Admin', 'Actions', 'Queries', 'Reports', 'Communication', 'Other'];\n\n constructor(cdr: ChangeDetectorRef) {\n this.cdr = cdr;\n }\n\n async ngOnInit(): Promise<void> {\n await this.loadData();\n }\n\n /**\n * Load all scopes\n */\n public async loadData(): Promise<void> {\n this.IsLoading = true;\n try {\n const rv = new RunView();\n const result = await rv.RunView<MJAPIScopeEntity>({\n EntityName: 'MJ: API Scopes',\n OrderBy: 'FullPath',\n ResultType: 'entity_object'\n });\n\n if (result.Success) {\n this.FlatScopes = result.Results;\n this.buildTree();\n }\n } catch (error) {\n console.error('Error loading scopes:', error);\n this.ErrorMessage = 'Failed to load scopes';\n } finally {\n this.IsLoading = false;\n this.cdr.markForCheck();\n }\n }\n\n /**\n * Build tree structure from flat scopes\n */\n private buildTree(): void {\n const scopeMap = new Map<string, ScopeTreeNode>();\n const rootNodes: ScopeTreeNode[] = [];\n\n // Create nodes\n for (const scope of this.FlatScopes) {\n scopeMap.set(scope.ID, {\n scope,\n children: [],\n expanded: true,\n level: 0\n });\n }\n\n // Build hierarchy\n for (const scope of this.FlatScopes) {\n const node = scopeMap.get(scope.ID)!;\n if (scope.ParentID) {\n const parent = scopeMap.get(scope.ParentID);\n if (parent) {\n parent.children.push(node);\n node.level = parent.level + 1;\n } else {\n rootNodes.push(node);\n }\n } else {\n rootNodes.push(node);\n }\n }\n\n // Calculate levels recursively\n const calculateLevels = (nodes: ScopeTreeNode[], level: number) => {\n for (const node of nodes) {\n node.level = level;\n calculateLevels(node.children, level + 1);\n }\n };\n calculateLevels(rootNodes, 0);\n\n this.ScopeTree = rootNodes;\n }\n\n /**\n * Open create dialog for new scope\n */\n public openCreateDialog(parentScope: MJAPIScopeEntity | null = null): void {\n this.EditName = '';\n this.EditDescription = '';\n this.EditCategory = parentScope?.Category || 'Entities';\n this.EditResourceType = '';\n this.EditParentId = parentScope?.ID || null;\n this.EditIsActive = true;\n this.EditingScope = null;\n this.SelectedParentScope = parentScope;\n this.ShowCreateDialog = true;\n }\n\n /**\n * Open edit dialog for existing scope\n */\n public openEditDialog(scope: MJAPIScopeEntity): void {\n this.EditingScope = scope;\n this.EditName = scope.Name;\n this.EditDescription = scope.Description || '';\n this.EditCategory = scope.Category || 'Entities';\n this.EditResourceType = scope.ResourceType || '';\n this.EditParentId = scope.ParentID;\n this.EditIsActive = scope.IsActive;\n this.SelectedParentScope = scope.ParentID\n ? this.FlatScopes.find(s => UUIDsEqual(s.ID, scope.ParentID)) || null\n : null;\n this.ShowEditDialog = true;\n }\n\n /**\n * Save scope (create or update)\n */\n public async saveScope(): Promise<void> {\n this.IsSaving = true;\n this.ErrorMessage = '';\n\n try {\n let scope: MJAPIScopeEntity;\n\n if (this.EditingScope) {\n scope = this.EditingScope;\n } else {\n scope = await this.md.GetEntityObject<MJAPIScopeEntity>('MJ: API Scopes');\n scope.NewRecord();\n }\n\n scope.Name = this.EditName.trim();\n scope.Description = this.EditDescription.trim() || null;\n scope.Category = this.EditCategory;\n scope.ResourceType = this.EditResourceType || null;\n scope.ParentID = this.EditParentId;\n scope.IsActive = this.EditIsActive;\n // FullPath is auto-computed by the trigger\n\n const result = await scope.Save();\n if (result) {\n this.SuccessMessage = this.EditingScope\n ? 'Scope updated successfully'\n : 'Scope created successfully';\n this.closeDialogs();\n await this.loadData();\n this.ScopeUpdated.emit();\n setTimeout(() => this.SuccessMessage = '', 3000);\n } else {\n this.ErrorMessage = 'Failed to save scope';\n }\n } catch (error) {\n console.error('Error saving scope:', error);\n this.ErrorMessage = 'An error occurred while saving';\n } finally {\n this.IsSaving = false;\n }\n }\n\n /**\n * Toggle node expansion\n */\n public toggleExpanded(node: ScopeTreeNode): void {\n node.expanded = !node.expanded;\n }\n\n /**\n * Expand all nodes\n */\n public expandAll(): void {\n const expand = (nodes: ScopeTreeNode[]) => {\n for (const node of nodes) {\n node.expanded = true;\n expand(node.children);\n }\n };\n expand(this.ScopeTree);\n }\n\n /**\n * Collapse all nodes\n */\n public collapseAll(): void {\n const collapse = (nodes: ScopeTreeNode[]) => {\n for (const node of nodes) {\n node.expanded = false;\n collapse(node.children);\n }\n };\n collapse(this.ScopeTree);\n }\n\n /**\n * Close all dialogs\n */\n public closeDialogs(): void {\n this.ShowCreateDialog = false;\n this.ShowEditDialog = false;\n this.EditingScope = null;\n this.SelectedParentScope = null;\n }\n\n /**\n * Get parent scopes for dropdown (exclude self and descendants)\n */\n public getParentOptions(): MJAPIScopeEntity[] {\n if (!this.EditingScope) {\n return this.FlatScopes;\n }\n\n // Exclude self and all descendants\n const excludeIds = new Set<string>([this.EditingScope.ID]);\n const addDescendants = (parentId: string) => {\n for (const scope of this.FlatScopes) {\n if (UUIDsEqual(scope.ParentID, parentId) && !excludeIds.has(scope.ID)) {\n excludeIds.add(scope.ID);\n addDescendants(scope.ID);\n }\n }\n };\n addDescendants(this.EditingScope.ID);\n\n return this.FlatScopes.filter(s => !excludeIds.has(s.ID));\n }\n\n /**\n * Get category color\n */\n public getCategoryColor(category: string | null): string {\n return this.CategoryColors[category || 'Other'] || this.CategoryColors['Other'];\n }\n\n /**\n * Get count of total scopes\n */\n public getTotalCount(): number {\n return this.FlatScopes.length;\n }\n\n /**\n * Get count of active scopes\n */\n public getActiveCount(): number {\n return this.FlatScopes.filter(s => s.IsActive).length;\n }\n}\n","<div class=\"scopes-panel\">\n @if (IsLoading) {\n <mj-loading text=\"Loading scopes...\"></mj-loading>\n }\n\n @if (!IsLoading) {\n <!-- Header -->\n <div class=\"panel-header\">\n <div class=\"header-left\">\n <h3 class=\"panel-title\">\n <i class=\"fa-solid fa-shield-halved\"></i>\n API Scopes\n </h3>\n <p class=\"panel-subtitle\">Manage hierarchical permission scopes for API access</p>\n </div>\n <div class=\"header-actions\">\n <div class=\"scope-stats\">\n <span class=\"stat\">\n <i class=\"fa-solid fa-shield\"></i>\n {{getTotalCount()}} total\n </span>\n <span class=\"stat active\">\n <i class=\"fa-solid fa-check-circle\"></i>\n {{getActiveCount()}} active\n </span>\n </div>\n <div class=\"tree-controls\">\n <button class=\"btn-icon\" (click)=\"expandAll()\" title=\"Expand All\">\n <i class=\"fa-solid fa-plus-square\"></i>\n </button>\n <button class=\"btn-icon\" (click)=\"collapseAll()\" title=\"Collapse All\">\n <i class=\"fa-solid fa-minus-square\"></i>\n </button>\n </div>\n <button class=\"btn-create\" (click)=\"openCreateDialog()\">\n <i class=\"fa-solid fa-plus\"></i>\n New Scope\n </button>\n </div>\n </div>\n <!-- Messages -->\n @if (SuccessMessage) {\n <div class=\"message success\">\n <i class=\"fa-solid fa-check-circle\"></i>\n {{SuccessMessage}}\n </div>\n }\n @if (ErrorMessage) {\n <div class=\"message error\">\n <i class=\"fa-solid fa-circle-exclamation\"></i>\n {{ErrorMessage}}\n </div>\n }\n <!-- Scope Tree -->\n <div class=\"scope-tree\">\n @for (node of ScopeTree; track node) {\n <ng-container *ngTemplateOutlet=\"scopeNode; context: { node: node }\"></ng-container>\n }\n <!-- Empty State -->\n @if (ScopeTree.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-shield-halved\"></i>\n <span>No scopes configured</span>\n <p>Create scopes to define API access permissions</p>\n </div>\n }\n </div>\n <!-- Recursive Node Template -->\n <ng-template #scopeNode let-node=\"node\">\n <div class=\"scope-node\" [style.padding-left.px]=\"node.level * 24\">\n <div class=\"node-content\" [class.inactive]=\"!node.scope.IsActive\">\n @if (node.children.length > 0) {\n <button class=\"expand-btn\"\n (click)=\"toggleExpanded(node)\">\n <i class=\"fa-solid\"\n [class.fa-chevron-right]=\"!node.expanded\"\n [class.fa-chevron-down]=\"node.expanded\"></i>\n </button>\n }\n @if (node.children.length === 0) {\n <span class=\"expand-placeholder\"></span>\n }\n <div class=\"scope-info\" (click)=\"openEditDialog(node.scope)\">\n <div class=\"scope-icon\" [style.backgroundColor]=\"getCategoryColor(node.scope.Category)\">\n <i class=\"fa-solid fa-shield\"></i>\n </div>\n <div class=\"scope-details\">\n <div class=\"scope-name\">\n {{node.scope.Name}}\n @if (node.scope.FullPath && node.scope.FullPath !== node.scope.Name) {\n <span class=\"full-path\">\n {{node.scope.FullPath}}\n </span>\n }\n @if (!node.scope.IsActive) {\n <span class=\"status-badge\">Inactive</span>\n }\n </div>\n <div class=\"scope-meta\">\n <span class=\"category\" [style.color]=\"getCategoryColor(node.scope.Category)\">\n {{node.scope.Category}}\n </span>\n @if (node.scope.ResourceType) {\n <span class=\"resource-type\">\n {{node.scope.ResourceType}}\n </span>\n }\n @if (node.scope.Description) {\n <span class=\"description\">\n {{node.scope.Description}}\n </span>\n }\n </div>\n </div>\n </div>\n <div class=\"node-actions\">\n <button class=\"btn-node-action\" (click)=\"openCreateDialog(node.scope)\" title=\"Add Child Scope\">\n <i class=\"fa-solid fa-plus\"></i>\n </button>\n <button class=\"btn-node-action\" (click)=\"openEditDialog(node.scope)\" title=\"Edit Scope\">\n <i class=\"fa-solid fa-pencil\"></i>\n </button>\n </div>\n </div>\n @if (node.expanded && node.children.length > 0) {\n <div class=\"children\">\n @for (child of node.children; track child) {\n <ng-container *ngTemplateOutlet=\"scopeNode; context: { node: child }\"></ng-container>\n }\n </div>\n }\n </div>\n </ng-template>\n }\n\n <!-- Create/Edit Dialog -->\n @if (ShowCreateDialog || ShowEditDialog) {\n <kendo-window\n [width]=\"560\"\n [minWidth]=\"420\"\n [minHeight]=\"480\"\n [resizable]=\"true\"\n [draggable]=\"true\"\n [top]=\"80\"\n (close)=\"closeDialogs()\">\n <kendo-window-titlebar>\n <div class=\"dialog-title\">\n <i class=\"fa-solid fa-shield-halved\"></i>\n <span>{{EditingScope ? 'Edit Scope' : 'New Scope'}}</span>\n </div>\n <button kendoButton fillMode=\"flat\" (click)=\"closeDialogs()\" class=\"window-close-btn\" title=\"Close (Esc)\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </kendo-window-titlebar>\n <div class=\"dialog-content\">\n <div class=\"form-field\">\n <label>Scope Name *</label>\n <input kendoTextBox [(ngModel)]=\"EditName\"\n placeholder=\"e.g., runview, create, execute\"\n class=\"form-input\" />\n <span class=\"field-hint\">Use lowercase, single word. Will be combined with parent for full path.</span>\n </div>\n <div class=\"form-field\">\n <label>Parent Scope</label>\n <kendo-dropdownlist [(ngModel)]=\"EditParentId\"\n [data]=\"getParentOptions()\"\n [textField]=\"'FullPath'\"\n [valueField]=\"'ID'\"\n [valuePrimitive]=\"true\"\n [defaultItem]=\"{ FullPath: '(No Parent - Root Level)', ID: null }\">\n </kendo-dropdownlist>\n @if (SelectedParentScope) {\n <span class=\"field-hint\">\n Full path will be: <code>{{SelectedParentScope.FullPath}}:{{EditName || '...'}}</code>\n </span>\n }\n </div>\n <div class=\"form-row\">\n <div class=\"form-field half\">\n <label>Category</label>\n <kendo-dropdownlist [(ngModel)]=\"EditCategory\"\n [data]=\"Categories\"\n [valuePrimitive]=\"true\">\n </kendo-dropdownlist>\n </div>\n <div class=\"form-field half\">\n <label>Resource Type</label>\n <kendo-dropdownlist [(ngModel)]=\"EditResourceType\"\n [data]=\"ResourceTypes\"\n [valuePrimitive]=\"true\"\n [defaultItem]=\"''\">\n </kendo-dropdownlist>\n </div>\n </div>\n <div class=\"form-field\">\n <label>Description</label>\n <textarea kendoTextArea [(ngModel)]=\"EditDescription\"\n placeholder=\"Describe what this scope allows...\"\n [rows]=\"3\"\n class=\"form-textarea\"></textarea>\n </div>\n <div class=\"form-field\">\n <label class=\"checkbox-label\">\n <input type=\"checkbox\" kendoCheckBox [(ngModel)]=\"EditIsActive\" />\n <div>\n <span>Active</span>\n <span class=\"checkbox-hint\">Inactive scopes cannot be assigned to keys or applications</span>\n </div>\n </label>\n </div>\n <div class=\"dialog-actions\">\n <button kendoButton [themeColor]=\"'primary'\"\n [disabled]=\"!EditName.trim() || IsSaving\"\n (click)=\"saveScope()\">\n @if (IsSaving) {\n <mj-loading [showText]=\"false\" size=\"small\"></mj-loading>\n }\n @if (!IsSaving) {\n <span>\n <i class=\"fa-solid fa-save\"></i>\n {{EditingScope ? 'Update' : 'Create'}}\n </span>\n }\n </button>\n <button kendoButton (click)=\"closeDialogs()\">Cancel</button>\n </div>\n </div>\n </kendo-window>\n }\n</div>\n"]}
|
|
1
|
+
{"version":3,"file":"api-scopes-panel.component.js","sourceRoot":"","sources":["../../src/APIKeys/api-scopes-panel.component.ts","../../src/APIKeys/api-scopes-panel.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, OnInit, EventEmitter, Output, ChangeDetectorRef } from '@angular/core';\nimport { Metadata, RunView } from '@memberjunction/core';\nimport { MJAPIScopeEntity } from '@memberjunction/core-entities';\nimport { UUIDsEqual } from '@memberjunction/global';\n/** Scope tree node structure */\ninterface ScopeTreeNode {\n scope: MJAPIScopeEntity;\n children: ScopeTreeNode[];\n expanded: boolean;\n level: number;\n}\n\n/**\n * API Scopes Panel Component\n * Manages API Scopes in a hierarchical tree structure\n */\n@Component({\n standalone: false,\n selector: 'mj-api-scopes-panel',\n templateUrl: './api-scopes-panel.component.html',\n styleUrls: ['./api-scopes-panel.component.css']\n})\nexport class APIScopesPanelComponent implements OnInit {\n @Output() ScopeUpdated = new EventEmitter<void>();\n\n private md = new Metadata();\n private cdr: ChangeDetectorRef;\n\n // Loading states\n public IsLoading = true;\n public IsSaving = false;\n\n // Data\n public ScopeTree: ScopeTreeNode[] = [];\n public FlatScopes: MJAPIScopeEntity[] = [];\n\n // Edit state\n public EditingScope: MJAPIScopeEntity | null = null;\n public EditName = '';\n public EditDescription = '';\n public EditCategory = '';\n public EditResourceType = '';\n public EditParentId: string | null = null;\n public EditIsActive = true;\n\n // Dialog states\n public ShowCreateDialog = false;\n public ShowEditDialog = false;\n public SelectedParentScope: MJAPIScopeEntity | null = null;\n\n // Messages\n public SuccessMessage = '';\n public ErrorMessage = '';\n\n // Category colors\n public readonly CategoryColors: Record<string, string> = {\n 'Entities': '#6366f1',\n 'Agents': '#10b981',\n 'Admin': '#f59e0b',\n 'Actions': '#8b5cf6',\n 'Queries': '#3b82f6',\n 'Reports': '#ef4444',\n 'Communication': '#ec4899',\n 'Other': '#6b7280'\n };\n\n // Resource type options\n public readonly ResourceTypes = ['Entity', 'Agent', 'Query', 'Mutation', 'Action', 'Report', 'Admin', 'Other'];\n public readonly Categories = ['Entities', 'Agents', 'Admin', 'Actions', 'Queries', 'Reports', 'Communication', 'Other'];\n\n constructor(cdr: ChangeDetectorRef) {\n this.cdr = cdr;\n }\n\n async ngOnInit(): Promise<void> {\n await this.loadData();\n }\n\n /**\n * Load all scopes\n */\n public async loadData(): Promise<void> {\n this.IsLoading = true;\n try {\n const rv = new RunView();\n const result = await rv.RunView<MJAPIScopeEntity>({\n EntityName: 'MJ: API Scopes',\n OrderBy: 'FullPath',\n ResultType: 'entity_object'\n });\n\n if (result.Success) {\n this.FlatScopes = result.Results;\n this.buildTree();\n }\n } catch (error) {\n console.error('Error loading scopes:', error);\n this.ErrorMessage = 'Failed to load scopes';\n } finally {\n this.IsLoading = false;\n this.cdr.markForCheck();\n }\n }\n\n /**\n * Build tree structure from flat scopes\n */\n private buildTree(): void {\n const scopeMap = new Map<string, ScopeTreeNode>();\n const rootNodes: ScopeTreeNode[] = [];\n\n // Create nodes\n for (const scope of this.FlatScopes) {\n scopeMap.set(scope.ID, {\n scope,\n children: [],\n expanded: true,\n level: 0\n });\n }\n\n // Build hierarchy\n for (const scope of this.FlatScopes) {\n const node = scopeMap.get(scope.ID)!;\n if (scope.ParentID) {\n const parent = scopeMap.get(scope.ParentID);\n if (parent) {\n parent.children.push(node);\n node.level = parent.level + 1;\n } else {\n rootNodes.push(node);\n }\n } else {\n rootNodes.push(node);\n }\n }\n\n // Calculate levels recursively\n const calculateLevels = (nodes: ScopeTreeNode[], level: number) => {\n for (const node of nodes) {\n node.level = level;\n calculateLevels(node.children, level + 1);\n }\n };\n calculateLevels(rootNodes, 0);\n\n this.ScopeTree = rootNodes;\n }\n\n /**\n * Open create dialog for new scope\n */\n public openCreateDialog(parentScope: MJAPIScopeEntity | null = null): void {\n this.EditName = '';\n this.EditDescription = '';\n this.EditCategory = parentScope?.Category || 'Entities';\n this.EditResourceType = '';\n this.EditParentId = parentScope?.ID || null;\n this.EditIsActive = true;\n this.EditingScope = null;\n this.SelectedParentScope = parentScope;\n this.ShowCreateDialog = true;\n }\n\n /**\n * Open edit dialog for existing scope\n */\n public openEditDialog(scope: MJAPIScopeEntity): void {\n this.EditingScope = scope;\n this.EditName = scope.Name;\n this.EditDescription = scope.Description || '';\n this.EditCategory = scope.Category || 'Entities';\n this.EditResourceType = scope.ResourceType || '';\n this.EditParentId = scope.ParentID;\n this.EditIsActive = scope.IsActive;\n this.SelectedParentScope = scope.ParentID\n ? this.FlatScopes.find(s => UUIDsEqual(s.ID, scope.ParentID)) || null\n : null;\n this.ShowEditDialog = true;\n }\n\n /**\n * Save scope (create or update)\n */\n public async saveScope(): Promise<void> {\n this.IsSaving = true;\n this.ErrorMessage = '';\n\n try {\n let scope: MJAPIScopeEntity;\n\n if (this.EditingScope) {\n scope = this.EditingScope;\n } else {\n scope = await this.md.GetEntityObject<MJAPIScopeEntity>('MJ: API Scopes');\n scope.NewRecord();\n }\n\n scope.Name = this.EditName.trim();\n scope.Description = this.EditDescription.trim() || null;\n scope.Category = this.EditCategory;\n scope.ResourceType = this.EditResourceType || null;\n scope.ParentID = this.EditParentId;\n scope.IsActive = this.EditIsActive;\n // FullPath is auto-computed by the trigger\n\n const result = await scope.Save();\n if (result) {\n this.SuccessMessage = this.EditingScope\n ? 'Scope updated successfully'\n : 'Scope created successfully';\n this.closeDialogs();\n await this.loadData();\n this.ScopeUpdated.emit();\n setTimeout(() => this.SuccessMessage = '', 3000);\n } else {\n this.ErrorMessage = 'Failed to save scope';\n }\n } catch (error) {\n console.error('Error saving scope:', error);\n this.ErrorMessage = 'An error occurred while saving';\n } finally {\n this.IsSaving = false;\n }\n }\n\n /**\n * Toggle node expansion\n */\n public toggleExpanded(node: ScopeTreeNode): void {\n node.expanded = !node.expanded;\n }\n\n /**\n * Expand all nodes\n */\n public expandAll(): void {\n const expand = (nodes: ScopeTreeNode[]) => {\n for (const node of nodes) {\n node.expanded = true;\n expand(node.children);\n }\n };\n expand(this.ScopeTree);\n }\n\n /**\n * Collapse all nodes\n */\n public collapseAll(): void {\n const collapse = (nodes: ScopeTreeNode[]) => {\n for (const node of nodes) {\n node.expanded = false;\n collapse(node.children);\n }\n };\n collapse(this.ScopeTree);\n }\n\n /**\n * Close all dialogs\n */\n public closeDialogs(): void {\n this.ShowCreateDialog = false;\n this.ShowEditDialog = false;\n this.EditingScope = null;\n this.SelectedParentScope = null;\n }\n\n /**\n * Get parent scopes for dropdown (exclude self and descendants)\n */\n public getParentOptions(): MJAPIScopeEntity[] {\n if (!this.EditingScope) {\n return this.FlatScopes;\n }\n\n // Exclude self and all descendants\n const excludeIds = new Set<string>([this.EditingScope.ID]);\n const addDescendants = (parentId: string) => {\n for (const scope of this.FlatScopes) {\n if (UUIDsEqual(scope.ParentID, parentId) && !excludeIds.has(scope.ID)) {\n excludeIds.add(scope.ID);\n addDescendants(scope.ID);\n }\n }\n };\n addDescendants(this.EditingScope.ID);\n\n return this.FlatScopes.filter(s => !excludeIds.has(s.ID));\n }\n\n /**\n * Get category color\n */\n public getCategoryColor(category: string | null): string {\n return this.CategoryColors[category || 'Other'] || this.CategoryColors['Other'];\n }\n\n /**\n * Get count of total scopes\n */\n public getTotalCount(): number {\n return this.FlatScopes.length;\n }\n\n /**\n * Get count of active scopes\n */\n public getActiveCount(): number {\n return this.FlatScopes.filter(s => s.IsActive).length;\n }\n}\n","<div class=\"scopes-panel\">\n @if (IsLoading) {\n <mj-loading text=\"Loading scopes...\"></mj-loading>\n }\n\n @if (!IsLoading) {\n <!-- Header -->\n <div class=\"panel-header\">\n <div class=\"header-left\">\n <h3 class=\"panel-title\">\n <i class=\"fa-solid fa-shield-halved\"></i>\n API Scopes\n </h3>\n <p class=\"panel-subtitle\">Manage hierarchical permission scopes for API access</p>\n </div>\n <div class=\"header-actions\">\n <div class=\"scope-stats\">\n <span class=\"stat\">\n <i class=\"fa-solid fa-shield\"></i>\n {{getTotalCount()}} total\n </span>\n <span class=\"stat active\">\n <i class=\"fa-solid fa-check-circle\"></i>\n {{getActiveCount()}} active\n </span>\n </div>\n <div class=\"tree-controls\">\n <button class=\"btn-icon\" (click)=\"expandAll()\" title=\"Expand All\">\n <i class=\"fa-solid fa-plus-square\"></i>\n </button>\n <button class=\"btn-icon\" (click)=\"collapseAll()\" title=\"Collapse All\">\n <i class=\"fa-solid fa-minus-square\"></i>\n </button>\n </div>\n <button class=\"btn-create\" (click)=\"openCreateDialog()\">\n <i class=\"fa-solid fa-plus\"></i>\n New Scope\n </button>\n </div>\n </div>\n <!-- Messages -->\n @if (SuccessMessage) {\n <div class=\"message success\">\n <i class=\"fa-solid fa-check-circle\"></i>\n {{SuccessMessage}}\n </div>\n }\n @if (ErrorMessage) {\n <div class=\"message error\">\n <i class=\"fa-solid fa-circle-exclamation\"></i>\n {{ErrorMessage}}\n </div>\n }\n <!-- Scope Tree -->\n <div class=\"scope-tree\">\n @for (node of ScopeTree; track node) {\n <ng-container *ngTemplateOutlet=\"scopeNode; context: { node: node }\"></ng-container>\n }\n <!-- Empty State -->\n @if (ScopeTree.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-shield-halved\"></i>\n <span>No scopes configured</span>\n <p>Create scopes to define API access permissions</p>\n </div>\n }\n </div>\n <!-- Recursive Node Template -->\n <ng-template #scopeNode let-node=\"node\">\n <div class=\"scope-node\" [style.padding-left.px]=\"node.level * 24\">\n <div class=\"node-content\" [class.inactive]=\"!node.scope.IsActive\">\n @if (node.children.length > 0) {\n <button class=\"expand-btn\"\n (click)=\"toggleExpanded(node)\">\n <i class=\"fa-solid\"\n [class.fa-chevron-right]=\"!node.expanded\"\n [class.fa-chevron-down]=\"node.expanded\"></i>\n </button>\n }\n @if (node.children.length === 0) {\n <span class=\"expand-placeholder\"></span>\n }\n <div class=\"scope-info\" (click)=\"openEditDialog(node.scope)\">\n <div class=\"scope-icon\" [style.backgroundColor]=\"getCategoryColor(node.scope.Category)\">\n <i class=\"fa-solid fa-shield\"></i>\n </div>\n <div class=\"scope-details\">\n <div class=\"scope-name\">\n {{node.scope.Name}}\n @if (node.scope.FullPath && node.scope.FullPath !== node.scope.Name) {\n <span class=\"full-path\">\n {{node.scope.FullPath}}\n </span>\n }\n @if (!node.scope.IsActive) {\n <span class=\"status-badge\">Inactive</span>\n }\n </div>\n <div class=\"scope-meta\">\n <span class=\"category\" [style.color]=\"getCategoryColor(node.scope.Category)\">\n {{node.scope.Category}}\n </span>\n @if (node.scope.ResourceType) {\n <span class=\"resource-type\">\n {{node.scope.ResourceType}}\n </span>\n }\n @if (node.scope.Description) {\n <span class=\"description\">\n {{node.scope.Description}}\n </span>\n }\n </div>\n </div>\n </div>\n <div class=\"node-actions\">\n <button class=\"btn-node-action\" (click)=\"openCreateDialog(node.scope)\" title=\"Add Child Scope\">\n <i class=\"fa-solid fa-plus\"></i>\n </button>\n <button class=\"btn-node-action\" (click)=\"openEditDialog(node.scope)\" title=\"Edit Scope\">\n <i class=\"fa-solid fa-pencil\"></i>\n </button>\n </div>\n </div>\n @if (node.expanded && node.children.length > 0) {\n <div class=\"children\">\n @for (child of node.children; track child) {\n <ng-container *ngTemplateOutlet=\"scopeNode; context: { node: child }\"></ng-container>\n }\n </div>\n }\n </div>\n </ng-template>\n }\n\n <!-- Create/Edit Dialog -->\n @if (ShowCreateDialog || ShowEditDialog) {\n <mj-window\n [Width]=\"560\"\n [MinWidth]=\"420\"\n [MinHeight]=\"480\"\n [Resizable]=\"true\"\n [Draggable]=\"true\"\n [Visible]=\"true\"\n [Top]=\"80\"\n (Close)=\"closeDialogs()\">\n <mj-window-titlebar>\n <div class=\"dialog-title\">\n <i class=\"fa-solid fa-shield-halved\"></i>\n <span>{{EditingScope ? 'Edit Scope' : 'New Scope'}}</span>\n </div>\n </mj-window-titlebar>\n <div class=\"dialog-content\">\n <div class=\"form-field\">\n <label>Scope Name *</label>\n <input class=\"mj-input form-input\" [(ngModel)]=\"EditName\"\n placeholder=\"e.g., runview, create, execute\" />\n <span class=\"field-hint\">Use lowercase, single word. Will be combined with parent for full path.</span>\n </div>\n <div class=\"form-field\">\n <label>Parent Scope</label>\n <mj-dropdown [(ngModel)]=\"EditParentId\"\n [Data]=\"getParentOptions()\"\n TextField=\"FullPath\"\n ValueField=\"ID\"\n [ValuePrimitive]=\"true\"\n [DefaultItem]=\"{ FullPath: '(No Parent - Root Level)', ID: null }\">\n </mj-dropdown>\n @if (SelectedParentScope) {\n <span class=\"field-hint\">\n Full path will be: <code>{{SelectedParentScope.FullPath}}:{{EditName || '...'}}</code>\n </span>\n }\n </div>\n <div class=\"form-row\">\n <div class=\"form-field half\">\n <label>Category</label>\n <mj-dropdown [(ngModel)]=\"EditCategory\"\n [Data]=\"Categories\"\n [ValuePrimitive]=\"true\">\n </mj-dropdown>\n </div>\n <div class=\"form-field half\">\n <label>Resource Type</label>\n <mj-dropdown [(ngModel)]=\"EditResourceType\"\n [Data]=\"ResourceTypes\"\n [ValuePrimitive]=\"true\"\n [DefaultItem]=\"''\">\n </mj-dropdown>\n </div>\n </div>\n <div class=\"form-field\">\n <label>Description</label>\n <textarea class=\"mj-textarea form-textarea\" [(ngModel)]=\"EditDescription\"\n placeholder=\"Describe what this scope allows...\"\n [rows]=\"3\"></textarea>\n </div>\n <div class=\"form-field\">\n <label class=\"checkbox-label\">\n <input type=\"checkbox\" class=\"mj-checkbox\" [(ngModel)]=\"EditIsActive\" />\n <div>\n <span>Active</span>\n <span class=\"checkbox-hint\">Inactive scopes cannot be assigned to keys or applications</span>\n </div>\n </label>\n </div>\n <div class=\"dialog-actions\">\n <button mjButton variant=\"primary\"\n [disabled]=\"!EditName.trim() || IsSaving\"\n (click)=\"saveScope()\">\n @if (IsSaving) {\n <mj-loading [showText]=\"false\" size=\"small\"></mj-loading>\n }\n @if (!IsSaving) {\n <span>\n <i class=\"fa-solid fa-save\"></i>\n {{EditingScope ? 'Update' : 'Create'}}\n </span>\n }\n </button>\n <button mjButton (click)=\"closeDialogs()\">Cancel</button>\n </div>\n </div>\n </mj-window>\n }\n</div>\n"]}
|