File
defaultRule
(Optional)
|
Type
|
boolean
|
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 || [];
}
}