@memberjunction/ng-dashboards 5.24.0 → 5.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/AI/components/agents/agent-configuration.component.d.ts +15 -33
- package/dist/AI/components/agents/agent-configuration.component.d.ts.map +1 -1
- package/dist/AI/components/agents/agent-configuration.component.js +233 -493
- package/dist/AI/components/agents/agent-configuration.component.js.map +1 -1
- package/dist/AI/components/agents/agent-editor.component.d.ts +2 -2
- package/dist/AI/components/agents/agent-editor.component.d.ts.map +1 -1
- package/dist/AI/components/agents/agent-editor.component.js +7 -7
- package/dist/AI/components/agents/agent-editor.component.js.map +1 -1
- package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.d.ts +43 -6
- package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.d.ts.map +1 -1
- package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.js +1135 -864
- package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.js.map +1 -1
- package/dist/AI/components/duplicates/duplicate-detection-resource.component.d.ts +4 -3
- package/dist/AI/components/duplicates/duplicate-detection-resource.component.d.ts.map +1 -1
- package/dist/AI/components/duplicates/duplicate-detection-resource.component.js +1 -0
- package/dist/AI/components/duplicates/duplicate-detection-resource.component.js.map +1 -1
- package/dist/AI/components/execution-monitoring.component.d.ts +4 -5
- package/dist/AI/components/execution-monitoring.component.d.ts.map +1 -1
- package/dist/AI/components/execution-monitoring.component.js +14 -15
- package/dist/AI/components/execution-monitoring.component.js.map +1 -1
- package/dist/AI/components/models/model-management.component.d.ts +4 -4
- package/dist/AI/components/models/model-management.component.d.ts.map +1 -1
- package/dist/AI/components/models/model-management.component.js +5 -5
- package/dist/AI/components/models/model-management.component.js.map +1 -1
- package/dist/AI/components/prompts/prompt-management.component.d.ts +4 -4
- package/dist/AI/components/prompts/prompt-management.component.d.ts.map +1 -1
- package/dist/AI/components/prompts/prompt-management.component.js +5 -5
- package/dist/AI/components/prompts/prompt-management.component.js.map +1 -1
- package/dist/AI/components/requests/agent-requests-resource.component.d.ts +2 -1
- package/dist/AI/components/requests/agent-requests-resource.component.d.ts.map +1 -1
- package/dist/AI/components/requests/agent-requests-resource.component.js +1 -0
- package/dist/AI/components/requests/agent-requests-resource.component.js.map +1 -1
- package/dist/AI/components/system/system-configuration.component.d.ts +2 -3
- package/dist/AI/components/system/system-configuration.component.d.ts.map +1 -1
- package/dist/AI/components/system/system-configuration.component.js +9 -11
- package/dist/AI/components/system/system-configuration.component.js.map +1 -1
- package/dist/AI/components/vectors/vector-management-resource.component.d.ts +44 -8
- package/dist/AI/components/vectors/vector-management-resource.component.d.ts.map +1 -1
- package/dist/AI/components/vectors/vector-management-resource.component.js +648 -384
- package/dist/AI/components/vectors/vector-management-resource.component.js.map +1 -1
- package/dist/APIKeys/api-keys-resource.component.d.ts +2 -1
- package/dist/APIKeys/api-keys-resource.component.d.ts.map +1 -1
- package/dist/APIKeys/api-keys-resource.component.js +2 -0
- package/dist/APIKeys/api-keys-resource.component.js.map +1 -1
- package/dist/Actions/components/actions-overview.component.d.ts +4 -5
- package/dist/Actions/components/actions-overview.component.d.ts.map +1 -1
- package/dist/Actions/components/actions-overview.component.js +11 -12
- package/dist/Actions/components/actions-overview.component.js.map +1 -1
- package/dist/Actions/components/code-management.component.d.ts +2 -3
- package/dist/Actions/components/code-management.component.d.ts.map +1 -1
- package/dist/Actions/components/code-management.component.js +4 -6
- package/dist/Actions/components/code-management.component.js.map +1 -1
- package/dist/Actions/components/entity-integration.component.d.ts +2 -3
- package/dist/Actions/components/entity-integration.component.d.ts.map +1 -1
- package/dist/Actions/components/entity-integration.component.js +4 -6
- package/dist/Actions/components/entity-integration.component.js.map +1 -1
- package/dist/Actions/components/execution-monitoring.component.d.ts +4 -5
- package/dist/Actions/components/execution-monitoring.component.d.ts.map +1 -1
- package/dist/Actions/components/execution-monitoring.component.js +10 -11
- package/dist/Actions/components/execution-monitoring.component.js.map +1 -1
- package/dist/Actions/components/explorer/action-explorer.component.d.ts +13 -12
- package/dist/Actions/components/explorer/action-explorer.component.d.ts.map +1 -1
- package/dist/Actions/components/explorer/action-explorer.component.js +39 -66
- package/dist/Actions/components/explorer/action-explorer.component.js.map +1 -1
- package/dist/Actions/components/scheduled-actions.component.d.ts +2 -3
- package/dist/Actions/components/scheduled-actions.component.d.ts.map +1 -1
- package/dist/Actions/components/scheduled-actions.component.js +4 -6
- package/dist/Actions/components/scheduled-actions.component.js.map +1 -1
- package/dist/Actions/components/security-permissions.component.d.ts +2 -3
- package/dist/Actions/components/security-permissions.component.d.ts.map +1 -1
- package/dist/Actions/components/security-permissions.component.js +4 -6
- package/dist/Actions/components/security-permissions.component.js.map +1 -1
- package/dist/ApplicationRoles/application-roles-resource.component.d.ts +112 -0
- package/dist/ApplicationRoles/application-roles-resource.component.d.ts.map +1 -0
- package/dist/ApplicationRoles/application-roles-resource.component.js +532 -0
- package/dist/ApplicationRoles/application-roles-resource.component.js.map +1 -0
- package/dist/Communication/communication-dashboard.component.d.ts.map +1 -1
- package/dist/Communication/communication-dashboard.component.js +1 -0
- package/dist/Communication/communication-dashboard.component.js.map +1 -1
- package/dist/Communication/communication-logs-resource.component.d.ts.map +1 -1
- package/dist/Communication/communication-logs-resource.component.js +4 -1
- package/dist/Communication/communication-logs-resource.component.js.map +1 -1
- package/dist/Communication/communication-monitor-resource.component.d.ts.map +1 -1
- package/dist/Communication/communication-monitor-resource.component.js +4 -1
- package/dist/Communication/communication-monitor-resource.component.js.map +1 -1
- package/dist/Communication/communication-providers-resource.component.d.ts.map +1 -1
- package/dist/Communication/communication-providers-resource.component.js +4 -1
- package/dist/Communication/communication-providers-resource.component.js.map +1 -1
- package/dist/Communication/communication-runs-resource.component.d.ts.map +1 -1
- package/dist/Communication/communication-runs-resource.component.js +4 -1
- package/dist/Communication/communication-runs-resource.component.js.map +1 -1
- package/dist/Communication/communication-templates-resource.component.d.ts.map +1 -1
- package/dist/Communication/communication-templates-resource.component.js +4 -1
- package/dist/Communication/communication-templates-resource.component.js.map +1 -1
- package/dist/ComponentStudio/component-studio-dashboard.component.d.ts +2 -1
- package/dist/ComponentStudio/component-studio-dashboard.component.d.ts.map +1 -1
- package/dist/ComponentStudio/component-studio-dashboard.component.js +1 -0
- package/dist/ComponentStudio/component-studio-dashboard.component.js.map +1 -1
- package/dist/Credentials/components/credentials-audit-resource.component.d.ts.map +1 -1
- package/dist/Credentials/components/credentials-audit-resource.component.js +2 -0
- package/dist/Credentials/components/credentials-audit-resource.component.js.map +1 -1
- package/dist/Credentials/components/credentials-categories-resource.component.d.ts +2 -3
- package/dist/Credentials/components/credentials-categories-resource.component.d.ts.map +1 -1
- package/dist/Credentials/components/credentials-categories-resource.component.js +10 -11
- package/dist/Credentials/components/credentials-categories-resource.component.js.map +1 -1
- package/dist/Credentials/components/credentials-list-resource.component.d.ts +2 -1
- package/dist/Credentials/components/credentials-list-resource.component.d.ts.map +1 -1
- package/dist/Credentials/components/credentials-list-resource.component.js +2 -0
- package/dist/Credentials/components/credentials-list-resource.component.js.map +1 -1
- package/dist/Credentials/components/credentials-overview-resource.component.d.ts +4 -4
- package/dist/Credentials/components/credentials-overview-resource.component.d.ts.map +1 -1
- package/dist/Credentials/components/credentials-overview-resource.component.js +8 -9
- package/dist/Credentials/components/credentials-overview-resource.component.js.map +1 -1
- package/dist/Credentials/components/credentials-types-resource.component.d.ts +2 -3
- package/dist/Credentials/components/credentials-types-resource.component.d.ts.map +1 -1
- package/dist/Credentials/components/credentials-types-resource.component.js +11 -12
- package/dist/Credentials/components/credentials-types-resource.component.js.map +1 -1
- package/dist/Credentials/credentials-dashboard.component.d.ts.map +1 -1
- package/dist/Credentials/credentials-dashboard.component.js +1 -0
- package/dist/Credentials/credentials-dashboard.component.js.map +1 -1
- package/dist/DashboardBrowser/dashboard-browser-resource.component.d.ts +2 -3
- package/dist/DashboardBrowser/dashboard-browser-resource.component.d.ts.map +1 -1
- package/dist/DashboardBrowser/dashboard-browser-resource.component.js +9 -10
- package/dist/DashboardBrowser/dashboard-browser-resource.component.js.map +1 -1
- package/dist/DataExplorer/components/filter-dialog/filter-dialog.component.js +2 -2
- package/dist/DataExplorer/components/navigation-panel/navigation-panel.component.d.ts +23 -15
- package/dist/DataExplorer/components/navigation-panel/navigation-panel.component.d.ts.map +1 -1
- package/dist/DataExplorer/components/navigation-panel/navigation-panel.component.js +167 -213
- package/dist/DataExplorer/components/navigation-panel/navigation-panel.component.js.map +1 -1
- package/dist/DataExplorer/data-explorer-dashboard.component.d.ts +68 -32
- package/dist/DataExplorer/data-explorer-dashboard.component.d.ts.map +1 -1
- package/dist/DataExplorer/data-explorer-dashboard.component.js +453 -420
- package/dist/DataExplorer/data-explorer-dashboard.component.js.map +1 -1
- package/dist/DataExplorer/data-explorer-resource.component.d.ts +10 -3
- package/dist/DataExplorer/data-explorer-resource.component.d.ts.map +1 -1
- package/dist/DataExplorer/data-explorer-resource.component.js +35 -11
- package/dist/DataExplorer/data-explorer-resource.component.js.map +1 -1
- package/dist/DataExplorer/models/explorer-state.interface.d.ts +12 -3
- package/dist/DataExplorer/models/explorer-state.interface.d.ts.map +1 -1
- package/dist/DataExplorer/models/explorer-state.interface.js +5 -1
- package/dist/DataExplorer/models/explorer-state.interface.js.map +1 -1
- package/dist/Home/home-dashboard.component.d.ts +4 -4
- package/dist/Home/home-dashboard.component.d.ts.map +1 -1
- package/dist/Home/home-dashboard.component.js +4 -5
- package/dist/Home/home-dashboard.component.js.map +1 -1
- package/dist/Integration/components/activity/activity.component.d.ts.map +1 -1
- package/dist/Integration/components/activity/activity.component.js +1 -0
- package/dist/Integration/components/activity/activity.component.js.map +1 -1
- package/dist/Integration/components/connections/connections.component.d.ts.map +1 -1
- package/dist/Integration/components/connections/connections.component.js +2 -0
- package/dist/Integration/components/connections/connections.component.js.map +1 -1
- package/dist/Integration/components/mapping-workspace/mapping-workspace.component.d.ts.map +1 -1
- package/dist/Integration/components/mapping-workspace/mapping-workspace.component.js +1 -0
- package/dist/Integration/components/mapping-workspace/mapping-workspace.component.js.map +1 -1
- package/dist/Integration/components/overview/overview.component.d.ts.map +1 -1
- package/dist/Integration/components/overview/overview.component.js +2 -0
- package/dist/Integration/components/overview/overview.component.js.map +1 -1
- package/dist/Integration/components/pipelines/pipelines.component.d.ts.map +1 -1
- package/dist/Integration/components/pipelines/pipelines.component.js +2 -0
- package/dist/Integration/components/pipelines/pipelines.component.js.map +1 -1
- package/dist/Integration/components/schedules/schedules.component.d.ts.map +1 -1
- package/dist/Integration/components/schedules/schedules.component.js +2 -0
- package/dist/Integration/components/schedules/schedules.component.js.map +1 -1
- package/dist/KnowledgeHub/components/analytics/analytics-resource.component.d.ts +4 -3
- package/dist/KnowledgeHub/components/analytics/analytics-resource.component.d.ts.map +1 -1
- package/dist/KnowledgeHub/components/analytics/analytics-resource.component.js +1 -0
- package/dist/KnowledgeHub/components/analytics/analytics-resource.component.js.map +1 -1
- package/dist/KnowledgeHub/components/clusters/cluster-visualization-resource.component.d.ts +4 -3
- package/dist/KnowledgeHub/components/clusters/cluster-visualization-resource.component.d.ts.map +1 -1
- package/dist/KnowledgeHub/components/clusters/cluster-visualization-resource.component.js +1 -0
- package/dist/KnowledgeHub/components/clusters/cluster-visualization-resource.component.js.map +1 -1
- package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.d.ts +13 -3
- package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.d.ts.map +1 -1
- package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.js +220 -138
- package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.js.map +1 -1
- package/dist/KnowledgeHub/components/scheduling/scheduling-resource.component.d.ts +4 -3
- package/dist/KnowledgeHub/components/scheduling/scheduling-resource.component.d.ts.map +1 -1
- package/dist/KnowledgeHub/components/scheduling/scheduling-resource.component.js +1 -0
- package/dist/KnowledgeHub/components/scheduling/scheduling-resource.component.js.map +1 -1
- package/dist/KnowledgeHub/index.d.ts +0 -1
- package/dist/KnowledgeHub/index.d.ts.map +1 -1
- package/dist/KnowledgeHub/index.js +0 -1
- package/dist/KnowledgeHub/index.js.map +1 -1
- package/dist/Lists/components/lists-browse-resource.component.d.ts +2 -1
- package/dist/Lists/components/lists-browse-resource.component.d.ts.map +1 -1
- package/dist/Lists/components/lists-browse-resource.component.js +2 -0
- package/dist/Lists/components/lists-browse-resource.component.js.map +1 -1
- package/dist/Lists/components/lists-categories-resource.component.d.ts +2 -1
- package/dist/Lists/components/lists-categories-resource.component.d.ts.map +1 -1
- package/dist/Lists/components/lists-categories-resource.component.js +2 -0
- package/dist/Lists/components/lists-categories-resource.component.js.map +1 -1
- package/dist/Lists/components/lists-my-lists-resource.component.d.ts +2 -1
- package/dist/Lists/components/lists-my-lists-resource.component.d.ts.map +1 -1
- package/dist/Lists/components/lists-my-lists-resource.component.js +2 -0
- package/dist/Lists/components/lists-my-lists-resource.component.js.map +1 -1
- package/dist/Lists/components/lists-operations-resource.component.d.ts +2 -1
- package/dist/Lists/components/lists-operations-resource.component.d.ts.map +1 -1
- package/dist/Lists/components/lists-operations-resource.component.js +2 -0
- package/dist/Lists/components/lists-operations-resource.component.js.map +1 -1
- package/dist/MCP/mcp-dashboard.component.d.ts +7 -28
- package/dist/MCP/mcp-dashboard.component.d.ts.map +1 -1
- package/dist/MCP/mcp-dashboard.component.js +25 -107
- package/dist/MCP/mcp-dashboard.component.js.map +1 -1
- package/dist/MCP/mcp-resource.component.d.ts.map +1 -1
- package/dist/MCP/mcp-resource.component.js +1 -0
- package/dist/MCP/mcp-resource.component.js.map +1 -1
- package/dist/QueryBrowser/query-browser-resource.component.d.ts +10 -23
- package/dist/QueryBrowser/query-browser-resource.component.d.ts.map +1 -1
- package/dist/QueryBrowser/query-browser-resource.component.js +41 -103
- package/dist/QueryBrowser/query-browser-resource.component.js.map +1 -1
- package/dist/Scheduling/components/scheduling-activity-resource.component.d.ts.map +1 -1
- package/dist/Scheduling/components/scheduling-activity-resource.component.js +1 -0
- package/dist/Scheduling/components/scheduling-activity-resource.component.js.map +1 -1
- package/dist/Scheduling/components/scheduling-jobs-resource.component.d.ts.map +1 -1
- package/dist/Scheduling/components/scheduling-jobs-resource.component.js +1 -0
- package/dist/Scheduling/components/scheduling-jobs-resource.component.js.map +1 -1
- package/dist/Scheduling/components/scheduling-overview-resource.component.d.ts.map +1 -1
- package/dist/Scheduling/components/scheduling-overview-resource.component.js +1 -0
- package/dist/Scheduling/components/scheduling-overview-resource.component.js.map +1 -1
- package/dist/Scheduling/scheduling-dashboard.component.d.ts.map +1 -1
- package/dist/Scheduling/scheduling-dashboard.component.js +1 -0
- package/dist/Scheduling/scheduling-dashboard.component.js.map +1 -1
- package/dist/SystemDiagnostics/system-diagnostics.component.d.ts +4 -4
- package/dist/SystemDiagnostics/system-diagnostics.component.d.ts.map +1 -1
- package/dist/SystemDiagnostics/system-diagnostics.component.js +9 -10
- package/dist/SystemDiagnostics/system-diagnostics.component.js.map +1 -1
- package/dist/Testing/components/testing-analytics-resource.component.d.ts.map +1 -1
- package/dist/Testing/components/testing-analytics-resource.component.js +2 -0
- package/dist/Testing/components/testing-analytics-resource.component.js.map +1 -1
- package/dist/Testing/components/testing-dashboard-tab-resource.component.d.ts +2 -1
- package/dist/Testing/components/testing-dashboard-tab-resource.component.d.ts.map +1 -1
- package/dist/Testing/components/testing-dashboard-tab-resource.component.js +2 -0
- package/dist/Testing/components/testing-dashboard-tab-resource.component.js.map +1 -1
- package/dist/Testing/components/testing-explorer-resource.component.d.ts.map +1 -1
- package/dist/Testing/components/testing-explorer-resource.component.js +2 -0
- package/dist/Testing/components/testing-explorer-resource.component.js.map +1 -1
- package/dist/Testing/components/testing-review-resource.component.d.ts.map +1 -1
- package/dist/Testing/components/testing-review-resource.component.js +2 -0
- package/dist/Testing/components/testing-review-resource.component.js.map +1 -1
- package/dist/Testing/components/testing-runs-resource.component.d.ts +2 -1
- package/dist/Testing/components/testing-runs-resource.component.d.ts.map +1 -1
- package/dist/Testing/components/testing-runs-resource.component.js +2 -0
- package/dist/Testing/components/testing-runs-resource.component.js.map +1 -1
- package/dist/Testing/testing-dashboard.component.d.ts +2 -1
- package/dist/Testing/testing-dashboard.component.d.ts.map +1 -1
- package/dist/Testing/testing-dashboard.component.js +1 -0
- package/dist/Testing/testing-dashboard.component.js.map +1 -1
- package/dist/VersionHistory/components/diff-resource.component.d.ts +4 -4
- package/dist/VersionHistory/components/diff-resource.component.d.ts.map +1 -1
- package/dist/VersionHistory/components/diff-resource.component.js +9 -10
- package/dist/VersionHistory/components/diff-resource.component.js.map +1 -1
- package/dist/VersionHistory/components/graph-resource.component.d.ts +2 -1
- package/dist/VersionHistory/components/graph-resource.component.d.ts.map +1 -1
- package/dist/VersionHistory/components/graph-resource.component.js +2 -0
- package/dist/VersionHistory/components/graph-resource.component.js.map +1 -1
- package/dist/VersionHistory/components/labels-resource.component.d.ts +4 -4
- package/dist/VersionHistory/components/labels-resource.component.d.ts.map +1 -1
- package/dist/VersionHistory/components/labels-resource.component.js +10 -11
- package/dist/VersionHistory/components/labels-resource.component.js.map +1 -1
- package/dist/VersionHistory/components/restore-resource.component.d.ts +2 -1
- package/dist/VersionHistory/components/restore-resource.component.d.ts.map +1 -1
- package/dist/VersionHistory/components/restore-resource.component.js +2 -0
- package/dist/VersionHistory/components/restore-resource.component.js.map +1 -1
- package/dist/ai-dashboards.module.d.ts +19 -19
- package/dist/ai-dashboards.module.d.ts.map +1 -1
- package/dist/ai-dashboards.module.js +4 -5
- package/dist/ai-dashboards.module.js.map +1 -1
- package/dist/core-dashboards.module.d.ts +19 -18
- package/dist/core-dashboards.module.d.ts.map +1 -1
- package/dist/core-dashboards.module.js +8 -0
- package/dist/core-dashboards.module.js.map +1 -1
- package/dist/data-explorer-dashboards.module.d.ts +2 -1
- package/dist/data-explorer-dashboards.module.d.ts.map +1 -1
- package/dist/data-explorer-dashboards.module.js +7 -3
- package/dist/data-explorer-dashboards.module.js.map +1 -1
- package/dist/public-api.d.ts +1 -1
- package/dist/public-api.d.ts.map +1 -1
- package/dist/public-api.js +2 -1
- package/dist/public-api.js.map +1 -1
- package/package.json +47 -47
- package/dist/KnowledgeHub/components/search/knowledge-search-resource.component.d.ts +0 -166
- package/dist/KnowledgeHub/components/search/knowledge-search-resource.component.d.ts.map +0 -1
- package/dist/KnowledgeHub/components/search/knowledge-search-resource.component.js +0 -991
- package/dist/KnowledgeHub/components/search/knowledge-search-resource.component.js.map +0 -1
|
@@ -0,0 +1,532 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { Component } from '@angular/core';
|
|
8
|
+
import { RegisterClass, UUIDsEqual } from '@memberjunction/global';
|
|
9
|
+
import { BaseResourceComponent } from '@memberjunction/ng-shared';
|
|
10
|
+
import { CompositeKey, Metadata, RunView } from '@memberjunction/core';
|
|
11
|
+
import * as i0 from "@angular/core";
|
|
12
|
+
import * as i1 from "@angular/common";
|
|
13
|
+
import * as i2 from "@angular/forms";
|
|
14
|
+
import * as i3 from "@memberjunction/ng-ui-components";
|
|
15
|
+
import * as i4 from "@memberjunction/ng-shared-generic";
|
|
16
|
+
const _forTrack0 = ($index, $item) => $item.ID;
|
|
17
|
+
function ApplicationRolesResourceComponent_Conditional_7_Conditional_4_Template(rf, ctx) { if (rf & 1) {
|
|
18
|
+
i0.ɵɵelement(0, "i", 13);
|
|
19
|
+
i0.ɵɵtext(1, " Saving... ");
|
|
20
|
+
} }
|
|
21
|
+
function ApplicationRolesResourceComponent_Conditional_7_Conditional_5_Template(rf, ctx) { if (rf & 1) {
|
|
22
|
+
i0.ɵɵelement(0, "i", 14);
|
|
23
|
+
i0.ɵɵtext(1, " Save Changes ");
|
|
24
|
+
} }
|
|
25
|
+
function ApplicationRolesResourceComponent_Conditional_7_Template(rf, ctx) { if (rf & 1) {
|
|
26
|
+
const _r1 = i0.ɵɵgetCurrentView();
|
|
27
|
+
i0.ɵɵelementStart(0, "button", 6);
|
|
28
|
+
i0.ɵɵlistener("click", function ApplicationRolesResourceComponent_Conditional_7_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.DiscardChanges()); });
|
|
29
|
+
i0.ɵɵelement(1, "i", 11);
|
|
30
|
+
i0.ɵɵtext(2, " Discard ");
|
|
31
|
+
i0.ɵɵelementEnd();
|
|
32
|
+
i0.ɵɵelementStart(3, "button", 12);
|
|
33
|
+
i0.ɵɵlistener("click", function ApplicationRolesResourceComponent_Conditional_7_Template_button_click_3_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.SaveChanges()); });
|
|
34
|
+
i0.ɵɵconditionalCreate(4, ApplicationRolesResourceComponent_Conditional_7_Conditional_4_Template, 2, 0)(5, ApplicationRolesResourceComponent_Conditional_7_Conditional_5_Template, 2, 0);
|
|
35
|
+
i0.ɵɵelementEnd();
|
|
36
|
+
} if (rf & 2) {
|
|
37
|
+
const ctx_r1 = i0.ɵɵnextContext();
|
|
38
|
+
i0.ɵɵproperty("disabled", ctx_r1.IsSaving);
|
|
39
|
+
i0.ɵɵadvance(3);
|
|
40
|
+
i0.ɵɵproperty("disabled", ctx_r1.IsSaving);
|
|
41
|
+
i0.ɵɵadvance();
|
|
42
|
+
i0.ɵɵconditional(ctx_r1.IsSaving ? 4 : 5);
|
|
43
|
+
} }
|
|
44
|
+
function ApplicationRolesResourceComponent_Conditional_11_Template(rf, ctx) { if (rf & 1) {
|
|
45
|
+
i0.ɵɵelementStart(0, "div", 8);
|
|
46
|
+
i0.ɵɵelement(1, "i", 15);
|
|
47
|
+
i0.ɵɵtext(2);
|
|
48
|
+
i0.ɵɵelementEnd();
|
|
49
|
+
} if (rf & 2) {
|
|
50
|
+
const ctx_r1 = i0.ɵɵnextContext();
|
|
51
|
+
i0.ɵɵadvance(2);
|
|
52
|
+
i0.ɵɵtextInterpolate1(" ", ctx_r1.ErrorMessage, " ");
|
|
53
|
+
} }
|
|
54
|
+
function ApplicationRolesResourceComponent_Conditional_12_Template(rf, ctx) { if (rf & 1) {
|
|
55
|
+
i0.ɵɵelementStart(0, "div", 9);
|
|
56
|
+
i0.ɵɵelement(1, "i", 16);
|
|
57
|
+
i0.ɵɵtext(2);
|
|
58
|
+
i0.ɵɵelementEnd();
|
|
59
|
+
} if (rf & 2) {
|
|
60
|
+
const ctx_r1 = i0.ɵɵnextContext();
|
|
61
|
+
i0.ɵɵadvance(2);
|
|
62
|
+
i0.ɵɵtextInterpolate1(" ", ctx_r1.SuccessMessage, " ");
|
|
63
|
+
} }
|
|
64
|
+
function ApplicationRolesResourceComponent_Conditional_13_Template(rf, ctx) { if (rf & 1) {
|
|
65
|
+
i0.ɵɵelement(0, "mj-loading", 10);
|
|
66
|
+
} }
|
|
67
|
+
function ApplicationRolesResourceComponent_Conditional_14_For_4_Conditional_8_Conditional_1_For_13_Conditional_4_Template(rf, ctx) { if (rf & 1) {
|
|
68
|
+
i0.ɵɵelementStart(0, "span", 40);
|
|
69
|
+
i0.ɵɵtext(1, "new");
|
|
70
|
+
i0.ɵɵelementEnd();
|
|
71
|
+
} }
|
|
72
|
+
function ApplicationRolesResourceComponent_Conditional_14_For_4_Conditional_8_Conditional_1_For_13_Template(rf, ctx) { if (rf & 1) {
|
|
73
|
+
const _r6 = i0.ɵɵgetCurrentView();
|
|
74
|
+
i0.ɵɵelementStart(0, "tr")(1, "td", 34);
|
|
75
|
+
i0.ɵɵelement(2, "i", 39);
|
|
76
|
+
i0.ɵɵtext(3);
|
|
77
|
+
i0.ɵɵconditionalCreate(4, ApplicationRolesResourceComponent_Conditional_14_For_4_Conditional_8_Conditional_1_For_13_Conditional_4_Template, 2, 0, "span", 40);
|
|
78
|
+
i0.ɵɵelementEnd();
|
|
79
|
+
i0.ɵɵelementStart(5, "td", 35)(6, "input", 41);
|
|
80
|
+
i0.ɵɵlistener("change", function ApplicationRolesResourceComponent_Conditional_14_For_4_Conditional_8_Conditional_1_For_13_Template_input_change_6_listener() { const row_r7 = i0.ɵɵrestoreView(_r6).$implicit; const ctx_r1 = i0.ɵɵnextContext(5); return i0.ɵɵresetView(ctx_r1.ToggleCanAccess(row_r7)); });
|
|
81
|
+
i0.ɵɵelementEnd()();
|
|
82
|
+
i0.ɵɵelementStart(7, "td", 36)(8, "input", 41);
|
|
83
|
+
i0.ɵɵlistener("change", function ApplicationRolesResourceComponent_Conditional_14_For_4_Conditional_8_Conditional_1_For_13_Template_input_change_8_listener() { const row_r7 = i0.ɵɵrestoreView(_r6).$implicit; const ctx_r1 = i0.ɵɵnextContext(5); return i0.ɵɵresetView(ctx_r1.ToggleCanAdmin(row_r7)); });
|
|
84
|
+
i0.ɵɵelementEnd()();
|
|
85
|
+
i0.ɵɵelementStart(9, "td", 37)(10, "button", 42);
|
|
86
|
+
i0.ɵɵlistener("click", function ApplicationRolesResourceComponent_Conditional_14_For_4_Conditional_8_Conditional_1_For_13_Template_button_click_10_listener() { const row_r7 = i0.ɵɵrestoreView(_r6).$implicit; const group_r4 = i0.ɵɵnextContext(3).$implicit; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.RemoveRole(group_r4, row_r7)); });
|
|
87
|
+
i0.ɵɵelement(11, "i", 43);
|
|
88
|
+
i0.ɵɵelementEnd()()();
|
|
89
|
+
} if (rf & 2) {
|
|
90
|
+
const row_r7 = ctx.$implicit;
|
|
91
|
+
i0.ɵɵclassProp("dirty", row_r7.IsDirty)("new-row", row_r7.IsNew);
|
|
92
|
+
i0.ɵɵadvance(3);
|
|
93
|
+
i0.ɵɵtextInterpolate1(" ", row_r7.RoleName, " ");
|
|
94
|
+
i0.ɵɵadvance();
|
|
95
|
+
i0.ɵɵconditional(row_r7.IsNew ? 4 : -1);
|
|
96
|
+
i0.ɵɵadvance(2);
|
|
97
|
+
i0.ɵɵproperty("checked", row_r7.CanAccess);
|
|
98
|
+
i0.ɵɵadvance(2);
|
|
99
|
+
i0.ɵɵproperty("checked", row_r7.CanAdmin);
|
|
100
|
+
} }
|
|
101
|
+
function ApplicationRolesResourceComponent_Conditional_14_For_4_Conditional_8_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
102
|
+
i0.ɵɵelementStart(0, "table", 27)(1, "thead")(2, "tr")(3, "th", 34);
|
|
103
|
+
i0.ɵɵtext(4, "Role");
|
|
104
|
+
i0.ɵɵelementEnd();
|
|
105
|
+
i0.ɵɵelementStart(5, "th", 35);
|
|
106
|
+
i0.ɵɵtext(6, "Can Access");
|
|
107
|
+
i0.ɵɵelementEnd();
|
|
108
|
+
i0.ɵɵelementStart(7, "th", 36);
|
|
109
|
+
i0.ɵɵtext(8, "Can Admin");
|
|
110
|
+
i0.ɵɵelementEnd();
|
|
111
|
+
i0.ɵɵelementStart(9, "th", 37);
|
|
112
|
+
i0.ɵɵtext(10, "Actions");
|
|
113
|
+
i0.ɵɵelementEnd()()();
|
|
114
|
+
i0.ɵɵelementStart(11, "tbody");
|
|
115
|
+
i0.ɵɵrepeaterCreate(12, ApplicationRolesResourceComponent_Conditional_14_For_4_Conditional_8_Conditional_1_For_13_Template, 12, 8, "tr", 38, i0.ɵɵcomponentInstance().TrackByRoleRow, true);
|
|
116
|
+
i0.ɵɵelementEnd()();
|
|
117
|
+
} if (rf & 2) {
|
|
118
|
+
const group_r4 = i0.ɵɵnextContext(2).$implicit;
|
|
119
|
+
i0.ɵɵadvance(12);
|
|
120
|
+
i0.ɵɵrepeater(group_r4.Roles);
|
|
121
|
+
} }
|
|
122
|
+
function ApplicationRolesResourceComponent_Conditional_14_For_4_Conditional_8_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
123
|
+
i0.ɵɵelementStart(0, "div", 28);
|
|
124
|
+
i0.ɵɵelement(1, "i", 44);
|
|
125
|
+
i0.ɵɵtext(2, " No role restrictions \u2014 all authenticated users can access this application. ");
|
|
126
|
+
i0.ɵɵelementEnd();
|
|
127
|
+
} }
|
|
128
|
+
function ApplicationRolesResourceComponent_Conditional_14_For_4_Conditional_8_For_8_Template(rf, ctx) { if (rf & 1) {
|
|
129
|
+
i0.ɵɵelementStart(0, "option", 32);
|
|
130
|
+
i0.ɵɵtext(1);
|
|
131
|
+
i0.ɵɵelementEnd();
|
|
132
|
+
} if (rf & 2) {
|
|
133
|
+
const role_r8 = ctx.$implicit;
|
|
134
|
+
i0.ɵɵproperty("value", role_r8.ID);
|
|
135
|
+
i0.ɵɵadvance();
|
|
136
|
+
i0.ɵɵtextInterpolate(role_r8.Name);
|
|
137
|
+
} }
|
|
138
|
+
function ApplicationRolesResourceComponent_Conditional_14_For_4_Conditional_8_Template(rf, ctx) { if (rf & 1) {
|
|
139
|
+
const _r5 = i0.ɵɵgetCurrentView();
|
|
140
|
+
i0.ɵɵelementStart(0, "div", 26);
|
|
141
|
+
i0.ɵɵconditionalCreate(1, ApplicationRolesResourceComponent_Conditional_14_For_4_Conditional_8_Conditional_1_Template, 14, 0, "table", 27)(2, ApplicationRolesResourceComponent_Conditional_14_For_4_Conditional_8_Conditional_2_Template, 3, 0, "div", 28);
|
|
142
|
+
i0.ɵɵelementStart(3, "div", 29)(4, "select", 30);
|
|
143
|
+
i0.ɵɵlistener("change", function ApplicationRolesResourceComponent_Conditional_14_For_4_Conditional_8_Template_select_change_4_listener($event) { i0.ɵɵrestoreView(_r5); const group_r4 = i0.ɵɵnextContext().$implicit; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnAddRoleSelect(group_r4, $event.target.value)); });
|
|
144
|
+
i0.ɵɵelementStart(5, "option", 31);
|
|
145
|
+
i0.ɵɵtext(6, "Select a role to add...");
|
|
146
|
+
i0.ɵɵelementEnd();
|
|
147
|
+
i0.ɵɵrepeaterCreate(7, ApplicationRolesResourceComponent_Conditional_14_For_4_Conditional_8_For_8_Template, 2, 2, "option", 32, _forTrack0);
|
|
148
|
+
i0.ɵɵelementEnd();
|
|
149
|
+
i0.ɵɵelementStart(9, "button", 6);
|
|
150
|
+
i0.ɵɵlistener("click", function ApplicationRolesResourceComponent_Conditional_14_For_4_Conditional_8_Template_button_click_9_listener() { i0.ɵɵrestoreView(_r5); const group_r4 = i0.ɵɵnextContext().$implicit; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.AddRole(group_r4)); });
|
|
151
|
+
i0.ɵɵelement(10, "i", 33);
|
|
152
|
+
i0.ɵɵtext(11, " Add Role ");
|
|
153
|
+
i0.ɵɵelementEnd()()();
|
|
154
|
+
} if (rf & 2) {
|
|
155
|
+
const group_r4 = i0.ɵɵnextContext().$implicit;
|
|
156
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
157
|
+
i0.ɵɵadvance();
|
|
158
|
+
i0.ɵɵconditional(group_r4.Roles.length > 0 ? 1 : 2);
|
|
159
|
+
i0.ɵɵadvance(3);
|
|
160
|
+
i0.ɵɵproperty("value", ctx_r1.SelectedRoleIdToAdd.get(group_r4.ApplicationID) || "");
|
|
161
|
+
i0.ɵɵadvance(3);
|
|
162
|
+
i0.ɵɵrepeater(ctx_r1.GetUnassignedRoles(group_r4));
|
|
163
|
+
i0.ɵɵadvance(2);
|
|
164
|
+
i0.ɵɵproperty("disabled", !ctx_r1.SelectedRoleIdToAdd.get(group_r4.ApplicationID));
|
|
165
|
+
} }
|
|
166
|
+
function ApplicationRolesResourceComponent_Conditional_14_For_4_Template(rf, ctx) { if (rf & 1) {
|
|
167
|
+
const _r3 = i0.ɵɵgetCurrentView();
|
|
168
|
+
i0.ɵɵelementStart(0, "div", 20)(1, "div", 21);
|
|
169
|
+
i0.ɵɵlistener("click", function ApplicationRolesResourceComponent_Conditional_14_For_4_Template_div_click_1_listener() { const group_r4 = i0.ɵɵrestoreView(_r3).$implicit; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.ToggleGroup(group_r4)); });
|
|
170
|
+
i0.ɵɵelementStart(2, "div", 22);
|
|
171
|
+
i0.ɵɵelement(3, "i", 23);
|
|
172
|
+
i0.ɵɵelementStart(4, "span", 24);
|
|
173
|
+
i0.ɵɵtext(5);
|
|
174
|
+
i0.ɵɵelementEnd();
|
|
175
|
+
i0.ɵɵelementStart(6, "span", 25);
|
|
176
|
+
i0.ɵɵtext(7);
|
|
177
|
+
i0.ɵɵelementEnd()()();
|
|
178
|
+
i0.ɵɵconditionalCreate(8, ApplicationRolesResourceComponent_Conditional_14_For_4_Conditional_8_Template, 12, 3, "div", 26);
|
|
179
|
+
i0.ɵɵelementEnd();
|
|
180
|
+
} if (rf & 2) {
|
|
181
|
+
const group_r4 = ctx.$implicit;
|
|
182
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
183
|
+
i0.ɵɵclassProp("expanded", group_r4.Expanded)("has-roles", group_r4.Roles.length > 0);
|
|
184
|
+
i0.ɵɵadvance(3);
|
|
185
|
+
i0.ɵɵproperty("ngClass", group_r4.Expanded ? "fa-chevron-down" : "fa-chevron-right");
|
|
186
|
+
i0.ɵɵadvance(2);
|
|
187
|
+
i0.ɵɵtextInterpolate(group_r4.ApplicationName);
|
|
188
|
+
i0.ɵɵadvance();
|
|
189
|
+
i0.ɵɵclassProp("open-access", group_r4.Roles.length === 0);
|
|
190
|
+
i0.ɵɵadvance();
|
|
191
|
+
i0.ɵɵtextInterpolate1(" ", ctx_r1.GetRoleCountLabel(group_r4), " ");
|
|
192
|
+
i0.ɵɵadvance();
|
|
193
|
+
i0.ɵɵconditional(group_r4.Expanded ? 8 : -1);
|
|
194
|
+
} }
|
|
195
|
+
function ApplicationRolesResourceComponent_Conditional_14_Template(rf, ctx) { if (rf & 1) {
|
|
196
|
+
i0.ɵɵelementStart(0, "p", 17);
|
|
197
|
+
i0.ɵɵtext(1, " Configure which roles can access each application. Applications with no role assignments are open to all users (backwards compatible). ");
|
|
198
|
+
i0.ɵɵelementEnd();
|
|
199
|
+
i0.ɵɵelementStart(2, "div", 18);
|
|
200
|
+
i0.ɵɵrepeaterCreate(3, ApplicationRolesResourceComponent_Conditional_14_For_4_Template, 9, 10, "div", 19, i0.ɵɵcomponentInstance().TrackByAppId, true);
|
|
201
|
+
i0.ɵɵelementEnd();
|
|
202
|
+
} if (rf & 2) {
|
|
203
|
+
const ctx_r1 = i0.ɵɵnextContext();
|
|
204
|
+
i0.ɵɵadvance(3);
|
|
205
|
+
i0.ɵɵrepeater(ctx_r1.ApplicationGroups);
|
|
206
|
+
} }
|
|
207
|
+
/**
|
|
208
|
+
* Admin dashboard for managing Application Role assignments.
|
|
209
|
+
* Shows which roles can access and administer each application.
|
|
210
|
+
*/
|
|
211
|
+
let ApplicationRolesResourceComponent = class ApplicationRolesResourceComponent extends BaseResourceComponent {
|
|
212
|
+
cdr;
|
|
213
|
+
ApplicationGroups = [];
|
|
214
|
+
AvailableRoles = [];
|
|
215
|
+
IsLoading = true;
|
|
216
|
+
IsSaving = false;
|
|
217
|
+
HasUnsavedChanges = false;
|
|
218
|
+
ErrorMessage = null;
|
|
219
|
+
SuccessMessage = null;
|
|
220
|
+
// For the "Add Role" dropdown per application
|
|
221
|
+
SelectedRoleIdToAdd = new Map();
|
|
222
|
+
constructor(cdr) {
|
|
223
|
+
super();
|
|
224
|
+
this.cdr = cdr;
|
|
225
|
+
}
|
|
226
|
+
async GetResourceDisplayName(_data) {
|
|
227
|
+
return 'App Roles';
|
|
228
|
+
}
|
|
229
|
+
async GetResourceIconClass(_data) {
|
|
230
|
+
return 'fa-solid fa-user-shield';
|
|
231
|
+
}
|
|
232
|
+
async ngOnInit() {
|
|
233
|
+
super.ngOnInit();
|
|
234
|
+
await this.loadData();
|
|
235
|
+
this.NotifyLoadComplete();
|
|
236
|
+
}
|
|
237
|
+
ngOnDestroy() {
|
|
238
|
+
super.ngOnDestroy();
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Load all application role data and available roles.
|
|
242
|
+
*/
|
|
243
|
+
async loadData() {
|
|
244
|
+
this.IsLoading = true;
|
|
245
|
+
this.ErrorMessage = null;
|
|
246
|
+
this.cdr.detectChanges();
|
|
247
|
+
try {
|
|
248
|
+
const md = new Metadata();
|
|
249
|
+
const rv = new RunView();
|
|
250
|
+
// Load available roles from metadata
|
|
251
|
+
this.AvailableRoles = md.Roles.map(r => ({ ID: r.ID, Name: r.Name }))
|
|
252
|
+
.sort((a, b) => a.Name.localeCompare(b.Name));
|
|
253
|
+
// Load existing ApplicationRole records
|
|
254
|
+
const result = await rv.RunView({
|
|
255
|
+
EntityName: 'MJ: Application Roles',
|
|
256
|
+
ResultType: 'simple',
|
|
257
|
+
});
|
|
258
|
+
if (!result.Success) {
|
|
259
|
+
this.ErrorMessage = result.ErrorMessage || 'Failed to load application roles.';
|
|
260
|
+
this.IsLoading = false;
|
|
261
|
+
this.cdr.detectChanges();
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
// Build grouped structure
|
|
265
|
+
const appMap = new Map();
|
|
266
|
+
// Seed all applications so we can show apps without any role records
|
|
267
|
+
for (const app of md.Applications) {
|
|
268
|
+
appMap.set(app.ID, {
|
|
269
|
+
ApplicationID: app.ID,
|
|
270
|
+
ApplicationName: app.Name,
|
|
271
|
+
Roles: [],
|
|
272
|
+
Expanded: false,
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
// Populate role assignments
|
|
276
|
+
for (const record of result.Results) {
|
|
277
|
+
const group = appMap.get(record.ApplicationID);
|
|
278
|
+
if (group) {
|
|
279
|
+
group.Roles.push({
|
|
280
|
+
ID: record.ID,
|
|
281
|
+
ApplicationID: record.ApplicationID,
|
|
282
|
+
ApplicationName: group.ApplicationName,
|
|
283
|
+
RoleID: record.RoleID,
|
|
284
|
+
RoleName: record.Role || '',
|
|
285
|
+
CanAccess: record.CanAccess,
|
|
286
|
+
CanAdmin: record.CanAdmin,
|
|
287
|
+
IsDirty: false,
|
|
288
|
+
IsNew: false,
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
// Sort roles within each group
|
|
293
|
+
for (const group of appMap.values()) {
|
|
294
|
+
group.Roles.sort((a, b) => a.RoleName.localeCompare(b.RoleName));
|
|
295
|
+
}
|
|
296
|
+
this.ApplicationGroups = Array.from(appMap.values())
|
|
297
|
+
.sort((a, b) => a.ApplicationName.localeCompare(b.ApplicationName));
|
|
298
|
+
}
|
|
299
|
+
catch (e) {
|
|
300
|
+
this.ErrorMessage = `Error loading data: ${e instanceof Error ? e.message : String(e)}`;
|
|
301
|
+
}
|
|
302
|
+
this.IsLoading = false;
|
|
303
|
+
this.HasUnsavedChanges = false;
|
|
304
|
+
this.cdr.detectChanges();
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Toggle the expanded/collapsed state of an application group.
|
|
308
|
+
*/
|
|
309
|
+
ToggleGroup(group) {
|
|
310
|
+
group.Expanded = !group.Expanded;
|
|
311
|
+
this.cdr.detectChanges();
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* Toggle CanAccess for a specific role assignment.
|
|
315
|
+
*/
|
|
316
|
+
ToggleCanAccess(row) {
|
|
317
|
+
row.CanAccess = !row.CanAccess;
|
|
318
|
+
row.IsDirty = true;
|
|
319
|
+
this.HasUnsavedChanges = true;
|
|
320
|
+
this.cdr.detectChanges();
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Toggle CanAdmin for a specific role assignment.
|
|
324
|
+
*/
|
|
325
|
+
ToggleCanAdmin(row) {
|
|
326
|
+
row.CanAdmin = !row.CanAdmin;
|
|
327
|
+
row.IsDirty = true;
|
|
328
|
+
this.HasUnsavedChanges = true;
|
|
329
|
+
this.cdr.detectChanges();
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* Get roles not yet assigned to a specific application (for the "Add Role" dropdown).
|
|
333
|
+
*/
|
|
334
|
+
GetUnassignedRoles(group) {
|
|
335
|
+
const assignedRoleIds = new Set(group.Roles.map(r => r.RoleID.toLowerCase()));
|
|
336
|
+
return this.AvailableRoles.filter(r => !assignedRoleIds.has(r.ID.toLowerCase()));
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* Add a new role assignment to an application group.
|
|
340
|
+
*/
|
|
341
|
+
AddRole(group) {
|
|
342
|
+
const roleId = this.SelectedRoleIdToAdd.get(group.ApplicationID);
|
|
343
|
+
if (!roleId)
|
|
344
|
+
return;
|
|
345
|
+
const role = this.AvailableRoles.find(r => UUIDsEqual(r.ID, roleId));
|
|
346
|
+
if (!role)
|
|
347
|
+
return;
|
|
348
|
+
group.Roles.push({
|
|
349
|
+
ID: '',
|
|
350
|
+
ApplicationID: group.ApplicationID,
|
|
351
|
+
ApplicationName: group.ApplicationName,
|
|
352
|
+
RoleID: role.ID,
|
|
353
|
+
RoleName: role.Name,
|
|
354
|
+
CanAccess: true,
|
|
355
|
+
CanAdmin: false,
|
|
356
|
+
IsDirty: true,
|
|
357
|
+
IsNew: true,
|
|
358
|
+
});
|
|
359
|
+
group.Roles.sort((a, b) => a.RoleName.localeCompare(b.RoleName));
|
|
360
|
+
this.SelectedRoleIdToAdd.delete(group.ApplicationID);
|
|
361
|
+
this.HasUnsavedChanges = true;
|
|
362
|
+
this.cdr.detectChanges();
|
|
363
|
+
}
|
|
364
|
+
/**
|
|
365
|
+
* Remove a role assignment (marks for deletion on save; removes immediately if new).
|
|
366
|
+
*/
|
|
367
|
+
RemoveRole(group, row) {
|
|
368
|
+
const idx = group.Roles.indexOf(row);
|
|
369
|
+
if (idx >= 0) {
|
|
370
|
+
group.Roles.splice(idx, 1);
|
|
371
|
+
}
|
|
372
|
+
// If not new, we need to delete it on save — track via dirty state
|
|
373
|
+
if (!row.IsNew) {
|
|
374
|
+
this._pendingDeletes.push(row.ID);
|
|
375
|
+
}
|
|
376
|
+
this.HasUnsavedChanges = true;
|
|
377
|
+
this.cdr.detectChanges();
|
|
378
|
+
}
|
|
379
|
+
_pendingDeletes = [];
|
|
380
|
+
/**
|
|
381
|
+
* Save all unsaved changes (new records, modified records, deleted records).
|
|
382
|
+
*/
|
|
383
|
+
async SaveChanges() {
|
|
384
|
+
this.IsSaving = true;
|
|
385
|
+
this.ErrorMessage = null;
|
|
386
|
+
this.SuccessMessage = null;
|
|
387
|
+
this.cdr.detectChanges();
|
|
388
|
+
try {
|
|
389
|
+
const md = new Metadata();
|
|
390
|
+
// Process deletes
|
|
391
|
+
for (const deleteId of this._pendingDeletes) {
|
|
392
|
+
const entity = await md.GetEntityObject('MJ: Application Roles');
|
|
393
|
+
await entity.InnerLoad(new CompositeKey([{ FieldName: 'ID', Value: deleteId }]));
|
|
394
|
+
const deleteResult = await entity.Delete();
|
|
395
|
+
if (!deleteResult) {
|
|
396
|
+
this.ErrorMessage = `Failed to delete role assignment: ${entity.LatestResult?.Message || 'Unknown error'}`;
|
|
397
|
+
this.IsSaving = false;
|
|
398
|
+
this.cdr.detectChanges();
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
// Process new and modified records
|
|
403
|
+
for (const group of this.ApplicationGroups) {
|
|
404
|
+
for (const row of group.Roles) {
|
|
405
|
+
if (!row.IsDirty)
|
|
406
|
+
continue;
|
|
407
|
+
if (row.IsNew) {
|
|
408
|
+
const entity = await md.GetEntityObject('MJ: Application Roles');
|
|
409
|
+
entity.NewRecord();
|
|
410
|
+
entity.Set('ApplicationID', row.ApplicationID);
|
|
411
|
+
entity.Set('RoleID', row.RoleID);
|
|
412
|
+
entity.Set('CanAccess', row.CanAccess);
|
|
413
|
+
entity.Set('CanAdmin', row.CanAdmin);
|
|
414
|
+
const saveResult = await entity.Save();
|
|
415
|
+
if (!saveResult) {
|
|
416
|
+
this.ErrorMessage = `Failed to save new role assignment for ${row.RoleName}: ${entity.LatestResult?.Message || 'Unknown error'}`;
|
|
417
|
+
this.IsSaving = false;
|
|
418
|
+
this.cdr.detectChanges();
|
|
419
|
+
return;
|
|
420
|
+
}
|
|
421
|
+
row.ID = entity.Get('ID');
|
|
422
|
+
}
|
|
423
|
+
else {
|
|
424
|
+
const entity = await md.GetEntityObject('MJ: Application Roles');
|
|
425
|
+
await entity.InnerLoad(new CompositeKey([{ FieldName: 'ID', Value: row.ID }]));
|
|
426
|
+
entity.Set('CanAccess', row.CanAccess);
|
|
427
|
+
entity.Set('CanAdmin', row.CanAdmin);
|
|
428
|
+
const saveResult = await entity.Save();
|
|
429
|
+
if (!saveResult) {
|
|
430
|
+
this.ErrorMessage = `Failed to update role assignment for ${row.RoleName}: ${entity.LatestResult?.Message || 'Unknown error'}`;
|
|
431
|
+
this.IsSaving = false;
|
|
432
|
+
this.cdr.detectChanges();
|
|
433
|
+
return;
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
row.IsDirty = false;
|
|
437
|
+
row.IsNew = false;
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
this._pendingDeletes = [];
|
|
441
|
+
this.HasUnsavedChanges = false;
|
|
442
|
+
this.SuccessMessage = 'All changes saved successfully.';
|
|
443
|
+
}
|
|
444
|
+
catch (e) {
|
|
445
|
+
this.ErrorMessage = `Error saving: ${e instanceof Error ? e.message : String(e)}`;
|
|
446
|
+
}
|
|
447
|
+
this.IsSaving = false;
|
|
448
|
+
this.cdr.detectChanges();
|
|
449
|
+
}
|
|
450
|
+
/**
|
|
451
|
+
* Discard all unsaved changes and reload data.
|
|
452
|
+
*/
|
|
453
|
+
async DiscardChanges() {
|
|
454
|
+
this._pendingDeletes = [];
|
|
455
|
+
await this.loadData();
|
|
456
|
+
}
|
|
457
|
+
/**
|
|
458
|
+
* Track by function for application groups.
|
|
459
|
+
*/
|
|
460
|
+
TrackByAppId(_index, group) {
|
|
461
|
+
return group.ApplicationID;
|
|
462
|
+
}
|
|
463
|
+
/**
|
|
464
|
+
* Track by function for role rows.
|
|
465
|
+
*/
|
|
466
|
+
TrackByRoleRow(_index, row) {
|
|
467
|
+
return row.IsNew ? `new-${row.RoleID}` : row.ID;
|
|
468
|
+
}
|
|
469
|
+
/**
|
|
470
|
+
* Get the role count label for an application.
|
|
471
|
+
*/
|
|
472
|
+
GetRoleCountLabel(group) {
|
|
473
|
+
if (group.Roles.length === 0)
|
|
474
|
+
return 'Open Access (no role restrictions)';
|
|
475
|
+
return `${group.Roles.length} role${group.Roles.length === 1 ? '' : 's'} assigned`;
|
|
476
|
+
}
|
|
477
|
+
/**
|
|
478
|
+
* Handle dropdown selection for adding roles.
|
|
479
|
+
*/
|
|
480
|
+
OnAddRoleSelect(group, roleId) {
|
|
481
|
+
this.SelectedRoleIdToAdd.set(group.ApplicationID, roleId);
|
|
482
|
+
}
|
|
483
|
+
static ɵfac = function ApplicationRolesResourceComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ApplicationRolesResourceComponent)(i0.ɵɵdirectiveInject(i0.ChangeDetectorRef)); };
|
|
484
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ApplicationRolesResourceComponent, selectors: [["mj-application-roles-resource"]], standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 15, vars: 8, consts: [[1, "app-roles-container"], [1, "header"], [1, "header-left"], [1, "fa-solid", "fa-user-shield", "header-icon"], [1, "header-title"], [1, "header-actions"], ["mjButton", "", "variant", "secondary", 3, "click", "disabled"], [1, "fa-solid", "fa-arrows-rotate"], [1, "message", "error-message"], [1, "message", "success-message"], ["text", "Loading application roles..."], [1, "fa-solid", "fa-rotate-left"], ["mjButton", "", "variant", "primary", 3, "click", "disabled"], [1, "fa-solid", "fa-spinner", "fa-spin"], [1, "fa-solid", "fa-floppy-disk"], [1, "fa-solid", "fa-circle-exclamation"], [1, "fa-solid", "fa-circle-check"], [1, "description"], [1, "app-groups"], [1, "app-group", 3, "expanded", "has-roles"], [1, "app-group"], [1, "app-group-header", 3, "click"], [1, "app-header-left"], [1, "fa-solid", 3, "ngClass"], [1, "app-name"], [1, "role-count-badge"], [1, "app-group-content"], [1, "roles-table"], [1, "no-roles-message"], [1, "add-role-row"], [1, "mj-input", "add-role-select", 3, "change", "value"], ["value", "", "disabled", ""], [3, "value"], [1, "fa-solid", "fa-plus"], [1, "col-role"], [1, "col-access"], [1, "col-admin"], [1, "col-actions"], [3, "dirty", "new-row"], [1, "fa-solid", "fa-shield-halved", "role-icon"], [1, "new-badge"], ["type", "checkbox", 1, "mj-checkbox", 3, "change", "checked"], ["title", "Remove role assignment", 1, "remove-btn", 3, "click"], [1, "fa-solid", "fa-trash-can"], [1, "fa-solid", "fa-unlock"]], template: function ApplicationRolesResourceComponent_Template(rf, ctx) { if (rf & 1) {
|
|
485
|
+
i0.ɵɵelementStart(0, "div", 0)(1, "div", 1)(2, "div", 2);
|
|
486
|
+
i0.ɵɵelement(3, "i", 3);
|
|
487
|
+
i0.ɵɵelementStart(4, "h2", 4);
|
|
488
|
+
i0.ɵɵtext(5, "Application Roles");
|
|
489
|
+
i0.ɵɵelementEnd()();
|
|
490
|
+
i0.ɵɵelementStart(6, "div", 5);
|
|
491
|
+
i0.ɵɵconditionalCreate(7, ApplicationRolesResourceComponent_Conditional_7_Template, 6, 3);
|
|
492
|
+
i0.ɵɵelementStart(8, "button", 6);
|
|
493
|
+
i0.ɵɵlistener("click", function ApplicationRolesResourceComponent_Template_button_click_8_listener() { return ctx.loadData(); });
|
|
494
|
+
i0.ɵɵelement(9, "i", 7);
|
|
495
|
+
i0.ɵɵtext(10, " Refresh ");
|
|
496
|
+
i0.ɵɵelementEnd()()();
|
|
497
|
+
i0.ɵɵconditionalCreate(11, ApplicationRolesResourceComponent_Conditional_11_Template, 3, 1, "div", 8);
|
|
498
|
+
i0.ɵɵconditionalCreate(12, ApplicationRolesResourceComponent_Conditional_12_Template, 3, 1, "div", 9);
|
|
499
|
+
i0.ɵɵconditionalCreate(13, ApplicationRolesResourceComponent_Conditional_13_Template, 1, 0, "mj-loading", 10);
|
|
500
|
+
i0.ɵɵconditionalCreate(14, ApplicationRolesResourceComponent_Conditional_14_Template, 5, 0);
|
|
501
|
+
i0.ɵɵelementEnd();
|
|
502
|
+
} if (rf & 2) {
|
|
503
|
+
i0.ɵɵadvance(7);
|
|
504
|
+
i0.ɵɵconditional(ctx.HasUnsavedChanges ? 7 : -1);
|
|
505
|
+
i0.ɵɵadvance();
|
|
506
|
+
i0.ɵɵproperty("disabled", ctx.IsLoading || ctx.IsSaving);
|
|
507
|
+
i0.ɵɵadvance();
|
|
508
|
+
i0.ɵɵclassProp("fa-spin", ctx.IsLoading);
|
|
509
|
+
i0.ɵɵadvance(2);
|
|
510
|
+
i0.ɵɵconditional(ctx.ErrorMessage ? 11 : -1);
|
|
511
|
+
i0.ɵɵadvance();
|
|
512
|
+
i0.ɵɵconditional(ctx.SuccessMessage ? 12 : -1);
|
|
513
|
+
i0.ɵɵadvance();
|
|
514
|
+
i0.ɵɵconditional(ctx.IsLoading ? 13 : -1);
|
|
515
|
+
i0.ɵɵadvance();
|
|
516
|
+
i0.ɵɵconditional(!ctx.IsLoading ? 14 : -1);
|
|
517
|
+
} }, dependencies: [i1.NgClass, i2.NgSelectOption, i2.ɵNgSelectMultipleOption, i3.MJButtonDirective, i4.LoadingComponent], styles: [".app-roles-container[_ngcontent-%COMP%] {\n padding: 24px;\n max-width: 960px;\n margin: 0 auto;\n}\n\n\n\n.header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 20px;\n}\n\n.header-left[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.header-icon[_ngcontent-%COMP%] {\n font-size: 24px;\n color: var(--mj-brand-primary);\n}\n\n.header-title[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 22px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.header-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n align-items: center;\n}\n\n\n\n.message[_ngcontent-%COMP%] {\n padding: 10px 14px;\n border-radius: 6px;\n margin-bottom: 16px;\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 14px;\n}\n\n.error-message[_ngcontent-%COMP%] {\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error-text);\n border: 1px solid var(--mj-status-error-border);\n}\n\n.success-message[_ngcontent-%COMP%] {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n border: 1px solid var(--mj-status-success-border);\n}\n\n\n\n.description[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n font-size: 14px;\n margin-bottom: 20px;\n line-height: 1.5;\n}\n\n\n\n.app-groups[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.app-group[_ngcontent-%COMP%] {\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n overflow: hidden;\n background: var(--mj-bg-surface);\n}\n\n.app-group.expanded[_ngcontent-%COMP%] {\n border-color: var(--mj-border-strong);\n}\n\n.app-group-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 12px 16px;\n cursor: pointer;\n user-select: none;\n background: var(--mj-bg-surface-card);\n transition: background 0.15s;\n}\n\n.app-group-header[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.app-header-left[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n}\n\n.app-header-left[_ngcontent-%COMP%] > i[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-muted);\n width: 14px;\n text-align: center;\n}\n\n.app-name[_ngcontent-%COMP%] {\n font-weight: 600;\n font-size: 15px;\n color: var(--mj-text-primary);\n}\n\n.role-count-badge[_ngcontent-%COMP%] {\n font-size: 12px;\n padding: 2px 8px;\n border-radius: 10px;\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.role-count-badge.open-access[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-status-success) 12%, var(--mj-bg-surface));\n color: var(--mj-status-success-text);\n}\n\n\n\n.app-group-content[_ngcontent-%COMP%] {\n padding: 16px;\n border-top: 1px solid var(--mj-border-subtle);\n}\n\n\n\n.roles-table[_ngcontent-%COMP%] {\n width: 100%;\n border-collapse: collapse;\n margin-bottom: 12px;\n}\n\n.roles-table[_ngcontent-%COMP%] th[_ngcontent-%COMP%] {\n text-align: left;\n padding: 8px 12px;\n font-size: 12px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--mj-text-muted);\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.roles-table[_ngcontent-%COMP%] td[_ngcontent-%COMP%] {\n padding: 10px 12px;\n font-size: 14px;\n color: var(--mj-text-primary);\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n\n.roles-table[_ngcontent-%COMP%] tr[_ngcontent-%COMP%]:last-child td[_ngcontent-%COMP%] {\n border-bottom: none;\n}\n\n.roles-table[_ngcontent-%COMP%] tr.dirty[_ngcontent-%COMP%] td[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-status-warning) 6%, var(--mj-bg-surface));\n}\n\n.roles-table[_ngcontent-%COMP%] tr.new-row[_ngcontent-%COMP%] td[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-status-success) 6%, var(--mj-bg-surface));\n}\n\n.col-role[_ngcontent-%COMP%] {\n width: 40%;\n}\n\n.col-access[_ngcontent-%COMP%], \n.col-admin[_ngcontent-%COMP%] {\n width: 20%;\n text-align: center;\n}\n\n.col-actions[_ngcontent-%COMP%] {\n width: 20%;\n text-align: center;\n}\n\n.roles-table[_ngcontent-%COMP%] th.col-access[_ngcontent-%COMP%], \n.roles-table[_ngcontent-%COMP%] th.col-admin[_ngcontent-%COMP%], \n.roles-table[_ngcontent-%COMP%] th.col-actions[_ngcontent-%COMP%] {\n text-align: center;\n}\n\n.role-icon[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n margin-right: 6px;\n}\n\n.new-badge[_ngcontent-%COMP%] {\n font-size: 10px;\n padding: 1px 6px;\n border-radius: 8px;\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n margin-left: 6px;\n text-transform: uppercase;\n font-weight: 600;\n}\n\n.remove-btn[_ngcontent-%COMP%] {\n border: none;\n background: none;\n color: var(--mj-text-muted);\n cursor: pointer;\n padding: 4px 8px;\n border-radius: 4px;\n transition: all 0.15s;\n}\n\n.remove-btn[_ngcontent-%COMP%]:hover {\n color: var(--mj-status-error);\n background: var(--mj-status-error-bg);\n}\n\n\n\n.no-roles-message[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 12px;\n font-size: 14px;\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface-sunken);\n border-radius: 6px;\n margin-bottom: 12px;\n}\n\n.no-roles-message[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-status-success);\n}\n\n\n\n.add-role-row[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n align-items: center;\n}\n\n.add-role-select[_ngcontent-%COMP%] {\n flex: 1;\n max-width: 300px;\n padding: 6px 10px;\n font-size: 14px;\n}"] });
|
|
518
|
+
};
|
|
519
|
+
ApplicationRolesResourceComponent = __decorate([
|
|
520
|
+
RegisterClass(BaseResourceComponent, 'ApplicationRolesResource')
|
|
521
|
+
], ApplicationRolesResourceComponent);
|
|
522
|
+
export { ApplicationRolesResourceComponent };
|
|
523
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ApplicationRolesResourceComponent, [{
|
|
524
|
+
type: Component,
|
|
525
|
+
args: [{ standalone: false, selector: 'mj-application-roles-resource', template: "<div class=\"app-roles-container\">\n <!-- Header -->\n <div class=\"header\">\n <div class=\"header-left\">\n <i class=\"fa-solid fa-user-shield header-icon\"></i>\n <h2 class=\"header-title\">Application Roles</h2>\n </div>\n <div class=\"header-actions\">\n @if (HasUnsavedChanges) {\n <button mjButton variant=\"secondary\" (click)=\"DiscardChanges()\" [disabled]=\"IsSaving\">\n <i class=\"fa-solid fa-rotate-left\"></i> Discard\n </button>\n <button mjButton variant=\"primary\" (click)=\"SaveChanges()\" [disabled]=\"IsSaving\">\n @if (IsSaving) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i> Saving...\n } @else {\n <i class=\"fa-solid fa-floppy-disk\"></i> Save Changes\n }\n </button>\n }\n <button mjButton variant=\"secondary\" (click)=\"loadData()\" [disabled]=\"IsLoading || IsSaving\">\n <i class=\"fa-solid fa-arrows-rotate\" [class.fa-spin]=\"IsLoading\"></i> Refresh\n </button>\n </div>\n </div>\n\n <!-- Status Messages -->\n @if (ErrorMessage) {\n <div class=\"message error-message\">\n <i class=\"fa-solid fa-circle-exclamation\"></i>\n {{ ErrorMessage }}\n </div>\n }\n @if (SuccessMessage) {\n <div class=\"message success-message\">\n <i class=\"fa-solid fa-circle-check\"></i>\n {{ SuccessMessage }}\n </div>\n }\n\n <!-- Loading State -->\n @if (IsLoading) {\n <mj-loading text=\"Loading application roles...\"></mj-loading>\n }\n\n <!-- Main Content -->\n @if (!IsLoading) {\n <p class=\"description\">\n Configure which roles can access each application. Applications with no role assignments are open to all users (backwards compatible).\n </p>\n\n <div class=\"app-groups\">\n @for (group of ApplicationGroups; track TrackByAppId($index, group)) {\n <div class=\"app-group\" [class.expanded]=\"group.Expanded\" [class.has-roles]=\"group.Roles.length > 0\">\n <!-- Application Header Row -->\n <div class=\"app-group-header\" (click)=\"ToggleGroup(group)\">\n <div class=\"app-header-left\">\n <i class=\"fa-solid\" [ngClass]=\"group.Expanded ? 'fa-chevron-down' : 'fa-chevron-right'\"></i>\n <span class=\"app-name\">{{ group.ApplicationName }}</span>\n <span class=\"role-count-badge\" [class.open-access]=\"group.Roles.length === 0\">\n {{ GetRoleCountLabel(group) }}\n </span>\n </div>\n </div>\n\n <!-- Expanded Content -->\n @if (group.Expanded) {\n <div class=\"app-group-content\">\n <!-- Existing Role Assignments -->\n @if (group.Roles.length > 0) {\n <table class=\"roles-table\">\n <thead>\n <tr>\n <th class=\"col-role\">Role</th>\n <th class=\"col-access\">Can Access</th>\n <th class=\"col-admin\">Can Admin</th>\n <th class=\"col-actions\">Actions</th>\n </tr>\n </thead>\n <tbody>\n @for (row of group.Roles; track TrackByRoleRow($index, row)) {\n <tr [class.dirty]=\"row.IsDirty\" [class.new-row]=\"row.IsNew\">\n <td class=\"col-role\">\n <i class=\"fa-solid fa-shield-halved role-icon\"></i>\n {{ row.RoleName }}\n @if (row.IsNew) {\n <span class=\"new-badge\">new</span>\n }\n </td>\n <td class=\"col-access\">\n <input type=\"checkbox\"\n class=\"mj-checkbox\"\n [checked]=\"row.CanAccess\"\n (change)=\"ToggleCanAccess(row)\">\n </td>\n <td class=\"col-admin\">\n <input type=\"checkbox\"\n class=\"mj-checkbox\"\n [checked]=\"row.CanAdmin\"\n (change)=\"ToggleCanAdmin(row)\">\n </td>\n <td class=\"col-actions\">\n <button class=\"remove-btn\" (click)=\"RemoveRole(group, row)\" title=\"Remove role assignment\">\n <i class=\"fa-solid fa-trash-can\"></i>\n </button>\n </td>\n </tr>\n }\n </tbody>\n </table>\n } @else {\n <div class=\"no-roles-message\">\n <i class=\"fa-solid fa-unlock\"></i>\n No role restrictions \u2014 all authenticated users can access this application.\n </div>\n }\n\n <!-- Add Role -->\n <div class=\"add-role-row\">\n <select class=\"mj-input add-role-select\"\n [value]=\"SelectedRoleIdToAdd.get(group.ApplicationID) || ''\"\n (change)=\"OnAddRoleSelect(group, $any($event.target).value)\">\n <option value=\"\" disabled>Select a role to add...</option>\n @for (role of GetUnassignedRoles(group); track role.ID) {\n <option [value]=\"role.ID\">{{ role.Name }}</option>\n }\n </select>\n <button mjButton\n variant=\"secondary\"\n (click)=\"AddRole(group)\"\n [disabled]=\"!SelectedRoleIdToAdd.get(group.ApplicationID)\">\n <i class=\"fa-solid fa-plus\"></i> Add Role\n </button>\n </div>\n </div>\n }\n </div>\n }\n </div>\n }\n</div>\n", styles: [".app-roles-container {\n padding: 24px;\n max-width: 960px;\n margin: 0 auto;\n}\n\n/* Header */\n.header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 20px;\n}\n\n.header-left {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.header-icon {\n font-size: 24px;\n color: var(--mj-brand-primary);\n}\n\n.header-title {\n margin: 0;\n font-size: 22px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.header-actions {\n display: flex;\n gap: 8px;\n align-items: center;\n}\n\n/* Messages */\n.message {\n padding: 10px 14px;\n border-radius: 6px;\n margin-bottom: 16px;\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 14px;\n}\n\n.error-message {\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error-text);\n border: 1px solid var(--mj-status-error-border);\n}\n\n.success-message {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n border: 1px solid var(--mj-status-success-border);\n}\n\n/* Description */\n.description {\n color: var(--mj-text-secondary);\n font-size: 14px;\n margin-bottom: 20px;\n line-height: 1.5;\n}\n\n/* Application Groups */\n.app-groups {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.app-group {\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n overflow: hidden;\n background: var(--mj-bg-surface);\n}\n\n.app-group.expanded {\n border-color: var(--mj-border-strong);\n}\n\n.app-group-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 12px 16px;\n cursor: pointer;\n user-select: none;\n background: var(--mj-bg-surface-card);\n transition: background 0.15s;\n}\n\n.app-group-header:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.app-header-left {\n display: flex;\n align-items: center;\n gap: 10px;\n}\n\n.app-header-left > i {\n font-size: 12px;\n color: var(--mj-text-muted);\n width: 14px;\n text-align: center;\n}\n\n.app-name {\n font-weight: 600;\n font-size: 15px;\n color: var(--mj-text-primary);\n}\n\n.role-count-badge {\n font-size: 12px;\n padding: 2px 8px;\n border-radius: 10px;\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.role-count-badge.open-access {\n background: color-mix(in srgb, var(--mj-status-success) 12%, var(--mj-bg-surface));\n color: var(--mj-status-success-text);\n}\n\n/* Expanded Content */\n.app-group-content {\n padding: 16px;\n border-top: 1px solid var(--mj-border-subtle);\n}\n\n/* Table */\n.roles-table {\n width: 100%;\n border-collapse: collapse;\n margin-bottom: 12px;\n}\n\n.roles-table th {\n text-align: left;\n padding: 8px 12px;\n font-size: 12px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--mj-text-muted);\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.roles-table td {\n padding: 10px 12px;\n font-size: 14px;\n color: var(--mj-text-primary);\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n\n.roles-table tr:last-child td {\n border-bottom: none;\n}\n\n.roles-table tr.dirty td {\n background: color-mix(in srgb, var(--mj-status-warning) 6%, var(--mj-bg-surface));\n}\n\n.roles-table tr.new-row td {\n background: color-mix(in srgb, var(--mj-status-success) 6%, var(--mj-bg-surface));\n}\n\n.col-role {\n width: 40%;\n}\n\n.col-access,\n.col-admin {\n width: 20%;\n text-align: center;\n}\n\n.col-actions {\n width: 20%;\n text-align: center;\n}\n\n.roles-table th.col-access,\n.roles-table th.col-admin,\n.roles-table th.col-actions {\n text-align: center;\n}\n\n.role-icon {\n color: var(--mj-text-muted);\n margin-right: 6px;\n}\n\n.new-badge {\n font-size: 10px;\n padding: 1px 6px;\n border-radius: 8px;\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n margin-left: 6px;\n text-transform: uppercase;\n font-weight: 600;\n}\n\n.remove-btn {\n border: none;\n background: none;\n color: var(--mj-text-muted);\n cursor: pointer;\n padding: 4px 8px;\n border-radius: 4px;\n transition: all 0.15s;\n}\n\n.remove-btn:hover {\n color: var(--mj-status-error);\n background: var(--mj-status-error-bg);\n}\n\n/* No Roles Message */\n.no-roles-message {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 12px;\n font-size: 14px;\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface-sunken);\n border-radius: 6px;\n margin-bottom: 12px;\n}\n\n.no-roles-message i {\n color: var(--mj-status-success);\n}\n\n/* Add Role Row */\n.add-role-row {\n display: flex;\n gap: 8px;\n align-items: center;\n}\n\n.add-role-select {\n flex: 1;\n max-width: 300px;\n padding: 6px 10px;\n font-size: 14px;\n}\n"] }]
|
|
526
|
+
}], () => [{ type: i0.ChangeDetectorRef }], null); })();
|
|
527
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ApplicationRolesResourceComponent, { className: "ApplicationRolesResourceComponent", filePath: "src/ApplicationRoles/application-roles-resource.component.ts", lineNumber: 43 }); })();
|
|
528
|
+
/** Tree-shaking prevention */
|
|
529
|
+
export function LoadApplicationRolesResource() {
|
|
530
|
+
// Prevents tree-shaking
|
|
531
|
+
}
|
|
532
|
+
//# sourceMappingURL=application-roles-resource.component.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"application-roles-resource.component.js","sourceRoot":"","sources":["../../src/ApplicationRoles/application-roles-resource.component.ts","../../src/ApplicationRoles/application-roles-resource.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, OnInit, OnDestroy, ChangeDetectorRef } from '@angular/core';\nimport { RegisterClass, UUIDsEqual } from '@memberjunction/global';\nimport { BaseResourceComponent } from '@memberjunction/ng-shared';\nimport { CompositeKey, Metadata, RunView } from '@memberjunction/core';\nimport { ResourceData } from '@memberjunction/core-entities';\n\n/**\n * Represents an application's role assignment for display in the grid.\n */\ninterface ApplicationRoleRow {\n ID: string;\n ApplicationID: string;\n ApplicationName: string;\n RoleID: string;\n RoleName: string;\n CanAccess: boolean;\n CanAdmin: boolean;\n IsDirty: boolean;\n IsNew: boolean;\n}\n\n/**\n * Represents an application with its role assignments grouped.\n */\ninterface ApplicationGroup {\n ApplicationID: string;\n ApplicationName: string;\n Roles: ApplicationRoleRow[];\n Expanded: boolean;\n}\n\n/**\n * Admin dashboard for managing Application Role assignments.\n * Shows which roles can access and administer each application.\n */\n@RegisterClass(BaseResourceComponent, 'ApplicationRolesResource')\n@Component({\n standalone: false,\n selector: 'mj-application-roles-resource',\n templateUrl: './application-roles-resource.component.html',\n styleUrls: ['./application-roles-resource.component.css']\n})\nexport class ApplicationRolesResourceComponent extends BaseResourceComponent implements OnInit, OnDestroy {\n ApplicationGroups: ApplicationGroup[] = [];\n AvailableRoles: { ID: string; Name: string }[] = [];\n IsLoading = true;\n IsSaving = false;\n HasUnsavedChanges = false;\n ErrorMessage: string | null = null;\n SuccessMessage: string | null = null;\n\n // For the \"Add Role\" dropdown per application\n SelectedRoleIdToAdd: Map<string, string> = new Map();\n\n constructor(private cdr: ChangeDetectorRef) {\n super();\n }\n\n override async GetResourceDisplayName(_data: ResourceData): Promise<string> {\n return 'App Roles';\n }\n\n override async GetResourceIconClass(_data: ResourceData): Promise<string> {\n return 'fa-solid fa-user-shield';\n }\n\n override async ngOnInit(): Promise<void> {\n super.ngOnInit();\n await this.loadData();\n this.NotifyLoadComplete();\n }\n\n override ngOnDestroy(): void {\n super.ngOnDestroy();\n }\n\n /**\n * Load all application role data and available roles.\n */\n async loadData(): Promise<void> {\n this.IsLoading = true;\n this.ErrorMessage = null;\n this.cdr.detectChanges();\n\n try {\n const md = new Metadata();\n const rv = new RunView();\n\n // Load available roles from metadata\n this.AvailableRoles = md.Roles.map(r => ({ ID: r.ID, Name: r.Name }))\n .sort((a, b) => a.Name.localeCompare(b.Name));\n\n // Load existing ApplicationRole records\n const result = await rv.RunView<{ ID: string; ApplicationID: string; Application: string; RoleID: string; Role: string; CanAccess: boolean; CanAdmin: boolean }>({\n EntityName: 'MJ: Application Roles',\n ResultType: 'simple',\n });\n\n if (!result.Success) {\n this.ErrorMessage = result.ErrorMessage || 'Failed to load application roles.';\n this.IsLoading = false;\n this.cdr.detectChanges();\n return;\n }\n\n // Build grouped structure\n const appMap = new Map<string, ApplicationGroup>();\n\n // Seed all applications so we can show apps without any role records\n for (const app of md.Applications) {\n appMap.set(app.ID, {\n ApplicationID: app.ID,\n ApplicationName: app.Name,\n Roles: [],\n Expanded: false,\n });\n }\n\n // Populate role assignments\n for (const record of result.Results) {\n const group = appMap.get(record.ApplicationID);\n if (group) {\n group.Roles.push({\n ID: record.ID,\n ApplicationID: record.ApplicationID,\n ApplicationName: group.ApplicationName,\n RoleID: record.RoleID,\n RoleName: record.Role || '',\n CanAccess: record.CanAccess,\n CanAdmin: record.CanAdmin,\n IsDirty: false,\n IsNew: false,\n });\n }\n }\n\n // Sort roles within each group\n for (const group of appMap.values()) {\n group.Roles.sort((a, b) => a.RoleName.localeCompare(b.RoleName));\n }\n\n this.ApplicationGroups = Array.from(appMap.values())\n .sort((a, b) => a.ApplicationName.localeCompare(b.ApplicationName));\n } catch (e) {\n this.ErrorMessage = `Error loading data: ${e instanceof Error ? e.message : String(e)}`;\n }\n\n this.IsLoading = false;\n this.HasUnsavedChanges = false;\n this.cdr.detectChanges();\n }\n\n /**\n * Toggle the expanded/collapsed state of an application group.\n */\n ToggleGroup(group: ApplicationGroup): void {\n group.Expanded = !group.Expanded;\n this.cdr.detectChanges();\n }\n\n /**\n * Toggle CanAccess for a specific role assignment.\n */\n ToggleCanAccess(row: ApplicationRoleRow): void {\n row.CanAccess = !row.CanAccess;\n row.IsDirty = true;\n this.HasUnsavedChanges = true;\n this.cdr.detectChanges();\n }\n\n /**\n * Toggle CanAdmin for a specific role assignment.\n */\n ToggleCanAdmin(row: ApplicationRoleRow): void {\n row.CanAdmin = !row.CanAdmin;\n row.IsDirty = true;\n this.HasUnsavedChanges = true;\n this.cdr.detectChanges();\n }\n\n /**\n * Get roles not yet assigned to a specific application (for the \"Add Role\" dropdown).\n */\n GetUnassignedRoles(group: ApplicationGroup): { ID: string; Name: string }[] {\n const assignedRoleIds = new Set(group.Roles.map(r => r.RoleID.toLowerCase()));\n return this.AvailableRoles.filter(r => !assignedRoleIds.has(r.ID.toLowerCase()));\n }\n\n /**\n * Add a new role assignment to an application group.\n */\n AddRole(group: ApplicationGroup): void {\n const roleId = this.SelectedRoleIdToAdd.get(group.ApplicationID);\n if (!roleId) return;\n\n const role = this.AvailableRoles.find(r => UUIDsEqual(r.ID, roleId));\n if (!role) return;\n\n group.Roles.push({\n ID: '',\n ApplicationID: group.ApplicationID,\n ApplicationName: group.ApplicationName,\n RoleID: role.ID,\n RoleName: role.Name,\n CanAccess: true,\n CanAdmin: false,\n IsDirty: true,\n IsNew: true,\n });\n\n group.Roles.sort((a, b) => a.RoleName.localeCompare(b.RoleName));\n this.SelectedRoleIdToAdd.delete(group.ApplicationID);\n this.HasUnsavedChanges = true;\n this.cdr.detectChanges();\n }\n\n /**\n * Remove a role assignment (marks for deletion on save; removes immediately if new).\n */\n RemoveRole(group: ApplicationGroup, row: ApplicationRoleRow): void {\n const idx = group.Roles.indexOf(row);\n if (idx >= 0) {\n group.Roles.splice(idx, 1);\n }\n // If not new, we need to delete it on save — track via dirty state\n if (!row.IsNew) {\n this._pendingDeletes.push(row.ID);\n }\n this.HasUnsavedChanges = true;\n this.cdr.detectChanges();\n }\n\n private _pendingDeletes: string[] = [];\n\n /**\n * Save all unsaved changes (new records, modified records, deleted records).\n */\n async SaveChanges(): Promise<void> {\n this.IsSaving = true;\n this.ErrorMessage = null;\n this.SuccessMessage = null;\n this.cdr.detectChanges();\n\n try {\n const md = new Metadata();\n\n // Process deletes\n for (const deleteId of this._pendingDeletes) {\n const entity = await md.GetEntityObject('MJ: Application Roles');\n await entity.InnerLoad(new CompositeKey([{ FieldName: 'ID', Value: deleteId }]));\n const deleteResult = await entity.Delete();\n if (!deleteResult) {\n this.ErrorMessage = `Failed to delete role assignment: ${entity.LatestResult?.Message || 'Unknown error'}`;\n this.IsSaving = false;\n this.cdr.detectChanges();\n return;\n }\n }\n\n // Process new and modified records\n for (const group of this.ApplicationGroups) {\n for (const row of group.Roles) {\n if (!row.IsDirty) continue;\n\n if (row.IsNew) {\n const entity = await md.GetEntityObject('MJ: Application Roles');\n entity.NewRecord();\n entity.Set('ApplicationID', row.ApplicationID);\n entity.Set('RoleID', row.RoleID);\n entity.Set('CanAccess', row.CanAccess);\n entity.Set('CanAdmin', row.CanAdmin);\n const saveResult = await entity.Save();\n if (!saveResult) {\n this.ErrorMessage = `Failed to save new role assignment for ${row.RoleName}: ${entity.LatestResult?.Message || 'Unknown error'}`;\n this.IsSaving = false;\n this.cdr.detectChanges();\n return;\n }\n row.ID = entity.Get('ID');\n } else {\n const entity = await md.GetEntityObject('MJ: Application Roles');\n await entity.InnerLoad(new CompositeKey([{ FieldName: 'ID', Value: row.ID }]));\n entity.Set('CanAccess', row.CanAccess);\n entity.Set('CanAdmin', row.CanAdmin);\n const saveResult = await entity.Save();\n if (!saveResult) {\n this.ErrorMessage = `Failed to update role assignment for ${row.RoleName}: ${entity.LatestResult?.Message || 'Unknown error'}`;\n this.IsSaving = false;\n this.cdr.detectChanges();\n return;\n }\n }\n\n row.IsDirty = false;\n row.IsNew = false;\n }\n }\n\n this._pendingDeletes = [];\n this.HasUnsavedChanges = false;\n this.SuccessMessage = 'All changes saved successfully.';\n } catch (e) {\n this.ErrorMessage = `Error saving: ${e instanceof Error ? e.message : String(e)}`;\n }\n\n this.IsSaving = false;\n this.cdr.detectChanges();\n }\n\n /**\n * Discard all unsaved changes and reload data.\n */\n async DiscardChanges(): Promise<void> {\n this._pendingDeletes = [];\n await this.loadData();\n }\n\n /**\n * Track by function for application groups.\n */\n TrackByAppId(_index: number, group: ApplicationGroup): string {\n return group.ApplicationID;\n }\n\n /**\n * Track by function for role rows.\n */\n TrackByRoleRow(_index: number, row: ApplicationRoleRow): string {\n return row.IsNew ? `new-${row.RoleID}` : row.ID;\n }\n\n /**\n * Get the role count label for an application.\n */\n GetRoleCountLabel(group: ApplicationGroup): string {\n if (group.Roles.length === 0) return 'Open Access (no role restrictions)';\n return `${group.Roles.length} role${group.Roles.length === 1 ? '' : 's'} assigned`;\n }\n\n /**\n * Handle dropdown selection for adding roles.\n */\n OnAddRoleSelect(group: ApplicationGroup, roleId: string): void {\n this.SelectedRoleIdToAdd.set(group.ApplicationID, roleId);\n }\n}\n\n/** Tree-shaking prevention */\nexport function LoadApplicationRolesResource(): void {\n // Prevents tree-shaking\n}\n","<div class=\"app-roles-container\">\n <!-- Header -->\n <div class=\"header\">\n <div class=\"header-left\">\n <i class=\"fa-solid fa-user-shield header-icon\"></i>\n <h2 class=\"header-title\">Application Roles</h2>\n </div>\n <div class=\"header-actions\">\n @if (HasUnsavedChanges) {\n <button mjButton variant=\"secondary\" (click)=\"DiscardChanges()\" [disabled]=\"IsSaving\">\n <i class=\"fa-solid fa-rotate-left\"></i> Discard\n </button>\n <button mjButton variant=\"primary\" (click)=\"SaveChanges()\" [disabled]=\"IsSaving\">\n @if (IsSaving) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i> Saving...\n } @else {\n <i class=\"fa-solid fa-floppy-disk\"></i> Save Changes\n }\n </button>\n }\n <button mjButton variant=\"secondary\" (click)=\"loadData()\" [disabled]=\"IsLoading || IsSaving\">\n <i class=\"fa-solid fa-arrows-rotate\" [class.fa-spin]=\"IsLoading\"></i> Refresh\n </button>\n </div>\n </div>\n\n <!-- Status Messages -->\n @if (ErrorMessage) {\n <div class=\"message error-message\">\n <i class=\"fa-solid fa-circle-exclamation\"></i>\n {{ ErrorMessage }}\n </div>\n }\n @if (SuccessMessage) {\n <div class=\"message success-message\">\n <i class=\"fa-solid fa-circle-check\"></i>\n {{ SuccessMessage }}\n </div>\n }\n\n <!-- Loading State -->\n @if (IsLoading) {\n <mj-loading text=\"Loading application roles...\"></mj-loading>\n }\n\n <!-- Main Content -->\n @if (!IsLoading) {\n <p class=\"description\">\n Configure which roles can access each application. Applications with no role assignments are open to all users (backwards compatible).\n </p>\n\n <div class=\"app-groups\">\n @for (group of ApplicationGroups; track TrackByAppId($index, group)) {\n <div class=\"app-group\" [class.expanded]=\"group.Expanded\" [class.has-roles]=\"group.Roles.length > 0\">\n <!-- Application Header Row -->\n <div class=\"app-group-header\" (click)=\"ToggleGroup(group)\">\n <div class=\"app-header-left\">\n <i class=\"fa-solid\" [ngClass]=\"group.Expanded ? 'fa-chevron-down' : 'fa-chevron-right'\"></i>\n <span class=\"app-name\">{{ group.ApplicationName }}</span>\n <span class=\"role-count-badge\" [class.open-access]=\"group.Roles.length === 0\">\n {{ GetRoleCountLabel(group) }}\n </span>\n </div>\n </div>\n\n <!-- Expanded Content -->\n @if (group.Expanded) {\n <div class=\"app-group-content\">\n <!-- Existing Role Assignments -->\n @if (group.Roles.length > 0) {\n <table class=\"roles-table\">\n <thead>\n <tr>\n <th class=\"col-role\">Role</th>\n <th class=\"col-access\">Can Access</th>\n <th class=\"col-admin\">Can Admin</th>\n <th class=\"col-actions\">Actions</th>\n </tr>\n </thead>\n <tbody>\n @for (row of group.Roles; track TrackByRoleRow($index, row)) {\n <tr [class.dirty]=\"row.IsDirty\" [class.new-row]=\"row.IsNew\">\n <td class=\"col-role\">\n <i class=\"fa-solid fa-shield-halved role-icon\"></i>\n {{ row.RoleName }}\n @if (row.IsNew) {\n <span class=\"new-badge\">new</span>\n }\n </td>\n <td class=\"col-access\">\n <input type=\"checkbox\"\n class=\"mj-checkbox\"\n [checked]=\"row.CanAccess\"\n (change)=\"ToggleCanAccess(row)\">\n </td>\n <td class=\"col-admin\">\n <input type=\"checkbox\"\n class=\"mj-checkbox\"\n [checked]=\"row.CanAdmin\"\n (change)=\"ToggleCanAdmin(row)\">\n </td>\n <td class=\"col-actions\">\n <button class=\"remove-btn\" (click)=\"RemoveRole(group, row)\" title=\"Remove role assignment\">\n <i class=\"fa-solid fa-trash-can\"></i>\n </button>\n </td>\n </tr>\n }\n </tbody>\n </table>\n } @else {\n <div class=\"no-roles-message\">\n <i class=\"fa-solid fa-unlock\"></i>\n No role restrictions — all authenticated users can access this application.\n </div>\n }\n\n <!-- Add Role -->\n <div class=\"add-role-row\">\n <select class=\"mj-input add-role-select\"\n [value]=\"SelectedRoleIdToAdd.get(group.ApplicationID) || ''\"\n (change)=\"OnAddRoleSelect(group, $any($event.target).value)\">\n <option value=\"\" disabled>Select a role to add...</option>\n @for (role of GetUnassignedRoles(group); track role.ID) {\n <option [value]=\"role.ID\">{{ role.Name }}</option>\n }\n </select>\n <button mjButton\n variant=\"secondary\"\n (click)=\"AddRole(group)\"\n [disabled]=\"!SelectedRoleIdToAdd.get(group.ApplicationID)\">\n <i class=\"fa-solid fa-plus\"></i> Add Role\n </button>\n </div>\n </div>\n }\n </div>\n }\n </div>\n }\n</div>\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"communication-dashboard.component.d.ts","sourceRoot":"","sources":["../../src/Communication/communication-dashboard.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,aAAa,EAAE,SAAS,EAAE,iBAAiB,EAA2B,MAAM,eAAe,CAAC;AAChH,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAK1D,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;;AAE7D,UAAU,2BAA2B;IACjC,SAAS,EAAE,MAAM,CAAC;CACrB;AAED,qBAQa,+BAAgC,SAAQ,aAAc,YAAW,aAAa,EAAE,SAAS;IAWtF,OAAO,CAAC,GAAG;IAVhB,SAAS,UAAS;IAClB,YAAY,UAAS;IACrB,SAAS,SAAa;IACtB,aAAa,SAAK;IAEzB,OAAO,CAAC,WAAW,CAAqB;IACjC,eAAe,EAAE,MAAM,EAAE,CAAqE;IAErG,OAAO,CAAC,kBAAkB,CAA8C;gBAEpD,GAAG,EAAE,iBAAiB;IAKpC,sBAAsB,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;IAIjE,eAAe,IAAI,IAAI;IAMvB,WAAW,IAAI,IAAI;
|
|
1
|
+
{"version":3,"file":"communication-dashboard.component.d.ts","sourceRoot":"","sources":["../../src/Communication/communication-dashboard.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,aAAa,EAAE,SAAS,EAAE,iBAAiB,EAA2B,MAAM,eAAe,CAAC;AAChH,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAK1D,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;;AAE7D,UAAU,2BAA2B;IACjC,SAAS,EAAE,MAAM,CAAC;CACrB;AAED,qBAQa,+BAAgC,SAAQ,aAAc,YAAW,aAAa,EAAE,SAAS;IAWtF,OAAO,CAAC,GAAG;IAVhB,SAAS,UAAS;IAClB,YAAY,UAAS;IACrB,SAAS,SAAa;IACtB,aAAa,SAAK;IAEzB,OAAO,CAAC,WAAW,CAAqB;IACjC,eAAe,EAAE,MAAM,EAAE,CAAqE;IAErG,OAAO,CAAC,kBAAkB,CAA8C;gBAEpD,GAAG,EAAE,iBAAiB;IAKpC,sBAAsB,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;IAIjE,eAAe,IAAI,IAAI;IAMvB,WAAW,IAAI,IAAI;IAKZ,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAchC,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAIlC,SAAS,IAAI,IAAI;IASxB,OAAO,CAAC,oBAAoB;IAQ5B,OAAO,CAAC,eAAe;IAOhB,aAAa,CAAC,KAAK,EAAE,OAAO,CAAC,2BAA2B,CAAC,GAAG,IAAI;IAUvE,aAAa,IAAI,IAAI;IAWrB,QAAQ,IAAI,IAAI;IAWT,kBAAkB,IAAI,MAAM;yCAzG1B,+BAA+B;2CAA/B,+BAA+B;CA8G3C"}
|