aboutsummaryrefslogtreecommitdiffstats
path: root/vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-tree
diff options
context:
space:
mode:
authorIttay Stern <ittay.stern@att.com>2018-08-29 17:01:32 +0300
committerIttay Stern <ittay.stern@att.com>2019-02-18 18:35:30 +0200
commit6f900cc45d7dd7f97430812b86b5c1d1693c8ae3 (patch)
tree936005c364dc5a7264d6304d4777c3d83494db22 /vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-tree
parent67d99f816cc583643c35193197594cf78d8ce60a (diff)
merge from ecomp a88f0072 - Modern UI
Issue-ID: VID-378 Change-Id: Ibcb23dd27f550cf32ce2fe0239f0f496ae014ff6 Signed-off-by: Ittay Stern <ittay.stern@att.com>
Diffstat (limited to 'vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-tree')
-rw-r--r--vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-tree/dragAndDrop/dragAndDrop.model.ts15
-rw-r--r--vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-tree/dragAndDrop/dragAndDrop.service.spec.ts227
-rw-r--r--vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-tree/dragAndDrop/dragAndDrop.service.ts78
-rw-r--r--vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-tree/drawing-board-tree.component.ts207
-rw-r--r--vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-tree/drawing-board-tree.html96
-rw-r--r--vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-tree/drawing-board-tree.scss405
-rw-r--r--vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-tree/drawing-board-tree.service.spec.ts147
-rw-r--r--vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-tree/drawing-board-tree.service.ts129
-rw-r--r--vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-tree/instance.tree.generator.ts8
-rw-r--r--vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-tree/tree-node-header-properties/tree-node-header-properties.component.html5
-rw-r--r--vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-tree/tree-node-header-properties/tree-node-header-properties.component.scss24
-rw-r--r--vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-tree/tree-node-header-properties/tree-node-header-properties.component.spec.ts25
-rw-r--r--vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-tree/tree-node-header-properties/tree-node-header-properties.component.ts10
13 files changed, 1376 insertions, 0 deletions
diff --git a/vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-tree/dragAndDrop/dragAndDrop.model.ts b/vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-tree/dragAndDrop/dragAndDrop.model.ts
new file mode 100644
index 000000000..a8e9b435a
--- /dev/null
+++ b/vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-tree/dragAndDrop/dragAndDrop.model.ts
@@ -0,0 +1,15 @@
+/******************************************
+ type - node type
+ isFirstLevel : node is first level
+ ******************************************/
+
+export class DragAndDropModel {
+ type : string;
+ isFirstLevel : boolean;
+
+ constructor(type : string, isFirstLevel : boolean){
+ this.type = type;
+ this.isFirstLevel = isFirstLevel;
+ }
+
+}
diff --git a/vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-tree/dragAndDrop/dragAndDrop.service.spec.ts b/vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-tree/dragAndDrop/dragAndDrop.service.spec.ts
new file mode 100644
index 000000000..1221cef5f
--- /dev/null
+++ b/vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-tree/dragAndDrop/dragAndDrop.service.spec.ts
@@ -0,0 +1,227 @@
+import {TestBed, getTestBed} from '@angular/core/testing';
+import {
+ HttpClientTestingModule,
+ HttpTestingController
+} from '@angular/common/http/testing';
+import {NgRedux} from "@angular-redux/store";
+import {DragAndDropService} from "./dragAndDrop.service";
+import {AppState} from "../../../../shared/store/reducers";
+
+class MockAppStore<T> {
+ dispatch(){
+
+ }
+ getState() {
+ return {
+ global: {
+ flags: {
+ "DRAG_AND_DROP_OPERATION" : true
+ }
+ },
+ service: {
+ serviceInstance: {
+ "serviceInstanceId": {
+ vnfs: {
+ "vnfStoreKey": {
+ isMissingData: true,
+ vfModules: {
+ "vfModulesName": {
+ "vfModulesName": {
+ isMissingData: true
+ }
+ }
+ }
+ },
+
+ "vnfStoreKey1": {
+ isMissingData: false,
+ vfModules: {
+ "vfModulesName": {
+ "vfModulesName": {
+ isMissingData: false
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+describe('Drag and drop service', () => {
+ let injector;
+ let service: DragAndDropService;
+ let httpMock: HttpTestingController;
+ let store: NgRedux<AppState>;
+
+ beforeAll(done => (async () => {
+ TestBed.configureTestingModule({
+ imports: [HttpClientTestingModule],
+ providers: [
+ DragAndDropService,
+ {provide: NgRedux, useClass: MockAppStore}]
+ });
+ await TestBed.compileComponents();
+
+ injector = getTestBed();
+ service = injector.get(DragAndDropService);
+ httpMock = injector.get(HttpTestingController);
+ store = injector.get(NgRedux);
+ })().then(done).catch(done.fail));
+
+
+ test('drag should move element position', () => {
+ let nodes = [{
+ "modelCustomizationId": "91415b44-753d-494c-926a-456a9172bbb9",
+ "modelId": "d6557200-ecf2-4641-8094-5393ae3aae60",
+ "modelUniqueId": "91415b44-753d-494c-926a-456a9172bbb9",
+ "missingData": false,
+ "id": "tjjongy92jn",
+ "action": "Create",
+ "inMaint": false,
+ "name": "yoav2_001",
+ "modelName": "VF_vMee 0",
+ "type": "VF",
+ "isEcompGeneratedNaming": true,
+ "networkStoreKey": "VF_vMee 0:0001",
+ "vnfStoreKey": "VF_vMee 0:0001",
+ "typeName": "VNF",
+ "menuActions": {"edit": {}, "showAuditInfo": {}, "duplicate": {}, "remove": {}, "delete": {}, "undoDelete": {}},
+ "isFailed": false,
+ "statusProperties": [{"key": "Prov Status:", "testId": "provStatus"}, {
+ "key": "Orch Status:",
+ "testId": "orchStatus"
+ }],
+ "trackById": "di9khuolht",
+ "parentType": "",
+ "position": 0,
+ "children": [{
+ "modelCustomizationId": "f8c040f1-7e51-4a11-aca8-acf256cfd861",
+ "modelId": "a27f5cfc-7f12-4f99-af08-0af9c3885c87",
+ "modelUniqueId": "f8c040f1-7e51-4a11-aca8-acf256cfd861",
+ "missingData": false,
+ "id": 6654971919519,
+ "action": "Create",
+ "name": "VFModule1",
+ "modelName": "vf_vmee0..VfVmee..base_vmme..module-0",
+ "type": "VFmodule",
+ "isEcompGeneratedNaming": true,
+ "dynamicInputs": [],
+ "dynamicModelName": "vf_vmee0..VfVmee..base_vmme..module-0bykqx",
+ "typeName": "M",
+ "menuActions": {"edit": {}, "showAuditInfo": {}, "remove": {}, "delete": {}, "undoDelete": {}},
+ "isFailed": false,
+ "statusProperties": [{"key": "Prov Status:", "testId": "provStatus"}, {
+ "key": "Orch Status:",
+ "testId": "orchStatus"
+ }],
+ "trackById": "5pfyfah820h",
+ "parentType": "VNF",
+ "position": 0,
+ "errors": {}
+ }, {
+ "modelCustomizationId": "6add59e0-7fe1-4bc4-af48-f8812422ae7c",
+ "modelId": "41708296-e443-4c71-953f-d9a010f059e1",
+ "modelUniqueId": "6add59e0-7fe1-4bc4-af48-f8812422ae7c",
+ "missingData": false,
+ "id": 987761655742,
+ "action": "Create",
+ "name": "VNFModule3",
+ "modelName": "vf_vmee0..VfVmee..vmme_gpb..module-2",
+ "type": "VFmodule",
+ "isEcompGeneratedNaming": true,
+ "dynamicInputs": [],
+ "dynamicModelName": "vf_vmee0..VfVmee..vmme_gpb..module-2fjrrc",
+ "typeName": "M",
+ "menuActions": {"edit": {}, "showAuditInfo": {}, "remove": {}, "delete": {}, "undoDelete": {}},
+ "isFailed": false,
+ "statusProperties": [{"key": "Prov Status:", "testId": "provStatus"}, {
+ "key": "Orch Status:",
+ "testId": "orchStatus"
+ }],
+ "trackById": "i3dllio31bb",
+ "parentType": "VNF",
+ "position": 1,
+ "errors": {}
+ }, {
+ "modelCustomizationId": "55b1be94-671a-403e-a26c-667e9c47d091",
+ "modelId": "522159d5-d6e0-4c2a-aa44-5a542a12a830",
+ "modelUniqueId": "55b1be94-671a-403e-a26c-667e9c47d091",
+ "missingData": false,
+ "id": 873798901625,
+ "action": "Create",
+ "name": "VFModule2",
+ "modelName": "vf_vmee0..VfVmee..vmme_vlc..module-1",
+ "type": "VFmodule",
+ "isEcompGeneratedNaming": true,
+ "dynamicInputs": [],
+ "dynamicModelName": "vf_vmee0..VfVmee..vmme_vlc..module-1djjni",
+ "typeName": "M",
+ "menuActions": {"edit": {}, "showAuditInfo": {}, "remove": {}, "delete": {}, "undoDelete": {}},
+ "isFailed": false,
+ "statusProperties": [{"key": "Prov Status:", "testId": "provStatus"}, {
+ "key": "Orch Status:",
+ "testId": "orchStatus"
+ }],
+ "trackById": "w7bvw1nh47s",
+ "parentType": "VNF",
+ "position": 2,
+ "errors": {}
+ }],
+ "errors": {}
+ }, {
+ "modelCustomizationId": "91415b44-753d-494c-926a-456a9172bbb9",
+ "modelId": "d6557200-ecf2-4641-8094-5393ae3aae60",
+ "modelUniqueId": "91415b44-753d-494c-926a-456a9172bbb9",
+ "missingData": false,
+ "id": "dywch8hkomi",
+ "action": "Create",
+ "inMaint": false,
+ "name": "yoav2",
+ "modelName": "VF_vMee 0",
+ "type": "VF",
+ "isEcompGeneratedNaming": true,
+ "networkStoreKey": "VF_vMee 0",
+ "vnfStoreKey": "VF_vMee 0",
+ "typeName": "VNF",
+ "menuActions": {"edit": {}, "showAuditInfo": {}, "duplicate": {}, "remove": {}, "delete": {}, "undoDelete": {}},
+ "isFailed": false,
+ "statusProperties": [{"key": "Prov Status:", "testId": "provStatus"}, {
+ "key": "Orch Status:",
+ "testId": "orchStatus"
+ }],
+ "trackById": "fjczf1urdqo",
+ "parentType": "",
+ "position": 1,
+ "children": [],
+ "errors": {}
+ }];
+ let from = {
+ data: {
+ type: 'VF',
+ index: 1
+ }
+ };
+
+ let to = {
+ parent: {
+ data: {
+ type: 'VF',
+ index: 0
+ }
+ }
+ };
+ jest.spyOn(service, 'array_move');
+
+ service.drag(store, "serviceInstanceId", nodes, {from, to});
+
+
+ expect(service.array_move).toHaveBeenCalled();
+
+ });
+
+
+});
diff --git a/vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-tree/dragAndDrop/dragAndDrop.service.ts b/vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-tree/dragAndDrop/dragAndDrop.service.ts
new file mode 100644
index 000000000..01763c685
--- /dev/null
+++ b/vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-tree/dragAndDrop/dragAndDrop.service.ts
@@ -0,0 +1,78 @@
+import {Injectable} from "@angular/core";
+import {NgRedux} from "@angular-redux/store";
+import {AppState} from "../../../../shared/store/reducers";
+import {DragAndDropModel} from "./dragAndDrop.model";
+import {FeatureFlagsService, Features} from "../../../../shared/services/featureFlag/feature-flags.service";
+import * as _ from 'lodash';
+
+@Injectable()
+export class DragAndDropService {
+
+ constructor(private store: NgRedux<AppState>){}
+
+ isAllow(): boolean {
+ return FeatureFlagsService.getFlagState(Features.DRAG_AND_DROP_OPERATION, this.store);
+ }
+ /********************************************************************
+ * manage drawing-board drag and drop operation
+ * @param nodes - array with elements data.
+ * @param tree - tree instance
+ * @param node - element information
+ * @param from - element from information
+ * @param to - element to information
+ ************************************************************/
+
+ drag(store, instanceId : string , nodes, {from, to}) :void{
+ if (!store.getState().global.flags["DRAG_AND_DROP_OPERATION"]) return;
+
+ let firstLevelNames : DragAndDropModel[] = [
+ new DragAndDropModel('VF',true),
+ new DragAndDropModel('VL',true),
+ new DragAndDropModel('VFmodule',false)
+ ];
+
+ const fromObject = _.find(firstLevelNames, ['type', from.data.type]);
+ const toObject = _.find(firstLevelNames, ['type', to.parent.data.type]);
+
+ /***********************************************************************************************
+ if the type are the same and there in same level + same parent -> then change element position
+ ***********************************************************************************************/
+ if(fromObject.isFirstLevel === toObject.isFirstLevel){ // moving element in the same level and in the first level
+ if(fromObject.isFirstLevel){
+ this.array_move(nodes, from.index , to.parent.index, instanceId);
+ } else if(fromObject.isFirstLevel === toObject.isFirstLevel){
+ /* check if they have the same parent */
+ if(from.parent.data.trackById === to.parent.parent.data.trackById){
+ let vfModules = nodes.find((parents)=> {
+ return parents.trackById === to.parent.parent.data.trackById;
+ }).children;
+ this.array_move(vfModules, from.index , to.parent.index, instanceId, to.parent.parent.data.vnfStoreKey);
+ }
+ }
+ }
+ }
+
+
+ /********************************************************************
+ * move element inside array with elements position
+ * @param arr - array with elements data.
+ * @param originalPosition - element original position
+ * @param destPosition - element dest position
+ * @param destPinstanceIdosition - instance id
+ ******************************************************************/
+ array_move(arr, originalPosition, destPosition, instanceId : string, parentStoreKey?) {
+ if (destPosition >= arr.length) {
+ let k = destPosition - arr.length + 1;
+ while (k--) {
+ arr.push(undefined);
+ }
+ }
+ arr.splice(destPosition, 0, arr.splice(originalPosition, 1)[0]);
+ arr.forEach((item, index) => {
+ if(item.position !== index){
+ item.position = index;
+ item.updatePoistionFunction(this, item, instanceId, parentStoreKey);
+ }
+ });
+ };
+}
diff --git a/vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-tree/drawing-board-tree.component.ts b/vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-tree/drawing-board-tree.component.ts
new file mode 100644
index 000000000..d0715982c
--- /dev/null
+++ b/vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-tree/drawing-board-tree.component.ts
@@ -0,0 +1,207 @@
+import {AfterViewInit, Component, EventEmitter, OnInit, Output, ViewChild,} from '@angular/core';
+import {ContextMenuComponent, ContextMenuService} from 'ngx-contextmenu';
+import {Constants} from '../../../shared/utils/constants';
+import {IDType, ITreeNode} from "angular-tree-component/dist/defs/api";
+import {TreeComponent, TreeModel, TreeNode} from "angular-tree-component";
+import {DialogService} from "ng2-bootstrap-modal";
+import {ActivatedRoute} from "@angular/router";
+import {NgRedux} from "@angular-redux/store";
+import {AppState} from "../../../shared/store/reducers";
+import {IframeService} from "../../../shared/utils/iframe.service";
+import {DuplicateService} from '../duplicate/duplicate.service';
+import {DrawingBoardTreeService, TreeNodeContextMenuModel} from "./drawing-board-tree.service";
+import {NetworkPopupService} from "../../../shared/components/genericFormPopup/genericFormServices/network/network.popup.service";
+import {VfModulePopuopService} from "../../../shared/components/genericFormPopup/genericFormServices/vfModule/vfModule.popuop.service";
+import {VnfPopupService} from "../../../shared/components/genericFormPopup/genericFormServices/vnf/vnf.popup.service";
+import {SdcUiServices} from "onap-ui-angular";
+import {HighlightPipe} from "../../../shared/pipes/highlight/highlight-filter.pipe";
+import {VnfGroupPopupService} from "../../../shared/components/genericFormPopup/genericFormServices/vnfGroup/vnfGroup.popup.service";
+import {ObjectToInstanceTreeService} from "../objectsToTree/objectToInstanceTree/objectToInstanceTree.service";
+import {SharedTreeService} from "../objectsToTree/shared.tree.service";
+import {Subject} from "rxjs/Subject";
+import {changeServiceIsDirty} from "../../../shared/storeUtil/utils/service/service.actions";
+import * as _ from 'lodash';
+import {ErrorMsgService} from "../../../shared/components/error-msg/error-msg.service";
+import {DragAndDropService} from "./dragAndDrop/dragAndDrop.service";
+import {FeatureFlagsService, Features} from "../../../shared/services/featureFlag/feature-flags.service";
+import {PopoverPlacement} from "../../../shared/components/popover/popover.component";
+
+@Component({
+ selector: 'drawing-board-tree',
+ templateUrl: './drawing-board-tree.html',
+ styleUrls: ['./drawing-board-tree.scss'],
+ providers: [HighlightPipe]
+})
+
+export class DrawingBoardTreeComponent implements OnInit, AfterViewInit {
+ _store: NgRedux<AppState>;
+ duplicateService: DuplicateService;
+ drawingBoardTreeService: DrawingBoardTreeService;
+ errorMsgService: ErrorMsgService;
+ isFilterEnabled: boolean = false;
+ filterValue: string = '';
+ contextMenuOptions: TreeNodeContextMenuModel[];
+ static triggerDeleteActionService: Subject<string> = new Subject<string>();
+ static triggerUndoDeleteActionService: Subject<string> = new Subject<string>();
+ static triggerreCalculateIsDirty: Subject<string> = new Subject<string>();
+ @ViewChild(ContextMenuComponent) public contextMenu: ContextMenuComponent;
+
+ constructor(private _contextMenuService: ContextMenuService,
+ private _iframeService: IframeService,
+ private dialogService: DialogService,
+ private store: NgRedux<AppState>,
+ private route: ActivatedRoute,
+ private _duplicateService: DuplicateService,
+ private modalService: SdcUiServices.ModalService,
+ private _drawingBoardTreeService: DrawingBoardTreeService,
+ private _networkPopupService: NetworkPopupService,
+ private _vfModulePopuopService: VfModulePopuopService,
+ private _vnfPopupService: VnfPopupService,
+ private _vnfGroupPopupService: VnfGroupPopupService,
+ private _errorMsgService: ErrorMsgService,
+ private _highlightPipe: HighlightPipe,
+ private _objectToInstanceTreeService: ObjectToInstanceTreeService,
+ private _sharedTreeService: SharedTreeService,
+ private _dragAndDropService : DragAndDropService) {
+
+ this.errorMsgService = _errorMsgService;
+ this.duplicateService = _duplicateService;
+ this.drawingBoardTreeService = _drawingBoardTreeService;
+ this.contextMenuOptions = _drawingBoardTreeService.generateContextMenuOptions();
+
+ DrawingBoardTreeComponent.triggerDeleteActionService.subscribe((serviceModelId) => {
+ this._sharedTreeService.shouldShowDeleteInstanceWithChildrenModal(this.nodes, serviceModelId, (node, serviceModelId)=>{
+ this.drawingBoardTreeService.deleteActionService(this.nodes, serviceModelId);
+ this.store.dispatch(changeServiceIsDirty(this.nodes, serviceModelId));
+ });
+ });
+
+ DrawingBoardTreeComponent.triggerUndoDeleteActionService.subscribe((serviceModelId) => {
+ this.drawingBoardTreeService.undoDeleteActionService(this.nodes, serviceModelId);
+ this.store.dispatch(changeServiceIsDirty(this.nodes, serviceModelId));
+ });
+
+ DrawingBoardTreeComponent.triggerreCalculateIsDirty.subscribe((serviceModelId) => {
+ this.store.dispatch(changeServiceIsDirty(this.nodes, serviceModelId));
+ });
+
+ this._store = store;
+ this.route
+ .queryParams
+ .subscribe(params => {
+ this.serviceModelId = params['serviceModelId'];
+ });
+ }
+
+ getNodeId(node: ITreeNode): string {
+ return (node.data.parentType !== "" ? (node.data.parentType + "_") : "") + node.data.typeName;
+ }
+
+ updateNodes(updateData: { nodes: any, filterValue: string }): void {
+ this.nodes = updateData.nodes;
+ this.filterValue = updateData.filterValue;
+ }
+
+ @Output()
+ highlightNode: EventEmitter<number> = new EventEmitter<number>();
+
+ @ViewChild('tree') tree: TreeComponent;
+ missingDataTooltip: string = Constants.Error.MISSING_VNF_DETAILS;
+ currentNode: ITreeNode = null;
+ flags: any;
+ nodes = [];
+ serviceModelId: string;
+ options = {
+ allowDrag: this._dragAndDropService.isAllow(),
+ actionMapping: {
+ mouse: {
+ drop: (tree:TreeModel, node:TreeNode, $event:any, {from, to}) => {
+ this._dragAndDropService.drag(this.store, this.serviceModelId, this.nodes, {from, to});
+ }
+ }
+ },
+ nodeHeight: 45,
+ dropSlotHeight: 1
+ };
+ parentElementClassName = 'content';
+
+ ngOnInit(): void {
+ this.store.subscribe(() => {
+ this.updateTree();
+ });
+ this.updateTree()
+ }
+
+ getNodeName(node: ITreeNode, filter: string) {
+ return this._highlightPipe.transform(node.data.name, filter ? filter : '');
+ }
+
+ updateTree() {
+ const serviceInstance = this.store.getState().service.serviceInstance[this.serviceModelId];
+ this.nodes = this._objectToInstanceTreeService.convertServiceInstanceToTreeData(serviceInstance, this.store.getState().service.serviceHierarchy[this.serviceModelId]);
+ console.log('right nodes', this.nodes);
+
+ }
+
+
+ ngAfterViewInit(): void {
+ this.tree.treeModel.expandAll();
+ }
+
+ public onContextMenu($event: MouseEvent, node: ITreeNode): void {
+ this.flags = this.store.getState().global.flags;
+
+ this.currentNode = node;
+ node.focus();
+ node.setActiveAndVisible(false);
+ this.selectNode(node);
+ setTimeout(() => {
+ this._contextMenuService.show.next({
+ contextMenu: this.contextMenu,
+ event: <any>$event,
+ item: node,
+ });
+ $event.preventDefault();
+ $event.stopPropagation();
+ }, 250);
+
+ }
+
+
+ executeMenuAction(methodName: string): void {
+ if (!_.isNil(this.currentNode.data.menuActions) && !_.isNil(this.currentNode.data.menuActions[methodName])) {
+ this.currentNode.data.menuActions[methodName]['method'](this.currentNode, this.serviceModelId);
+ this.store.dispatch(changeServiceIsDirty(this.nodes, this.serviceModelId));
+ }
+ }
+
+ isEnabled(node: ITreeNode, serviceModelId: string, methodName: string): boolean {
+ if (!_.isNil(this.currentNode) && !_.isNil(this.currentNode.data.menuActions) && !_.isNil(this.currentNode.data.menuActions[methodName])) {
+ return this.currentNode.data.menuActions[methodName]['enable'](this.currentNode, this.serviceModelId);
+ }
+ return false;
+ }
+
+ isVisible(node: ITreeNode, methodName: string): boolean {
+ if (!_.isNil(this.currentNode) && !_.isNil(this.currentNode.data.menuActions) && !_.isNil(this.currentNode.data.menuActions[methodName])) {
+ return this.currentNode.data.menuActions[methodName]['visible'](this.currentNode, this.serviceModelId);
+ }
+ return false;
+ }
+
+ public selectNode(node: ITreeNode): void {
+ node.expand();
+ this._sharedTreeService.setSelectedVNF(node);
+ this.highlightNode.emit(node.data.modelUniqueId);
+ if (FeatureFlagsService.getFlagState(Features.FLAG_1906_COMPONENT_INFO, this.store)) {
+ node.data.onSelectedNode(node);
+ }
+ }
+
+ expandParentByNodeId(id: IDType): void {
+ this.tree.treeModel.getNodeById(id).parent.expand();
+ }
+
+}
+
+
diff --git a/vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-tree/drawing-board-tree.html b/vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-tree/drawing-board-tree.html
new file mode 100644
index 000000000..8af909ffc
--- /dev/null
+++ b/vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-tree/drawing-board-tree.html
@@ -0,0 +1,96 @@
+<error-msg></error-msg>
+<div class="drawing-board-tree" style="height: calc(100vh - 55px);">
+ <div *ngIf="nodes?.length == 0" style="text-align: center; margin-top: 50px;">
+ <no-content-message-and-icon class="span-over"
+ data-title="Please add objects (VNFs, network, modules etc.)"
+ title2="from the left tree to design the service instance"
+ subtitle="Once done, click Deploy to start instantiation"
+ iconPath="./assets/img/UPLOAD.svg"
+ iconClass="upload-icon-service-planing"></no-content-message-and-icon>
+ </div>
+ <div class="tree-header" *ngIf="nodes?.length > 0">
+ <div class="title-tree">Instance:</div>
+ <search-component (updateNodes)="updateNodes($event)"
+ [nodes]="nodes" [tree]="tree"
+ [inputTestId]="'search-right-tree'"
+ *ngIf="drawingBoardTreeService.isViewEditFlagTrue()"></search-component>
+ </div>
+ <tree-root [attr.data-tests-id]="'drawing-board-tree'" #tree [nodes]="nodes" [options]="options"
+ id="drawing-board-tree">
+
+ <ng-template #treeNodeTemplate let-node let-index="index" >
+ <div [attr.id]="getNodeId(node)" [attr.data-tests-id]="'node-'+node.data.modelId +'-' +node.data.modelName" (click)="selectNode(node)" >
+ <custom-popover class="failed-popover-wrap" *ngIf= "node?.data?.isFailed" [value]= "node?.data?.statusMessage" [placement]="'left'" [popoverType]="'error'">
+ <div class="failed-msg" [attr.data-tests-id]="'failed-error-message'" *ngIf= "node?.data?.isFailed">Failed</div>
+ </custom-popover>
+ <div class="instance-type" style="position: relative;">
+ <div *ngIf="node?.data?.action == 'Create'" class="notShowOnViewMode notShowOnCreateMode newIcon"></div>
+ <div><span title="{{node.data.type}}" [attr.data-tests-id]="'node-type-indicator'">{{node?.data?.typeName}}</span></div>
+ </div>
+ <div class="model-info">
+ <span class="header-info">
+ <span class="property-name">
+ <span class="auto-name"
+ [ngClass]="{'text_decoration' : drawingBoardTreeService.isTextDecoration(node)}"
+ [innerHtml]="getNodeName(node, filterValue) | safe : 'html'"
+ [attr.data-tests-id]="'node-name'"
+ ></span>
+ </span>
+ </span>
+ <tree-node-header-properties
+ *ngIf="(node?.data?.action !== 'Create' || node?.data?.parentType === 'VnfGroup') && !node?.data?.isFailed"
+ [properties]="node.data.statusProperties"></tree-node-header-properties>
+ </div>
+ <div class="scaling invalid" *ngIf="node?.data?.errors?.scalingError" [attr.data-tests-id]="'scaling-policy'">
+ <span>Limit</span><span>{{node?.data?.limitMembers}}</span>
+ </div>
+ <div class="model-actions notShowOnViewMode">
+ <span class="icon-browse"
+ [attr.data-tests-id]="'node-'+node.data.modelId +'-' +node.data.modelName+'-menu-btn'"
+ (click)="onContextMenu($event, node)">
+ <context-menu>
+ <ng-template *ngFor="let contextMenuOption of contextMenuOptions"
+ contextMenuItem (execute)="executeMenuAction(contextMenuOption.methodName)"
+ [visible]="isVisible(currentNode, contextMenuOption.methodName)"
+ [enabled]="isEnabled(currentNode, serviceModelId, contextMenuOption.methodName)">
+ <div [attr.data-tests-id]="contextMenuOption.dataTestId">
+ <div style="float: left;margin-top: 3px;">
+ <svg-icon
+ [ngClass]="contextMenuOption.iconClass"
+ class="icon-edit"
+ [size]="'small'"
+ [name]="contextMenuOption.iconClass">
+ </svg-icon></div>
+ <div style="padding-left: 25px;">{{contextMenuOption.label}}</div>
+ </div>
+ </ng-template>
+ </context-menu>
+ </span>
+ <span
+ *ngIf="drawingBoardTreeService.isVNFMissingData(node, serviceModelId)"
+ tooltip="{{ missingDataTooltip }}"
+ tooltipPlacement="left"
+ [attr.data-tests-id]="'node-'+node.data.modelId +'-' +node.data.modelName+'-alert-icon'"
+ class="icon-alert" >
+ <svg-icon
+ [mode]="'warning'"
+ [testId]="'icon-alert'"
+ [size]="'medium'"
+ [name]="'alert-triangle-o'">
+ </svg-icon>
+ </span>
+
+ <!--<span *ngIf="drawingBoardTreeService.isVNFMissingData(node, serviceModelId)" class="icon-alert"-->
+ <!--tooltip="{{ missingDataTooltip }}" tooltipPlacement="left"-->
+ <!--[attr.data-tests-id]="'node-'+node.data.modelId +'-' +node.data.modelName+'-alert-icon'"></span>-->
+ <span *ngIf="drawingBoardTreeService.isVFModuleMissingData(node, serviceModelId)" class="icon-alert"
+ tooltip="{{ missingDataTooltip }}" tooltipPlacement="left"
+ [attr.data-tests-id]="'node-'+node.data.modelId +'-' +node.data.modelName+'-alert-icon'"></span>
+ </div>
+ </div >
+ </ng-template>
+ </tree-root>
+</div>
+
+
+
diff --git a/vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-tree/drawing-board-tree.scss b/vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-tree/drawing-board-tree.scss
new file mode 100644
index 000000000..be9f9f2d4
--- /dev/null
+++ b/vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-tree/drawing-board-tree.scss
@@ -0,0 +1,405 @@
+@mixin highlight($background-color, $color) {
+ background: none;
+ padding: 0;
+ background-color: $background-color;
+ border: $color 1px solid;
+ color: $color;
+}
+@mixin highlight-toggle-children {
+ tree-node-expander {
+ .toggle-children-wrapper {
+ span.toggle-children {
+ @include highlight(white, #009FDB);
+ border-right: none;
+ .isFailed {
+ left: 0px !important;
+ }
+ }
+ }
+
+ }
+}
+
+#VNF > node-content-wrapper {
+ border: 1px dashed #D2D2D2 !important;
+}
+
+@mixin highlight-tree-node-content {
+ tree-node-content {
+ > div {
+ .model-actions {
+ .icon-browse:before {
+ display: inline-block;
+ }
+ }
+ }
+ }
+}
+
+#RETRY_EDIT drawing-board-tree tree-node-collection > div,
+#RETRY drawing-board-tree tree-node-collection > div {
+ margin-top: 0px;
+ width: calc(100% - 50px);
+ margin-left: auto;
+ }
+
+drawing-board-tree {
+ flex: 1;
+ color: #5A5A5A;
+ line-height: 14px;
+ flex-direction:column;
+
+ &.col-md-6,&.col-md-5{
+ padding: 0;
+ }
+ .tree-header {
+ display: flex;
+ justify-content: space-between;
+
+ .title-tree {
+ font-family: OpenSans-SemiBold;
+ font-size: 16px;
+ color: #191919;
+ text-align: left;
+ text-transform: uppercase;
+ padding-bottom: 48px;
+ }
+ .search-container {
+ width: 275px;
+ }
+ }
+ .highlight {
+ background-color: #9DD9EF;
+ }
+ .toggle-children-wrapper.toggle-children-wrapper-expanded {
+ .toggle-children:before {
+ color: #009FDB;
+ }
+ }
+ .drawing-board-tree {
+ width: 100%;
+ padding: 30px 45px;
+ }
+
+ .tree-node-level-1 {
+ margin-bottom: 10px;
+ }
+ tree-viewport {
+ tree-node {
+ tree-node-drop-slot {
+ .node-drop-slot {
+ display: none;
+ }
+ }
+ & .tree-node-focused,
+ & .tree-node-active {
+ & > tree-node-wrapper {
+ .node-wrapper {
+ @include highlight-toggle-children;
+ .node-content-wrapper-focused,
+ .node-content-wrapper-active {
+ @include highlight-toggle-children;
+ @include highlight(#E6F6FB, #009FDB);
+ .property-name,.instance-type {
+ color: #009FDB !important;
+ position: relative;
+ }
+ .status-properties {
+ .status-property-value,.status-property-name {
+ color: #009FDB;
+ }
+ }
+ .icon-browse:before {
+ color: #5A5A5A;
+ }
+ @include highlight-tree-node-content;
+ }
+ }
+ }
+ }
+ & .tree-node-expanded {
+ > tree-node-wrapper .node-wrapper {
+ box-shadow: 0 0px 2px rgba(90,90,90,0.24);
+ }
+ }
+
+ .tree-node-active .tree-children {
+ //border: 1px solid #009FDB;
+ padding-left: 45px;
+ }
+
+ .tree-node.tree-node-active.tree-node-expanded {
+ }
+
+ .tree-children .tree-node-leaf .node-wrapper{
+ margin-left: -5px;
+ }
+
+ .tree-node.tree-node-expanded > tree-node-wrapper{
+ box-shadow: 0 2px 2px 0 rgba(0,0,0,.1);
+ position: relative;
+ z-index: 1;
+ display: block;
+ }
+ tree-node-wrapper {
+ .node-wrapper {
+ height: 45px;
+ &:hover {
+ .node-content-wrapper:not(.node-content-wrapper-focused) {
+ background: #F2F2F2;
+ .icon-browse:before {
+ color: #5A5A5A;
+ }
+ @include highlight-tree-node-content;
+ }
+ }
+ tree-node-expander {
+ font-family: 'icomoon' !important;
+ height: 100%;
+ .failed-msg {
+
+ }
+ .toggle-children-wrapper {
+ padding: 0;
+ display: block;
+ height: 100%;
+ span.toggle-children {
+ display: flex;
+ width: 45px;
+ padding: 0;
+ top: 0;
+ height: inherit;
+ background-image: none;
+ background-color: white;
+ border: 1px solid #D2D2D2;
+ border-right: none;
+ &:before {
+ content: "\e900";
+ font-size: 20px;
+ font-weight: 600;
+ text-align: center;
+ display: inline-block;
+ flex: auto;
+ align-self: center;
+ }
+ }
+ }
+ .toggle-children-wrapper-expanded {
+ span.toggle-children {
+ transform: none;
+ &:before {
+ content: "\e930";
+ }
+ }
+ }
+ .toggle-children-placeholder {
+ width:45px;
+ }
+ }
+
+ .node-content-wrapper {
+ padding: 0;
+ background: none;
+ box-shadow: none;
+ border-radius: 0;
+ border: 1px solid #D2D2D2;
+ height: 100%;
+ flex: 1;
+ .resourceGroup {
+ border: 1px dashed #D2D2D2 !important;
+ }
+ tree-node-content {
+ > div {
+ height: 100%;
+ display: flex;
+ align-items: center;
+
+ .instance-type {
+ width: 40px;
+ height: 100%;
+ padding-top: 16px;
+ text-transform: uppercase;
+ text-align: center;
+ border-right: 1px solid #D2D2D2;
+ word-break: break-all;
+ color: #959595;
+ font-size: 13px;
+ font-family: OpenSans-SemiBold;
+ .newIcon {
+ background: #45B16D;
+ position: absolute;
+ top: 5%;
+ width: 90%;
+ left: 5%;
+ right: 5%;
+ border-radius: 2px;
+ height: 5px;
+ }
+ span {
+ width: 40px;
+ display: block;
+ }
+ } > span {
+ flex: 1;
+ display: block;
+
+ span:nth-child(2) {
+ display: block;
+ }
+ }
+ .model-info {
+ padding-left: 16px;
+ width: 100%;
+ .property-name {
+ font-family: OpenSans-SemiBold;
+ font-size: 13px;
+ color: #191919;
+ //text-transform: capitalize; problematic with search
+ .auto-name{
+ display: inline-flex;//required for search more then one sub highlight,
+ font-size: 13px;
+ }
+ .text_decoration{
+ text-decoration: line-through;
+ }
+
+ .text_decoration:after {
+ height: 10px;
+ }
+ }
+ tree-node-header-properties{
+ display: block;
+ }
+ }
+ .scaling {
+ background: #4ca90c;
+ padding: 5px;
+ border-radius: 3px;
+ font-family: OpenSans-SemiBold;
+ font-size: 12px;
+ color: #FFF9F9;
+ &.invalid{
+ background: #cf2a2a;
+ }
+ span:first-child{
+ margin-right: 3px;
+ }
+ }
+ .model-actions {
+ display: flex;
+ align-items: center;
+ .icon-browse {
+ padding: 0;
+ width: 30px;
+ height: 24px;
+ &:before {
+ content: "\e924";
+ font-size: 24px;
+ display: none;
+ }
+ &:hover:before {
+ color: #009FDB;
+ }
+ &:focus:before,
+ &:active:before {
+ color: #009FDB;
+ }
+ }
+
+ .icon-alert {
+ padding-right: 10px;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ tree-node-children {
+ .tree-children {
+ padding-left: 45px;
+ .model-info span:first-child {
+ flex: 1.1 !important;
+ }
+ }
+ }
+ }
+ }
+}
+
+
+.tree-node-level-1.tree-node.tree-node-expanded {
+ .failed-popover-wrap {
+ left: -50px !important;
+ position: absolute;
+ }
+}
+.tree-node-level-1 {
+ .failed-popover-wrap {
+ left: 45px !important;
+ position: absolute;
+ }
+}
+
+.tree-node-level-2.tree-node.tree-node-leaf {
+ .failed-popover-wrap {
+ left: 135px !important;
+ position: absolute;
+ }
+}
+
+.tree-node-level-1.tree-node.tree-node-collapsed {
+ .failed-popover-wrap{
+ left: 0px !important;
+ position: absolute;
+ }
+}
+
+.failed-msg{
+ background: #cf2a2a;
+ padding: 5px;
+ border-radius: 3px;
+ font-family: OpenSans-SemiBold;
+ font-size: 12px;
+ color: #FFF9F9;
+}
+
+.cdk-overlay-pane.ngx-contextmenu {
+ ul.dropdown-menu {
+ width: 200px;
+ box-shadow: none;
+ padding: 0;
+ padding-top: 10px;
+ margin: 0;
+ border: 1px solid #D2D2D2;
+ border-top: 3px solid #009FDB;
+ box-shadow: 0 0px 2px rgba(90,90,90,0.24);
+ border-radius: 2px;
+ li {
+ height: 40px;
+ a {
+ font-family: OpenSans-Regular;
+ display: flex;
+ align-items: center;
+ height: 100%;
+ padding: 12px;
+ color: #5A5A5A;
+ &:hover {
+ background: #E6F6FB;
+ color: #009FDB;
+ }
+ span {
+ padding-right: 12px;
+ &.icon-edit:before {
+ content: '\e917';
+ }
+ &.icon-trash:before {
+ content: '\e937';
+ }
+ }
+ }
+ }
+ }
+}
+
+
diff --git a/vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-tree/drawing-board-tree.service.spec.ts b/vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-tree/drawing-board-tree.service.spec.ts
new file mode 100644
index 000000000..1b913cfe9
--- /dev/null
+++ b/vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-tree/drawing-board-tree.service.spec.ts
@@ -0,0 +1,147 @@
+import {TestBed, getTestBed} from '@angular/core/testing';
+import {
+ HttpClientTestingModule,
+ HttpTestingController
+} from '@angular/common/http/testing';
+import {NgRedux} from "@angular-redux/store";
+import {DrawingBoardTreeService, TreeNodeContextMenuModel} from "./drawing-board-tree.service";
+import {ITreeNode} from "angular-tree-component/dist/defs/api";
+
+ class MockAppStore<T>{
+ getState() {
+ return {
+ service : {
+ serviceInstance : {
+ "serviceInstanceId" : {
+ vnfs : {
+ "vnfStoreKey" : {
+ isMissingData : true,
+ vfModules : {
+ "vfModulesName" : {
+ "vfModulesName" : {
+ isMissingData : true
+ }
+ }
+ }
+ },
+
+ "vnfStoreKey1" : {
+ isMissingData : false,
+ vfModules : {
+ "vfModulesName" : {
+ "vfModulesName" : {
+ isMissingData : false
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+describe('Drawing board tree Service', () => {
+ let injector;
+ let service: DrawingBoardTreeService;
+ let httpMock: HttpTestingController;
+
+
+ beforeAll(done => (async () => {
+ TestBed.configureTestingModule({
+ imports: [HttpClientTestingModule],
+ providers: [
+ DrawingBoardTreeService,
+ {provide: NgRedux, useClass: MockAppStore}]
+ });
+ await TestBed.compileComponents();
+
+ injector = getTestBed();
+ service = injector.get(DrawingBoardTreeService);
+ httpMock = injector.get(HttpTestingController);
+
+ })().then(done).catch(done.fail));
+
+
+
+
+ test('generateContextMenuOptions should return list of optional context menu', () => {
+ const options : TreeNodeContextMenuModel[] = service.generateContextMenuOptions();
+ const expected : TreeNodeContextMenuModel[] = [
+ new TreeNodeContextMenuModel('edit', 'context-menu-edit', 'Edit', 'edit-file-o'),
+ new TreeNodeContextMenuModel('duplicate', 'context-menu-duplicate', 'Duplicate', 'copy-o'),
+ new TreeNodeContextMenuModel('showAuditInfo', 'context-menu-showAuditInfo', 'Show audit info', 'eye-o'),
+ new TreeNodeContextMenuModel('addGroupMember', 'context-menu-addGroupMember', 'Add group members', 'plus'),
+ new TreeNodeContextMenuModel('delete', 'context-menu-delete', 'Delete', 'trash-o'),
+ new TreeNodeContextMenuModel('remove', 'context-menu-remove', 'Remove', 'trash-o'),
+ new TreeNodeContextMenuModel('undoDelete', 'context-menu-undoDelete', 'Undo Delete', 'undo-delete')
+ ];
+ expect(options.length).toEqual(7);
+ expect(options).toEqual(expected);
+ });
+
+ test('isVNFMissingData should return true if vnf isMissingData = true', () => {
+ let node : ITreeNode = <any>{
+ data : {
+ type : 'VF',
+ vnfStoreKey : "vnfStoreKey"
+ }
+ };
+ let result : boolean = service.isVNFMissingData(node, "serviceInstanceId");
+ expect(result).toBeTruthy();
+ });
+
+
+ test('isVNFMissingData should return false if vnf has isMissingData = false', () => {
+ let node : ITreeNode = <any>{
+ data : {
+ type : 'VFModule',
+ modelName : "vfModulesName",
+ dynamicModelName : "vfModulesName",
+ parent : {
+ vnfStoreKey : "vnfStoreKey1",
+ type : 'VF'
+ }
+ }
+ };
+ let result : boolean = service.isVNFMissingData(node, "serviceInstanceId");
+ expect(result).toBeFalsy();
+ });
+
+
+ test('isVFModuleMissingData should return true if vnfModule has isMissingData = true', () => {
+ let node : ITreeNode = <any>{
+ data : {
+ type : 'VFModule',
+ modelName : "vfModulesName",
+ dynamicModelName : "vfModulesName",
+ parent : {
+ vnfStoreKey : "vnfStoreKey",
+ type : 'VF'
+ }
+ }
+ };
+ let result : boolean = service.isVFModuleMissingData(node, "serviceInstanceId");
+ expect(result).toBeFalsy();
+ });
+
+
+ test('isVFModuleMissingData should return false if vnfModule has isMissingData = false', () => {
+ let node : ITreeNode = <any>{
+ data : {
+ type : 'VFModule',
+ modelName : "vfModulesName",
+ dynamicModelName : "vfModulesName",
+ parent : {
+ vnfStoreKey : "vnfStoreKey1",
+ type : 'VF'
+ }
+ }
+ };
+ let result : boolean = service.isVFModuleMissingData(node, "serviceInstanceId");
+ expect(result).toBeFalsy();
+ });
+
+});
diff --git a/vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-tree/drawing-board-tree.service.ts b/vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-tree/drawing-board-tree.service.ts
new file mode 100644
index 000000000..17f761c41
--- /dev/null
+++ b/vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-tree/drawing-board-tree.service.ts
@@ -0,0 +1,129 @@
+import {Injectable} from "@angular/core";
+import {ITreeNode} from "angular-tree-component/dist/defs/api";
+import * as _ from 'lodash';
+import {NgRedux} from "@angular-redux/store";
+import {AppState} from "../../../shared/store/reducers";
+import {FeatureFlagsService, Features} from "../../../shared/services/featureFlag/feature-flags.service";
+import {ServiceInstanceActions} from "../../../shared/models/serviceInstanceActions";
+
+@Injectable()
+export class DrawingBoardTreeService {
+ constructor(private store: NgRedux<AppState>){}
+ isVFModuleMissingData(node: ITreeNode, serviceModelId : string): boolean {
+ if(node.data.type === 'VFmodule' &&!_.isNil(this.store.getState().service.serviceInstance[serviceModelId].vnfs) && !_.isNil(this.store.getState().service.serviceInstance[serviceModelId].vnfs[node.parent.data.vnfStoreKey])){
+ if(!_.isNil(this.store.getState().service.serviceInstance[serviceModelId].vnfs[node.parent.data.vnfStoreKey].vfModules)
+ && !_.isNil(this.store.getState().service.serviceInstance[serviceModelId].vnfs[node.parent.data.vnfStoreKey].vfModules[node.data.modelName])
+ && !_.isNil(this.store.getState().service.serviceInstance[serviceModelId].vnfs[node.parent.data.vnfStoreKey].vfModules[node.data.modelName][node.data.dynamicModelName])){
+
+ return this.store.getState().service.serviceInstance[serviceModelId].vnfs[node.parent.data.vnfStoreKey].vfModules[node.data.modelName][node.data.dynamicModelName].isMissingData;
+ }
+ }
+ return false;
+ }
+
+ isVNFMissingData(node : ITreeNode, serviceModelId : string) : boolean {
+ if(node.data.type == 'VF' && !_.isNil(this.store.getState().service.serviceInstance[serviceModelId].vnfs[node.data.vnfStoreKey])){
+ return this.store.getState().service.serviceInstance[serviceModelId].vnfs[node.data.vnfStoreKey].isMissingData;
+ }
+ }
+
+ isViewEditFlagTrue():boolean{
+ return FeatureFlagsService.getFlagState(Features.FLAG_1902_NEW_VIEW_EDIT, this.store);
+ }
+
+ /**********************************************
+ return all drawing board context menu options
+ ***********************************************/
+ generateContextMenuOptions() : TreeNodeContextMenuModel[]{
+ return [
+ new TreeNodeContextMenuModel('edit', 'context-menu-edit', 'Edit', 'edit-file-o'),
+ new TreeNodeContextMenuModel('duplicate', 'context-menu-duplicate', 'Duplicate', 'copy-o'),
+ new TreeNodeContextMenuModel('showAuditInfo', 'context-menu-showAuditInfo', 'Show audit info', 'eye-o'),
+ new TreeNodeContextMenuModel('addGroupMember', 'context-menu-addGroupMember', 'Add group members', 'plus'),
+ new TreeNodeContextMenuModel('delete', 'context-menu-delete', 'Delete', 'trash-o'),
+ new TreeNodeContextMenuModel('remove', 'context-menu-remove', 'Remove', 'trash-o'),
+ new TreeNodeContextMenuModel('undoDelete', 'context-menu-undoDelete', 'Undo Delete', 'undo-delete')
+ ];
+ }
+
+
+ /*******************************************************************
+ delete or remove all service child's on delete existing service
+ *******************************************************************/
+ deleteActionService(nodes : ITreeNode[], serviceModelId : string){
+ if(!_.isNil(nodes)){
+ for(let node of nodes){
+ node.data = node;
+ if(!_.isNil(node.children)){
+ node.children.map((child)=>{
+ child.data = child;
+ child.parent = node;
+ });
+ }
+
+ let menuActionsName : string = node.data.action === ServiceInstanceActions.Create ? 'remove' : 'delete';
+ if(!_.isNil(node.data.menuActions) && !_.isNil(node.data.menuActions[menuActionsName])){
+ node.data.menuActions[menuActionsName]['method'](node, serviceModelId)
+ }
+
+ }
+ }
+ }
+ /*******************************************************************
+ undo delete all service child's on undo delete existing service
+ *******************************************************************/
+ undoDeleteActionService(nodes : ITreeNode[], serviceModelId : string){
+ if(!_.isNil(nodes)){
+ for(let node of nodes){
+ node.data = node;
+ if(!_.isNil(node.children)){
+ node.children.map((child)=>{
+ child.data = child;
+ child.parent = node;
+ });
+ }
+
+ if(!_.isNil(node.data.menuActions) && !_.isNil(node.data.menuActions['undoDelete'])){
+ node.data.menuActions['undoDelete']['method'](node, serviceModelId)
+ }
+ }
+ }
+ }
+
+ /***********************************************************
+ return true if should add line hover the instance name
+ ***********************************************************/
+ isTextDecoration(node) : boolean{
+ return !_.isNil(node.data) && !_.isNil(node.data.action) && node.data.action.split('_').pop() === 'Delete';
+ }
+
+
+ /******************************************
+ should create object of instances action
+ ******************************************/
+ generateServiceActionObject(nodes){
+ let obj = {};
+ let index = 0;
+ for(let node of nodes){
+ obj[index] = {};
+ index++;
+ }
+ }
+}
+
+export class TreeNodeContextMenuModel {
+ methodName: string;
+ dataTestId: string;
+ label: string;
+ iconClass: string;
+
+ constructor(methodName: string,
+ dataTestId: string,
+ label: string,
+ iconClass: string) {
+ this.methodName = methodName;
+ this.dataTestId = dataTestId;
+ this.label = label;
+ this.iconClass = iconClass;
+ }
+}
diff --git a/vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-tree/instance.tree.generator.ts b/vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-tree/instance.tree.generator.ts
new file mode 100644
index 000000000..188feaaba
--- /dev/null
+++ b/vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-tree/instance.tree.generator.ts
@@ -0,0 +1,8 @@
+import {Injectable} from "@angular/core";
+
+@Injectable()
+export class InstanceTreeGenerator {
+ convertServiceInstanceToTreeData(serviceInstance, serviceModelId : string) {
+
+ }
+}
diff --git a/vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-tree/tree-node-header-properties/tree-node-header-properties.component.html b/vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-tree/tree-node-header-properties/tree-node-header-properties.component.html
new file mode 100644
index 000000000..dae6762e0
--- /dev/null
+++ b/vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-tree/tree-node-header-properties/tree-node-header-properties.component.html
@@ -0,0 +1,5 @@
+<div class="status-properties" *ngFor="let prop of properties">
+ <span class="status-property-name" [ngClass]="{'mark': prop.key=='In-maintenance'}">{{ prop.key }}</span>
+ <span class="status-property-value" [attr.data-tests-id]="'status-property-'+prop?.testId" >{{ prop.value }}</span>
+ <span class="separator">|</span>
+</div>
diff --git a/vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-tree/tree-node-header-properties/tree-node-header-properties.component.scss b/vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-tree/tree-node-header-properties/tree-node-header-properties.component.scss
new file mode 100644
index 000000000..305de8cd7
--- /dev/null
+++ b/vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-tree/tree-node-header-properties/tree-node-header-properties.component.scss
@@ -0,0 +1,24 @@
+.status-properties{
+ display: inline-block;
+ font-family: OpenSans-Regular;
+ font-size: 12px;
+ padding-top: 3px;
+ .status-property-name{
+ color: #5A5A5A;
+ &.mark{
+ background-color: #959595;
+ color: #ffffff;
+ }
+ }
+ .status-property-value{
+ color: #191919;
+ }
+ .separator{
+ padding: 0 8px;
+ }
+ &:last-child .separator{
+ display: none;
+ }
+
+}
+
diff --git a/vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-tree/tree-node-header-properties/tree-node-header-properties.component.spec.ts b/vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-tree/tree-node-header-properties/tree-node-header-properties.component.spec.ts
new file mode 100644
index 000000000..047f2e89d
--- /dev/null
+++ b/vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-tree/tree-node-header-properties/tree-node-header-properties.component.spec.ts
@@ -0,0 +1,25 @@
+import {ComponentFixture, TestBed } from '@angular/core/testing';
+import { TreeNodeHeaderPropertiesComponent } from './tree-node-header-properties.component';
+
+describe('TreeNodeHeaderPropertiesComponent', () => {
+ let component: TreeNodeHeaderPropertiesComponent;
+ let fixture: ComponentFixture<TreeNodeHeaderPropertiesComponent>;
+
+
+ beforeAll(done => (async () => {
+ TestBed.configureTestingModule({
+ declarations: [ TreeNodeHeaderPropertiesComponent ]
+ });
+ await TestBed.compileComponents();
+
+ fixture = TestBed.createComponent(TreeNodeHeaderPropertiesComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+
+ })().then(done).catch(done.fail));
+
+
+ test('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-tree/tree-node-header-properties/tree-node-header-properties.component.ts b/vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-tree/tree-node-header-properties/tree-node-header-properties.component.ts
new file mode 100644
index 000000000..535d7ea52
--- /dev/null
+++ b/vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-tree/tree-node-header-properties/tree-node-header-properties.component.ts
@@ -0,0 +1,10 @@
+import {Component, Input} from '@angular/core';
+
+@Component({
+ selector: 'tree-node-header-properties',
+ templateUrl: './tree-node-header-properties.component.html',
+ styleUrls: ['./tree-node-header-properties.component.scss']
+})
+export class TreeNodeHeaderPropertiesComponent {
+ @Input() properties : object[] = [];
+}