| /* |
| ****************************************************************************** |
| * Copyright © 2018 PTA GmbH. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * |
| * http://www.eclipse.org/legal/epl-v10.html |
| ****************************************************************************** |
| */ |
| import { |
| Component, OnInit, Input, OnChanges, SimpleChanges, ViewChild, AfterViewChecked, |
| ElementRef, OnDestroy, ChangeDetectorRef, AfterViewInit |
| } from '@angular/core'; |
| import { SingleGridMeasure } from '../../model/single-grid-measure'; |
| import { Step } from '../../model/step'; |
| import * as X2JS from '../../../assets/js/xml2json.min.js'; |
| import { ErrorType } from '../../common/enums'; |
| import { CimCacheService } from '../../services/cim-cache.service'; |
| import { PowerSystemResource } from './../../model/power-system-resource'; |
| import { FormGroup } from '@angular/forms'; |
| import { SessionContext } from './../../common/session-context'; |
| import { Subscription } from 'rxjs/Subscription'; |
| import { TreeModel, Tree } from 'ng2-tree'; |
| import { TreeModelImpl } from './../../model/TreeModelImpl'; |
| import { ToasterMessageService } from '../../services/toaster-message.service'; |
| |
| @Component({ |
| selector: 'app-step', |
| templateUrl: './step.component.html', |
| styleUrls: ['./step.component.css'] |
| }) |
| export class StepComponent implements OnInit, OnChanges, OnDestroy, AfterViewChecked, AfterViewInit { |
| @Input() isReadOnlyForm: boolean; |
| @Input() dateTimePattern: string; |
| @Input() dateFormatLocale: string; |
| @Input() isCollapsible = true; |
| @Input() singleGridMeasure: SingleGridMeasure; |
| |
| form: HTMLFormElement; |
| readOnlyForm: boolean; |
| stepFormValid: boolean; |
| isStatusCollapsed = true; |
| storageInProgress: boolean; |
| step: Step = new Step(); |
| currentPowerSystemResourceDB: PowerSystemResource; |
| stepAffectedResourcesString: PowerSystemResource; |
| stepAffectedResourcesGroupList = ['']; |
| stepAffectedResourcesList: Array<PowerSystemResource> = []; |
| subscription: Subscription; |
| tmpPowerSystemResource: PowerSystemResource; |
| inactiveFields: Array<string> = []; |
| treeIdCounter = 1; |
| tree: TreeModel = { value: '' }; |
| isTreeAvailable = false; |
| |
| @ViewChild('treeComponent') treeComponent; |
| @ViewChild('stepFormContainer') stepFormCotainer: ElementRef; |
| @ViewChild('stepForm') stepForm: FormGroup; |
| |
| constructor(private cimCacheService: CimCacheService, |
| private sessionContext: SessionContext, |
| private toasterMessageService: ToasterMessageService) { } |
| |
| ngOnInit() { |
| this.inactiveFields = this.sessionContext.getInactiveFields(); |
| this.getRessourceTypes(); |
| this.currentPowerSystemResourceDB = this.singleGridMeasure.powerSystemResource; |
| } |
| |
| ngAfterViewInit() { |
| this.initInactiveFields(); |
| } |
| |
| ngAfterViewChecked() { |
| if (this.stepForm) { |
| this.step._isValide = this.stepForm.valid; |
| } |
| } |
| |
| ngOnChanges(changes: SimpleChanges): void { |
| |
| if (changes['isReadOnlyForm']) { |
| this.readOnlyForm = changes['isReadOnlyForm'].currentValue; |
| this.initInactiveFields(); |
| } |
| } |
| |
| public initInactiveFields() { |
| const el: HTMLElement = this.stepFormCotainer.nativeElement as HTMLElement; |
| const fields = el.querySelectorAll('*[id]'); |
| for (let index = 0; index < fields.length; index++) { |
| const field = fields[index]; |
| if (this.readOnlyForm || this.isFieldInactive(field['id'])) { |
| field.setAttribute('disabled', 'disabled'); |
| } else { |
| field.removeAttribute('disabled'); |
| } |
| } |
| } |
| private isFieldInactive(fieldName: string): boolean { |
| return this.inactiveFields.filter(field => field === fieldName).length > 0; |
| } |
| |
| ngOnDestroy() { |
| } |
| |
| public onUseRessourceBtnClick(selectedVal: any) { |
| if (selectedVal) { |
| this.step.switchingObject = selectedVal; |
| } |
| } |
| |
| public processAddStep() { |
| |
| if (!this.isStepEmpty()) { |
| |
| const stepDeepCopy = JSON.parse(JSON.stringify(this.step)); |
| stepDeepCopy.id = -1; |
| |
| this.storageInProgress = true; |
| if (!this.singleGridMeasure.listSteps || this.singleGridMeasure.listSteps.length === 0) { |
| this.singleGridMeasure.listSteps = new Array(); |
| stepDeepCopy.sortorder = 1; |
| } else { |
| // stepDeepCopy.sortorder = this.singleGridMeasure.listSteps.length + 1; |
| stepDeepCopy.sortorder = this.singleGridMeasure.listSteps[this.singleGridMeasure.listSteps.length - 1].sortorder + 1; |
| } |
| |
| /* A simple push on liststeps (this.singleGridMeasure.listSteps.push(stepDeepCopy)) doesn't |
| trigger Angular to refresh the view-model. This is why you have to use the following way |
| which creates a "new" array (copy of the old) and appends it. */ |
| this.singleGridMeasure.listSteps = [...this.singleGridMeasure.listSteps, stepDeepCopy]; |
| |
| this.storageInProgress = false; |
| } else { |
| this.toasterMessageService.showWarn('Bitte alle Felder in Schrittsequenz aufüllen!'); |
| } |
| |
| } |
| |
| onStepFormValidation(valid: boolean) { |
| this.step._isValide = valid; |
| } |
| |
| isStepEmpty() { |
| if (!this.step.switchingObject || !this.step.targetState || !this.step.presentState |
| || !this.step.presentTime || !this.step.type || !this.step.operator) { |
| return true; |
| } else { |
| return false; |
| } |
| } |
| |
| onChangeResourceGroup(val) { |
| if (val) { |
| this.stepAffectedResourcesList = []; |
| this.getRessourceTypesWithType(val); |
| } else { |
| this.stepAffectedResourcesList = []; |
| this.isTreeAvailable = false; |
| } |
| } |
| |
| |
| private getRessourceTypes() { |
| this.cimCacheService.getRessourceTypes().subscribe(res => { |
| this.processRessourceTypesResponse(res); |
| }, |
| error => { |
| // this.messageService.emitError('CimCache', ErrorType.retrieve); |
| this.toasterMessageService.showError(ErrorType.retrieve, 'CimCache'); |
| console.log(error); |
| }); |
| } |
| |
| private async getRessourceTypesWithType(value: string) { |
| const newTreeModel: TreeModel = new TreeModelImpl(); |
| |
| const xmlStringRes = await this.cimCacheService.getRessourcesWithType(value).toPromise().catch(error => { |
| // this.messageService.emitError('CimCache', ErrorType.retrieve); |
| this.toasterMessageService.showError(ErrorType.retrieve, 'CimCache'); |
| }); |
| |
| this.stepAffectedResourcesList = this.processRessourceWithTypeResponse(xmlStringRes); |
| this.tmpPowerSystemResource = this.stepAffectedResourcesList[0]; |
| this.treeIdCounter = 1; |
| const newTreeChilds = await this.prepareTreeModel(this.stepAffectedResourcesList); |
| newTreeModel.children = newTreeChilds; |
| this.tree = newTreeModel; |
| } |
| |
| convertXmlToJsonObj(xml: string) { |
| return new X2JS().xml_str2json(xml); |
| } |
| |
| |
| processRessourceWithTypeResponse(res: string): Array<PowerSystemResource> { |
| if (!res) { |
| return; |
| } |
| const jsonObj = this.convertXmlToJsonObj(res); |
| const powerSystemResources = jsonObj.ResponseMessage.Payload.PowerSystemResources; |
| |
| const powerSystemResourceRetList = new Array<PowerSystemResource>(); |
| |
| /* tslint:disable */ |
| for (const prop in powerSystemResources) { |
| const anonymousPowerSystemResources = powerSystemResources[prop]; |
| |
| if (Array.isArray(anonymousPowerSystemResources)) { |
| anonymousPowerSystemResources.forEach(element => { |
| const powerSystemResource = new PowerSystemResource(); |
| powerSystemResource.cimId = element.mRID; |
| powerSystemResource.cimName = element.name; |
| powerSystemResource.cimDescription = element.description; |
| powerSystemResourceRetList.push(powerSystemResource); |
| }); |
| } else { |
| const powerSystemResource = new PowerSystemResource(); |
| powerSystemResource.cimId = anonymousPowerSystemResources.mRID; |
| powerSystemResource.cimName = anonymousPowerSystemResources.name; |
| powerSystemResource.cimDescription = anonymousPowerSystemResources.description; |
| powerSystemResourceRetList.push(powerSystemResource); |
| } |
| } |
| if (powerSystemResourceRetList.length === 0) { |
| // keine Daten "Objekt" |
| const powerSystemResource = new PowerSystemResource(); |
| powerSystemResource.cimId = '-1'; |
| powerSystemResource.cimName = 'keine Daten'; |
| powerSystemResourceRetList.push(powerSystemResource); |
| } |
| |
| /* tslint:enable */ |
| |
| return powerSystemResourceRetList; |
| |
| } |
| |
| handleSelected(tree: Tree) { |
| this.step.switchingObject = tree.node.value + ''; |
| } |
| |
| async handleNextLevel(tree: Tree) { |
| const currentNodeId = tree.node.id; |
| const oopNodeController = this.treeComponent.getControllerByNodeId(tree.node.id); |
| const nodeIdNr = +currentNodeId; |
| |
| // Für die richtige Anbindung auskommentieren bzw. Webservice für die "Objekt der Schaltung" implementieren |
| // Fehlt jdoch noch im CIM-Cache |
| /* const value = tree.node.value + ''; |
| const xmlStringRes = await this.cimCacheService.getRessourcesWithType(value).toPromise().catch(error => { |
| this.messageService.emitError('CimCache', ErrorType.retrieve); |
| }); */ |
| |
| // ...deswegen Fake Childs atm fest auf 'ac-line-segment' |
| const xmlStringRes = await this.cimCacheService.getRessourcesWithType('ac-line-segment').toPromise().catch(error => { |
| // this.messageService.emitError('CimCache', ErrorType.retrieve); |
| this.toasterMessageService.showError(ErrorType.retrieve, 'CimCache'); |
| }); |
| |
| const newTreeChildren = await this.prepareTreeModel(this.processRessourceWithTypeResponse(xmlStringRes), nodeIdNr); |
| |
| oopNodeController.setChildren(newTreeChildren); |
| } |
| |
| async prepareTreeModel(nodes: Array<PowerSystemResource>, treeId?: number) { |
| const newChildsLvl1: TreeModel[] = []; |
| |
| // richtige Variante jedoch noch nicht im CIM-Cache verfügbar |
| // const promises = nodes.map((pwrElementLvl1) => this.cimCacheService.getRessourcesWithType(pwrElementLvl1.cimName).toPromise()); |
| |
| // Fake Childs |
| const promises = nodes.map((pwrElementLvl1) => this.cimCacheService.getRessourcesWithType('substation-type').toPromise()); |
| const results = await Promise.all(promises); |
| |
| for (let index = 0; index < results.length; index++) { |
| const newChildsLvl2: TreeModel[] = []; |
| const asyncResult = results[index]; |
| const pwrElementLvl1 = nodes[index]; |
| const powerSystemResourceListLvl2 = this.processRessourceWithTypeResponse(asyncResult); |
| |
| if (powerSystemResourceListLvl2 && powerSystemResourceListLvl2.length > 0 && powerSystemResourceListLvl2[0].cimId !== '-1') { |
| // Childs vorhanden |
| newChildsLvl1.push({ |
| emitLoadNextLevel: true, id: this.treeIdCounter++, value: pwrElementLvl1.cimName, |
| valueObject: pwrElementLvl1, children: newChildsLvl2 |
| }); |
| this.isTreeAvailable = true; |
| } else { |
| // keine Childs vorhanden |
| newChildsLvl1.push({ |
| emitLoadNextLevel: false, id: this.treeIdCounter++, value: pwrElementLvl1.cimName, |
| valueObject: pwrElementLvl1 |
| }); |
| this.isTreeAvailable = false; |
| } |
| |
| } |
| |
| |
| return newChildsLvl1; |
| } |
| |
| processRessourceTypesResponse(res: string): void { |
| const jsonObj = this.convertXmlToJsonObj(res); |
| const PSRTypeList = jsonObj.ResponseMessage.Payload.PowerSystemResourceTypes.PSRType; |
| for (let index = 0; index < PSRTypeList.length; index++) { |
| this.stepAffectedResourcesGroupList.push(PSRTypeList[index].name); |
| } |
| } |
| |
| } |