File

libs/acl/angular/src/lib/hierarchical-inspector/rules/rules.component.ts

Index

Properties

Properties

active
Type boolean
condition
Type string
defaultRule (Optional)
Type boolean
state
Type string
import { AclRule, AclRuleState } from '@allianz/taly-acl';
import { Component, EventEmitter, Input, Output } from '@angular/core';
import {
  NxFlatTreeControl,
  NxFlatTreeNode,
  NxTreeFlatDataSource,
  NxTreeNode
} from '@aposin/ng-aquila/tree';
import { Observable } from 'rxjs';
import { AclService } from '../../services/acl.service';

interface AclRuleTreeNode extends NxTreeNode {
  children?: AclRuleTreeNode[];
  resource: string;
  fullPath: string;
  state?: Observable<AclRuleState>;
  active?: boolean;
  ruleDetails?: RuleDetail[];
}

export interface AclRuleFlatTreeNode extends NxFlatTreeNode {
  resource: string;
  fullPath: string;
  state?: AclRuleState;
  active?: boolean;
  ruleDetails?: RuleDetail[];
}

interface RuleDetail {
  condition: string;
  state: string;
  defaultRule?: boolean;
  active: boolean;
}

@Component({
  selector: 'acl-rules',
  templateUrl: './rules.component.html',
  styleUrls: ['./rules.component.scss'],
  standalone: false
})
export class RulesComponent {
  @Input() set rules(value: AclRule[]) {
    this.aclRuleTreeNodes = this.createTreeNodes(value);
    this._dataSource = new NxTreeFlatDataSource(this._treeControl, this.aclRuleTreeNodes);
    this._treeControl.expandAll();
  }

  @Output() openRuleEditor = new EventEmitter<AclRuleFlatTreeNode>();

  aclRuleTreeNodes: AclRuleTreeNode[] = [];
  _dataSource!: NxTreeFlatDataSource<AclRuleTreeNode, AclRuleFlatTreeNode>;
  _treeControl: NxFlatTreeControl<AclRuleFlatTreeNode>;

  constructor(private readonly aclService: AclService) {
    this._treeControl = new NxFlatTreeControl();
  }

  _hasChild = (_: number, node: NxFlatTreeNode) => node.expandable;

  private createTreeNodes(rules: AclRule[]) {
    const root: AclRuleTreeNode = { resource: '', fullPath: '', children: [] };
    // record of all available nodes in the tree
    // it's only used to identify if the node is already exist
    const treeNodeRecord: Record<string, AclRuleTreeNode> = { '': root };

    rules.forEach((rule) => {
      const resources = rule.path.split('/');

      let parent = root;
      let fullPath = '';

      resources.forEach((resource, index) => {
        fullPath = fullPath ? `${fullPath}/${resource}` : resource;

        let node = treeNodeRecord[fullPath];

        // if the node is not exist, create a new one
        if (!node) {
          node = { resource, fullPath };
          treeNodeRecord[fullPath] = node;
          parent.children = parent.children || [];
          parent.children.push(node);
        }

        // store rule info in the last node of each path
        // e.g. given rule page-a/bb-a/form-a, some-condition, hidden => some-condition and hidden will be stored in the form-a node only
        if (index === resources.length - 1) {
          node.state = this.aclService.currentState$(node.fullPath);
          // an initial active status is always true
          // if the toggle in the main view is switched off, the corresponding ACL resource will become visible & editable
          node.active = true;
          node.ruleDetails ??= [];
          node.ruleDetails.push({
            condition: rule.condition,
            state: rule.state,
            active: rule.active,
            defaultRule: rule.defaultRule
          });
        }

        // store the current node as a parent of the next node
        parent = node;
      });
    });

    return root.children || [];
  }
}

results matching ""

    No results matching ""