libs/acl/angular/ngx-devtools-plugin/src/lib/policy-editor/policy-editor.component.ts

Metadata

Relationships

Depends on

No results matching.

Index

Properties
Methods
Inputs
Outputs

Inputs

persistPolicyUrl
Type : string
Default value : ''
policy
Type : AclRule[]
Default value : []

Outputs

changed
Type : AclRule[]

Methods

copyToClipboard
copyToClipboard()
Returns : void
createRule
createRule()
Returns : void
dropRule
dropRule(event: CdkDragDrop<AclRule>)
Parameters :
Name Type Optional
event CdkDragDrop<AclRule> No
Returns : void
duplicateRule
duplicateRule(rule: AclRule, index: number)
Parameters :
Name Type Optional
rule AclRule No
index number No
Returns : void
persistPolicy
persistPolicy()
Returns : void
removeRule
removeRule(index: number)
Parameters :
Name Type Optional
index number No
Returns : void
requestUpdate
requestUpdate()
Returns : void
toggleAll
toggleAll()
Returns : void

Properties

aclIconName
Type : unknown
Default value : AclIconName
mutablePolicy
Type : unknown
Default value : linkedSignal(() => this.policy())
toggleAllState
Type : unknown
Default value : computed(() => this.hasActiveNonDefaultRules())
import {
  ChangeDetectionStrategy,
  Component,
  computed,
  input,
  linkedSignal,
  output
} from '@angular/core';
import { AclRule, convertRulesToPolicyTxt } from '@allianz/taly-acl';
import { CdkDragDrop } from '@angular/cdk/drag-drop';
import { AclIconName, copyToClipboard } from '@allianz/taly-acl/angular';

@Component({
  selector: 'acl-policy-editor',
  templateUrl: './policy-editor.component.html',
  styleUrls: ['./policy-editor.component.scss'],
  standalone: false,
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class PolicyEditorComponent {
  policy = input<AclRule[]>([]);
  persistPolicyUrl = input<string>('');
  changed = output<AclRule[]>();

  mutablePolicy = linkedSignal(() => this.policy());
  toggleAllState = computed(() => this.hasActiveNonDefaultRules());
  aclIconName = AclIconName;

  dropRule(event: CdkDragDrop<AclRule>) {
    const policy = [...this.mutablePolicy()];
    const draggedRule = policy[event.previousIndex];
    if (!draggedRule) {
      throw new Error(`Could not move rule with index ${event.previousIndex}`);
    }

    policy.splice(event.previousIndex, 1);

    const indexForFirstDefaultRule = policy.findIndex((rule) => rule.defaultRule);

    if (indexForFirstDefaultRule === -1) {
      policy.splice(event.currentIndex, 0, draggedRule);
    } else {
      const currentIndex = Math.min(indexForFirstDefaultRule, event.currentIndex);
      policy.splice(currentIndex, 0, draggedRule);
    }

    this.mutablePolicy.set(policy);
    this.requestUpdate();
  }

  private hasActiveNonDefaultRules() {
    const mutablePolicy = this.mutablePolicy();
    if (mutablePolicy.length === 0) {
      return true;
    }
    return mutablePolicy.filter((rule) => !rule.defaultRule).some((rule) => rule.active);
  }

  requestUpdate() {
    this.changed.emit(this.mutablePolicy());
  }

  toggleAll() {
    const policy = this.mutablePolicy();
    if (policy.length === 0) {
      return;
    }
    const newState = !this.hasActiveNonDefaultRules();
    this.mutablePolicy.set(
      policy.map((rule) => (rule.defaultRule ? rule : { ...rule, active: newState }))
    );
    this.requestUpdate();
  }

  copyToClipboard() {
    const policyString = convertRulesToPolicyTxt(this.mutablePolicy());

    copyToClipboard(policyString);
  }

  persistPolicy() {
    const policyString = convertRulesToPolicyTxt(this.mutablePolicy());

    fetch(this.persistPolicyUrl(), { method: 'POST', body: policyString, credentials: 'include' });
  }

  createRule() {
    this.mutablePolicy.set([
      { active: true, condition: '', path: '*', state: 'visible', defaultRule: false },
      ...this.mutablePolicy()
    ]);
    this.requestUpdate();
  }

  duplicateRule(rule: AclRule, index: number) {
    const policy = [...this.mutablePolicy()];
    const indexForFirstDefaultRule = policy.findIndex((r) => r.defaultRule);
    const insertIndex =
      indexForFirstDefaultRule === -1 ? index : Math.min(indexForFirstDefaultRule, index);

    policy.splice(insertIndex, 0, { ...rule, defaultRule: false });

    this.mutablePolicy.set(policy);
    this.requestUpdate();
  }

  removeRule(index: number) {
    const newRules = [...this.mutablePolicy()];
    newRules.splice(index, 1);
    this.mutablePolicy.set(newRules);
    this.requestUpdate();
  }
}
<div class="inspector-actions">
  <button class="btn-icon" (click)="toggleAll()">
    @if (toggleAllState()) {
    <acl-icon [name]="aclIconName.EyeBig" title="toggle all rules" size="24"></acl-icon>
    } @if (!toggleAllState()) {
    <acl-icon [name]="aclIconName.EyeBigClosed" title="toggle all rules" size="24"></acl-icon>
    }
  </button>
  <button class="btn-icon" (click)="createRule()">
    <acl-icon [name]="aclIconName.Plus" title="create rule" size="24"></acl-icon>
  </button>
  <button class="btn-icon" (click)="copyToClipboard()">
    <acl-icon [name]="aclIconName.Copy" title="copy to clipboard" size="24"></acl-icon>
  </button>
  @if (persistPolicyUrl()) {
  <button class="btn-icon persist-policy" (click)="persistPolicy()" title="persist policy">
    <acl-icon [name]="aclIconName.Save" title="persist policy" size="24"></acl-icon>
    <span>Persist Policy</span>
  </button>
  }
  <button class="btn-icon" (click)="this.requestUpdate()">
    <acl-icon [name]="aclIconName.Reload" title="refresh component" size="24"></acl-icon>
  </button>
</div>

<div class="list" cdkDropList (cdkDropListDropped)="dropRule($event)">
  @for (rule of mutablePolicy(); track $index; let index = $index) {
  <acl-rule
    [rule]="rule"
    [index]="index + 1"
    (duplicated)="duplicateRule($event, index)"
    (removed)="removeRule(index)"
    (changed)="requestUpdate()"
    cdkDrag
    [cdkDragData]="rule"
    [attr.data-testid]="'rule-' + (index + 1)"
  >
    <acl-icon
      cdkDragHandle
      [name]="aclIconName.DragVertical"
      title="drag rule"
      size="28"
    ></acl-icon>
  </acl-rule>
  }
</div>

./policy-editor.component.scss

@use '../inspector.shared' as *;

:host {
  display: grid;
  grid-template-rows: auto 1fr;
}

.persist-policy {
  width: auto !important;
  padding: 0 5px !important;

  span {
    vertical-align: middle;
  }
}
Legend
Html element
Component
Html element with directive

results matching ""

    No results matching ""