2 * ============LICENSE_START==========================================
4 * ===================================================================
5 * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved.
6 * ===================================================================
8 * Unless otherwise specified, all software contained herein is licensed
9 * under the Apache License, Version 2.0 (the "License");
10 * you may not use this software except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
21 * Unless otherwise specified, all documentation contained herein is licensed
22 * under the Creative Commons License, Attribution 4.0 Intl. (the "License");
23 * you may not use this documentation except in compliance with the License.
24 * You may obtain a copy of the License at
26 * https://creativecommons.org/licenses/by/4.0/
28 * Unless required by applicable law or agreed to in writing, documentation
29 * distributed under the License is distributed on an "AS IS" BASIS,
30 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
31 * See the License for the specific language governing permissions and
32 * limitations under the License.
34 * ============LICENSE_END============================================
39 import { Component, OnInit, Input, Output, EventEmitter, Injectable} from '@angular/core';
40 import { NgbActiveModal, NgbModal } from '@ng-bootstrap/ng-bootstrap';
41 import { NotificationService, FunctionalMenuService } from 'src/app/shared/services';
42 import { SelectionModel } from '@angular/cdk/collections';
43 import { FlatTreeControl } from '@angular/cdk/tree';
44 import { MatTreeFlatDataSource, MatTreeFlattener } from '@angular/material/tree';
45 import { BehaviorSubject } from 'rxjs';
46 import { ConfirmationModalComponent } from 'src/app/modals/confirmation-modal/confirmation-modal.component';
47 import { InformationModalComponent } from 'src/app/modals/information-modal/information-modal.component';
50 selector: 'app-new-notification-modal',
51 templateUrl: './new-notification-modal.component.html',
52 styleUrls: ['./new-notification-modal.component.scss']
54 export class NewNotificationModalComponent implements OnInit {
57 'notificationId': null,
58 'isOnlineUsersOnly': null,
59 'isForAllRoles': null,
65 'msgDescription': null,
67 'isFunctionalMenu': null,
69 'anyTreeItemSelected': false,
72 notificationRoleIds: null
74 'notificationRoleIds': null
78 * The Json object for to-do list data.
81 notificationId = null;
83 selectedEcompFunc = null;
89 onlineAllUsersOptions = [{
92 "title": "Online Users Only"
97 "title": "Online & Offline Users"
137 @Input() selectedNotification: any;
138 @Output() passEntry: EventEmitter<any> = new EventEmitter();
141 functionalMenuRes = {};
145 dataChange = new BehaviorSubject<TodoItemNode[]>([]);
146 get data(): TodoItemNode[] { return this.dataChange.value; }
148 constructor(public ngbModal: NgbModal,
149 public activeModal: NgbActiveModal,
150 private notificationService: NotificationService,
151 public functionalMenuService: FunctionalMenuService) { }
154 this.notification.isFunctionalMenu='Y';
155 console.log("selectedNotification ::::",this.selectedNotification);
156 if(this.selectedNotification && this.selectedNotification.msgSource !=''){
158 this.isEditMode = true;
159 this.notification = Object.assign({}, this.selectedNotification);
160 if(this.selectedNotification && this.selectedNotification.priority ==1 ){
161 this.notification.priority = this.priorityOptions[0].value;
163 this.notification.priority = this.priorityOptions[1].value;
165 if(this.selectedNotification && this.selectedNotification.startTime){
166 this.notification.startTime = new Date(this.selectedNotification.startTime);
168 if(this.selectedNotification && this.selectedNotification.endTime ){
169 this.notification.endTime = new Date(this.selectedNotification.endTime);
171 this.notification.isFunctionalMenu='Y';
173 this.isEditMode = false;
174 this.notification.isActive = this.isActiveOptions[0];
175 this.notification.isOnlineUsersOnly = this.onlineAllUsersOptions[1];
176 this.notification.isForAllRoles = this.isForAllRoles[0].value;
177 this.notification.priority = this.priorityOptions[0].value;
178 this.notification.isFunctionalMenu = "Y";
179 this.notification.msgHeader = '';
180 this.notification.msgDescription = '';
181 this.notification.treeTitle = "Functional Menu";
182 this.notification.notifObj = {
183 isCategoriesFunctionalMenu: true
186 this.getFunctionalMenu();
187 this.treeFlattener = new MatTreeFlattener(this.transformer, this.getLevel, this.isExpandable, this.getChildren);
188 this.treeControl = new FlatTreeControl<TodoItemFlatNode>(this.getLevel, this.isExpandable);
189 this.dataSource = new MatTreeFlatDataSource(this.treeControl, this.treeFlattener);
190 const data = this.buildFileTree(this.MAT_TREE_DATA, 0);
191 this.dataChange.next(data);
192 this.dataChange.subscribe(data => {
193 this.dataSource.data = data;
197 addUserNotification(){
198 let notificationRoleIds = []
199 let endDate = new Date(this.notification.endTime);
200 let selectedTreeNode: Array<TodoItemFlatNode> = this.checklistSelection.selected;
201 selectedTreeNode.forEach(element => {
202 if(element && element.roleIds && element.roleIds.length >0){
203 element.roleIds.forEach(id =>{
204 if(id && id !='undefined'){
205 notificationRoleIds.push(id);
210 console.log("notificationRoleIds >>>>>>>>",notificationRoleIds);
211 if(notificationRoleIds && notificationRoleIds.length >0){
212 notificationRoleIds.sort();
215 let newUserNotification = {
216 'notificationId': (this.notification && this.notification.notificationId ? this.notification.notificationId: null),
217 'isForOnlineUsers': (this.notification && this.notification.isOnlineUsersOnly ? this.notification.isOnlineUsersOnly.value : null),
218 'isForAllRoles': this.notification.isForAllRoles,
219 'priority': this.notification.priority,
220 'activeYn': (this.notification && this.notification.isActive ? this.notification.isActive.value :'Y'),
221 'startTime': new Date(this.notification.startTime),
222 'endTime': new Date(this.notification.endTime),
223 'msgHeader': this.notification.msgHeader,
224 'msgDescription': this.notification.msgDescription,
225 'roleIds': notificationRoleIds,
226 'createdDate': new Date()
229 if((newUserNotification.isForAllRoles) && (newUserNotification.priority) && (newUserNotification.activeYn)
230 && (newUserNotification.startTime) && (newUserNotification.endTime)
231 && (newUserNotification.msgHeader != '') && (newUserNotification.msgDescription != '')){
233 console.log("newUserNotification >>> ",newUserNotification);
234 // POST ajax call here;
235 if (this.isEditMode) {
236 this.notificationService.updateAdminNotification(newUserNotification)
237 .subscribe(_data => {
239 if(this.result && this.result.status ==='ERROR'){
240 this.openConfirmationModal('Error', this.result.response);
242 this.passEntry.emit(this.result);
243 this.ngbModal.dismissAll();
247 this.openConfirmationModal('Error', error);
251 this.notificationService.addAdminNotification(newUserNotification)
252 .subscribe(_data => {
254 if(this.result && this.result.status ==='ERROR'){
255 this.openConfirmationModal('Error', this.result.response);
258 this.passEntry.emit(this.result);
259 this.ngbModal.dismissAll();
263 this.openConfirmationModal('Error', error);
268 this.openConfirmationModal("","Please fill in all required(*) fields.");
274 let menu_role_dict = {};
275 /**First Rest Call */
276 this.functionalMenuService.getFunctionalMenuRole()
277 .subscribe(role_res => {
278 this.result = role_res;
279 if (this.result == null || this.result == 'undefined') {
280 console.log('FunctionalMenuService::getFunctionalMenu Failed: Result or result.data is null');
282 //console.log('First Rest Call Data ::',this.result);
283 for (var i in role_res) {
284 // if first time appear in menu_role_dict
285 if (!(role_res[i].menuId in menu_role_dict)) {
286 menu_role_dict[role_res[i].menuId] = [role_res[i].roleId];
288 menu_role_dict[role_res[i].menuId].push(role_res[i].roleId);
293 this.functionalMenuService.getManagedFunctionalMenuForNotificationTree()
296 //console.log("2nd REST CALL RESPONSE :: ",this.result);
297 var exclude_list = ['Favorites'];
299 //Adding children and label attribute to all objects in res
300 for (let i = 0; i < this.result.length; i++) {
302 res[i].name = res[i].text;
303 res[i].id = res[i].text;
304 res[i].displayCheckbox = true;
306 isAnyRoleSelected: false
308 res[i].roleId = menu_role_dict[res[i].menuId];
309 res[i].onSelect = function() {
310 this.notification.anyTreeItemSelected = this.checkTreeSelect();
313 let intersectionObj: any;
314 intersectionObj = res[i].roleId & this.notification.notificationRoleIds;
315 if (res[i].roleId && res[i].roleId.length == intersectionObj.length) {
316 res[i].isSelected = true;
317 res[i].selected = true;
318 res[i].indeterminate = false;
321 res[i].isSelected = false;
322 res[i].selected = false;
323 res[i].indeterminate = false;
327 // Adding actual child items to children array in res
329 let parentChildDict = {};
330 let parentChildRoleIdDict = {};
331 for (let i = 0; i < this.result.length; i++) {
332 let parentId = this.result[i].menuId;
333 parentChildDict[parentId] = [];
334 parentChildRoleIdDict[parentId] = [];
335 for (let j = 0; j < this.result.length; j++) {
336 let childId = res[j].parentMenuId;
337 if (parentId === childId) {
338 res[i].child.push(res[j]);
339 parentChildDict[parentId].push(res[j].menuId);
340 //if res[j].roleId is defined
342 for (let k in res[j].roleId) {
343 parentChildRoleIdDict[parentId].push(res[j].roleId[k]);
351 //check if grand children exist
352 for (var key in parentChildDict) {
353 var child = parentChildDict[key];
354 var isGrandParent = false;
355 if (child.length > 0) {
356 for (var i in child) {
357 if (parentChildDict[child[i]].length > 0) {
358 isGrandParent = true;
364 for (var i in child) {
365 // if the child has children
366 if (parentChildDict[child[i]].length > 0) {
367 for (var j in parentChildRoleIdDict[child[i]]) {
368 if (parentChildRoleIdDict[key].indexOf(parentChildRoleIdDict[child[i]][j]) === -1) {
369 parentChildRoleIdDict[key].push(parentChildRoleIdDict[child[i]][j]);
378 // Sort the top-level menu items in order based on the column
379 this.result.sort(function(a, b) {
380 return a.column - b.column;
383 // Sort all the child in order based on the column
384 for (let i = 0; i < this.result.length; i++) {
385 res[i].child.sort(function(a, b) {
386 return a.column - b.column;
390 //Forming actual parent items
391 for (let i = 0; i < this.result.length; i++) {
392 let pmid = res[i].parentMenuId;
394 actualData.push(res[i]);
397 var treedata = actualData[0].child;
401 /*Remove favorite from the list */
402 for (var i in treedata) {
403 if (!(treedata[i].name.indexOf(exclude_list) > -1)) {
404 this.treedata.push(treedata[i])
407 //setting b2b tree parameter
408 this.settingTreeParam();
409 this.populateTreeDataSourceByFunctionalMenu(this.treedata);
421 /**************first level****************/
422 for (var fi = 0; fi < this.treedata.length; fi++) {
423 var fLevel = this.treedata[fi];
424 var sLevel = this.treedata[fi].child;
425 var sLevelSelectedCount = 0;
426 var sLevelChildNumber = 0
427 if (fLevel.child.length == 0 && fLevel.roleId == null) {
430 /**************Second level****************/
431 var sLevelDelArray = [];
432 for (var si = 0; si < sLevel.length; si++) {
433 var deletThisSLev = false;
434 if (sLevel[si].child.length == 0 && sLevel[si].roleId == null) {
435 sLevel[si].displayCheckbox = false;
436 sLevelDelArray.push(sLevel[si].name);
437 sLevel[si].name = '';
438 sLevel[si].active = false;
439 delete sLevel[si].child;
440 } else if (sLevel[si].child.length == 0) {
441 delete sLevel[si].child;
443 /**************Third level****************/
444 var tLevel = sLevel[si].child;
445 var tLevelSelectedCount = 0;
446 var tLevelChildNumber = 0;
448 var tLevelDelArray = [];
449 var tLevelLen = tLevel.length;
450 var tLevelRoleIdUndefined = 0;
451 for (var ti = 0; ti < tLevel.length; ti++) {
452 delete tLevel[ti].child;
453 if (tLevel[ti].roleId == null) {
454 tLevel[ti].displayCheckbox = false;
455 tLevelDelArray.push(tLevel[ti].name);
456 tLevel[ti].name = '';
457 tLevel[ti].active = false;
458 tLevelRoleIdUndefined++
460 if (tLevel[ti].isSelected)
461 tLevelSelectedCount++;
463 if (tLevel[ti].displayCheckbox)
467 if (tLevelRoleIdUndefined == tLevelLen)
468 deletThisSLev = true;
469 if (tLevelSelectedCount == tLevelChildNumber) {
470 sLevel[si].isSelected = true;
471 sLevel[si].indeterminate = false;
472 sLevel[si].active = true;
473 } else if (tLevelSelectedCount > 0) {
474 sLevel[si].indeterminate = true;
475 sLevel[si].active = true;
478 /*Cleanup unused third level items*/
479 for (var i = 0; i < tLevelDelArray.length; i++) {
480 var name = tLevelDelArray[i];
481 for (var ti = 0; ti < tLevel.length; ti++) {
482 if (name == tLevel[ti].text) {
483 tLevel.splice(ti, 1);
490 if (deletThisSLev) { //remove the whole second level item if all it's child has no roleId
491 sLevel[si].displayCheckbox = false;
492 sLevelDelArray.push(sLevel[si].name);
493 sLevel[si].name = '';
494 sLevel[si].active = false;
496 if (sLevel[si].isSelected)
497 sLevelSelectedCount++;
498 if (sLevel[si].displayCheckbox)
502 if (sLevelSelectedCount == sLevelChildNumber && sLevelChildNumber != 0) {
503 fLevel.isSelected = true;
504 fLevel.indeterminate = false;
505 fLevel.active = true;
506 } else if (sLevelSelectedCount > 0) {
507 fLevel.indeterminate = true;
508 fLevel.active = true;
510 //fLevel.active=false;
511 fLevel.indeterminate = false;
513 /*Cleanup unused second level items*/
514 for (var i = 0; i < sLevelDelArray.length; i++) {
515 var name = sLevelDelArray[i];
516 for (var si = 0; si < sLevel.length; si++) {
517 if (name == sLevel[si].text) {
518 sLevel.splice(si, 1);
530 for (var fi = 0; fi < this.treedata.length; fi++) {
531 var fLevel = this.treedata[fi];
532 if (fLevel.isSelected) {
535 var sLevel = fLevel.child;
537 for (var si = 0; si < sLevel.length; si++) {
538 if (sLevel[si].isSelected) {
541 var tLevel = sLevel[si].child;
543 for (var ti = 0; ti < tLevel.length; ti++) {
544 if (tLevel[ti].isSelected) {
557 this.notification.notifObj = {
558 isCategoriesFunctionalMenu: false
560 this.notificationService.getAppRoleIds()
561 .subscribe(_data => {
564 var app_id_name_list = {};
566 isAnyRoleSelected: false
568 for (let i = 0; i < this.result.length; i++) {
569 if (!(this.result[i].appId in app_id_name_list)) {
570 app_id_name_list[this.result[i].appId] = this.result[i].appName;
572 this.result[i].child = [];
573 this.result[i].name = this.result[i].roleName;
574 this.result[i].displayCheckbox = true;
575 this.result[i].id = this.result[i].roleId;
576 this.result[i].menuId = this.result[i].roleId;
577 this.result[i].parentMenuId = this.result[i].appId;
578 this.result[i].can_check = true;
579 this.result[i].roleId = [this.result[i].roleId];
580 this.result[i].onSelect = function() {
581 this.notification.anyTreeItemSelected = this.checkTreeSelect();
583 /*assigning selected value*/
584 let intersectionObj: any;
585 intersectionObj = this.result[i].roleId & this.notification.notificationRoleIds;
586 if (this.result[i].roleId && this.result[i].roleId.length == intersectionObj.length) {
587 this.result[i].isSelected = true;
588 this.result[i].selected = true;
589 this.result[i].indeterminate = false;
592 this.result[i].isSelected = false;
593 this.result[i].selected = false;
594 this.result[i].indeterminate = false;
598 for (var app_id in app_id_name_list) {
604 'displayCheckbox': null,
609 'msgDescription': null,
616 new_res.name = app_id_name_list[app_id];
618 new_res.displayCheckbox = true;
619 new_res.menuId = app_id;
620 new_res.parentMenuId = null;
621 new_res.appId = null;
622 new_res.can_check = true;
623 new_res.roleId = null;
624 new_res.onSelect = function() {
625 this.notification.anyTreeItemSelected = this.checkTreeSelect();
627 this.result.push(new_res);
630 let parentChildRoleIdDict = {};
631 //Adding actual child items to child array in res objects
632 for (let i = 0; i < this.result.length; i++) {
633 let parentId = this.result[i].menuId;
634 parentChildRoleIdDict[parentId] = [];
635 for (let j = 0; j < this.result.length; j++) {
636 let childId = this.result[j].parentMenuId;
637 if (parentId == childId) {
638 this.result[i].child.push(this.result[j]);
639 if (this.result[j].roleId) {
640 for (let k in this.result[j].roleId) {
641 parentChildRoleIdDict[parentId].push(this.result[j].roleId[k]);
648 //Forming actual parent items
649 for (let i = 0; i < this.result.length; i++) {
650 let parentId = this.result[i].parentMenuId;
651 if (parentId === null) {
652 actualData.push(this.result[i]);
656 this.treedata = actualData;
657 //setting correct parameters for b2b tree
658 this.settingTreeParam();
659 this.makeFinalTreeDataByProcessingAppRoleIds(this.treedata);
666 makeFinalTreeDataByProcessingAppRoleIds(treeData_approleids){
667 let datamap: any = new Map();
668 let data = treeData_approleids;
670 if(data && data.length > 0){
671 data.forEach(element => {
672 let iskeyPresent: boolean = false;
674 if(datamap.get(element.id)){
680 let temp = datamap.get(element.id);
682 datamap.set(element.id,temp)
684 datamap.set(element.id,element);
689 if(datamap && datamap.size > 0){
691 datamap.forEach((value, key) => {
695 for(let item of value.child){
696 keyname = item.appName+"~"+'undefined';
697 let childItem = item.roleName+"~"+item.roleId;
698 childArray.push(childItem);
700 treeNode[keyname] = childArray;
703 console.log("makeFinalTreeDataByProcessingAppRoleIds >>",treeNode);
705 this.treeFlattener = new MatTreeFlattener(this.transformer, this.getLevel, this.isExpandable, this.getChildren);
706 this.treeControl = new FlatTreeControl<TodoItemFlatNode>(this.getLevel, this.isExpandable);
707 this.dataSource = new MatTreeFlatDataSource(this.treeControl, this.treeFlattener);
708 const data = this.buildFileTree(treeNode, 0);
709 this.dataChange.next(data);
710 this.dataChange.subscribe(data => {
711 this.dataSource.data = data;
718 * Prepare Tree datasoure using functional Menu Data.
719 * @param functionMenuData
721 populateTreeDataSourceByFunctionalMenu(functionMenuData: any){
722 console.log("populateTreeDataSourceByFunctionalMenu :: ",functionMenuData);
723 if(functionMenuData){
725 functionMenuData.forEach(element => {
726 let name = element.text+"~"+element.roleId;
727 treeNode[name] = { };
729 if(element.child && element.child.length >0){
731 element.child.forEach(element => {
732 let childItem = element.text+"~"+element.roleId;
733 childArray.push(childItem);
735 treeNode[name] = childArray;
739 console.log("treeNode>>",treeNode);
741 this.treeFlattener = new MatTreeFlattener(this.transformer, this.getLevel, this.isExpandable, this.getChildren);
742 this.treeControl = new FlatTreeControl<TodoItemFlatNode>(this.getLevel, this.isExpandable);
743 this.dataSource = new MatTreeFlatDataSource(this.treeControl, this.treeFlattener);
744 const data = this.buildFileTree(treeNode, 0);
745 this.dataChange.next(data);
746 this.dataChange.subscribe(data => {
747 this.dataSource.data = data;
752 openConfirmationModal(_title: string, _message: string) {
753 const modalInfoRef = this.ngbModal.open(ConfirmationModalComponent);
754 modalInfoRef.componentInstance.title = _title;
755 modalInfoRef.componentInstance.message = _message;
758 openInformationModal(_title: string, _message: string){
759 const modalInfoRef = this.ngbModal.open(InformationModalComponent);
760 modalInfoRef.componentInstance.title = _title;
761 modalInfoRef.componentInstance.message = _message;
766 /*************************************** mat-tree code start here ******************************/
768 /** Map from flat node to nested node. This helps us finding the nested node to be modified */
769 flatNodeMap = new Map<TodoItemFlatNode, TodoItemNode>();
770 /** Map from nested node to flattened node. This helps us to keep the same object for selection */
771 nestedNodeMap = new Map<TodoItemNode, TodoItemFlatNode>();
772 /** A selected parent node to be inserted */
773 selectedParent: TodoItemFlatNode | null = null;
774 /** The new item's name */
776 treeControl: FlatTreeControl<TodoItemFlatNode>;
777 treeFlattener: MatTreeFlattener<TodoItemNode, TodoItemFlatNode>;
778 dataSource: MatTreeFlatDataSource<TodoItemNode, TodoItemFlatNode>;
779 /** The selection for checklist */
780 checklistSelection = new SelectionModel<TodoItemFlatNode>(true /* multiple */);
781 getLevel = (node: TodoItemFlatNode) => node.level;
782 isExpandable = (node: TodoItemFlatNode) => node.expandable;
783 getChildren = (node: TodoItemNode): TodoItemNode[] => node.children;
784 hasChild = (_: number, _nodeData: TodoItemFlatNode) => _nodeData.expandable;
785 hasNoContent = (_: number, _nodeData: TodoItemFlatNode) => _nodeData.item === '';
788 * Transformer to convert nested node to flat node. Record the nodes in maps for later use.
790 transformer = (node: TodoItemNode, level: number) => {
791 const existingNode = this.nestedNodeMap.get(node);
792 const flatNode = existingNode && existingNode.item === node.item
794 : new TodoItemFlatNode();
795 flatNode.item = node.item;
796 flatNode.level = level;
797 flatNode.expandable = !!node.children;
798 flatNode.roleIds = node.roleIds;
799 this.flatNodeMap.set(flatNode, node);
800 this.nestedNodeMap.set(node, flatNode);
804 /** Whether all the descendants of the node are selected. */
805 descendantsAllSelected(node: TodoItemFlatNode): boolean {
806 const descendants = this.treeControl.getDescendants(node);
807 const descAllSelected = descendants.every(child =>
808 this.checklistSelection.isSelected(child)
810 return descAllSelected;
813 /** Whether part of the descendants are selected */
814 descendantsPartiallySelected(node: TodoItemFlatNode): boolean {
815 const descendants = this.treeControl.getDescendants(node);
816 const result = descendants.some(child => this.checklistSelection.isSelected(child));
817 return result && !this.descendantsAllSelected(node);
820 /** Toggle the to-do item selection. Select/deselect all the descendants node */
821 todoItemSelectionToggle(node: TodoItemFlatNode): void {
822 this.checklistSelection.toggle(node);
823 const descendants = this.treeControl.getDescendants(node);
824 this.checklistSelection.isSelected(node)
825 ? this.checklistSelection.select(...descendants)
826 : this.checklistSelection.deselect(...descendants);
828 // Force update for the parent
829 descendants.every(child =>
830 this.checklistSelection.isSelected(child)
832 this.checkAllParentsSelection(node);
835 /** Toggle a leaf to-do item selection. Check all the parents to see if they changed */
836 todoLeafItemSelectionToggle(node: TodoItemFlatNode): void {
837 this.checklistSelection.toggle(node);
838 this.checkAllParentsSelection(node);
841 /* Checks all the parents when a leaf node is selected/unselected */
842 checkAllParentsSelection(node: TodoItemFlatNode): void {
843 let parent: TodoItemFlatNode | null = this.getParentNode(node);
845 this.checkRootNodeSelection(parent);
846 parent = this.getParentNode(parent);
850 /** Check root node checked state and change it accordingly */
851 checkRootNodeSelection(node: TodoItemFlatNode): void {
852 const nodeSelected = this.checklistSelection.isSelected(node);
853 const descendants = this.treeControl.getDescendants(node);
854 const descAllSelected = descendants.every(child =>
855 this.checklistSelection.isSelected(child)
857 if (nodeSelected && !descAllSelected) {
858 this.checklistSelection.deselect(node);
859 } else if (!nodeSelected && descAllSelected) {
860 this.checklistSelection.select(node);
864 /* Get the parent node of a node */
865 getParentNode(node: TodoItemFlatNode): TodoItemFlatNode | null {
866 const currentLevel = this.getLevel(node);
868 if (currentLevel < 1) {
872 const startIndex = this.treeControl.dataNodes.indexOf(node) - 1;
874 for (let i = startIndex; i >= 0; i--) {
875 const currentNode = this.treeControl.dataNodes[i];
877 if (this.getLevel(currentNode) < currentLevel) {
886 * Build the file structure tree. The `value` is the Json object, or a sub-tree of a Json object.
887 * The return value is the list of `TodoItemNode`.
889 buildFileTree(obj: {[key: string]: any}, level: number): TodoItemNode[] {
890 return Object.keys(obj).reduce<TodoItemNode[]>((accumulator, key) => {
891 const value = obj[key];
892 const node = new TodoItemNode();
895 if(key.indexOf("~") !== -1){
896 let nodeDetails = key.split("~");
897 node.item = nodeDetails[0];
899 node.roleIds = nodeDetails[1].split(",");
906 if (typeof value === 'object') {
907 node.children = this.buildFileTree(value, level + 1);
910 if(value.indexOf("~") !== -1){
911 let nodeDetails = value.split("~");
912 node.item = nodeDetails[0];
914 node.roleIds = nodeDetails[1].split(",");
922 return accumulator.concat(node);
925 /*************************************** mat-tree code end here ******************************/
929 * Node for to-do item
931 export class TodoItemNode {
932 children: TodoItemNode[];
937 /** Flat to-do item node with expandable and level information */
938 export class TodoItemFlatNode {