import {Injectable} from "@angular/core"; import {ILevelNodeInfo} from "../models/basic.model.info"; import {ObjectToTreeService} from "../objectToTree.service"; import {DefaultDataGeneratorService} from "../../../../shared/services/defaultDataServiceGenerator/default.data.generator.service"; import * as _ from "lodash"; import {ServiceInstanceActions} from "../../../../shared/models/serviceInstanceActions"; import {ErrorMsgService} from "../../../../shared/components/error-msg/error-msg.service"; import {FeatureFlagsService, Features} from "../../../../shared/services/featureFlag/feature-flags.service"; import {NgRedux} from "@angular-redux/store"; import {AppState} from "../../../../shared/store/reducers"; import {SharedTreeService} from "../shared.tree.service"; @Injectable() export class ObjectToInstanceTreeService { constructor(private _objectToTreeService: ObjectToTreeService, private _errorMsgService: ErrorMsgService, private store: NgRedux, private _sharedTreeService: SharedTreeService) { this.numberOfFailed = 0; this.numberOfElements = 0; } /** store number of failed ******** ONLY IN RETRY MODE ******** **/ numberOfFailed: number = 0; /** store number of existing elements **/ numberOfElements: number = 0; /***************************************************************** * return array of first level node with there child's * @param serviceInstance - The service instance object from store * @param serviceHierarchy - The service Hierarchy store ****************************************************************/ convertServiceInstanceToTreeData(serviceInstance, serviceHierarchy): any[] { this._errorMsgService.triggerClearError.next(); let nodes = []; this.numberOfFailed = 0; this.numberOfElements = 0; let _this = this; const serviceModelId:string = serviceInstance.modelInfo.modelVersionId; const firstLevelOptions: ILevelNodeInfo[] = _this._objectToTreeService.getFirstLevelOptions(); for (let option of firstLevelOptions) { _.forOwn(serviceInstance[option.name], function (instance, modelName) { nodes.push(_this.getNodeInstance(modelName, null, instance, serviceHierarchy, option, serviceModelId)); }); } return this.sortElementsByPosition(nodes); } /***************************************************************** * should increase number of failed * @param node - the current node ****************************************************************/ increaseNumberOfFailed(node) { if (node && node.isFailed) { this.numberOfFailed++; node['errors'] = !_.isNil(node['errors']) ? node['errors'] : {}; node['errors']["isFailed"] = true; this._errorMsgService.triggerShowError.next(this._errorMsgService.getRetryErrorObject(this.numberOfFailed)); } } /***************************************************************** * should increase number of existing elements * @param node - the current node ****************************************************************/ increaseNumberOfExcitingElements() { this.numberOfElements++; } /***************************************************************** * return array of first level node with there child's * @param modelName * @param parentModel * @param instance * @param serviceHierarchy - The service Hierarchy store * @param option * @param serviceModelId * @param parentType ****************************************************************/ getNodeInstance(modelName: string, parentModel: any, instance: any, serviceHierarchy, option: ILevelNodeInfo, serviceModelId: string, parentType ?: string) { const instanceModel = this._sharedTreeService.modelByIdentifiers( serviceHierarchy, option.name, this._sharedTreeService.modelUniqueNameOrId(instance), modelName ); const model = option.getModel(instanceModel); let optionalNodes = option.createInstanceTreeNode(instance, model, parentModel, modelName, serviceModelId); this.increaseNumberOfFailed(optionalNodes); this.increaseNumberOfExcitingElements(); let nodes: any[] = _.isArray(optionalNodes) ? optionalNodes : [optionalNodes]; for (let node of nodes) { node = this.addingExtraDataToNode(node, modelName, parentModel, instance, serviceHierarchy, option, parentType); let children = this.addNextInstanceTreeNode(instance, model, option, node, serviceHierarchy, serviceModelId); if (!_.isNil(children) && children.length > 0) { node.children = this.sortElementsByPosition(children); } this.updateScalingPolicy(node); } return nodes.length === 1 ? nodes[0] : nodes; } addingExtraDataToNode(node, modelName: string, parentModel: any, instance: any, serviceHierarchy, option: ILevelNodeInfo, parentType ?: string) { if(!_.isNil(node)){ node.trackById = _.isNil(node.trackById) ? DefaultDataGeneratorService.createRandomTrackById() : node['trackById']; node.parentType = !_.isNil(parentType) ? parentType : ""; node.updatePoistionFunction = option.updatePosition; node.position = option.getNodePosition(instance, node.dynamicModelName); node.modelTypeName = option.name; node.getModel = option.getModel.bind(option); node.getInfo = !_.isNil(option.getInfo) ? option.getInfo.bind(option) : ()=>{}; node.componentInfoType = option.componentInfoType; } return node; } sortElementsByPosition(nodes: any[]): any[] { if (!FeatureFlagsService.getFlagState(Features.FLAG_1911_INSTANTIATION_ORDER_IN_ASYNC_ALACARTE, this.store)) return nodes; return nodes.sort((nodeA, nodeB) => { return nodeA.position - nodeB.position; }); } /***************************************************************** * return next level node with there child's * @param parentInstance * @param parentModel * @param levelNodeInfo * @param parentNode * @param serviceHierarchy - The service Hierarchy store * @param serviceModelId ****************************************************************/ addNextInstanceTreeNode(parentInstance, parentModel, levelNodeInfo: ILevelNodeInfo, parentNode, serviceHierarchy, serviceModelId: string): any[] { if (!_.isNil(levelNodeInfo.childNames)&& levelNodeInfo.childNames.length > 0) { const that = this; parentNode.children = []; levelNodeInfo.childNames.forEach(function (childName) { if (!_.isNil(parentInstance[childName])) { let parentType = levelNodeInfo.type; let nextLevelNodeInfo = levelNodeInfo.getNextLevelObject.apply(that, [childName]); Object.keys(parentInstance[childName]).map((modelName) => { let nextLevelInstance = parentInstance[childName][modelName]; let nodes: any[] | any = that.getNodeInstance(modelName, parentModel, nextLevelInstance, serviceHierarchy, nextLevelNodeInfo, serviceModelId, parentType); if (_.isArray(nodes)) { parentNode.children = parentNode.children.concat(nodes); } else { parentNode.children.push(nodes); } }); } }); return this.sortElementsByPosition(parentNode.children); } return !_.isNil(parentNode) ? parentNode.children : null; } /************************************************************************************ * update instance scaling policy according to instance limit and existing children * @param node *********************************************************************************/ updateScalingPolicy(node): void { if(_.isNil(node)) return node; node['errors'] = !_.isNil(node['errors']) ? node['errors'] : {}; if (!_.isNil(node['limitMembers']) && !_.isNil(node.children)) { let effectiveChildren = (node.children).filter(child => [ ServiceInstanceActions.Create, ServiceInstanceActions.None, ServiceInstanceActions.Update ].includes(child.action)); if (effectiveChildren.length > node.limitMembers) { node['errors']["scalingError"] = true; this._errorMsgService.triggerShowError.next(this._errorMsgService.getScalingErrorObject()); } else { delete node['errors']["scalingError"]; } } } }