var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    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;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import { Component } from '@angular/core';
import { RegisterClass, UUIDsEqual } from '@memberjunction/global';
import { BaseResourceComponent } from '@memberjunction/ng-shared';
import { CompositeKey, RunView } from '@memberjunction/core';
import { validateStringParam } from '../shared/agent-tool-validation';
import { buildApplicationNotFoundError, buildApplicationRolesAgentContext, buildApplicationRolesCsv, resolveApplicationByIdOrName, } from './application-roles-agent-context';
import * as i0 from "@angular/core";
import * as i1 from "@angular/forms";
import * as i2 from "@memberjunction/ng-ui-components";
import * as i3 from "@memberjunction/ng-shared-generic";
const _forTrack0 = ($index, $item) => $item.ID;
function ApplicationRolesResourceComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
    i0.ɵɵelementStart(0, "div", 1);
    i0.ɵɵelement(1, "mj-stat-badge", 7);
    i0.ɵɵelementEnd();
} }
function ApplicationRolesResourceComponent_Conditional_4_Conditional_5_Template(rf, ctx) { if (rf & 1) {
    i0.ɵɵelement(0, "i", 12);
    i0.ɵɵelementStart(1, "span", 10);
    i0.ɵɵtext(2, "Saving...");
    i0.ɵɵelementEnd();
} }
function ApplicationRolesResourceComponent_Conditional_4_Conditional_6_Template(rf, ctx) { if (rf & 1) {
    i0.ɵɵelement(0, "i", 13);
    i0.ɵɵelementStart(1, "span", 10);
    i0.ɵɵtext(2, "Save Changes");
    i0.ɵɵelementEnd();
} }
function ApplicationRolesResourceComponent_Conditional_4_Template(rf, ctx) { if (rf & 1) {
    const _r1 = i0.ɵɵgetCurrentView();
    i0.ɵɵelementStart(0, "button", 8);
    i0.ɵɵlistener("click", function ApplicationRolesResourceComponent_Conditional_4_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.DiscardChanges()); });
    i0.ɵɵelement(1, "i", 9);
    i0.ɵɵelementStart(2, "span", 10);
    i0.ɵɵtext(3, "Discard");
    i0.ɵɵelementEnd()();
    i0.ɵɵelementStart(4, "button", 11);
    i0.ɵɵlistener("click", function ApplicationRolesResourceComponent_Conditional_4_Template_button_click_4_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.SaveChanges()); });
    i0.ɵɵconditionalCreate(5, ApplicationRolesResourceComponent_Conditional_4_Conditional_5_Template, 3, 0)(6, ApplicationRolesResourceComponent_Conditional_4_Conditional_6_Template, 3, 0);
    i0.ɵɵelementEnd();
} if (rf & 2) {
    const ctx_r1 = i0.ɵɵnextContext();
    i0.ɵɵproperty("disabled", ctx_r1.IsSaving);
    i0.ɵɵadvance(4);
    i0.ɵɵproperty("disabled", ctx_r1.IsSaving);
    i0.ɵɵadvance();
    i0.ɵɵconditional(ctx_r1.IsSaving ? 5 : 6);
} }
function ApplicationRolesResourceComponent_Conditional_6_Template(rf, ctx) { if (rf & 1) {
    i0.ɵɵelementStart(0, "mj-alert", 4);
    i0.ɵɵtext(1);
    i0.ɵɵelementEnd();
} if (rf & 2) {
    const ctx_r1 = i0.ɵɵnextContext();
    i0.ɵɵadvance();
    i0.ɵɵtextInterpolate(ctx_r1.ErrorMessage);
} }
function ApplicationRolesResourceComponent_Conditional_7_Template(rf, ctx) { if (rf & 1) {
    i0.ɵɵelementStart(0, "mj-alert", 5);
    i0.ɵɵtext(1);
    i0.ɵɵelementEnd();
} if (rf & 2) {
    const ctx_r1 = i0.ɵɵnextContext();
    i0.ɵɵadvance();
    i0.ɵɵtextInterpolate(ctx_r1.SuccessMessage);
} }
function ApplicationRolesResourceComponent_Conditional_8_Template(rf, ctx) { if (rf & 1) {
    i0.ɵɵelement(0, "mj-loading", 6);
} }
function ApplicationRolesResourceComponent_Conditional_9_For_4_ng_template_1_Template(rf, ctx) { if (rf & 1) {
    i0.ɵɵelementStart(0, "span", 20);
    i0.ɵɵtext(1);
    i0.ɵɵelementEnd();
    i0.ɵɵelementStart(2, "span", 21);
    i0.ɵɵtext(3);
    i0.ɵɵelementEnd();
} if (rf & 2) {
    const group_r4 = i0.ɵɵnextContext().$implicit;
    const ctx_r1 = i0.ɵɵnextContext(2);
    i0.ɵɵadvance();
    i0.ɵɵtextInterpolate(group_r4.ApplicationName);
    i0.ɵɵadvance();
    i0.ɵɵclassProp("open-access", group_r4.Roles.length === 0);
    i0.ɵɵadvance();
    i0.ɵɵtextInterpolate1(" ", ctx_r1.GetRoleCountLabel(group_r4), " ");
} }
function ApplicationRolesResourceComponent_Conditional_9_For_4_ng_template_2_Conditional_1_For_13_Conditional_4_Template(rf, ctx) { if (rf & 1) {
    i0.ɵɵelementStart(0, "span", 37);
    i0.ɵɵtext(1, "new");
    i0.ɵɵelementEnd();
} }
function ApplicationRolesResourceComponent_Conditional_9_For_4_ng_template_2_Conditional_1_For_13_Template(rf, ctx) { if (rf & 1) {
    const _r6 = i0.ɵɵgetCurrentView();
    i0.ɵɵelementStart(0, "tr")(1, "td", 31);
    i0.ɵɵelement(2, "i", 36);
    i0.ɵɵtext(3);
    i0.ɵɵconditionalCreate(4, ApplicationRolesResourceComponent_Conditional_9_For_4_ng_template_2_Conditional_1_For_13_Conditional_4_Template, 2, 0, "span", 37);
    i0.ɵɵelementEnd();
    i0.ɵɵelementStart(5, "td", 32)(6, "input", 38);
    i0.ɵɵlistener("change", function ApplicationRolesResourceComponent_Conditional_9_For_4_ng_template_2_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)); });
    i0.ɵɵelementEnd()();
    i0.ɵɵelementStart(7, "td", 33)(8, "input", 38);
    i0.ɵɵlistener("change", function ApplicationRolesResourceComponent_Conditional_9_For_4_ng_template_2_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)); });
    i0.ɵɵelementEnd()();
    i0.ɵɵelementStart(9, "td", 34)(10, "button", 39);
    i0.ɵɵlistener("click", function ApplicationRolesResourceComponent_Conditional_9_For_4_ng_template_2_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)); });
    i0.ɵɵelement(11, "i", 40);
    i0.ɵɵelementEnd()()();
} if (rf & 2) {
    const row_r7 = ctx.$implicit;
    i0.ɵɵclassProp("dirty", row_r7.IsDirty)("new-row", row_r7.IsNew);
    i0.ɵɵadvance(3);
    i0.ɵɵtextInterpolate1(" ", row_r7.RoleName, " ");
    i0.ɵɵadvance();
    i0.ɵɵconditional(row_r7.IsNew ? 4 : -1);
    i0.ɵɵadvance(2);
    i0.ɵɵproperty("checked", row_r7.CanAccess);
    i0.ɵɵadvance(2);
    i0.ɵɵproperty("checked", row_r7.CanAdmin);
} }
function ApplicationRolesResourceComponent_Conditional_9_For_4_ng_template_2_Conditional_1_Template(rf, ctx) { if (rf & 1) {
    i0.ɵɵelementStart(0, "table", 23)(1, "thead")(2, "tr")(3, "th", 31);
    i0.ɵɵtext(4, "Role");
    i0.ɵɵelementEnd();
    i0.ɵɵelementStart(5, "th", 32);
    i0.ɵɵtext(6, "Can Access");
    i0.ɵɵelementEnd();
    i0.ɵɵelementStart(7, "th", 33);
    i0.ɵɵtext(8, "Can Admin");
    i0.ɵɵelementEnd();
    i0.ɵɵelementStart(9, "th", 34);
    i0.ɵɵtext(10, "Actions");
    i0.ɵɵelementEnd()()();
    i0.ɵɵelementStart(11, "tbody");
    i0.ɵɵrepeaterCreate(12, ApplicationRolesResourceComponent_Conditional_9_For_4_ng_template_2_Conditional_1_For_13_Template, 12, 8, "tr", 35, i0.ɵɵcomponentInstance().TrackByRoleRow, true);
    i0.ɵɵelementEnd()();
} if (rf & 2) {
    const group_r4 = i0.ɵɵnextContext(2).$implicit;
    i0.ɵɵadvance(12);
    i0.ɵɵrepeater(group_r4.Roles);
} }
function ApplicationRolesResourceComponent_Conditional_9_For_4_ng_template_2_Conditional_2_Template(rf, ctx) { if (rf & 1) {
    i0.ɵɵelementStart(0, "div", 24);
    i0.ɵɵelement(1, "i", 41);
    i0.ɵɵtext(2, " No role restrictions \u2014 all authenticated users can access this application. ");
    i0.ɵɵelementEnd();
} }
function ApplicationRolesResourceComponent_Conditional_9_For_4_ng_template_2_For_8_Template(rf, ctx) { if (rf & 1) {
    i0.ɵɵelementStart(0, "option", 28);
    i0.ɵɵtext(1);
    i0.ɵɵelementEnd();
} if (rf & 2) {
    const role_r8 = ctx.$implicit;
    i0.ɵɵproperty("value", role_r8.ID);
    i0.ɵɵadvance();
    i0.ɵɵtextInterpolate(role_r8.Name);
} }
function ApplicationRolesResourceComponent_Conditional_9_For_4_ng_template_2_Template(rf, ctx) { if (rf & 1) {
    const _r5 = i0.ɵɵgetCurrentView();
    i0.ɵɵelementStart(0, "div", 22);
    i0.ɵɵconditionalCreate(1, ApplicationRolesResourceComponent_Conditional_9_For_4_ng_template_2_Conditional_1_Template, 14, 0, "table", 23)(2, ApplicationRolesResourceComponent_Conditional_9_For_4_ng_template_2_Conditional_2_Template, 3, 0, "div", 24);
    i0.ɵɵelementStart(3, "div", 25)(4, "select", 26);
    i0.ɵɵlistener("change", function ApplicationRolesResourceComponent_Conditional_9_For_4_ng_template_2_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)); });
    i0.ɵɵelementStart(5, "option", 27);
    i0.ɵɵtext(6, "Select a role to add...");
    i0.ɵɵelementEnd();
    i0.ɵɵrepeaterCreate(7, ApplicationRolesResourceComponent_Conditional_9_For_4_ng_template_2_For_8_Template, 2, 2, "option", 28, _forTrack0);
    i0.ɵɵelementEnd();
    i0.ɵɵelementStart(9, "button", 29);
    i0.ɵɵlistener("click", function ApplicationRolesResourceComponent_Conditional_9_For_4_ng_template_2_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)); });
    i0.ɵɵelement(10, "i", 30);
    i0.ɵɵtext(11, " Add Role ");
    i0.ɵɵelementEnd()()();
} if (rf & 2) {
    const group_r4 = i0.ɵɵnextContext().$implicit;
    const ctx_r1 = i0.ɵɵnextContext(2);
    i0.ɵɵadvance();
    i0.ɵɵconditional(group_r4.Roles.length > 0 ? 1 : 2);
    i0.ɵɵadvance(3);
    i0.ɵɵproperty("value", ctx_r1.SelectedRoleIdToAdd.get(group_r4.ApplicationID) || "");
    i0.ɵɵadvance(3);
    i0.ɵɵrepeater(ctx_r1.GetUnassignedRoles(group_r4));
    i0.ɵɵadvance(2);
    i0.ɵɵproperty("disabled", !ctx_r1.SelectedRoleIdToAdd.get(group_r4.ApplicationID));
} }
function ApplicationRolesResourceComponent_Conditional_9_For_4_Template(rf, ctx) { if (rf & 1) {
    const _r3 = i0.ɵɵgetCurrentView();
    i0.ɵɵelementStart(0, "mj-accordion-panel", 17);
    i0.ɵɵlistener("ExpandedChange", function ApplicationRolesResourceComponent_Conditional_9_For_4_Template_mj_accordion_panel_ExpandedChange_0_listener($event) { const group_r4 = i0.ɵɵrestoreView(_r3).$implicit; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnGroupExpandedChange(group_r4, $event)); });
    i0.ɵɵtemplate(1, ApplicationRolesResourceComponent_Conditional_9_For_4_ng_template_1_Template, 4, 4, "ng-template", 18)(2, ApplicationRolesResourceComponent_Conditional_9_For_4_ng_template_2_Template, 12, 3, "ng-template", 19);
    i0.ɵɵelementEnd();
} if (rf & 2) {
    const group_r4 = ctx.$implicit;
    i0.ɵɵproperty("FlushBody", true)("Expanded", group_r4.Expanded);
} }
function ApplicationRolesResourceComponent_Conditional_9_Template(rf, ctx) { if (rf & 1) {
    i0.ɵɵelementStart(0, "p", 14);
    i0.ɵɵtext(1, " Configure which roles can access each application. Applications with no role assignments are open to all users (backwards compatible). ");
    i0.ɵɵelementEnd();
    i0.ɵɵelementStart(2, "div", 15);
    i0.ɵɵrepeaterCreate(3, ApplicationRolesResourceComponent_Conditional_9_For_4_Template, 3, 2, "mj-accordion-panel", 16, i0.ɵɵcomponentInstance().TrackByAppId, true);
    i0.ɵɵelementEnd();
} if (rf & 2) {
    const ctx_r1 = i0.ɵɵnextContext();
    i0.ɵɵadvance(3);
    i0.ɵɵrepeater(ctx_r1.ApplicationGroups);
} }
/**
 * Admin dashboard for managing Application Role assignments.
 * Shows which roles can access and administer each application.
 */
let ApplicationRolesResourceComponent = class ApplicationRolesResourceComponent extends BaseResourceComponent {
    cdr;
    ApplicationGroups = [];
    AvailableRoles = [];
    IsLoading = true;
    IsSaving = false;
    HasUnsavedChanges = false;
    ErrorMessage = null;
    SuccessMessage = null;
    /** Application currently selected for inspection (read-only, agent-driven select / inspect). */
    SelectedApplicationId = null;
    SelectedApplicationName = null;
    // For the "Add Role" dropdown per application
    SelectedRoleIdToAdd = new Map();
    constructor(cdr) {
        super();
        this.cdr = cdr;
    }
    async GetResourceDisplayName(_data) {
        return 'App Roles';
    }
    async GetResourceIconClass(_data) {
        return 'fa-solid fa-user-shield';
    }
    async ngOnInit() {
        super.ngOnInit();
        await this.loadData();
        this.NotifyLoadComplete();
    }
    /**
     * After the view initializes, publish the initial agent context and register the read-only client
     * tools the AI agent can invoke against this surface. The ongoing context re-emit happens in
     * {@link loadData} and the UI handlers below, on every meaningful state change.
     */
    ngAfterViewInit() {
        this.publishAgentContext();
        this.registerAgentClientTools();
    }
    ngOnDestroy() {
        super.ngOnDestroy();
    }
    /**
     * Load all application role data and available roles.
     */
    async loadData() {
        this.IsLoading = true;
        this.ErrorMessage = null;
        this.cdr.detectChanges();
        try {
            const md = this.ProviderToUse;
            const rv = RunView.FromMetadataProvider(this.ProviderToUse);
            // Load available roles from metadata
            this.AvailableRoles = md.Roles.map(r => ({ ID: r.ID, Name: r.Name }))
                .sort((a, b) => a.Name.localeCompare(b.Name));
            // Load existing ApplicationRole records
            const result = await rv.RunView({
                EntityName: 'MJ: Application Roles',
                ResultType: 'simple',
            });
            if (!result.Success) {
                this.ErrorMessage = result.ErrorMessage || 'Failed to load application roles.';
                this.IsLoading = false;
                this.cdr.detectChanges();
                return;
            }
            // Build grouped structure
            const appMap = new Map();
            // Seed all applications so we can show apps without any role records
            for (const app of md.Applications) {
                appMap.set(app.ID, {
                    ApplicationID: app.ID,
                    ApplicationName: app.Name,
                    Roles: [],
                    Expanded: false,
                });
            }
            // Populate role assignments
            for (const record of result.Results) {
                const group = appMap.get(record.ApplicationID);
                if (group) {
                    group.Roles.push({
                        ID: record.ID,
                        ApplicationID: record.ApplicationID,
                        ApplicationName: group.ApplicationName,
                        RoleID: record.RoleID,
                        RoleName: record.Role || '',
                        CanAccess: record.CanAccess,
                        CanAdmin: record.CanAdmin,
                        IsDirty: false,
                        IsNew: false,
                    });
                }
            }
            // Sort roles within each group
            for (const group of appMap.values()) {
                group.Roles.sort((a, b) => a.RoleName.localeCompare(b.RoleName));
            }
            this.ApplicationGroups = Array.from(appMap.values())
                .sort((a, b) => a.ApplicationName.localeCompare(b.ApplicationName));
        }
        catch (e) {
            this.ErrorMessage = `Error loading data: ${e instanceof Error ? e.message : String(e)}`;
        }
        this.IsLoading = false;
        this.HasUnsavedChanges = false;
        this.cdr.detectChanges();
        this.publishAgentContext();
    }
    /**
     * Toggle the expanded/collapsed state of an application group.
     */
    ToggleGroup(group) {
        group.Expanded = !group.Expanded;
        this.cdr.detectChanges();
        this.publishAgentContext();
    }
    /**
     * Set an application group's expanded state from the accordion panel's
     * (ExpandedChange) output. Preserves the side-effects of {@link ToggleGroup}
     * (change detection + agent-context re-emit) while taking the explicit value.
     */
    OnGroupExpandedChange(group, expanded) {
        group.Expanded = expanded;
        this.cdr.detectChanges();
        this.publishAgentContext();
    }
    /**
     * Toggle CanAccess for a specific role assignment.
     */
    ToggleCanAccess(row) {
        row.CanAccess = !row.CanAccess;
        row.IsDirty = true;
        this.HasUnsavedChanges = true;
        this.cdr.detectChanges();
    }
    /**
     * Toggle CanAdmin for a specific role assignment.
     */
    ToggleCanAdmin(row) {
        row.CanAdmin = !row.CanAdmin;
        row.IsDirty = true;
        this.HasUnsavedChanges = true;
        this.cdr.detectChanges();
    }
    /**
     * Get roles not yet assigned to a specific application (for the "Add Role" dropdown).
     */
    GetUnassignedRoles(group) {
        const assignedRoleIds = new Set(group.Roles.map(r => r.RoleID.toLowerCase()));
        return this.AvailableRoles.filter(r => !assignedRoleIds.has(r.ID.toLowerCase()));
    }
    /**
     * Add a new role assignment to an application group.
     */
    AddRole(group) {
        const roleId = this.SelectedRoleIdToAdd.get(group.ApplicationID);
        if (!roleId)
            return;
        const role = this.AvailableRoles.find(r => UUIDsEqual(r.ID, roleId));
        if (!role)
            return;
        group.Roles.push({
            ID: '',
            ApplicationID: group.ApplicationID,
            ApplicationName: group.ApplicationName,
            RoleID: role.ID,
            RoleName: role.Name,
            CanAccess: true,
            CanAdmin: false,
            IsDirty: true,
            IsNew: true,
        });
        group.Roles.sort((a, b) => a.RoleName.localeCompare(b.RoleName));
        this.SelectedRoleIdToAdd.delete(group.ApplicationID);
        this.HasUnsavedChanges = true;
        this.cdr.detectChanges();
    }
    /**
     * Remove a role assignment (marks for deletion on save; removes immediately if new).
     */
    RemoveRole(group, row) {
        const idx = group.Roles.indexOf(row);
        if (idx >= 0) {
            group.Roles.splice(idx, 1);
        }
        // If not new, we need to delete it on save — track via dirty state
        if (!row.IsNew) {
            this._pendingDeletes.push(row.ID);
        }
        this.HasUnsavedChanges = true;
        this.cdr.detectChanges();
    }
    _pendingDeletes = [];
    /**
     * Save all unsaved changes (new records, modified records, deleted records).
     */
    async SaveChanges() {
        this.IsSaving = true;
        this.ErrorMessage = null;
        this.SuccessMessage = null;
        this.cdr.detectChanges();
        try {
            const md = this.ProviderToUse;
            // Process deletes
            for (const deleteId of this._pendingDeletes) {
                const entity = await md.GetEntityObject('MJ: Application Roles');
                await entity.InnerLoad(new CompositeKey([{ FieldName: 'ID', Value: deleteId }]));
                const deleteResult = await entity.Delete();
                if (!deleteResult) {
                    this.ErrorMessage = `Failed to delete role assignment: ${entity.LatestResult?.Message || 'Unknown error'}`;
                    this.IsSaving = false;
                    this.cdr.detectChanges();
                    return;
                }
            }
            // Process new and modified records
            for (const group of this.ApplicationGroups) {
                for (const row of group.Roles) {
                    if (!row.IsDirty)
                        continue;
                    if (row.IsNew) {
                        const entity = await md.GetEntityObject('MJ: Application Roles');
                        entity.NewRecord();
                        entity.Set('ApplicationID', row.ApplicationID);
                        entity.Set('RoleID', row.RoleID);
                        entity.Set('CanAccess', row.CanAccess);
                        entity.Set('CanAdmin', row.CanAdmin);
                        const saveResult = await entity.Save();
                        if (!saveResult) {
                            this.ErrorMessage = `Failed to save new role assignment for ${row.RoleName}: ${entity.LatestResult?.Message || 'Unknown error'}`;
                            this.IsSaving = false;
                            this.cdr.detectChanges();
                            return;
                        }
                        row.ID = entity.Get('ID');
                    }
                    else {
                        const entity = await md.GetEntityObject('MJ: Application Roles');
                        await entity.InnerLoad(new CompositeKey([{ FieldName: 'ID', Value: row.ID }]));
                        entity.Set('CanAccess', row.CanAccess);
                        entity.Set('CanAdmin', row.CanAdmin);
                        const saveResult = await entity.Save();
                        if (!saveResult) {
                            this.ErrorMessage = `Failed to update role assignment for ${row.RoleName}: ${entity.LatestResult?.Message || 'Unknown error'}`;
                            this.IsSaving = false;
                            this.cdr.detectChanges();
                            return;
                        }
                    }
                    row.IsDirty = false;
                    row.IsNew = false;
                }
            }
            this._pendingDeletes = [];
            this.HasUnsavedChanges = false;
            this.SuccessMessage = 'All changes saved successfully.';
        }
        catch (e) {
            this.ErrorMessage = `Error saving: ${e instanceof Error ? e.message : String(e)}`;
        }
        this.IsSaving = false;
        this.cdr.detectChanges();
    }
    /**
     * Discard all unsaved changes and reload data.
     */
    async DiscardChanges() {
        this._pendingDeletes = [];
        await this.loadData();
    }
    /**
     * Track by function for application groups.
     */
    TrackByAppId(_index, group) {
        return group.ApplicationID;
    }
    /**
     * Track by function for role rows.
     */
    TrackByRoleRow(_index, row) {
        return row.IsNew ? `new-${row.RoleID}` : row.ID;
    }
    /**
     * Get the role count label for an application.
     */
    GetRoleCountLabel(group) {
        if (group.Roles.length === 0)
            return 'Open Access (no role restrictions)';
        return `${group.Roles.length} role${group.Roles.length === 1 ? '' : 's'} assigned`;
    }
    /**
     * Handle dropdown selection for adding roles.
     */
    OnAddRoleSelect(group, roleId) {
        this.SelectedRoleIdToAdd.set(group.ApplicationID, roleId);
    }
    // ========================================
    // AI AGENT CONTEXT & CLIENT TOOLS
    //
    // 🔒 SAFETY BOUNDARY — Application Roles is a PERMISSION-MUTATING surface. The agent integration is
    // strictly READ-ONLY plus benign UI navigation. The following are DELIBERATELY NOT exposed to the
    // agent, because each writes/grants/revokes access:
    //   - ToggleCanAccess / ToggleCanAdmin (flip a role's access/admin permission)
    //   - AddRole / RemoveRole            (grant / revoke a role assignment)
    //   - SaveChanges / DiscardChanges    (persist or discard permission mutations)
    // Only select / read / filter / navigate / refresh / export capabilities are wired below. Export
    // serializes ONLY the already-visible matrix (no credential, no secret). Do NOT add a mutating
    // tool here — permission changes must originate from an explicit human action in the UI. The
    // published context carries counts, names, and CanAccess/CanAdmin are NEVER streamed into context.
    // ========================================
    /**
     * Publish the current Application Roles state to the AI agent via NavigationService. The shaping
     * lives in the pure {@link buildApplicationRolesAgentContext} helper so it stays unit-testable.
     * Called on init and on every meaningful state change (load, expand/collapse, select).
     */
    publishAgentContext() {
        const selectedGroup = this.SelectedApplicationId
            ? this.ApplicationGroups.find(g => UUIDsEqual(g.ApplicationID, this.SelectedApplicationId))
            : undefined;
        const context = buildApplicationRolesAgentContext({
            ApplicationGroupCount: this.ApplicationGroups.length,
            TotalRoleAssignmentCount: this.ApplicationGroups.reduce((sum, g) => sum + g.Roles.length, 0),
            HasUnsavedChanges: this.HasUnsavedChanges,
            IsLoading: this.IsLoading,
            ExpandedApplicationIds: this.ApplicationGroups.filter(g => g.Expanded).map(g => g.ApplicationID),
            ApplicationSummaries: this.ApplicationGroups.map(g => ({
                ApplicationID: g.ApplicationID,
                ApplicationName: g.ApplicationName,
                RoleCount: g.Roles.length,
                Expanded: g.Expanded,
            })),
            SelectedApplicationId: this.SelectedApplicationId,
            SelectedApplicationName: this.SelectedApplicationName,
            SelectedApplicationRoleNames: selectedGroup ? selectedGroup.Roles.map(r => r.RoleName) : [],
            AvailableRoleCount: this.AvailableRoles.length,
        });
        this.navigationService.SetAgentContext(this, context);
    }
    /** Application candidates (id+name) for the tolerant id→name→contains resolver. */
    applicationCandidates() {
        return this.ApplicationGroups.map(g => ({ ApplicationID: g.ApplicationID, ApplicationName: g.ApplicationName }));
    }
    /**
     * Register the READ-ONLY client tools the AI agent can invoke against the Application Roles
     * surface. Each handler delegates to a read/navigation method a user interaction would call, and
     * returns `{ Success: true, Data? }` on success or `{ Success: false, ErrorMessage }` on failure.
     * Handlers are tolerant — they never throw. NO mutating tool is registered here (see the SAFETY
     * BOUNDARY comment above).
     */
    registerAgentClientTools() {
        this.navigationService.SetAgentClientTools(this, [
            {
                Name: 'ToggleApplicationGroup',
                Description: 'Expand or collapse the role assignments for one application (by application ID or name). This only changes the UI expand/collapse state — it does not modify any permissions.',
                ParameterSchema: { type: 'object', properties: { applicationId: { type: 'string', description: 'The application ID or name' } }, required: ['applicationId'] },
                Handler: async (params) => this.toolToggleApplicationGroup(params),
            },
            {
                Name: 'GetRoleCountForApplication',
                Description: 'Read-only: return the number of roles assigned to one application (by application ID or name), and the names of those roles.',
                ParameterSchema: { type: 'object', properties: { applicationId: { type: 'string', description: 'The application ID or name' } }, required: ['applicationId'] },
                Handler: async (params) => this.toolGetRoleCountForApplication(params),
            },
            {
                Name: 'SelectApplication',
                Description: 'Read-only: select an application (by application ID or name) to inspect its assigned roles. Expands its group and reports its role names. Does not modify any permission.',
                ParameterSchema: { type: 'object', properties: { applicationId: { type: 'string', description: 'The application ID or name to inspect' } }, required: ['applicationId'] },
                Handler: async (params) => this.toolSelectApplication(params),
            },
            {
                Name: 'RefreshApplicationRoleData',
                Description: 'Reload the application role assignment data from the server. Discards any unsaved edits in the grid.',
                ParameterSchema: { type: 'object', properties: {} },
                Handler: async () => {
                    await this.loadData();
                    return { Success: true };
                },
            },
            {
                Name: 'ExportApplicationRoles',
                Description: 'Read-only: export the currently displayed application→roles matrix to a CSV download (application, role, can-access, can-admin). Serializes only on-screen data — does not modify anything.',
                ParameterSchema: { type: 'object', properties: {} },
                Handler: async () => this.toolExportApplicationRoles(),
            },
        ]);
    }
    /** Resolve an application group by id or name and toggle its expand/collapse state (UI only). */
    toolToggleApplicationGroup(params) {
        const validated = validateStringParam(params['applicationId'], 'applicationId');
        if (!validated.ok) {
            return validated.result;
        }
        const match = resolveApplicationByIdOrName(validated.value, this.applicationCandidates());
        if (!match) {
            return { Success: false, ErrorMessage: buildApplicationNotFoundError(validated.value, this.applicationCandidates()) };
        }
        const group = this.ApplicationGroups.find(g => UUIDsEqual(g.ApplicationID, match.ApplicationID));
        this.ToggleGroup(group);
        return { Success: true, Data: { ApplicationName: group.ApplicationName, Expanded: group.Expanded } };
    }
    /** Read-only: resolve an application group by id or name and return its assigned-role count + names. */
    toolGetRoleCountForApplication(params) {
        const validated = validateStringParam(params['applicationId'], 'applicationId');
        if (!validated.ok) {
            return validated.result;
        }
        const match = resolveApplicationByIdOrName(validated.value, this.applicationCandidates());
        if (!match) {
            return { Success: false, ErrorMessage: buildApplicationNotFoundError(validated.value, this.applicationCandidates()) };
        }
        const group = this.ApplicationGroups.find(g => UUIDsEqual(g.ApplicationID, match.ApplicationID));
        return {
            Success: true,
            Data: { ApplicationName: group.ApplicationName, RoleCount: group.Roles.length, RoleNames: group.Roles.slice(0, 25).map(r => r.RoleName) },
        };
    }
    /** Read-only: select an application to inspect (sets selection, expands its group, reports roles). */
    toolSelectApplication(params) {
        const validated = validateStringParam(params['applicationId'], 'applicationId');
        if (!validated.ok) {
            return validated.result;
        }
        const match = resolveApplicationByIdOrName(validated.value, this.applicationCandidates());
        if (!match) {
            return { Success: false, ErrorMessage: buildApplicationNotFoundError(validated.value, this.applicationCandidates()) };
        }
        const group = this.ApplicationGroups.find(g => UUIDsEqual(g.ApplicationID, match.ApplicationID));
        this.SelectedApplicationId = group.ApplicationID;
        this.SelectedApplicationName = group.ApplicationName;
        if (!group.Expanded) {
            group.Expanded = true;
        }
        this.cdr.detectChanges();
        this.publishAgentContext();
        return {
            Success: true,
            Data: { ApplicationName: group.ApplicationName, RoleCount: group.Roles.length, RoleNames: group.Roles.slice(0, 25).map(r => r.RoleName) },
        };
    }
    /** Read-only: serialize the visible matrix to CSV and trigger a browser download. */
    toolExportApplicationRoles() {
        const rows = [];
        for (const group of this.ApplicationGroups) {
            if (group.Roles.length === 0) {
                rows.push({ ApplicationName: group.ApplicationName, RoleName: '(open access)', CanAccess: true, CanAdmin: false });
                continue;
            }
            for (const role of group.Roles) {
                rows.push({ ApplicationName: group.ApplicationName, RoleName: role.RoleName, CanAccess: role.CanAccess, CanAdmin: role.CanAdmin });
            }
        }
        const csv = buildApplicationRolesCsv(rows);
        this.downloadCsv(csv, `application-roles-${new Date().toISOString().slice(0, 19).replace(/:/g, '-')}.csv`);
        return { Success: true, Data: { RowCount: rows.length } };
    }
    /** Trigger a client-side CSV download. Side-effect-only (no mutation of any record). */
    downloadCsv(csv, fileName) {
        const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
        const url = URL.createObjectURL(blob);
        const link = document.createElement('a');
        link.href = url;
        link.download = fileName;
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link);
        URL.revokeObjectURL(url);
    }
    static ɵfac = function ApplicationRolesResourceComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ApplicationRolesResourceComponent)(i0.ɵɵdirectiveInject(i0.ChangeDetectorRef)); };
    static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ApplicationRolesResourceComponent, selectors: [["mj-application-roles-resource"]], standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 10, vars: 8, consts: [["Role", "toolbar", "AriaLabel", "Application roles actions", "Title", "Application Roles", "Subtitle", "Assign roles per application"], ["meta", ""], ["actions", ""], [3, "Clicked", "Loading", "Disabled"], ["Variant", "error"], ["Variant", "success"], ["text", "Loading application roles..."], ["Icon", "fa-solid fa-circle-exclamation", "Label", "Unsaved changes", "Variant", "warning"], ["mjButton", "", "variant", "secondary", "size", "sm", 3, "click", "disabled"], [1, "fa-solid", "fa-rotate-left"], [1, "mj-action-label"], ["mjButton", "", "variant", "primary", "size", "sm", 3, "click", "disabled"], [1, "fa-solid", "fa-spinner", "fa-spin"], [1, "fa-solid", "fa-floppy-disk"], [1, "description"], [1, "app-groups"], ["Size", "sm", 3, "FlushBody", "Expanded"], ["Size", "sm", 3, "ExpandedChange", "FlushBody", "Expanded"], ["mjAccordionTitle", ""], ["mjAccordionBody", ""], [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"], ["mjButton", "", "variant", "secondary", 3, "click", "disabled"], [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) {
            i0.ɵɵelementStart(0, "mj-page-header-interior", 0);
            i0.ɵɵconditionalCreate(1, ApplicationRolesResourceComponent_Conditional_1_Template, 2, 0, "div", 1);
            i0.ɵɵelementStart(2, "div", 2)(3, "mj-refresh-button", 3);
            i0.ɵɵlistener("Clicked", function ApplicationRolesResourceComponent_Template_mj_refresh_button_Clicked_3_listener() { return ctx.loadData(); });
            i0.ɵɵelementEnd();
            i0.ɵɵconditionalCreate(4, ApplicationRolesResourceComponent_Conditional_4_Template, 7, 3);
            i0.ɵɵelementEnd()();
            i0.ɵɵelementStart(5, "mj-page-body-interior");
            i0.ɵɵconditionalCreate(6, ApplicationRolesResourceComponent_Conditional_6_Template, 2, 1, "mj-alert", 4);
            i0.ɵɵconditionalCreate(7, ApplicationRolesResourceComponent_Conditional_7_Template, 2, 1, "mj-alert", 5);
            i0.ɵɵconditionalCreate(8, ApplicationRolesResourceComponent_Conditional_8_Template, 1, 0, "mj-loading", 6);
            i0.ɵɵconditionalCreate(9, ApplicationRolesResourceComponent_Conditional_9_Template, 5, 0);
            i0.ɵɵelementEnd();
        } if (rf & 2) {
            i0.ɵɵadvance();
            i0.ɵɵconditional(ctx.HasUnsavedChanges ? 1 : -1);
            i0.ɵɵadvance(2);
            i0.ɵɵproperty("Loading", ctx.IsLoading)("Disabled", ctx.IsSaving);
            i0.ɵɵadvance();
            i0.ɵɵconditional(ctx.HasUnsavedChanges ? 4 : -1);
            i0.ɵɵadvance(2);
            i0.ɵɵconditional(ctx.ErrorMessage ? 6 : -1);
            i0.ɵɵadvance();
            i0.ɵɵconditional(ctx.SuccessMessage ? 7 : -1);
            i0.ɵɵadvance();
            i0.ɵɵconditional(ctx.IsLoading ? 8 : -1);
            i0.ɵɵadvance();
            i0.ɵɵconditional(!ctx.IsLoading ? 9 : -1);
        } }, dependencies: [i1.NgSelectOption, i1.ɵNgSelectMultipleOption, i2.MJButtonDirective, i2.MJPageHeaderInteriorComponent, i2.MJPageBodyInteriorComponent, i2.MJStatBadgeComponent, i2.MJRefreshButtonComponent, i2.MJAlertComponent, i2.MJAccordionPanelComponent, i2.MJAccordionTitleDirective, i2.MJAccordionBodyDirective, i3.LoadingComponent], styles: ["\n\n\n\n[_nghost-%COMP%] {\n  display: flex;\n  flex-direction: column;\n  height: 100%;\n  overflow: hidden;\n  background: var(--mj-bg-page);\n}\n\n\n\n.scrollable-content[_ngcontent-%COMP%] {\n  flex: 1;\n  overflow-y: auto;\n  padding: var(--mj-space-6);\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\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\n.app-group-content[_ngcontent-%COMP%] {\n  padding: 16px;\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}"] });
};
ApplicationRolesResourceComponent = __decorate([
    RegisterClass(BaseResourceComponent, 'ApplicationRolesResource')
], ApplicationRolesResourceComponent);
export { ApplicationRolesResourceComponent };
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ApplicationRolesResourceComponent, [{
        type: Component,
        args: [{ standalone: false, selector: 'mj-application-roles-resource', template: "<!--\n  Interior chrome \u2014 see Section 10 of explorer-chrome-conventions. Role=\"toolbar\"\n  because this is an action band, not a search/filter region.\n-->\n<mj-page-header-interior\n  Role=\"toolbar\"\n  AriaLabel=\"Application roles actions\"\n  Title=\"Application Roles\"\n  Subtitle=\"Assign roles per application\">\n  @if (HasUnsavedChanges) {\n    <div meta>\n      <mj-stat-badge\n        Icon=\"fa-solid fa-circle-exclamation\"\n        Label=\"Unsaved changes\"\n        Variant=\"warning\">\n      </mj-stat-badge>\n    </div>\n  }\n  <div actions>\n    <!-- Order: secondary buttons (Refresh, Discard) \u2192 primary CTA (Save) rightmost,\n         per chrome conventions \u00A72 [actions]. -->\n    <mj-refresh-button [Loading]=\"IsLoading\" [Disabled]=\"IsSaving\" (Clicked)=\"loadData()\"></mj-refresh-button>\n    @if (HasUnsavedChanges) {\n      <button mjButton variant=\"secondary\" size=\"sm\" (click)=\"DiscardChanges()\" [disabled]=\"IsSaving\">\n        <i class=\"fa-solid fa-rotate-left\"></i> <span class=\"mj-action-label\">Discard</span>\n      </button>\n      <button mjButton variant=\"primary\" size=\"sm\" (click)=\"SaveChanges()\" [disabled]=\"IsSaving\">\n        @if (IsSaving) {\n          <i class=\"fa-solid fa-spinner fa-spin\"></i> <span class=\"mj-action-label\">Saving...</span>\n        } @else {\n          <i class=\"fa-solid fa-floppy-disk\"></i> <span class=\"mj-action-label\">Save Changes</span>\n        }\n      </button>\n    }\n  </div>\n</mj-page-header-interior>\n\n<!-- Scrollable Content \u2014 owned by <mj-page-body-interior>. -->\n  <mj-page-body-interior>\n    <!-- Status Messages -->\n    @if (ErrorMessage) {\n      <mj-alert Variant=\"error\">{{ ErrorMessage }}</mj-alert>\n    }\n    @if (SuccessMessage) {\n      <mj-alert Variant=\"success\">{{ SuccessMessage }}</mj-alert>\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          <mj-accordion-panel Size=\"sm\" [FlushBody]=\"true\"\n              [Expanded]=\"group.Expanded\"\n              (ExpandedChange)=\"OnGroupExpandedChange(group, $event)\">\n            <ng-template mjAccordionTitle>\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            </ng-template>\n\n            <ng-template mjAccordionBody>\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            </ng-template>\n          </mj-accordion-panel>\n        }\n      </div>\n    }\n  </mj-page-body-interior>\n", styles: ["/* :host is flex-column / 100% height via mj-left-nav-content's ::ng-deep\n   sizing. Interior chrome lives in <mj-page-header-interior> \u2014 see Section 10\n   of explorer-chrome-conventions. */\n:host {\n  display: flex;\n  flex-direction: column;\n  height: 100%;\n  overflow: hidden;\n  background: var(--mj-bg-page);\n}\n\n/* Scrollable Content */\n.scrollable-content {\n  flex: 1;\n  overflow-y: auto;\n  padding: var(--mj-space-6);\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 card chrome + header/chevron now owned by <mj-accordion-panel>. */\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 \u2014 body padding here because the panel uses [FlushBody].\n   The header/body separator is now owned by <mj-accordion-panel>. */\n.app-group-content {\n  padding: 16px;\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"] }]
    }], () => [{ type: i0.ChangeDetectorRef }], null); })();
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ApplicationRolesResourceComponent, { className: "ApplicationRolesResourceComponent", filePath: "src/ApplicationRoles/application-roles-resource.component.ts", lineNumber: 51 }); })();
/** Tree-shaking prevention */
export function LoadApplicationRolesResource() {
    // Prevents tree-shaking
}
//# sourceMappingURL=application-roles-resource.component.js.map