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 { PermissionConstrainedError } from '@memberjunction/core';
import { PermissionEngine } from '@memberjunction/core-entities';
import { RegisterClass } from '@memberjunction/global';
import { BaseResourceComponent } from '@memberjunction/ng-shared';
import { validateStringParam } from '../shared/agent-tool-validation';
import { buildPermissionsNotFoundError, buildResourceAccessAgentContext, resolvePermissionsCandidate, } from './permissions-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";
import * as i4 from "@angular/common";
const _forTrack0 = ($index, $item) => $item.ID;
function PermissionsResourceAccessResourceComponent_Conditional_3_Template(rf, ctx) { if (rf & 1) {
    i0.ɵɵelementStart(0, "mj-alert", 1);
    i0.ɵɵtext(1);
    i0.ɵɵelementEnd();
} if (rf & 2) {
    const ctx_r0 = i0.ɵɵnextContext();
    i0.ɵɵadvance();
    i0.ɵɵtextInterpolate(ctx_r0.ErrorMessage);
} }
function PermissionsResourceAccessResourceComponent_For_9_Template(rf, ctx) { if (rf & 1) {
    i0.ɵɵelementStart(0, "option", 5);
    i0.ɵɵtext(1);
    i0.ɵɵelementEnd();
} if (rf & 2) {
    const d_r2 = ctx.$implicit;
    i0.ɵɵproperty("ngValue", d_r2.Name);
    i0.ɵɵadvance();
    i0.ɵɵtextInterpolate(d_r2.Name);
} }
function PermissionsResourceAccessResourceComponent_Conditional_17_Template(rf, ctx) { if (rf & 1) {
    i0.ɵɵelement(0, "i", 14);
    i0.ɵɵtext(1, " Looking up... ");
} }
function PermissionsResourceAccessResourceComponent_Conditional_18_Template(rf, ctx) { if (rf & 1) {
    i0.ɵɵelement(0, "i", 15);
    i0.ɵɵtext(1, " Lookup ");
} }
function PermissionsResourceAccessResourceComponent_Conditional_19_Template(rf, ctx) { if (rf & 1) {
    i0.ɵɵelement(0, "mj-loading", 11);
} }
function PermissionsResourceAccessResourceComponent_Conditional_20_Template(rf, ctx) { if (rf & 1) {
    i0.ɵɵelement(0, "mj-empty-state", 12);
} }
function PermissionsResourceAccessResourceComponent_Conditional_21_Template(rf, ctx) { if (rf & 1) {
    i0.ɵɵelement(0, "mj-empty-state", 13);
} if (rf & 2) {
    const ctx_r0 = i0.ɵɵnextContext();
    i0.ɵɵproperty("Message", ctx_r0.NoGranteesMessage);
} }
function PermissionsResourceAccessResourceComponent_Conditional_22_For_22_Conditional_4_Template(rf, ctx) { if (rf & 1) {
    i0.ɵɵelementStart(0, "span", 21);
    i0.ɵɵtext(1);
    i0.ɵɵelementEnd();
} if (rf & 2) {
    const row_r3 = i0.ɵɵnextContext().$implicit;
    i0.ɵɵadvance();
    i0.ɵɵtextInterpolate(row_r3.GranteeID);
} }
function PermissionsResourceAccessResourceComponent_Conditional_22_For_22_For_10_Template(rf, ctx) { if (rf & 1) {
    i0.ɵɵelementStart(0, "span", 23);
    i0.ɵɵtext(1);
    i0.ɵɵelementEnd();
} if (rf & 2) {
    const action_r4 = ctx.$implicit;
    i0.ɵɵadvance();
    i0.ɵɵtextInterpolate(action_r4);
} }
function PermissionsResourceAccessResourceComponent_Conditional_22_For_22_Conditional_15_Template(rf, ctx) { if (rf & 1) {
    i0.ɵɵelementStart(0, "span");
    i0.ɵɵtext(1);
    i0.ɵɵpipe(2, "date");
    i0.ɵɵelementEnd();
} if (rf & 2) {
    const row_r3 = i0.ɵɵnextContext().$implicit;
    i0.ɵɵadvance();
    i0.ɵɵtextInterpolate(i0.ɵɵpipeBind2(2, 1, row_r3.ExpiresAt, "short"));
} }
function PermissionsResourceAccessResourceComponent_Conditional_22_For_22_Conditional_16_Template(rf, ctx) { if (rf & 1) {
    i0.ɵɵelementStart(0, "span", 25);
    i0.ɵɵtext(1, "\u2014");
    i0.ɵɵelementEnd();
} }
function PermissionsResourceAccessResourceComponent_Conditional_22_For_22_Template(rf, ctx) { if (rf & 1) {
    i0.ɵɵelementStart(0, "tr")(1, "td", 19)(2, "span", 20);
    i0.ɵɵtext(3);
    i0.ɵɵelementEnd();
    i0.ɵɵconditionalCreate(4, PermissionsResourceAccessResourceComponent_Conditional_22_For_22_Conditional_4_Template, 2, 1, "span", 21);
    i0.ɵɵelementEnd();
    i0.ɵɵelementStart(5, "td");
    i0.ɵɵtext(6);
    i0.ɵɵelementEnd();
    i0.ɵɵelementStart(7, "td")(8, "div", 22);
    i0.ɵɵrepeaterCreate(9, PermissionsResourceAccessResourceComponent_Conditional_22_For_22_For_10_Template, 2, 1, "span", 23, i0.ɵɵrepeaterTrackByIdentity);
    i0.ɵɵelementEnd()();
    i0.ɵɵelementStart(11, "td")(12, "span", 24);
    i0.ɵɵtext(13);
    i0.ɵɵelementEnd()();
    i0.ɵɵelementStart(14, "td");
    i0.ɵɵconditionalCreate(15, PermissionsResourceAccessResourceComponent_Conditional_22_For_22_Conditional_15_Template, 3, 4, "span")(16, PermissionsResourceAccessResourceComponent_Conditional_22_For_22_Conditional_16_Template, 2, 0, "span", 25);
    i0.ɵɵelementEnd()();
} if (rf & 2) {
    const row_r3 = ctx.$implicit;
    i0.ɵɵadvance(3);
    i0.ɵɵtextInterpolate(row_r3.GranteeName || row_r3.GranteeID || row_r3.GranteeType);
    i0.ɵɵadvance();
    i0.ɵɵconditional(row_r3.GranteeID && row_r3.GranteeName && row_r3.GranteeName !== row_r3.GranteeID ? 4 : -1);
    i0.ɵɵadvance(2);
    i0.ɵɵtextInterpolate(row_r3.GranteeType);
    i0.ɵɵadvance(3);
    i0.ɵɵrepeater(row_r3.Actions);
    i0.ɵɵadvance(3);
    i0.ɵɵclassProp("effect-allow", row_r3.Effect === "Allow")("effect-deny", row_r3.Effect === "Deny");
    i0.ɵɵadvance();
    i0.ɵɵtextInterpolate1(" ", row_r3.Effect, " ");
    i0.ɵɵadvance(2);
    i0.ɵɵconditional(row_r3.ExpiresAt ? 15 : 16);
} }
function PermissionsResourceAccessResourceComponent_Conditional_22_Template(rf, ctx) { if (rf & 1) {
    i0.ɵɵelementStart(0, "div", 16)(1, "strong");
    i0.ɵɵtext(2);
    i0.ɵɵelementEnd();
    i0.ɵɵtext(3);
    i0.ɵɵelementStart(4, "strong");
    i0.ɵɵtext(5);
    i0.ɵɵelementEnd()();
    i0.ɵɵelementStart(6, "div", 17)(7, "table", 18)(8, "thead")(9, "tr")(10, "th");
    i0.ɵɵtext(11, "Grantee");
    i0.ɵɵelementEnd();
    i0.ɵɵelementStart(12, "th");
    i0.ɵɵtext(13, "Type");
    i0.ɵɵelementEnd();
    i0.ɵɵelementStart(14, "th");
    i0.ɵɵtext(15, "Actions");
    i0.ɵɵelementEnd();
    i0.ɵɵelementStart(16, "th");
    i0.ɵɵtext(17, "Effect");
    i0.ɵɵelementEnd();
    i0.ɵɵelementStart(18, "th");
    i0.ɵɵtext(19, "Expires");
    i0.ɵɵelementEnd()()();
    i0.ɵɵelementStart(20, "tbody");
    i0.ɵɵrepeaterCreate(21, PermissionsResourceAccessResourceComponent_Conditional_22_For_22_Template, 17, 9, "tr", null, i0.ɵɵcomponentInstance().TrackByResourceRow, true);
    i0.ɵɵelementEnd()()();
} if (rf & 2) {
    const ctx_r0 = i0.ɵɵnextContext();
    i0.ɵɵadvance(2);
    i0.ɵɵtextInterpolate(ctx_r0.ResourceAccessRows.length);
    i0.ɵɵadvance();
    i0.ɵɵtextInterpolate1(" grantee", ctx_r0.ResourceAccessRows.length === 1 ? "" : "s", " on ");
    i0.ɵɵadvance(2);
    i0.ɵɵtextInterpolate(ctx_r0.LastQueryLabel);
    i0.ɵɵadvance(16);
    i0.ɵɵrepeater(ctx_r0.ResourceAccessRows);
} }
/**
 * Resource Access Report resource — one of three tabs in the Permissions admin application.
 * Given a (domain, resource type, resource ID) triple, lists every grantee on that resource
 * with their effective actions, effect (Allow/Deny), and optional expiration.
 * Powered by `PermissionEngine.GetResourcePermissions`.
 */
let PermissionsResourceAccessResourceComponent = class PermissionsResourceAccessResourceComponent extends BaseResourceComponent {
    cdr;
    Domains = [];
    SelectedDomainName = null;
    /** Auto-populated whenever the selected domain changes. Empty = adapter doesn't enumerate its types. */
    ResourceTypes = [];
    ResourceTypeInput = '';
    ResourceIdInput = '';
    ResourceAccessRows = [];
    IsLoading = false;
    LastQueryLabel = null;
    ErrorMessage = null;
    /** Message shown when a lookup returns no grantees (echoes the query). */
    get NoGranteesMessage() {
        return `No grantees found for ${this.LastQueryLabel ?? 'this resource'}.`;
    }
    constructor(cdr) {
        super();
        this.cdr = cdr;
    }
    async GetResourceDisplayName(_data) {
        return 'Resource Access Report';
    }
    async GetResourceIconClass(_data) {
        return 'fa-solid fa-cube';
    }
    async ngOnInit() {
        super.ngOnInit();
        try {
            this.Domains = PermissionEngine.Instance.Domains;
        }
        catch (e) {
            if (e instanceof PermissionConstrainedError) {
                this.Domains = [];
            }
            else {
                throw e;
            }
        }
        if (this.Domains.length > 0) {
            this.SelectedDomainName = this.Domains[0].Name;
            this.loadResourceTypesForDomain(this.SelectedDomainName);
        }
        this.NotifyLoadComplete();
    }
    ngAfterViewInit() {
        this.registerAgentClientTools();
        this.publishAgentContext();
    }
    ngOnDestroy() {
        super.ngOnDestroy();
    }
    // ================================================================
    // AI Agent Context & Client Tools
    //
    // 🚨 SAFETY BOUNDARY — READ-ONLY / LOOKUP ONLY 🚨
    // Resource Access Report is a security-sensitive surface that reveals WHO can
    // access a given resource. The agent context and client tools registered here
    // are strictly READ-ONLY: pick a permission domain and look up the grantees on
    // a (domain, resource type, resource ID) triple. The agent CANNOT grant or
    // revoke access, mutate any domain, impersonate a user, alter audit records, or
    // bulk-export effective permissions — those operations are DELIBERATELY NOT
    // exposed and must remain human-initiated. Context exposes only the current
    // selection, the available domains/resource-types, the last-lookup row count,
    // and a BOUNDED sample of grantee DISPLAY names — never credentials or secrets.
    // ================================================================
    /**
     * Publish the current resource-access state to the AI agent. Re-invoked on
     * every meaningful state change (domain change, lookup completion). The shaping
     * lives in the pure {@link buildResourceAccessAgentContext} helper so it stays
     * unit-testable and decoupled from change-detection timing.
     */
    publishAgentContext() {
        const context = buildResourceAccessAgentContext({
            SelectedDomainName: this.SelectedDomainName,
            AvailableDomainNames: this.Domains.map((d) => d.Name),
            ResourceTypes: this.ResourceTypes,
            ResourceTypeInput: this.ResourceTypeInput,
            ResourceIdInput: this.ResourceIdInput,
            LastQueryLabel: this.LastQueryLabel,
            GranteeCount: this.ResourceAccessRows.length,
            GranteeNames: this.ResourceAccessRows.map((r) => r.GranteeName ?? r.GranteeType).filter((n) => !!n),
            IsLoading: this.IsLoading,
        });
        this.navigationService.SetAgentContext(this, context);
    }
    /** Domain candidates (id+name) for the tolerant id→name→contains resolver. */
    domainCandidates() {
        return this.Domains.map((d) => ({ ID: d.ID, Name: d.Name }));
    }
    /**
     * Register the read-only / lookup client tools the agent may invoke. Every
     * Handler is tolerant: validates input and returns
     * `{ Success: false, ErrorMessage }` rather than throwing.
     */
    registerAgentClientTools() {
        this.navigationService.SetAgentClientTools(this, [
            {
                Name: 'LookupResourcePermissions',
                Description: 'Look up the grantees (who can access) for a specific resource. Read-only — does not grant or revoke any access. Requires the permission domain (name or ID), resource type, and resource ID.',
                ParameterSchema: {
                    type: 'object',
                    properties: {
                        domainName: { type: 'string', description: 'The permission domain name or ID' },
                        resourceType: { type: 'string', description: 'The resource type within the domain' },
                        resourceId: { type: 'string', description: 'The ID of the resource to inspect' },
                    },
                    required: ['domainName', 'resourceType', 'resourceId'],
                },
                Handler: async (params) => this.handleLookupResourceTool(params),
            },
            {
                Name: 'ChangeDomain',
                Description: 'Select a different permission domain for resource lookups (by name or ID). Read-only — only changes the active selection, does not mutate any domain.',
                ParameterSchema: {
                    type: 'object',
                    properties: { domainName: { type: 'string', description: 'The permission domain name or ID to select' } },
                    required: ['domainName'],
                },
                Handler: async (params) => this.handleChangeDomainTool(params),
            },
            {
                Name: 'ListResourceTypesForDomain',
                Description: 'Read-only: list the resource types supported by a permission domain (by name or ID). Helps the user pick a valid resource type before a lookup.',
                ParameterSchema: {
                    type: 'object',
                    properties: { domainName: { type: 'string', description: 'The permission domain name or ID (defaults to the current selection)' } },
                },
                Handler: async (params) => this.handleListResourceTypesTool(params),
            },
            {
                Name: 'SearchResourceGrantees',
                Description: 'Read-only: search the grantees from the most recent lookup by a name substring. Returns the matching grantee display names — does not modify any access.',
                ParameterSchema: {
                    type: 'object',
                    properties: { query: { type: 'string', description: 'Case-insensitive substring to match against grantee names' } },
                    required: ['query'],
                },
                Handler: async (params) => this.handleSearchGranteesTool(params),
            },
        ]);
    }
    async handleLookupResourceTool(params) {
        const domain = validateStringParam(params?.['domainName'], 'domainName');
        if (!domain.ok)
            return domain.result;
        const type = validateStringParam(params?.['resourceType'], 'resourceType');
        if (!type.ok)
            return type.result;
        const id = validateStringParam(params?.['resourceId'], 'resourceId');
        if (!id.ok)
            return id.result;
        if (!domain.value.trim() || !type.value.trim() || !id.value.trim()) {
            return { Success: false, ErrorMessage: 'domainName, resourceType, and resourceId are all required.' };
        }
        const match = resolvePermissionsCandidate(domain.value, this.domainCandidates());
        if (!match) {
            return { Success: false, ErrorMessage: buildPermissionsNotFoundError(domain.value, 'permission domain', this.domainCandidates()) };
        }
        this.SelectedDomainName = match.Name;
        this.loadResourceTypesForDomain(this.SelectedDomainName);
        this.ResourceTypeInput = type.value.trim();
        this.ResourceIdInput = id.value.trim();
        await this.OnLookupResource();
        this.publishAgentContext();
        if (this.ErrorMessage) {
            return { Success: false, ErrorMessage: this.ErrorMessage };
        }
        return {
            Success: true,
            Data: {
                DomainName: match.Name,
                GranteeCount: this.ResourceAccessRows.length,
                GranteeNames: this.ResourceAccessRows.slice(0, 25).map((r) => r.GranteeName ?? r.GranteeType),
            },
        };
    }
    handleChangeDomainTool(params) {
        const domain = validateStringParam(params?.['domainName'], 'domainName');
        if (!domain.ok)
            return domain.result;
        const match = resolvePermissionsCandidate(domain.value, this.domainCandidates());
        if (!match) {
            return { Success: false, ErrorMessage: buildPermissionsNotFoundError(domain.value, 'permission domain', this.domainCandidates()) };
        }
        this.OnDomainChanged(match.Name);
        this.publishAgentContext();
        return { Success: true, Data: { DomainName: match.Name, ResourceTypes: this.ResourceTypes.slice(0, 25) } };
    }
    handleListResourceTypesTool(params) {
        const raw = validateStringParam(params?.['domainName'] ?? '', 'domainName');
        if (!raw.ok)
            return raw.result;
        let domainName = this.SelectedDomainName;
        if (raw.value.trim()) {
            const match = resolvePermissionsCandidate(raw.value, this.domainCandidates());
            if (!match) {
                return { Success: false, ErrorMessage: buildPermissionsNotFoundError(raw.value, 'permission domain', this.domainCandidates()) };
            }
            domainName = match.Name;
        }
        if (!domainName) {
            return { Success: false, ErrorMessage: 'No permission domain is selected. Provide a domain name or ID.' };
        }
        const types = PermissionEngine.Instance.GetResourceTypes(domainName, this.ProviderToUse);
        return { Success: true, Data: { DomainName: domainName, ResourceTypes: types.slice(0, 25), ResourceTypeCount: types.length } };
    }
    handleSearchGranteesTool(params) {
        const q = validateStringParam(params?.['query'], 'query');
        if (!q.ok)
            return q.result;
        const needle = q.value.trim().toLowerCase();
        if (!needle) {
            return { Success: false, ErrorMessage: 'query is required.' };
        }
        if (this.ResourceAccessRows.length === 0) {
            return { Success: false, ErrorMessage: 'No grantees are loaded. Run a resource lookup first.' };
        }
        const matches = this.ResourceAccessRows
            .map((r) => r.GranteeName ?? r.GranteeType)
            .filter((n) => !!n && n.toLowerCase().includes(needle));
        return { Success: true, Data: { MatchCount: matches.length, Matches: matches.slice(0, 25) } };
    }
    async OnLookupResource() {
        if (!this.SelectedDomainName) {
            this.ErrorMessage = 'Pick a permission domain first.';
            return;
        }
        if (!this.ResourceTypeInput.trim() || !this.ResourceIdInput.trim()) {
            this.ErrorMessage = 'Resource type and resource ID are both required.';
            return;
        }
        this.ErrorMessage = null;
        this.IsLoading = true;
        this.ResourceAccessRows = [];
        this.LastQueryLabel = null;
        this.cdr.detectChanges();
        try {
            const rows = await PermissionEngine.Instance.GetResourcePermissions(this.SelectedDomainName, this.ResourceTypeInput.trim(), this.ResourceIdInput.trim());
            this.ResourceAccessRows = rows.sort((a, b) => (a.GranteeName ?? '').localeCompare(b.GranteeName ?? ''));
            this.LastQueryLabel = `${this.SelectedDomainName} / ${this.ResourceTypeInput.trim()} / ${this.ResourceIdInput.trim()}`;
        }
        catch (e) {
            this.ErrorMessage = `Error looking up resource: ${e instanceof Error ? e.message : String(e)}`;
        }
        this.IsLoading = false;
        this.cdr.detectChanges();
        this.publishAgentContext();
    }
    OnDomainChanged(domainName) {
        this.SelectedDomainName = domainName;
        this.loadResourceTypesForDomain(domainName);
        this.ResourceAccessRows = [];
        this.LastQueryLabel = null;
        this.cdr.detectChanges();
        this.publishAgentContext();
    }
    /**
     * Populate {@link ResourceTypes} from the provider behind `domainName`. If the
     * current `ResourceTypeInput` isn't a member of the new list, clear it — the
     * previous choice doesn't make sense against a different domain. When a
     * domain has exactly one supported type we auto-select it so the user
     * doesn't have to open the picker for a trivial choice.
     */
    loadResourceTypesForDomain(domainName) {
        if (!domainName) {
            this.ResourceTypes = [];
            this.ResourceTypeInput = '';
            return;
        }
        this.ResourceTypes = PermissionEngine.Instance.GetResourceTypes(domainName, this.ProviderToUse);
        if (this.ResourceTypes.length === 1) {
            this.ResourceTypeInput = this.ResourceTypes[0];
        }
        else if (!this.ResourceTypes.includes(this.ResourceTypeInput)) {
            this.ResourceTypeInput = '';
        }
    }
    TrackByResourceRow(_index, row) {
        return row.SourceRecordID ?? `${row.GranteeType}|${row.GranteeID ?? ''}`;
    }
    static ɵfac = function PermissionsResourceAccessResourceComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || PermissionsResourceAccessResourceComponent)(i0.ɵɵdirectiveInject(i0.ChangeDetectorRef)); };
    static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: PermissionsResourceAccessResourceComponent, selectors: [["mj-permissions-resource-access-resource"]], standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 23, vars: 14, consts: [["Title", "Resource Access Report", "Icon", "fa-solid fa-cube", "Subtitle", "Look up every grantee for a specific resource"], ["Variant", "error"], [1, "selector-row", "wrap"], ["for", "domain-select", 1, "selector-label"], ["id", "domain-select", 1, "mj-input", 3, "ngModelChange", "ngModel", "disabled"], [3, "ngValue"], ["for", "rtype-input", 1, "selector-label"], ["id", "rtype-input", "Placeholder", "Select or type a resource type", 3, "ngModelChange", "Data", "ValuePrimitive", "Filterable", "AllowCustom", "Disabled", "ngModel"], ["for", "rid-input", 1, "selector-label"], ["id", "rid-input", "placeholder", "UUID or record ID", 1, "mj-input", "mono", 3, "ngModelChange", "ngModel", "disabled"], ["mjButton", "", "variant", "primary", 3, "click", "disabled"], ["text", "Looking up grantees...", "size", "medium"], ["Icon", "fa-solid fa-cube", "Title", "No lookup yet", "Message", "Pick a domain and enter a resource type + ID, then press Lookup to see who has access."], ["Variant", "no-results", "Icon", "fa-solid fa-user-slash", "Title", "No grantees found", 3, "Message"], [1, "fa-solid", "fa-spinner", "fa-spin"], [1, "fa-solid", "fa-magnifying-glass"], [1, "total-summary"], [1, "domain-body"], [1, "perms-table"], [1, "resource-cell"], [1, "resource-name"], [1, "resource-id"], [1, "action-chips"], [1, "action-chip"], [1, "effect-badge"], [1, "muted"]], template: function PermissionsResourceAccessResourceComponent_Template(rf, ctx) { if (rf & 1) {
            i0.ɵɵelementStart(0, "mj-page-layout");
            i0.ɵɵelement(1, "mj-page-header", 0);
            i0.ɵɵelementStart(2, "mj-page-body");
            i0.ɵɵconditionalCreate(3, PermissionsResourceAccessResourceComponent_Conditional_3_Template, 2, 1, "mj-alert", 1);
            i0.ɵɵelementStart(4, "div", 2)(5, "label", 3);
            i0.ɵɵtext(6, "Domain:");
            i0.ɵɵelementEnd();
            i0.ɵɵelementStart(7, "select", 4);
            i0.ɵɵlistener("ngModelChange", function PermissionsResourceAccessResourceComponent_Template_select_ngModelChange_7_listener($event) { return ctx.OnDomainChanged($event); });
            i0.ɵɵrepeaterCreate(8, PermissionsResourceAccessResourceComponent_For_9_Template, 2, 2, "option", 5, _forTrack0);
            i0.ɵɵelementEnd();
            i0.ɵɵelementStart(10, "label", 6);
            i0.ɵɵtext(11, "Resource Type:");
            i0.ɵɵelementEnd();
            i0.ɵɵelementStart(12, "mj-combobox", 7);
            i0.ɵɵtwoWayListener("ngModelChange", function PermissionsResourceAccessResourceComponent_Template_mj_combobox_ngModelChange_12_listener($event) { i0.ɵɵtwoWayBindingSet(ctx.ResourceTypeInput, $event) || (ctx.ResourceTypeInput = $event); return $event; });
            i0.ɵɵelementEnd();
            i0.ɵɵelementStart(13, "label", 8);
            i0.ɵɵtext(14, "Resource ID:");
            i0.ɵɵelementEnd();
            i0.ɵɵelementStart(15, "input", 9);
            i0.ɵɵtwoWayListener("ngModelChange", function PermissionsResourceAccessResourceComponent_Template_input_ngModelChange_15_listener($event) { i0.ɵɵtwoWayBindingSet(ctx.ResourceIdInput, $event) || (ctx.ResourceIdInput = $event); return $event; });
            i0.ɵɵelementEnd();
            i0.ɵɵelementStart(16, "button", 10);
            i0.ɵɵlistener("click", function PermissionsResourceAccessResourceComponent_Template_button_click_16_listener() { return ctx.OnLookupResource(); });
            i0.ɵɵconditionalCreate(17, PermissionsResourceAccessResourceComponent_Conditional_17_Template, 2, 0)(18, PermissionsResourceAccessResourceComponent_Conditional_18_Template, 2, 0);
            i0.ɵɵelementEnd()();
            i0.ɵɵconditionalCreate(19, PermissionsResourceAccessResourceComponent_Conditional_19_Template, 1, 0, "mj-loading", 11)(20, PermissionsResourceAccessResourceComponent_Conditional_20_Template, 1, 0, "mj-empty-state", 12)(21, PermissionsResourceAccessResourceComponent_Conditional_21_Template, 1, 1, "mj-empty-state", 13)(22, PermissionsResourceAccessResourceComponent_Conditional_22_Template, 23, 3);
            i0.ɵɵelementEnd()();
        } if (rf & 2) {
            i0.ɵɵadvance(3);
            i0.ɵɵconditional(ctx.ErrorMessage ? 3 : -1);
            i0.ɵɵadvance(4);
            i0.ɵɵproperty("ngModel", ctx.SelectedDomainName)("disabled", ctx.IsLoading);
            i0.ɵɵadvance();
            i0.ɵɵrepeater(ctx.Domains);
            i0.ɵɵadvance(4);
            i0.ɵɵproperty("Data", ctx.ResourceTypes)("ValuePrimitive", true)("Filterable", true)("AllowCustom", true)("Disabled", ctx.IsLoading || !ctx.SelectedDomainName);
            i0.ɵɵtwoWayProperty("ngModel", ctx.ResourceTypeInput);
            i0.ɵɵadvance(3);
            i0.ɵɵtwoWayProperty("ngModel", ctx.ResourceIdInput);
            i0.ɵɵproperty("disabled", ctx.IsLoading);
            i0.ɵɵadvance();
            i0.ɵɵproperty("disabled", ctx.IsLoading);
            i0.ɵɵadvance();
            i0.ɵɵconditional(ctx.IsLoading ? 17 : 18);
            i0.ɵɵadvance(2);
            i0.ɵɵconditional(ctx.IsLoading ? 19 : !ctx.LastQueryLabel ? 20 : ctx.ResourceAccessRows.length === 0 ? 21 : 22);
        } }, dependencies: [i1.NgSelectOption, i1.ɵNgSelectMultipleOption, i1.DefaultValueAccessor, i1.SelectControlValueAccessor, i1.NgControlStatus, i1.NgModel, i2.MJButtonDirective, i2.MJComboboxComponent, i2.MJPageHeaderComponent, i2.MJPageLayoutComponent, i2.MJPageBodyComponent, i2.MJEmptyStateComponent, i2.MJAlertComponent, i3.LoadingComponent, i4.DatePipe], styles: ["\n\n.tab-bar[_ngcontent-%COMP%] {\n  display: flex;\n  gap: 4px;\n  border-bottom: 1px solid var(--mj-border-default);\n  margin-bottom: 16px;\n}\n\n.tab[_ngcontent-%COMP%] {\n  background: transparent;\n  border: none;\n  padding: 10px 16px;\n  cursor: pointer;\n  color: var(--mj-text-secondary);\n  font: inherit;\n  font-weight: 500;\n  border-bottom: 2px solid transparent;\n  display: inline-flex;\n  align-items: center;\n  gap: 6px;\n}\n\n.tab[_ngcontent-%COMP%]:hover {\n  color: var(--mj-text-primary);\n  background: var(--mj-bg-surface-hover);\n}\n\n.tab-active[_ngcontent-%COMP%] {\n  color: var(--mj-brand-primary);\n  border-bottom-color: var(--mj-brand-primary);\n}\n\n.selector-row.wrap[_ngcontent-%COMP%] {\n  flex-wrap: wrap;\n}\n\n.mj-input.mono[_ngcontent-%COMP%] {\n  font-family: var(--mj-font-mono, monospace);\n  min-width: 300px;\n}\n\n.muted[_ngcontent-%COMP%] {\n  color: var(--mj-text-muted);\n}\n\n\n\n.user-selector-row[_ngcontent-%COMP%], \n.selector-row[_ngcontent-%COMP%] {\n  display: flex;\n  align-items: center;\n  gap: 12px;\n  margin-bottom: 20px;\n  flex-wrap: wrap;\n}\n\n.user-selector-label[_ngcontent-%COMP%], \n.selector-label[_ngcontent-%COMP%] {\n  font-weight: 600;\n  color: var(--mj-text-primary);\n}\n\n#user-select[_ngcontent-%COMP%], \n#domain-select[_ngcontent-%COMP%] {\n  min-width: 320px;\n  flex: 0 1 auto;\n}\n\n.roles-badge[_ngcontent-%COMP%] {\n  display: inline-flex;\n  align-items: center;\n  gap: 6px;\n  padding: 4px 10px;\n  background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n  color: var(--mj-brand-primary);\n  border-radius: 12px;\n  font-size: 12px;\n  font-weight: 500;\n}\n\n.total-summary[_ngcontent-%COMP%] {\n  color: var(--mj-text-secondary);\n  font-size: 13px;\n  margin-bottom: 12px;\n}\n\n.total-summary[_ngcontent-%COMP%]   strong[_ngcontent-%COMP%] {\n  color: var(--mj-text-primary);\n}\n\n\n\n.domain-groups[_ngcontent-%COMP%] {\n  display: flex;\n  flex-direction: column;\n  gap: 8px;\n}\n\n\n\n\n.domain-icon[_ngcontent-%COMP%] {\n  color: var(--mj-brand-primary);\n  font-size: 16px;\n}\n\n.domain-name[_ngcontent-%COMP%] {\n  flex: 1;\n  font-weight: 600;\n  font-size: 15px;\n}\n\n\n\n\n\n\n\n\n.domain-body[_ngcontent-%COMP%] {\n  padding: 0;\n  background: var(--mj-bg-surface);\n  overflow-x: auto;\n}\n\n\n\n.perms-table[_ngcontent-%COMP%] {\n  width: 100%;\n  border-collapse: collapse;\n  font-size: 13px;\n}\n\n.perms-table[_ngcontent-%COMP%]   th[_ngcontent-%COMP%], \n.perms-table[_ngcontent-%COMP%]   td[_ngcontent-%COMP%] {\n  padding: 8px 16px;\n  text-align: left;\n  border-bottom: 1px solid var(--mj-border-subtle);\n  vertical-align: top;\n}\n\n.perms-table[_ngcontent-%COMP%]   th[_ngcontent-%COMP%] {\n  background: var(--mj-bg-surface-sunken);\n  color: var(--mj-text-secondary);\n  font-weight: 600;\n  text-transform: uppercase;\n  font-size: 11px;\n  letter-spacing: 0.5px;\n}\n\n.perms-table[_ngcontent-%COMP%]   tbody[_ngcontent-%COMP%]   tr[_ngcontent-%COMP%]:last-child   td[_ngcontent-%COMP%] {\n  border-bottom: none;\n}\n\n.perms-table[_ngcontent-%COMP%]   tbody[_ngcontent-%COMP%]   tr[_ngcontent-%COMP%]:hover {\n  background: var(--mj-bg-surface-hover);\n}\n\n.resource-cell[_ngcontent-%COMP%] {\n  display: flex;\n  flex-direction: column;\n  gap: 2px;\n}\n\n.resource-name[_ngcontent-%COMP%] {\n  color: var(--mj-text-primary);\n  font-weight: 500;\n}\n\n.resource-id[_ngcontent-%COMP%] {\n  color: var(--mj-text-muted);\n  font-size: 11px;\n  font-family: var(--mj-font-mono, monospace);\n}\n\n\n\n.action-chips[_ngcontent-%COMP%] {\n  display: flex;\n  flex-wrap: wrap;\n  gap: 4px;\n}\n\n.action-chip[_ngcontent-%COMP%] {\n  display: inline-flex;\n  align-items: center;\n  padding: 2px 8px;\n  background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n  color: var(--mj-brand-primary);\n  border-radius: 10px;\n  font-size: 11px;\n  font-weight: 500;\n}\n\n\n\n.effect-badge[_ngcontent-%COMP%] {\n  display: inline-flex;\n  align-items: center;\n  padding: 2px 8px;\n  border-radius: 10px;\n  font-size: 11px;\n  font-weight: 600;\n  text-transform: uppercase;\n  letter-spacing: 0.3px;\n}\n\n.effect-allow[_ngcontent-%COMP%] {\n  background: var(--mj-status-success-bg);\n  color: var(--mj-status-success-text);\n}\n\n.effect-deny[_ngcontent-%COMP%] {\n  background: var(--mj-status-error-bg);\n  color: var(--mj-status-error-text);\n}"] });
};
PermissionsResourceAccessResourceComponent = __decorate([
    RegisterClass(BaseResourceComponent, 'PermissionsResourceAccessResource')
], PermissionsResourceAccessResourceComponent);
export { PermissionsResourceAccessResourceComponent };
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(PermissionsResourceAccessResourceComponent, [{
        type: Component,
        args: [{ standalone: false, selector: 'mj-permissions-resource-access-resource', template: "<mj-page-layout>\n  <mj-page-header\n    Title=\"Resource Access Report\"\n    Icon=\"fa-solid fa-cube\"\n    Subtitle=\"Look up every grantee for a specific resource\">\n  </mj-page-header>\n\n  <mj-page-body>\n\n  @if (ErrorMessage) {\n    <mj-alert Variant=\"error\">{{ ErrorMessage }}</mj-alert>\n  }\n\n  <div class=\"selector-row wrap\">\n    <label class=\"selector-label\" for=\"domain-select\">Domain:</label>\n    <select\n      id=\"domain-select\"\n      class=\"mj-input\"\n      [ngModel]=\"SelectedDomainName\"\n      (ngModelChange)=\"OnDomainChanged($event)\"\n      [disabled]=\"IsLoading\"\n    >\n      @for (d of Domains; track d.ID) {\n        <option [ngValue]=\"d.Name\">{{ d.Name }}</option>\n      }\n    </select>\n\n    <label class=\"selector-label\" for=\"rtype-input\">Resource Type:</label>\n    <mj-combobox\n      id=\"rtype-input\"\n      [Data]=\"ResourceTypes\"\n      [ValuePrimitive]=\"true\"\n      [Filterable]=\"true\"\n      [AllowCustom]=\"true\"\n      Placeholder=\"Select or type a resource type\"\n      [Disabled]=\"IsLoading || !SelectedDomainName\"\n      [(ngModel)]=\"ResourceTypeInput\">\n    </mj-combobox>\n\n    <label class=\"selector-label\" for=\"rid-input\">Resource ID:</label>\n    <input\n      id=\"rid-input\"\n      class=\"mj-input mono\"\n      placeholder=\"UUID or record ID\"\n      [(ngModel)]=\"ResourceIdInput\"\n      [disabled]=\"IsLoading\"\n    />\n\n    <button\n      mjButton\n      variant=\"primary\"\n      (click)=\"OnLookupResource()\"\n      [disabled]=\"IsLoading\"\n    >\n      @if (IsLoading) {\n        <i class=\"fa-solid fa-spinner fa-spin\"></i> Looking up...\n      } @else {\n        <i class=\"fa-solid fa-magnifying-glass\"></i> Lookup\n      }\n    </button>\n  </div>\n\n  @if (IsLoading) {\n    <mj-loading text=\"Looking up grantees...\" size=\"medium\"></mj-loading>\n  } @else if (!LastQueryLabel) {\n    <mj-empty-state Icon=\"fa-solid fa-cube\"\n      Title=\"No lookup yet\"\n      Message=\"Pick a domain and enter a resource type + ID, then press Lookup to see who has access.\" />\n  } @else if (ResourceAccessRows.length === 0) {\n    <mj-empty-state Variant=\"no-results\" Icon=\"fa-solid fa-user-slash\"\n      Title=\"No grantees found\"\n      [Message]=\"NoGranteesMessage\" />\n  } @else {\n    <div class=\"total-summary\">\n      <strong>{{ ResourceAccessRows.length }}</strong> grantee{{ ResourceAccessRows.length === 1 ? '' : 's' }}\n      on <strong>{{ LastQueryLabel }}</strong>\n    </div>\n\n    <div class=\"domain-body\">\n      <table class=\"perms-table\">\n        <thead>\n          <tr>\n            <th>Grantee</th>\n            <th>Type</th>\n            <th>Actions</th>\n            <th>Effect</th>\n            <th>Expires</th>\n          </tr>\n        </thead>\n        <tbody>\n          @for (row of ResourceAccessRows; track TrackByResourceRow($index, row)) {\n            <tr>\n              <td class=\"resource-cell\">\n                <span class=\"resource-name\">{{ row.GranteeName || row.GranteeID || row.GranteeType }}</span>\n                @if (row.GranteeID && row.GranteeName && row.GranteeName !== row.GranteeID) {\n                  <span class=\"resource-id\">{{ row.GranteeID }}</span>\n                }\n              </td>\n              <td>{{ row.GranteeType }}</td>\n              <td>\n                <div class=\"action-chips\">\n                  @for (action of row.Actions; track action) {\n                    <span class=\"action-chip\">{{ action }}</span>\n                  }\n                </div>\n              </td>\n              <td>\n                <span class=\"effect-badge\" [class.effect-allow]=\"row.Effect === 'Allow'\" [class.effect-deny]=\"row.Effect === 'Deny'\">\n                  {{ row.Effect }}\n                </span>\n              </td>\n              <td>\n                @if (row.ExpiresAt) {\n                  <span>{{ row.ExpiresAt | date:'short' }}</span>\n                } @else {\n                  <span class=\"muted\">\u2014</span>\n                }\n              </td>\n            </tr>\n          }\n        </tbody>\n      </table>\n    </div>\n  }\n  </mj-page-body>\n</mj-page-layout>\n", styles: ["/* Tab bar */\n.tab-bar {\n  display: flex;\n  gap: 4px;\n  border-bottom: 1px solid var(--mj-border-default);\n  margin-bottom: 16px;\n}\n\n.tab {\n  background: transparent;\n  border: none;\n  padding: 10px 16px;\n  cursor: pointer;\n  color: var(--mj-text-secondary);\n  font: inherit;\n  font-weight: 500;\n  border-bottom: 2px solid transparent;\n  display: inline-flex;\n  align-items: center;\n  gap: 6px;\n}\n\n.tab:hover {\n  color: var(--mj-text-primary);\n  background: var(--mj-bg-surface-hover);\n}\n\n.tab-active {\n  color: var(--mj-brand-primary);\n  border-bottom-color: var(--mj-brand-primary);\n}\n\n.selector-row.wrap {\n  flex-wrap: wrap;\n}\n\n.mj-input.mono {\n  font-family: var(--mj-font-mono, monospace);\n  min-width: 300px;\n}\n\n.muted {\n  color: var(--mj-text-muted);\n}\n\n/* User selector (legacy name kept for User Access tab, plus generic selector-row for Resource tab) */\n.user-selector-row,\n.selector-row {\n  display: flex;\n  align-items: center;\n  gap: 12px;\n  margin-bottom: 20px;\n  flex-wrap: wrap;\n}\n\n.user-selector-label,\n.selector-label {\n  font-weight: 600;\n  color: var(--mj-text-primary);\n}\n\n#user-select,\n#domain-select {\n  min-width: 320px;\n  flex: 0 1 auto;\n}\n\n.roles-badge {\n  display: inline-flex;\n  align-items: center;\n  gap: 6px;\n  padding: 4px 10px;\n  background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n  color: var(--mj-brand-primary);\n  border-radius: 12px;\n  font-size: 12px;\n  font-weight: 500;\n}\n\n.total-summary {\n  color: var(--mj-text-secondary);\n  font-size: 13px;\n  margin-bottom: 12px;\n}\n\n.total-summary strong {\n  color: var(--mj-text-primary);\n}\n\n/* Domain groups */\n.domain-groups {\n  display: flex;\n  flex-direction: column;\n  gap: 8px;\n}\n\n/* Group wrapper + header/chevron chrome now owned by <mj-accordion-panel>. */\n\n.domain-icon {\n  color: var(--mj-brand-primary);\n  font-size: 16px;\n}\n\n.domain-name {\n  flex: 1;\n  font-weight: 600;\n  font-size: 15px;\n}\n\n/* Domain count pill migrated to <mj-accordion-badge mj-accordion-badge--right>;\n   bespoke .domain-count rule removed. */\n\n/* .toggle-icon chevron now owned by <mj-accordion-panel>. */\n\n.domain-body {\n  padding: 0;\n  background: var(--mj-bg-surface);\n  overflow-x: auto;\n}\n\n/* Permissions table */\n.perms-table {\n  width: 100%;\n  border-collapse: collapse;\n  font-size: 13px;\n}\n\n.perms-table th,\n.perms-table td {\n  padding: 8px 16px;\n  text-align: left;\n  border-bottom: 1px solid var(--mj-border-subtle);\n  vertical-align: top;\n}\n\n.perms-table th {\n  background: var(--mj-bg-surface-sunken);\n  color: var(--mj-text-secondary);\n  font-weight: 600;\n  text-transform: uppercase;\n  font-size: 11px;\n  letter-spacing: 0.5px;\n}\n\n.perms-table tbody tr:last-child td {\n  border-bottom: none;\n}\n\n.perms-table tbody tr:hover {\n  background: var(--mj-bg-surface-hover);\n}\n\n.resource-cell {\n  display: flex;\n  flex-direction: column;\n  gap: 2px;\n}\n\n.resource-name {\n  color: var(--mj-text-primary);\n  font-weight: 500;\n}\n\n.resource-id {\n  color: var(--mj-text-muted);\n  font-size: 11px;\n  font-family: var(--mj-font-mono, monospace);\n}\n\n/* Action chips */\n.action-chips {\n  display: flex;\n  flex-wrap: wrap;\n  gap: 4px;\n}\n\n.action-chip {\n  display: inline-flex;\n  align-items: center;\n  padding: 2px 8px;\n  background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n  color: var(--mj-brand-primary);\n  border-radius: 10px;\n  font-size: 11px;\n  font-weight: 500;\n}\n\n/* Effect badge */\n.effect-badge {\n  display: inline-flex;\n  align-items: center;\n  padding: 2px 8px;\n  border-radius: 10px;\n  font-size: 11px;\n  font-weight: 600;\n  text-transform: uppercase;\n  letter-spacing: 0.3px;\n}\n\n.effect-allow {\n  background: var(--mj-status-success-bg);\n  color: var(--mj-status-success-text);\n}\n\n.effect-deny {\n  background: var(--mj-status-error-bg);\n  color: var(--mj-status-error-text);\n}\n"] }]
    }], () => [{ type: i0.ChangeDetectorRef }], null); })();
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(PermissionsResourceAccessResourceComponent, { className: "PermissionsResourceAccessResourceComponent", filePath: "src/Permissions/resource-access-resource.component.ts", lineNumber: 27 }); })();
/** Tree-shaking prevention — referenced from `public-api.ts`. */
export function LoadPermissionsResourceAccessResource() {
    // intentionally empty
}
//# sourceMappingURL=resource-access-resource.component.js.map